aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/access/access.cpp12
-rw-r--r--engines/access/access.h2
-rw-r--r--engines/access/detection.cpp12
-rw-r--r--engines/access/scripts.cpp2
-rw-r--r--engines/adl/detection.cpp75
-rw-r--r--engines/adl/graphics.cpp2
-rw-r--r--engines/advancedDetector.cpp332
-rw-r--r--engines/advancedDetector.h89
-rw-r--r--engines/agi/detection.cpp14
-rw-r--r--engines/agos/detection.cpp2
-rw-r--r--engines/agos/detection_tables.h150
-rw-r--r--engines/agos/intern.h3
-rw-r--r--engines/agos/midi.cpp12
-rw-r--r--engines/agos/sound.cpp2
-rw-r--r--engines/agos/string.cpp2
-rw-r--r--engines/avalanche/avalanche.cpp8
-rw-r--r--engines/avalanche/avalanche.h7
-rw-r--r--engines/avalanche/detection.cpp15
-rw-r--r--engines/avalanche/dropdown.cpp4
-rw-r--r--engines/bbvs/bbvs.h2
-rw-r--r--engines/bbvs/detection.cpp4
-rw-r--r--engines/bbvs/saveload.cpp10
-rw-r--r--engines/bladerunner/actor.cpp296
-rw-r--r--engines/bladerunner/actor.h77
-rw-r--r--engines/bladerunner/actor_clues.cpp186
-rw-r--r--engines/bladerunner/actor_clues.h23
-rw-r--r--engines/bladerunner/actor_combat.cpp654
-rw-r--r--engines/bladerunner/actor_combat.h79
-rw-r--r--engines/bladerunner/actor_dialogue_queue.cpp58
-rw-r--r--engines/bladerunner/actor_dialogue_queue.h8
-rw-r--r--engines/bladerunner/actor_walk.cpp48
-rw-r--r--engines/bladerunner/actor_walk.h5
-rw-r--r--engines/bladerunner/ambient_sounds.cpp122
-rw-r--r--engines/bladerunner/ambient_sounds.h51
-rw-r--r--engines/bladerunner/archive.cpp30
-rw-r--r--engines/bladerunner/archive.h7
-rw-r--r--engines/bladerunner/aud_stream.cpp7
-rw-r--r--engines/bladerunner/audio_player.cpp2
-rw-r--r--engines/bladerunner/audio_speech.cpp10
-rw-r--r--engines/bladerunner/audio_speech.h3
-rw-r--r--engines/bladerunner/bladerunner.cpp306
-rw-r--r--engines/bladerunner/bladerunner.h25
-rw-r--r--engines/bladerunner/boundingbox.cpp2
-rw-r--r--engines/bladerunner/boundingbox.h2
-rw-r--r--engines/bladerunner/chapters.cpp3
-rw-r--r--engines/bladerunner/combat.cpp126
-rw-r--r--engines/bladerunner/combat.h45
-rw-r--r--engines/bladerunner/crimes_database.cpp16
-rw-r--r--engines/bladerunner/crimes_database.h7
-rw-r--r--engines/bladerunner/debugger.cpp75
-rw-r--r--engines/bladerunner/debugger.h2
-rw-r--r--engines/bladerunner/detection_tables.h32
-rw-r--r--engines/bladerunner/dialogue_menu.cpp51
-rw-r--r--engines/bladerunner/dialogue_menu.h6
-rw-r--r--engines/bladerunner/fog.cpp7
-rw-r--r--engines/bladerunner/fog.h3
-rw-r--r--engines/bladerunner/font.cpp8
-rw-r--r--engines/bladerunner/font.h1
-rw-r--r--engines/bladerunner/game_constants.h60
-rw-r--r--engines/bladerunner/game_flags.cpp16
-rw-r--r--engines/bladerunner/game_flags.h6
-rw-r--r--engines/bladerunner/game_info.cpp66
-rw-r--r--engines/bladerunner/game_info.h18
-rw-r--r--engines/bladerunner/item.cpp70
-rw-r--r--engines/bladerunner/item.h20
-rw-r--r--engines/bladerunner/item_pickup.h2
-rw-r--r--engines/bladerunner/items.cpp141
-rw-r--r--engines/bladerunner/items.h22
-rw-r--r--engines/bladerunner/light.cpp4
-rw-r--r--engines/bladerunner/light.h3
-rw-r--r--engines/bladerunner/matrix.h4
-rw-r--r--engines/bladerunner/module.mk14
-rw-r--r--engines/bladerunner/mouse.cpp67
-rw-r--r--engines/bladerunner/mouse.h7
-rw-r--r--engines/bladerunner/movement_track.cpp30
-rw-r--r--engines/bladerunner/movement_track.h5
-rw-r--r--engines/bladerunner/music.cpp63
-rw-r--r--engines/bladerunner/music.h11
-rw-r--r--engines/bladerunner/obstacles.cpp502
-rw-r--r--engines/bladerunner/obstacles.h68
-rw-r--r--engines/bladerunner/overlays.cpp53
-rw-r--r--engines/bladerunner/overlays.h22
-rw-r--r--engines/bladerunner/rect.h75
-rw-r--r--engines/bladerunner/regions.cpp20
-rw-r--r--engines/bladerunner/regions.h6
-rw-r--r--engines/bladerunner/savefile.cpp166
-rw-r--r--engines/bladerunner/savefile.h75
-rw-r--r--engines/bladerunner/scene.cpp42
-rw-r--r--engines/bladerunner/scene.h11
-rw-r--r--engines/bladerunner/scene_objects.cpp81
-rw-r--r--engines/bladerunner/scene_objects.h38
-rw-r--r--engines/bladerunner/screen_effects.h14
-rw-r--r--engines/bladerunner/script/ai/bullet_bob.cpp555
-rw-r--r--engines/bladerunner/script/ai/clovis.cpp216
-rw-r--r--engines/bladerunner/script/ai/dektora.cpp10
-rw-r--r--engines/bladerunner/script/ai/early_q.cpp1037
-rw-r--r--engines/bladerunner/script/ai/free_slot_a.cpp659
-rw-r--r--engines/bladerunner/script/ai/free_slot_b.cpp541
-rw-r--r--engines/bladerunner/script/ai/gaff.cpp2
-rw-r--r--engines/bladerunner/script/ai/generic_walker_a.cpp5
-rw-r--r--engines/bladerunner/script/ai/generic_walker_b.cpp5
-rw-r--r--engines/bladerunner/script/ai/generic_walker_c.cpp5
-rw-r--r--engines/bladerunner/script/ai/gordo.cpp2
-rw-r--r--engines/bladerunner/script/ai/guzza.cpp2
-rw-r--r--engines/bladerunner/script/ai/hanoi.cpp740
-rw-r--r--engines/bladerunner/script/ai/hasan.cpp315
-rw-r--r--engines/bladerunner/script/ai/hysteria_patron1.cpp2
-rw-r--r--engines/bladerunner/script/ai/leon.cpp2
-rw-r--r--engines/bladerunner/script/ai/lucy.cpp6
-rw-r--r--engines/bladerunner/script/ai/luther.cpp439
-rw-r--r--engines/bladerunner/script/ai/mccoy.cpp36
-rw-r--r--engines/bladerunner/script/ai/mutant1.cpp15
-rw-r--r--engines/bladerunner/script/ai/mutant2.cpp12
-rw-r--r--engines/bladerunner/script/ai/mutant3.cpp12
-rw-r--r--engines/bladerunner/script/ai/officer_grayford.cpp1422
-rw-r--r--engines/bladerunner/script/ai/officer_leary.cpp2
-rw-r--r--engines/bladerunner/script/ai/rajif.cpp2
-rw-r--r--engines/bladerunner/script/ai/sadik.cpp1039
-rw-r--r--engines/bladerunner/script/ai/steele.cpp2
-rw-r--r--engines/bladerunner/script/ai/taffy_patron.cpp6
-rw-r--r--engines/bladerunner/script/ai/zuben.cpp4
-rw-r--r--engines/bladerunner/script/ai_script.cpp51
-rw-r--r--engines/bladerunner/script/ai_script.h76
-rw-r--r--engines/bladerunner/script/police_maze.cpp603
-rw-r--r--engines/bladerunner/script/police_maze.h106
-rw-r--r--engines/bladerunner/script/scene/ct07.cpp2
-rw-r--r--engines/bladerunner/script/scene/ct11.cpp8
-rw-r--r--engines/bladerunner/script/scene/ct12.cpp2
-rw-r--r--engines/bladerunner/script/scene/dr02.cpp2
-rw-r--r--engines/bladerunner/script/scene/dr04.cpp2
-rw-r--r--engines/bladerunner/script/scene/dr06.cpp4
-rw-r--r--engines/bladerunner/script/scene/hf01.cpp12
-rw-r--r--engines/bladerunner/script/scene/hf03.cpp4
-rw-r--r--engines/bladerunner/script/scene/hf05.cpp20
-rw-r--r--engines/bladerunner/script/scene/hf06.cpp13
-rw-r--r--engines/bladerunner/script/scene/hf07.cpp8
-rw-r--r--engines/bladerunner/script/scene/kp05.cpp2
-rw-r--r--engines/bladerunner/script/scene/ma04.cpp4
-rw-r--r--engines/bladerunner/script/scene/nr01.cpp2
-rw-r--r--engines/bladerunner/script/scene/nr04.cpp2
-rw-r--r--engines/bladerunner/script/scene/nr09.cpp2
-rw-r--r--engines/bladerunner/script/scene/nr11.cpp6
-rw-r--r--engines/bladerunner/script/scene/ps10.cpp459
-rw-r--r--engines/bladerunner/script/scene/ps11.cpp2
-rw-r--r--engines/bladerunner/script/scene/ps12.cpp8
-rw-r--r--engines/bladerunner/script/scene/ps13.cpp8
-rw-r--r--engines/bladerunner/script/scene/rc01.cpp2
-rw-r--r--engines/bladerunner/script/scene/tb05.cpp4
-rw-r--r--engines/bladerunner/script/scene/ug02.cpp4
-rw-r--r--engines/bladerunner/script/scene/ug05.cpp4
-rw-r--r--engines/bladerunner/script/scene/ug07.cpp2
-rw-r--r--engines/bladerunner/script/scene/ug15.cpp4
-rw-r--r--engines/bladerunner/script/scene/ug18.cpp5
-rw-r--r--engines/bladerunner/script/scene_script.cpp2
-rw-r--r--engines/bladerunner/script/scene_script.h2
-rw-r--r--engines/bladerunner/script/script.cpp116
-rw-r--r--engines/bladerunner/script/script.h26
-rw-r--r--engines/bladerunner/script/vk_script.cpp8
-rw-r--r--engines/bladerunner/set.cpp93
-rw-r--r--engines/bladerunner/set.h34
-rw-r--r--engines/bladerunner/set_effects.cpp8
-rw-r--r--engines/bladerunner/set_effects.h6
-rw-r--r--engines/bladerunner/settings.cpp61
-rw-r--r--engines/bladerunner/settings.h22
-rw-r--r--engines/bladerunner/slice_animations.cpp32
-rw-r--r--engines/bladerunner/slice_animations.h6
-rw-r--r--engines/bladerunner/slice_renderer.cpp134
-rw-r--r--engines/bladerunner/slice_renderer.h2
-rw-r--r--engines/bladerunner/text_resource.cpp6
-rw-r--r--engines/bladerunner/time.cpp68
-rw-r--r--engines/bladerunner/time.h50
-rw-r--r--engines/bladerunner/ui/elevator.cpp3
-rw-r--r--engines/bladerunner/ui/end_credits.cpp170
-rw-r--r--engines/bladerunner/ui/end_credits.h42
-rw-r--r--engines/bladerunner/ui/kia.cpp2
-rw-r--r--engines/bladerunner/ui/kia_log.cpp2
-rw-r--r--engines/bladerunner/ui/kia_log.h2
-rw-r--r--engines/bladerunner/ui/scores.cpp218
-rw-r--r--engines/bladerunner/ui/scores.h82
-rw-r--r--engines/bladerunner/ui/spinner.cpp15
-rw-r--r--engines/bladerunner/ui/spinner.h7
-rw-r--r--engines/bladerunner/ui/ui_scroll_box.cpp5
-rw-r--r--engines/bladerunner/vector.h12
-rw-r--r--engines/bladerunner/view.cpp19
-rw-r--r--engines/bladerunner/waypoints.cpp22
-rw-r--r--engines/bladerunner/waypoints.h6
-rw-r--r--engines/cge/cge.h9
-rw-r--r--engines/cge/cge_main.cpp35
-rw-r--r--engines/cge/detection.cpp55
-rw-r--r--engines/cge/vga13h.cpp2
-rw-r--r--engines/cge2/cge2.h12
-rw-r--r--engines/cge2/detection.cpp55
-rw-r--r--engines/cge2/events.cpp1
-rw-r--r--engines/cge2/saveload.cpp36
-rw-r--r--engines/cge2/vga13h.cpp4
-rw-r--r--engines/chewy/chewy.cpp2
-rw-r--r--engines/chewy/console.cpp2
-rw-r--r--engines/chewy/detection.cpp4
-rw-r--r--engines/chewy/scene.cpp6
-rw-r--r--engines/cine/detection.cpp2
-rw-r--r--engines/cine/sound.cpp6
-rw-r--r--engines/composer/detection.cpp4
-rw-r--r--engines/cruise/detection.cpp11
-rw-r--r--engines/cruise/saveload.cpp13
-rw-r--r--engines/cruise/saveload.h2
-rw-r--r--engines/cruise/sound.cpp6
-rw-r--r--engines/cryo/cryo.h3
-rw-r--r--engines/cryo/eden.cpp5
-rw-r--r--engines/cryo/sound.cpp226
-rw-r--r--engines/cryo/sound.h140
-rw-r--r--engines/cryo/video.cpp2
-rw-r--r--engines/director/detection.cpp8
-rw-r--r--engines/director/frame.cpp2
-rw-r--r--engines/director/lingo/lingo-gr.cpp8
-rw-r--r--engines/director/lingo/lingo-lex.cpp42
-rw-r--r--engines/director/resource.cpp2
-rw-r--r--engines/dm/dm.h2
-rw-r--r--engines/dm/dungeonman.cpp1
-rw-r--r--engines/dm/gfx.cpp23
-rw-r--r--engines/dm/group.cpp1
-rw-r--r--engines/dm/loadsave.cpp13
-rw-r--r--engines/dm/menus.cpp5
-rw-r--r--engines/dm/projexpl.cpp2
-rw-r--r--engines/draci/detection.cpp10
-rw-r--r--engines/draci/game.cpp2
-rw-r--r--engines/draci/game.h2
-rw-r--r--engines/draci/saveload.cpp15
-rw-r--r--engines/draci/saveload.h2
-rw-r--r--engines/drascula/detection.cpp6
-rw-r--r--engines/dreamweb/detection.cpp7
-rw-r--r--engines/fullpipe/detection.cpp8
-rw-r--r--engines/fullpipe/gameloader.h4
-rw-r--r--engines/fullpipe/interaction.h3
-rw-r--r--engines/fullpipe/modal.cpp19
-rw-r--r--engines/fullpipe/scenes/scene22.cpp2
-rw-r--r--engines/fullpipe/stateloader.cpp33
-rw-r--r--engines/fullpipe/utils.cpp4
-rw-r--r--engines/game.cpp222
-rw-r--r--engines/game.h176
-rw-r--r--engines/gnap/detection.cpp15
-rw-r--r--engines/gnap/gnap.cpp2
-rw-r--r--engines/gnap/gnap.h2
-rw-r--r--engines/gnap/menu.cpp7
-rw-r--r--engines/gob/detection/detection.cpp29
-rw-r--r--engines/hopkins/computer.cpp4
-rw-r--r--engines/hopkins/detection.cpp9
-rw-r--r--engines/hopkins/dialogs.cpp6
-rw-r--r--engines/hopkins/font.cpp4
-rw-r--r--engines/hopkins/hopkins.cpp44
-rw-r--r--engines/hopkins/objects.cpp4
-rw-r--r--engines/hopkins/saveload.cpp19
-rw-r--r--engines/hopkins/saveload.h4
-rw-r--r--engines/hopkins/talk.cpp16
-rw-r--r--engines/hugo/detection.cpp7
-rw-r--r--engines/hugo/hugo.cpp1
-rw-r--r--engines/kyra/detection.cpp4
-rw-r--r--engines/kyra/eobcommon.h2
-rw-r--r--engines/kyra/kyra_v1.h2
-rw-r--r--engines/kyra/saveload.cpp11
-rw-r--r--engines/kyra/screen_eob.cpp4
-rw-r--r--engines/kyra/sequences_darkmoon.cpp2
-rw-r--r--engines/kyra/sequences_hof.cpp2
-rw-r--r--engines/kyra/sequences_lok.cpp2
-rw-r--r--engines/kyra/sound_digital.cpp8
-rw-r--r--engines/kyra/sound_intern.h72
-rw-r--r--engines/lab/lab.h2
-rw-r--r--engines/lab/map.cpp6
-rw-r--r--engines/lab/savegame.cpp14
-rw-r--r--engines/lastexpress/menu/menu.cpp2
-rw-r--r--engines/lilliput/configure.engine3
-rw-r--r--engines/lilliput/console.cpp (renamed from engines/sludge/transition.h)20
-rw-r--r--engines/lilliput/console.h49
-rw-r--r--engines/lilliput/detection.cpp292
-rw-r--r--engines/lilliput/lilliput.cpp2856
-rw-r--r--engines/lilliput/lilliput.h384
-rw-r--r--engines/lilliput/module.mk20
-rw-r--r--engines/lilliput/script.cpp3355
-rw-r--r--engines/lilliput/script.h316
-rw-r--r--engines/lilliput/sound.cpp248
-rw-r--r--engines/lilliput/sound.h71
-rw-r--r--engines/lilliput/stream.cpp42
-rw-r--r--engines/lilliput/stream.h42
-rw-r--r--engines/lure/sound.cpp5
-rw-r--r--engines/macventure/detection.cpp19
-rw-r--r--engines/macventure/saveload.cpp9
-rw-r--r--engines/made/detection.cpp6
-rw-r--r--engines/made/resource.cpp3
-rw-r--r--engines/mads/detection.cpp12
-rw-r--r--engines/mads/game.cpp12
-rw-r--r--engines/mads/game.h2
-rw-r--r--engines/mads/nebular/game_nebular.cpp5
-rw-r--r--engines/mads/nebular/nebular_scenes4.cpp4
-rw-r--r--engines/metaengine.h21
-rw-r--r--engines/mohawk/bitmap.cpp8
-rw-r--r--engines/mohawk/bitmap.h22
-rw-r--r--engines/mohawk/console.h12
-rw-r--r--engines/mohawk/cstime.h4
-rw-r--r--engines/mohawk/cursors.cpp8
-rw-r--r--engines/mohawk/cursors.h54
-rw-r--r--engines/mohawk/detection.cpp40
-rw-r--r--engines/mohawk/detection_tables.h233
-rw-r--r--engines/mohawk/dialogs.cpp37
-rw-r--r--engines/mohawk/dialogs.h34
-rw-r--r--engines/mohawk/graphics.cpp4
-rw-r--r--engines/mohawk/graphics.h2
-rw-r--r--engines/mohawk/installer_archive.cpp6
-rw-r--r--engines/mohawk/installer_archive.h12
-rw-r--r--engines/mohawk/livingbooks.cpp1
-rw-r--r--engines/mohawk/livingbooks.h4
-rw-r--r--engines/mohawk/livingbooks_code.cpp3
-rw-r--r--engines/mohawk/mohawk.cpp8
-rw-r--r--engines/mohawk/mohawk.h17
-rw-r--r--engines/mohawk/myst.cpp287
-rw-r--r--engines/mohawk/myst.h19
-rw-r--r--engines/mohawk/myst_areas.cpp58
-rw-r--r--engines/mohawk/myst_areas.h54
-rw-r--r--engines/mohawk/myst_graphics.cpp9
-rw-r--r--engines/mohawk/myst_graphics.h5
-rw-r--r--engines/mohawk/myst_scripts.cpp29
-rw-r--r--engines/mohawk/myst_scripts.h3
-rw-r--r--engines/mohawk/myst_sound.h2
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp28
-rw-r--r--engines/mohawk/myst_stacks/channelwood.h6
-rw-r--r--engines/mohawk/myst_stacks/credits.cpp13
-rw-r--r--engines/mohawk/myst_stacks/credits.h4
-rw-r--r--engines/mohawk/myst_stacks/demo.cpp8
-rw-r--r--engines/mohawk/myst_stacks/demo.h6
-rw-r--r--engines/mohawk/myst_stacks/dni.cpp40
-rw-r--r--engines/mohawk/myst_stacks/dni.h4
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp9
-rw-r--r--engines/mohawk/myst_stacks/intro.h4
-rw-r--r--engines/mohawk/myst_stacks/makingof.cpp3
-rw-r--r--engines/mohawk/myst_stacks/makingof.h4
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp56
-rw-r--r--engines/mohawk/myst_stacks/mechanical.h6
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp313
-rw-r--r--engines/mohawk/myst_stacks/myst.h22
-rw-r--r--engines/mohawk/myst_stacks/preview.cpp15
-rw-r--r--engines/mohawk/myst_stacks/preview.h4
-rw-r--r--engines/mohawk/myst_stacks/selenitic.cpp84
-rw-r--r--engines/mohawk/myst_stacks/selenitic.h16
-rw-r--r--engines/mohawk/myst_stacks/slides.cpp8
-rw-r--r--engines/mohawk/myst_stacks/slides.h4
-rw-r--r--engines/mohawk/myst_stacks/stoneship.cpp49
-rw-r--r--engines/mohawk/myst_stacks/stoneship.h6
-rw-r--r--engines/mohawk/myst_state.cpp71
-rw-r--r--engines/mohawk/myst_state.h58
-rw-r--r--engines/mohawk/resource.cpp4
-rw-r--r--engines/mohawk/resource.h20
-rw-r--r--engines/mohawk/resource_cache.cpp4
-rw-r--r--engines/mohawk/riven.cpp35
-rw-r--r--engines/mohawk/riven.h18
-rw-r--r--engines/mohawk/riven_card.cpp150
-rw-r--r--engines/mohawk/riven_card.h3
-rw-r--r--engines/mohawk/riven_graphics.cpp40
-rw-r--r--engines/mohawk/riven_graphics.h10
-rw-r--r--engines/mohawk/riven_inventory.h2
-rw-r--r--engines/mohawk/riven_saveload.cpp69
-rw-r--r--engines/mohawk/riven_saveload.h9
-rw-r--r--engines/mohawk/riven_scripts.cpp18
-rw-r--r--engines/mohawk/riven_sound.h2
-rw-r--r--engines/mohawk/riven_stacks/jspit.cpp2
-rw-r--r--engines/mohawk/riven_stacks/pspit.cpp15
-rw-r--r--engines/mohawk/riven_video.h2
-rw-r--r--engines/mohawk/sound.cpp96
-rw-r--r--engines/mohawk/sound.h11
-rw-r--r--engines/mohawk/video.cpp6
-rw-r--r--engines/mohawk/video.h2
-rw-r--r--engines/mohawk/view.cpp68
-rw-r--r--engines/mortevielle/mortevielle.h1
-rw-r--r--engines/mortevielle/saveload.cpp22
-rw-r--r--engines/mortevielle/saveload.h3
-rw-r--r--engines/neverhood/detection.cpp4
-rw-r--r--engines/neverhood/menumodule.cpp2
-rw-r--r--engines/neverhood/neverhood.h2
-rw-r--r--engines/neverhood/saveload.cpp10
-rw-r--r--engines/obsolete.cpp10
-rw-r--r--engines/obsolete.h2
-rw-r--r--engines/pegasus/items/biochips/pegasuschip.h2
-rw-r--r--engines/plumbers/console.cpp2
-rw-r--r--engines/plumbers/console.h5
-rw-r--r--engines/plumbers/plumbers.cpp16
-rw-r--r--engines/plumbers/plumbers.h5
-rw-r--r--engines/prince/archive.cpp12
-rw-r--r--engines/prince/cursor.cpp99
-rw-r--r--engines/prince/decompress.cpp254
-rw-r--r--engines/prince/detection.cpp38
-rw-r--r--engines/prince/draw.cpp765
-rw-r--r--engines/prince/hero.cpp2
-rw-r--r--engines/prince/inventory.cpp709
-rw-r--r--engines/prince/mob.cpp158
-rw-r--r--engines/prince/module.mk7
-rw-r--r--engines/prince/music.cpp236
-rw-r--r--engines/prince/music.h (renamed from engines/prince/sound.h)4
-rw-r--r--engines/prince/object.cpp3
-rw-r--r--engines/prince/option_text.h19
-rw-r--r--engines/prince/prince.cpp3696
-rw-r--r--engines/prince/prince.h20
-rw-r--r--engines/prince/pscr.cpp3
-rw-r--r--engines/prince/resource.cpp371
-rw-r--r--engines/prince/resource.h103
-rw-r--r--engines/prince/saveload.cpp67
-rw-r--r--engines/prince/script.cpp37
-rw-r--r--engines/prince/sound.cpp264
-rw-r--r--engines/prince/walk.cpp1610
-rw-r--r--engines/queen/detection.cpp49
-rw-r--r--engines/queen/music.cpp5
-rw-r--r--engines/saga/detection.cpp8
-rw-r--r--engines/saga/events.cpp2
-rw-r--r--engines/saga/interface.cpp4
-rw-r--r--engines/saga/isomap.cpp100
-rw-r--r--engines/saga/isomap.h14
-rw-r--r--engines/saga/puzzle.cpp22
-rw-r--r--engines/saga/resource_hrs.cpp1
-rw-r--r--engines/saga/resource_res.cpp2
-rw-r--r--engines/sci/detection.cpp23
-rw-r--r--engines/sci/engine/kgraphics.cpp1
-rw-r--r--engines/sci/engine/kpathing.cpp2
-rw-r--r--engines/sci/event.cpp2
-rw-r--r--engines/sci/graphics/animate.cpp5
-rw-r--r--engines/sci/graphics/celobj32.h3
-rw-r--r--engines/sci/graphics/palette.cpp59
-rw-r--r--engines/sci/graphics/palette.h3
-rw-r--r--engines/sci/sound/drivers/midi.cpp26
-rw-r--r--engines/scumm/camera.cpp15
-rw-r--r--engines/scumm/configure.engine2
-rw-r--r--engines/scumm/detection.cpp37
-rw-r--r--engines/scumm/dialogs.h10
-rw-r--r--engines/scumm/he/moonbase/ai_main.cpp12
-rw-r--r--engines/scumm/imuse/imuse.cpp7
-rw-r--r--engines/scumm/imuse_digi/dimuse_track.h2
-rw-r--r--engines/scumm/input.cpp2
-rw-r--r--engines/scumm/object.cpp18
-rw-r--r--engines/scumm/players/player_ad.cpp1
-rw-r--r--engines/scumm/players/player_nes.cpp6
-rw-r--r--engines/scumm/players/player_towns.cpp3
-rw-r--r--engines/scumm/saveload.cpp4
-rw-r--r--engines/scumm/script_v2.cpp7
-rw-r--r--engines/scumm/scumm.cpp4
-rw-r--r--engines/sherlock/detection.cpp7
-rw-r--r--engines/sherlock/image_file.cpp20
-rw-r--r--engines/sherlock/music.cpp4
-rw-r--r--engines/sherlock/objects.h2
-rw-r--r--engines/sherlock/resources.cpp17
-rw-r--r--engines/sherlock/saveload.cpp22
-rw-r--r--engines/sherlock/saveload.h2
-rw-r--r--engines/sherlock/scalpel/scalpel.cpp4
-rw-r--r--engines/sherlock/sherlock.cpp4
-rw-r--r--engines/sherlock/tattoo/tattoo_people.cpp2
-rw-r--r--engines/sky/detection.cpp33
-rw-r--r--engines/sludge/backdrop.cpp30
-rw-r--r--engines/sludge/bg_effects.cpp8
-rw-r--r--engines/sludge/builtin.cpp706
-rw-r--r--engines/sludge/builtin.h2
-rw-r--r--engines/sludge/csludge.h2
-rw-r--r--engines/sludge/cursors.cpp23
-rw-r--r--engines/sludge/cursors.h2
-rw-r--r--engines/sludge/detection.cpp22
-rw-r--r--engines/sludge/event.cpp26
-rw-r--r--engines/sludge/event.h2
-rw-r--r--engines/sludge/fileset.cpp27
-rw-r--r--engines/sludge/fileset.h8
-rw-r--r--engines/sludge/floor.cpp296
-rw-r--r--engines/sludge/floor.h41
-rw-r--r--engines/sludge/fonttext.cpp16
-rw-r--r--engines/sludge/fonttext.h9
-rw-r--r--engines/sludge/freeze.cpp22
-rw-r--r--engines/sludge/freeze.h10
-rw-r--r--engines/sludge/function.cpp788
-rw-r--r--engines/sludge/function.h73
-rw-r--r--engines/sludge/functionlist.h338
-rw-r--r--engines/sludge/graphics.cpp11
-rw-r--r--engines/sludge/graphics.h24
-rw-r--r--engines/sludge/loadsave.cpp351
-rw-r--r--engines/sludge/loadsave.h15
-rw-r--r--engines/sludge/main_loop.cpp10
-rw-r--r--engines/sludge/module.mk1
-rw-r--r--engines/sludge/moreio.cpp11
-rw-r--r--engines/sludge/moreio.h2
-rw-r--r--engines/sludge/movie.cpp3
-rw-r--r--engines/sludge/newfatal.cpp79
-rw-r--r--engines/sludge/newfatal.h42
-rw-r--r--engines/sludge/people.cpp804
-rw-r--r--engines/sludge/people.h165
-rw-r--r--engines/sludge/region.cpp167
-rw-r--r--engines/sludge/region.h50
-rw-r--r--engines/sludge/savedata.cpp158
-rw-r--r--engines/sludge/savedata.h22
-rw-r--r--engines/sludge/sludge.cpp21
-rw-r--r--engines/sludge/sludge.h11
-rw-r--r--engines/sludge/sludger.cpp795
-rw-r--r--engines/sludge/sludger.h42
-rw-r--r--engines/sludge/sound.cpp2
-rw-r--r--engines/sludge/speech.cpp67
-rw-r--r--engines/sludge/speech.h6
-rw-r--r--engines/sludge/sprites.h29
-rw-r--r--engines/sludge/statusba.cpp18
-rw-r--r--engines/sludge/thumbnail.cpp23
-rw-r--r--engines/sludge/timing.cpp54
-rw-r--r--engines/sludge/timing.h24
-rw-r--r--engines/sludge/transition.cpp19
-rw-r--r--engines/sludge/variable.cpp511
-rw-r--r--engines/sludge/variable.h107
-rw-r--r--engines/supernova/detection.cpp25
-rw-r--r--engines/supernova/graphics.cpp25
-rw-r--r--engines/supernova/graphics.h6
-rw-r--r--engines/supernova/imageid.h654
-rw-r--r--engines/supernova/module.mk7
-rw-r--r--engines/supernova/msn_def.h292
-rw-r--r--engines/supernova/resman.cpp395
-rw-r--r--engines/supernova/resman.h77
-rw-r--r--engines/supernova/rooms.cpp403
-rw-r--r--engines/supernova/rooms.h45
-rw-r--r--engines/supernova/screen.cpp636
-rw-r--r--engines/supernova/screen.h197
-rw-r--r--engines/supernova/screenstatic.cpp328
-rw-r--r--engines/supernova/sound.cpp65
-rw-r--r--engines/supernova/sound.h80
-rw-r--r--engines/supernova/state.cpp371
-rw-r--r--engines/supernova/state.h37
-rw-r--r--engines/supernova/supernova.cpp858
-rw-r--r--engines/supernova/supernova.h174
-rw-r--r--engines/sword1/detection.cpp80
-rw-r--r--engines/sword2/sword2.cpp35
-rw-r--r--engines/sword25/gfx/graphicengine.cpp10
-rw-r--r--engines/sword25/sfx/soundengine.cpp2
-rw-r--r--engines/sword25/util/lua/llex.cpp6
-rw-r--r--engines/sword25/util/lua/lstrlib.cpp6
-rw-r--r--engines/teenagent/detection.cpp7
-rw-r--r--engines/testbed/graphics.cpp43
-rw-r--r--engines/tinsel/cursor.cpp4
-rw-r--r--engines/tinsel/detection.cpp21
-rw-r--r--engines/tinsel/dialogs.cpp5
-rw-r--r--engines/tinsel/multiobj.cpp9
-rw-r--r--engines/tinsel/pcode.cpp4
-rw-r--r--engines/titanic/continue_save_dialog.cpp2
-rw-r--r--engines/titanic/core/game_object.cpp1
-rw-r--r--engines/titanic/core/list.h4
-rw-r--r--engines/titanic/core/project_item.cpp25
-rw-r--r--engines/titanic/core/project_item.h2
-rw-r--r--engines/titanic/debugger.cpp2
-rw-r--r--engines/titanic/detection.cpp10
-rw-r--r--engines/titanic/game/bomb.cpp4
-rw-r--r--engines/titanic/game/chicken_dispensor.cpp2
-rw-r--r--engines/titanic/npcs/deskbot.cpp2
-rw-r--r--engines/titanic/pet_control/pet_load_save.cpp5
-rw-r--r--engines/titanic/sound/music_room_handler.cpp2
-rw-r--r--engines/titanic/sound/music_room_instrument.cpp2
-rw-r--r--engines/titanic/sound/music_song.cpp4
-rw-r--r--engines/titanic/star_control/base_stars.cpp2
-rw-r--r--engines/titanic/star_control/camera_auto_mover.cpp4
-rw-r--r--engines/titanic/star_control/camera_auto_mover.h6
-rw-r--r--engines/titanic/star_control/frect.h2
-rw-r--r--engines/titanic/star_control/marked_auto_mover.h2
-rw-r--r--engines/titanic/star_control/star_camera.h2
-rw-r--r--engines/titanic/star_control/star_closeup.cpp12
-rw-r--r--engines/titanic/star_control/star_control.cpp2
-rw-r--r--engines/titanic/star_control/star_crosshairs.h8
-rw-r--r--engines/titanic/star_control/star_field.h6
-rw-r--r--engines/titanic/star_control/star_view.h6
-rw-r--r--engines/titanic/star_control/unmarked_camera_mover.cpp2
-rw-r--r--engines/titanic/star_control/viewport.cpp2
-rw-r--r--engines/titanic/star_control/viewport.h14
-rw-r--r--engines/titanic/support/avi_surface.cpp2
-rw-r--r--engines/titanic/support/simple_file.cpp2
-rw-r--r--engines/titanic/support/simple_file.h2
-rw-r--r--engines/titanic/titanic.cpp8
-rw-r--r--engines/titanic/true_talk/doorbot_script.cpp4
-rw-r--r--engines/titanic/true_talk/tt_parser.cpp4
-rw-r--r--engines/titanic/true_talk/tt_talker.h2
-rw-r--r--engines/titanic/true_talk/tt_vocab.cpp1170
-rw-r--r--engines/toltecs/detection.cpp4
-rw-r--r--engines/toltecs/menu.cpp2
-rw-r--r--engines/toltecs/saveload.cpp10
-rw-r--r--engines/toltecs/toltecs.h2
-rw-r--r--engines/tony/gfxcore.cpp8
-rw-r--r--engines/tony/loc.cpp2
-rw-r--r--engines/tony/mpal/lzo.cpp12
-rw-r--r--engines/tony/sound.cpp6
-rw-r--r--engines/toon/detection.cpp8
-rw-r--r--engines/toon/flux.cpp3
-rw-r--r--engines/toon/hotspot.cpp16
-rw-r--r--engines/toon/hotspot.h8
-rw-r--r--engines/toon/script_func.cpp8
-rw-r--r--engines/toon/toon.cpp24
-rw-r--r--engines/touche/detection.cpp11
-rw-r--r--engines/touche/touche.cpp3
-rw-r--r--engines/touche/touche.h1
-rw-r--r--engines/tsage/blue_force/blueforce_scenes9.cpp8
-rw-r--r--engines/tsage/blue_force/blueforce_scenes9.h4
-rw-r--r--engines/tsage/detection.cpp9
-rw-r--r--engines/tsage/saveload.cpp15
-rw-r--r--engines/tsage/saveload.h2
-rw-r--r--engines/tucker/detection.cpp11
-rw-r--r--engines/tucker/locations.cpp28
-rw-r--r--engines/tucker/resource.cpp80
-rw-r--r--engines/tucker/saveload.cpp86
-rw-r--r--engines/tucker/sequences.cpp124
-rw-r--r--engines/tucker/tucker.cpp301
-rw-r--r--engines/tucker/tucker.h115
-rw-r--r--engines/voyeur/detection.cpp3
-rw-r--r--engines/voyeur/files_threads.cpp2
-rw-r--r--engines/voyeur/voyeur.cpp11
-rw-r--r--engines/voyeur/voyeur.h2
-rw-r--r--engines/wintermute/base/base_engine.h18
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.cpp2
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.h2
-rw-r--r--engines/wintermute/base/particles/part_emitter.cpp6
-rw-r--r--engines/wintermute/base/sound/base_sound_buffer.cpp6
-rw-r--r--engines/wintermute/configure.engine2
-rw-r--r--engines/wintermute/debugger/error.h36
-rw-r--r--engines/wintermute/detection.cpp9
-rw-r--r--engines/wintermute/detection_tables.h9
-rw-r--r--engines/wintermute/game_description.h17
-rw-r--r--engines/wintermute/wintermute.cpp21
-rw-r--r--engines/wintermute/wintermute.h9
-rw-r--r--engines/xeen/POTFILES1
-rw-r--r--engines/xeen/character.cpp196
-rw-r--r--engines/xeen/character.h63
-rw-r--r--engines/xeen/combat.cpp348
-rw-r--r--engines/xeen/combat.h32
-rw-r--r--engines/xeen/configure.engine2
-rw-r--r--engines/xeen/debugger.cpp31
-rw-r--r--engines/xeen/debugger.h12
-rw-r--r--engines/xeen/detection.cpp55
-rw-r--r--engines/xeen/detection_tables.h28
-rw-r--r--engines/xeen/dialogs/credits_screen.cpp4
-rw-r--r--engines/xeen/dialogs/dialogs.cpp83
-rw-r--r--engines/xeen/dialogs/dialogs.h34
-rw-r--r--engines/xeen/dialogs/dialogs_char_info.cpp33
-rw-r--r--engines/xeen/dialogs/dialogs_control_panel.cpp14
-rw-r--r--engines/xeen/dialogs/dialogs_copy_protection.cpp100
-rw-r--r--engines/xeen/dialogs/dialogs_copy_protection.h64
-rw-r--r--engines/xeen/dialogs/dialogs_create_char.cpp11
-rw-r--r--engines/xeen/dialogs/dialogs_dismiss.cpp4
-rw-r--r--engines/xeen/dialogs/dialogs_input.cpp63
-rw-r--r--engines/xeen/dialogs/dialogs_input.h6
-rw-r--r--engines/xeen/dialogs/dialogs_items.cpp366
-rw-r--r--engines/xeen/dialogs/dialogs_items.h41
-rw-r--r--engines/xeen/dialogs/dialogs_message.cpp2
-rw-r--r--engines/xeen/dialogs/dialogs_party.cpp6
-rw-r--r--engines/xeen/dialogs/dialogs_query.cpp9
-rw-r--r--engines/xeen/dialogs/dialogs_quests.cpp98
-rw-r--r--engines/xeen/dialogs/dialogs_spells.cpp403
-rw-r--r--engines/xeen/dialogs/dialogs_spells.h37
-rw-r--r--engines/xeen/events.cpp68
-rw-r--r--engines/xeen/events.h65
-rw-r--r--engines/xeen/files.cpp20
-rw-r--r--engines/xeen/files.h11
-rw-r--r--engines/xeen/font.cpp7
-rw-r--r--engines/xeen/interface.cpp215
-rw-r--r--engines/xeen/interface.h11
-rw-r--r--engines/xeen/interface_minimap.cpp10
-rw-r--r--engines/xeen/interface_scene.cpp122
-rw-r--r--engines/xeen/interface_scene.h25
-rw-r--r--engines/xeen/item.cpp255
-rw-r--r--engines/xeen/item.h98
-rw-r--r--engines/xeen/locations.cpp535
-rw-r--r--engines/xeen/locations.h8
-rw-r--r--engines/xeen/map.cpp118
-rw-r--r--engines/xeen/map.h36
-rw-r--r--engines/xeen/module.mk3
-rw-r--r--engines/xeen/party.cpp347
-rw-r--r--engines/xeen/party.h22
-rw-r--r--engines/xeen/patcher.cpp101
-rw-r--r--engines/xeen/patcher.h (renamed from engines/xeen/worldofxeen/worldofxeen_resources.h)39
-rw-r--r--engines/xeen/resources.cpp31
-rw-r--r--engines/xeen/resources.h29
-rw-r--r--engines/xeen/saves.cpp70
-rw-r--r--engines/xeen/saves.h2
-rw-r--r--engines/xeen/screen.cpp2
-rw-r--r--engines/xeen/scripts.cpp548
-rw-r--r--engines/xeen/scripts.h16
-rw-r--r--engines/xeen/sound.cpp83
-rw-r--r--engines/xeen/sound.h8
-rw-r--r--engines/xeen/sound_driver.cpp19
-rw-r--r--engines/xeen/sound_driver.h11
-rw-r--r--engines/xeen/spells.cpp88
-rw-r--r--engines/xeen/spells.h2
-rw-r--r--engines/xeen/sprites.cpp17
-rw-r--r--engines/xeen/subtitles.cpp2
-rw-r--r--engines/xeen/subtitles.h2
-rw-r--r--engines/xeen/swordsofxeen/swordsofxeen.cpp40
-rw-r--r--engines/xeen/swordsofxeen/swordsofxeen.h5
-rw-r--r--engines/xeen/window.cpp14
-rw-r--r--engines/xeen/worldofxeen/clouds_cutscenes.cpp16
-rw-r--r--engines/xeen/worldofxeen/darkside_cutscenes.cpp22
-rw-r--r--engines/xeen/worldofxeen/worldofxeen.cpp23
-rw-r--r--engines/xeen/worldofxeen/worldofxeen_cutscenes.cpp20
-rw-r--r--engines/xeen/worldofxeen/worldofxeen_menu.cpp88
-rw-r--r--engines/xeen/worldofxeen/worldofxeen_menu.h20
-rw-r--r--engines/xeen/worldofxeen/worldofxeen_resources.cpp62
-rw-r--r--engines/xeen/xeen.cpp37
-rw-r--r--engines/xeen/xeen.h36
-rw-r--r--engines/zvision/detection.cpp10
-rw-r--r--engines/zvision/detection_tables.h2
-rw-r--r--engines/zvision/file/save_manager.cpp41
-rw-r--r--engines/zvision/file/save_manager.h9
698 files changed, 39322 insertions, 15383 deletions
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index 1855280a24..c1af19026b 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -488,11 +488,6 @@ Common::Error AccessEngine::loadGameState(int slot) {
if (!readSavegameHeader(saveFile, header))
error("Invalid savegame");
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
// Load most of the savegame data
synchronize(s);
delete saveFile;
@@ -537,9 +532,8 @@ void AccessEngine::synchronize(Common::Serializer &s) {
const char *const SAVEGAME_STR = "ACCESS";
#define SAVEGAME_STR_SIZE 6
-bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header) {
+WARN_UNUSED_RESULT bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = nullptr;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -557,9 +551,9 @@ bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHead
header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header._year = in->readSint16LE();
diff --git a/engines/access/access.h b/engines/access/access.h
index 972dd4c380..56646f01c9 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -306,7 +306,7 @@ public:
/**
* Read in a savegame header
*/
- static bool readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header, bool skipThumbnail = true);
/**
* Write out a savegame header
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp
index 3e70de3635..186fcbdf06 100644
--- a/engines/access/detection.cpp
+++ b/engines/access/detection.cpp
@@ -157,11 +157,9 @@ SaveStateList AccessMetaEngine::listSaves(const char *target) const {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- Access::AccessEngine::readSavegameHeader(in, header);
- saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+ if (Access::AccessEngine::readSavegameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
- header._thumbnail->free();
- delete header._thumbnail;
delete in;
}
}
@@ -187,7 +185,11 @@ SaveStateDescriptor AccessMetaEngine::querySaveMetaInfos(const char *target, int
if (f) {
Access::AccessSavegameHeader header;
- Access::AccessEngine::readSavegameHeader(f, header);
+ if (!Access::AccessEngine::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
+
delete f;
// Create the return descriptor
diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp
index 2cebc3e3c6..a0b4ef68ee 100644
--- a/engines/access/scripts.cpp
+++ b/engines/access/scripts.cpp
@@ -152,7 +152,7 @@ void Scripts::searchForSequence() {
_data->seek(0);
int sequenceId;
do {
- while (_data->readByte() != SCRIPT_START_BYTE) ;
+ while (_data->readByte() != SCRIPT_START_BYTE) {}
sequenceId = _data->readUint16LE();
} while (sequenceId != _sequence);
}
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index e63beb2c07..2276576baa 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -332,9 +332,9 @@ public:
int getMaximumSaveSlot() const { return 'O' - 'A'; }
SaveStateList listSaves(const char *target) const;
void removeSaveState(const char *target, int slot) const;
- virtual ADGameDescList detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const;
+ ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const override;
- bool addFileProps(const FileMap &allFiles, Common::String fname, ADFilePropertiesMap &filePropsMap) const;
+ bool addFileProps(const FileMap &allFiles, Common::String fname, FilePropertiesMap &filePropsMap) const;
bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
};
@@ -401,7 +401,11 @@ SaveStateDescriptor AdlMetaEngine::querySaveMetaInfos(const char *target, int sl
return SaveStateDescriptor();
}
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*inFile);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*inFile, thumbnail)) {
+ delete inFile;
+ return SaveStateDescriptor();
+ }
sd.setThumbnail(thumbnail);
delete inFile;
@@ -488,14 +492,14 @@ Common::Platform getPlatform(const AdlGameDescription &adlDesc) {
return adlDesc.desc.platform;
}
-bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname, ADFilePropertiesMap &filePropsMap) const {
+bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname, FilePropertiesMap &filePropsMap) const {
if (filePropsMap.contains(fname))
return true;
if (!allFiles.contains(fname))
return false;
- ADFileProperties fileProps;
+ FileProperties fileProps;
fileProps.size = computeMD5(allFiles[fname], fileProps.md5, 16384);
if (fileProps.size != -1) {
@@ -507,42 +511,39 @@ bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname,
}
// Based on AdvancedMetaEngine::detectGame
-ADGameDescList AdlMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
+ADDetectedGames AdlMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
// We run the file-based detector first and then add to the returned list
- ADGameDescList matched = AdvancedMetaEngine::detectGame(parent, allFiles, language, platform, extra);
+ ADDetectedGames matched = AdvancedMetaEngine::detectGame(parent, allFiles, language, platform, extra);
debug(3, "Starting disk image detection in dir '%s'", parent.getPath().c_str());
- ADFilePropertiesMap filesProps;
- ADGameIdList matchedGameIds;
+ FilePropertiesMap filesProps;
bool gotAnyMatchesWithAllFiles = false;
for (uint g = 0; gameDiskDescriptions[g].desc.gameId != 0; ++g) {
- const ADGameDescription &desc = gameDiskDescriptions[g].desc;
+ ADDetectedGame game(&gameDiskDescriptions[g].desc);
// Skip games that don't meet the language/platform/extra criteria
- if (language != Common::UNK_LANG && desc.language != Common::UNK_LANG) {
- if (desc.language != language && !(language == Common::EN_ANY && (desc.flags & ADGF_ADDENGLISH)))
- continue;
+ if (language != Common::UNK_LANG && game.desc->language != Common::UNK_LANG) {
+ if (game.desc->language != language && !(language == Common::EN_ANY && (game.desc->flags & ADGF_ADDENGLISH)))
+ continue;
}
- if (platform != Common::kPlatformUnknown && desc.platform != Common::kPlatformUnknown && desc.platform != platform)
+ if (platform != Common::kPlatformUnknown && game.desc->platform != Common::kPlatformUnknown && game.desc->platform != platform)
continue;
- if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && desc.extra != extra)
+ if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && game.desc->extra != extra)
continue;
- bool fileMissing = false;
bool allFilesPresent = true;
- bool hashOrSizeMismatch = false;
- for (uint f = 0; desc.filesDescriptions[f].fileName; ++f) {
- const ADGameFileDescription &fDesc = desc.filesDescriptions[f];
+ for (uint f = 0; game.desc->filesDescriptions[f].fileName; ++f) {
+ const ADGameFileDescription &fDesc = game.desc->filesDescriptions[f];
Common::String fileName;
bool foundDiskImage = false;
for (uint e = 0; e < ARRAYSIZE(diskImageExts); ++e) {
- if (diskImageExts[e].platform == desc.platform) {
+ if (diskImageExts[e].platform == game.desc->platform) {
Common::String testFileName(fDesc.fileName);
testFileName += diskImageExts[e].extension;
@@ -559,49 +560,41 @@ ADGameDescList AdlMetaEngine::detectGame(const Common::FSNode &parent, const Fil
}
if (!foundDiskImage) {
- fileMissing = true;
allFilesPresent = false;
break;
}
- if (hashOrSizeMismatch)
+ game.matchedFiles[fileName] = filesProps[fileName];
+
+ if (game.hasUnknownFiles)
continue;
if (fDesc.md5 && fDesc.md5 != filesProps[fileName].md5) {
debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fDesc.md5, filesProps[fileName].md5.c_str());
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
if (fDesc.fileSize != -1 && fDesc.fileSize != filesProps[fileName].size) {
debug(3, "Size Mismatch. Skipping");
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
debug(3, "Matched file: %s", fileName.c_str());
}
- if (!fileMissing) {
- debug(2, "Found game: %s (%s/%s) (%d)", desc.gameId, getPlatformDescription(desc.platform), getLanguageDescription(desc.language), g);
- matched.push_back(&desc);
+ if (allFilesPresent && !game.hasUnknownFiles) {
+ debug(2, "Found game: %s (%s/%s) (%d)", game.desc->gameId, getPlatformDescription(game.desc->platform), getLanguageDescription(game.desc->language), g);
+ gotAnyMatchesWithAllFiles = true;
+ matched.push_back(game);
} else {
- if (allFilesPresent) {
- gotAnyMatchesWithAllFiles = true;
- if (!matchedGameIds.size() || strcmp(matchedGameIds.back(), desc.gameId) != 0)
- matchedGameIds.push_back(desc.gameId);
+ if (allFilesPresent && !gotAnyMatchesWithAllFiles) {
+ if (matched.empty() || strcmp(matched.back().desc->gameId, game.desc->gameId) != 0)
+ matched.push_back(game);
}
- debug(5, "Skipping game: %s (%s/%s) (%d)", desc.gameId, getPlatformDescription(desc.platform), getLanguageDescription(desc.language), g);
- }
- }
-
- // TODO: This could be improved to handle matched and unknown games together in a single directory
- if (matched.empty()) {
- if (!filesProps.empty() && gotAnyMatchesWithAllFiles) {
- reportUnknown(parent, filesProps, matchedGameIds);
+ debug(5, "Skipping game: %s (%s/%s) (%d)", game.desc->gameId, getPlatformDescription(game.desc->platform), getLanguageDescription(game.desc->language), g);
}
}
diff --git a/engines/adl/graphics.cpp b/engines/adl/graphics.cpp
index 0f80bac988..2fcd1473a0 100644
--- a/engines/adl/graphics.cpp
+++ b/engines/adl/graphics.cpp
@@ -350,7 +350,7 @@ void GraphicsMan_v2::fillAt(Common::Point p, const byte pattern) {
const bool stopBit = !_display.getPixelBit(p);
// Move up into the open space above p
- while (--p.y >= _bounds.top && canFillAt(p, stopBit));
+ while (--p.y >= _bounds.top && canFillAt(p, stopBit)) {}
// Then fill by moving down
while (++p.y < _bounds.bottom && canFillAt(p, stopBit))
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index 9d695058dd..6f4efcfb57 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -33,32 +33,16 @@
#include "engines/advancedDetector.h"
#include "engines/obsolete.h"
-static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGameDescriptor *sg) {
- const char *title = 0;
- const char *extra;
-
- if (g.flags & ADGF_USEEXTRAASTITLE) {
- title = g.extra;
- extra = "";
- } else {
- while (sg->gameId) {
- if (!scumm_stricmp(g.gameId, sg->gameId))
- title = sg->description;
- sg++;
- }
+static Common::String sanitizeName(const char *name) {
+ Common::String res;
- extra = g.extra;
+ while (*name) {
+ if (Common::isAlnum(*name))
+ res += tolower(*name);
+ name++;
}
- GameSupportLevel gsl = kStableGame;
- if (g.flags & ADGF_UNSTABLE)
- gsl = kUnstableGame;
- else if (g.flags & ADGF_TESTING)
- gsl = kTestingGame;
-
- GameDescriptor gd(g.gameId, title, g.language, g.platform, 0, gsl);
- gd.updateDesc(extra);
- return gd;
+ return res;
}
/**
@@ -67,8 +51,14 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa
* or (if ADGF_DEMO has been set)
* GAMEID-demo-PLAFORM-LANG
*/
-static Common::String generatePreferredTarget(const Common::String &id, const ADGameDescription *desc) {
- Common::String res(id);
+static Common::String generatePreferredTarget(const ADGameDescription *desc) {
+ Common::String res;
+
+ if (desc->flags & ADGF_AUTOGENTARGET && desc->extra && *desc->extra) {
+ res = sanitizeName(desc->extra);
+ } else {
+ res = desc->gameId;
+ }
if (desc->flags & ADGF_DEMO) {
res = res + "-demo";
@@ -89,49 +79,50 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD
return res;
}
-static Common::String sanitizeName(const char *name) {
- Common::String res;
-
- while (*name) {
- if (Common::isAlnum(*name))
- res += tolower(*name);
- name++;
- }
+DetectedGame AdvancedMetaEngine::toDetectedGame(const ADDetectedGame &adGame) const {
+ const ADGameDescription *desc = adGame.desc;
- return res;
-}
+ const char *gameId = _singleId ? _singleId : desc->gameId;
-void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const {
- if (_singleId != NULL) {
- desc["preferredtarget"] = desc["gameid"];
- desc["gameid"] = _singleId;
+ const char *title;
+ const char *extra;
+ if (desc->flags & ADGF_USEEXTRAASTITLE) {
+ title = desc->extra;
+ extra = "";
+ } else {
+ const PlainGameDescriptor *pgd = findPlainGameDescriptor(desc->gameId, _gameIds);
+ title = pgd->description;
+ extra = desc->extra;
}
- if (!desc.contains("preferredtarget"))
- desc["preferredtarget"] = desc["gameid"];
+ DetectedGame game(gameId, title, desc->language, desc->platform, extra);
+ game.hasUnknownFiles = adGame.hasUnknownFiles;
+ game.matchedFiles = adGame.matchedFiles;
+ game.preferredTarget = generatePreferredTarget(desc);
- if (realDesc->flags & ADGF_AUTOGENTARGET) {
- if (*realDesc->extra)
- desc["preferredtarget"] = sanitizeName(realDesc->extra);
- }
+ game.gameSupportLevel = kStableGame;
+ if (desc->flags & ADGF_UNSTABLE)
+ game.gameSupportLevel = kUnstableGame;
+ else if (desc->flags & ADGF_TESTING)
+ game.gameSupportLevel = kTestingGame;
- desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc);
+ game.setGUIOptions(desc->guiOptions + _guiOptions);
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(desc->language));
- if (_flags & kADFlagUseExtraAsHint)
- desc["extra"] = realDesc->extra;
+ if (desc->flags & ADGF_ADDENGLISH)
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
- desc.setGUIOptions(realDesc->guiOptions + _guiOptions);
- desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
+ if (_flags & kADFlagUseExtraAsHint)
+ game.extra = desc->extra;
- if (realDesc->flags & ADGF_ADDENGLISH)
- desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
+ return game;
}
-bool cleanupPirated(ADGameDescList &matched) {
+bool cleanupPirated(ADDetectedGames &matched) {
// OKay, now let's sense presence of pirated games
if (!matched.empty()) {
for (uint j = 0; j < matched.size();) {
- if (matched[j]->flags & ADGF_PIRATED)
+ if (matched[j].desc->flags & ADGF_PIRATED)
matched.remove_at(j);
else
++j;
@@ -148,35 +139,46 @@ bool cleanupPirated(ADGameDescList &matched) {
}
-GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
- ADGameDescList matches;
- GameList detectedGames;
+DetectedGames AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
FileMap allFiles;
if (fslist.empty())
- return detectedGames;
+ return DetectedGames();
// Compose a hashmap of all files in fslist.
composeFileHashMap(allFiles, fslist, (_maxScanDepth == 0 ? 1 : _maxScanDepth));
// Run the detector on this
- matches = detectGame(fslist.begin()->getParent(), allFiles, Common::UNK_LANG, Common::kPlatformUnknown, "");
+ ADDetectedGames matches = detectGame(fslist.begin()->getParent(), allFiles, Common::UNK_LANG, Common::kPlatformUnknown, "");
- if (matches.empty()) {
- // Use fallback detector if there were no matches by other means
- const ADGameDescription *fallbackDesc = fallbackDetect(allFiles, fslist);
- if (fallbackDesc != 0) {
- GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameIds));
- updateGameDescriptor(desc, fallbackDesc);
- detectedGames.push_back(desc);
+ cleanupPirated(matches);
+
+ DetectedGames detectedGames;
+ for (uint i = 0; i < matches.size(); i++) {
+ DetectedGame game = toDetectedGame(matches[i]);
+
+ if (game.hasUnknownFiles) {
+ // Non fallback games with unknown files cannot be added/launched
+ game.canBeAdded = false;
}
- } else {
- // Otherwise use the found matches
- cleanupPirated(matches);
- for (uint i = 0; i < matches.size(); i++) {
- GameDescriptor desc(toGameDescriptor(*matches[i], _gameIds));
- updateGameDescriptor(desc, matches[i]);
- detectedGames.push_back(desc);
+
+ detectedGames.push_back(game);
+ }
+
+ bool foundKnownGames = false;
+ for (uint i = 0; i < detectedGames.size(); i++) {
+ foundKnownGames |= detectedGames[i].canBeAdded;
+ }
+
+ if (!foundKnownGames) {
+ // Use fallback detector if there were no matches by other means
+ ADDetectedGame fallbackDetectionResult = fallbackDetect(allFiles, fslist);
+
+ if (fallbackDetectionResult.desc) {
+ DetectedGame fallbackDetectedGame = toDetectedGame(fallbackDetectionResult);
+ fallbackDetectedGame.preferredTarget += "-fallback";
+
+ detectedGames.push_back(fallbackDetectedGame);
}
}
@@ -214,7 +216,6 @@ const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::Strin
Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
assert(engine);
- const ADGameDescription *agdDesc = 0;
Common::Language language = Common::UNK_LANG;
Common::Platform platform = Common::kPlatformUnknown;
Common::String extra;
@@ -235,18 +236,6 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
path = ConfMan.get("path");
} else {
path = ".";
-
- // This situation may happen only when game was
- // launched from a command line with wrong target and
- // no path was provided.
- //
- // A dummy entry will get created and will keep game path
- // We mark this entry, so it will not be added to the
- // config file.
- //
- // Fixes bug #1544799
- ConfMan.setBool("autoadded", true);
-
warning("No path was provided. Assuming the data files are in the current directory");
}
Common::FSNode dir(path);
@@ -264,46 +253,43 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
composeFileHashMap(allFiles, files, (_maxScanDepth == 0 ? 1 : _maxScanDepth));
// Run the detector on this
- ADGameDescList matches = detectGame(files.begin()->getParent(), allFiles, language, platform, extra);
+ ADDetectedGames matches = detectGame(files.begin()->getParent(), allFiles, language, platform, extra);
if (cleanupPirated(matches))
return Common::kNoGameDataFoundError;
- if (_singleId == NULL) {
- // Find the first match with correct gameid.
- for (uint i = 0; i < matches.size(); i++) {
- if (matches[i]->gameId == gameid) {
- agdDesc = matches[i];
- break;
- }
+ ADDetectedGame agdDesc;
+ for (uint i = 0; i < matches.size(); i++) {
+ if ((_singleId || matches[i].desc->gameId == gameid) && !matches[i].hasUnknownFiles) {
+ agdDesc = matches[i];
+ break;
}
- } else if (matches.size() > 0) {
- agdDesc = matches[0];
}
- if (agdDesc == 0) {
+ if (!agdDesc.desc) {
// Use fallback detector if there were no matches by other means
- agdDesc = fallbackDetect(allFiles, files);
- if (agdDesc != 0) {
+ ADDetectedGame fallbackDetectedGame = fallbackDetect(allFiles, files);
+ agdDesc = fallbackDetectedGame;
+ if (agdDesc.desc) {
// Seems we found a fallback match. But first perform a basic
// sanity check: the gameid must match.
- if (_singleId == NULL && agdDesc->gameId != gameid)
- agdDesc = 0;
+ if (!_singleId && agdDesc.desc->gameId != gameid)
+ agdDesc = ADDetectedGame();
}
}
- if (agdDesc == 0)
+ if (!agdDesc.desc)
return Common::kNoGameDataFoundError;
// If the GUI options were updated, we catch this here and update them in the users config
// file transparently.
- Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc->language);
- if (agdDesc->flags & ADGF_ADDENGLISH)
+ Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc.desc->language);
+ if (agdDesc.desc->flags & ADGF_ADDENGLISH)
lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY);
- Common::updateGameGUIOptions(agdDesc->guiOptions + _guiOptions, lang);
+ Common::updateGameGUIOptions(agdDesc.desc->guiOptions + _guiOptions, lang);
- GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameIds);
+ DetectedGame gameDescriptor = toDetectedGame(agdDesc);
bool showTestingWarning = false;
@@ -311,53 +297,20 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
showTestingWarning = true;
#endif
- if (((gameDescriptor.getSupportLevel() == kUnstableGame
- || (gameDescriptor.getSupportLevel() == kTestingGame
+ if (((gameDescriptor.gameSupportLevel == kUnstableGame
+ || (gameDescriptor.gameSupportLevel == kTestingGame
&& showTestingWarning)))
&& !Engine::warnUserAboutUnsupportedGame())
return Common::kUserCanceled;
- debug(2, "Running %s", gameDescriptor.description().c_str());
- initSubSystems(agdDesc);
- if (!createInstance(syst, engine, agdDesc))
+ debug(2, "Running %s", gameDescriptor.description.c_str());
+ initSubSystems(agdDesc.desc);
+ if (!createInstance(syst, engine, agdDesc.desc))
return Common::kNoGameDataFoundError;
else
return Common::kNoError;
}
-void AdvancedMetaEngine::reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps, const ADGameIdList &matchedGameIds) const {
- Common::String report = Common::String::format(
- _("The game in '%s' seems to be an unknown %s engine game "
- "variant.\n\nPlease report the following data to the ScummVM "
- "team at %s along with the name of the game you tried to add and "
- "its version, language, etc.:"),
- path.getPath().c_str(), getName(), "https://bugs.scummvm.org/");
-
- if (matchedGameIds.size()) {
- report += "\n\n";
- report += _("Matched game IDs:");
- report += " ";
-
- for (ADGameIdList::const_iterator gameId = matchedGameIds.begin(); gameId != matchedGameIds.end(); ++gameId) {
- if (gameId != matchedGameIds.begin()) {
- report += ", ";
- }
- report += *gameId;
- }
- }
-
- report += "\n\n";
-
- report.wordWrap(80);
-
- for (ADFilePropertiesMap::const_iterator file = filesProps.begin(); file != filesProps.end(); ++file)
- report += Common::String::format(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);
-
- report += "\n";
-
- g_system->logMessage(LogMessageType::kInfo, report.c_str());
-}
-
void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName) const {
if (depth <= 0)
return;
@@ -398,7 +351,7 @@ void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSL
}
}
-bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const {
+bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const {
// FIXME/TODO: We don't handle the case that a file is listed as a regular
// file and as one with resource fork.
@@ -428,8 +381,9 @@ bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const F
return true;
}
-ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
- ADFilePropertiesMap filesProps;
+ADDetectedGames AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
+ FilePropertiesMap filesProps;
+ ADDetectedGames matched;
const ADGameFileDescription *fileDesc;
const ADGameDescription *g;
@@ -439,12 +393,12 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// Check which files are included in some ADGameDescription *and* are present.
// Compute MD5s and file sizes for these files.
- for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize) {
+ for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != nullptr; descPtr += _descItemSize) {
g = (const ADGameDescription *)descPtr;
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
Common::String fname = fileDesc->fileName;
- ADFileProperties tmp;
+ FileProperties tmp;
if (filesProps.contains(fname))
continue;
@@ -456,16 +410,13 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
}
}
- ADGameDescList matched;
- ADGameIdList matchedGameIds;
int maxFilesMatched = 0;
bool gotAnyMatchesWithAllFiles = false;
// MD5 based matching
uint i;
- for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize, ++i) {
+ for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != nullptr; descPtr += _descItemSize, ++i) {
g = (const ADGameDescription *)descPtr;
- bool fileMissing = false;
// Do not even bother to look at entries which do not have matching
// language and platform (if specified).
@@ -478,34 +429,33 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra)
continue;
+ ADDetectedGame game(g);
bool allFilesPresent = true;
int curFilesMatched = 0;
- bool hashOrSizeMismatch = false;
// Try to match all files for this game
- for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
+ for (fileDesc = game.desc->filesDescriptions; fileDesc->fileName; fileDesc++) {
Common::String tstr = fileDesc->fileName;
if (!filesProps.contains(tstr)) {
- fileMissing = true;
allFilesPresent = false;
break;
}
- if (hashOrSizeMismatch)
+ game.matchedFiles[tstr] = filesProps[tstr];
+
+ if (game.hasUnknownFiles)
continue;
- if (fileDesc->md5 != NULL && fileDesc->md5 != filesProps[tstr].md5) {
+ if (fileDesc->md5 != nullptr && fileDesc->md5 != filesProps[tstr].md5) {
debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesProps[tstr].md5.c_str());
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesProps[tstr].size) {
debug(3, "Size Mismatch. Skipping");
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
@@ -522,13 +472,12 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// Potentially this could rule out variants where some particular file
// is really missing, but the developers should better know about such
// cases.
- if (allFilesPresent) {
- gotAnyMatchesWithAllFiles = true;
- if (!matchedGameIds.size() || strcmp(matchedGameIds.back(), g->gameId) != 0)
- matchedGameIds.push_back(g->gameId);
+ if (allFilesPresent && !gotAnyMatchesWithAllFiles) {
+ if (matched.empty() || strcmp(matched.back().desc->gameId, g->gameId) != 0)
+ matched.push_back(game);
}
- if (!fileMissing) {
+ if (allFilesPresent && !game.hasUnknownFiles) {
debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameId, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
@@ -537,37 +486,29 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
maxFilesMatched = curFilesMatched;
matched.clear(); // Remove any prior, lower ranked matches.
- matched.push_back(g);
+ matched.push_back(game);
} else if (curFilesMatched == maxFilesMatched) {
- matched.push_back(g);
+ matched.push_back(game);
} else {
debug(2, " ... skipped");
}
+ gotAnyMatchesWithAllFiles = true;
} else {
debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameId, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
}
}
- // We didn't find a match
- if (matched.empty()) {
- if (!filesProps.empty() && gotAnyMatchesWithAllFiles) {
- reportUnknown(parent, filesProps, matchedGameIds);
- }
-
- // Filename based fallback
- }
-
return matched;
}
-const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps) const {
+ADDetectedGame AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback) const {
const ADFileBasedFallback *ptr;
const char* const* filenames;
int maxNumMatchedFiles = 0;
- const ADGameDescription *matchedDesc = 0;
+ ADDetectedGame result;
for (ptr = fileBasedFallback; ptr->desc; ++ptr) {
const ADGameDescription *agdesc = ptr->desc;
@@ -588,35 +529,36 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &
debug(4, "Matched: %s", agdesc->gameId);
if (numMatchedFiles > maxNumMatchedFiles) {
- matchedDesc = agdesc;
maxNumMatchedFiles = numMatchedFiles;
debug(4, "and overridden");
- if (filesProps) {
- for (filenames = ptr->filenames; *filenames; ++filenames) {
- ADFileProperties tmp;
+ ADDetectedGame game(agdesc);
+ game.hasUnknownFiles = true;
+
+ for (filenames = ptr->filenames; *filenames; ++filenames) {
+ FileProperties tmp;
- if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp))
- (*filesProps)[*filenames] = tmp;
- }
+ if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp))
+ game.matchedFiles[*filenames] = tmp;
}
+ result = game;
}
}
}
- return matchedDesc;
+ return result;
}
-GameList AdvancedMetaEngine::getSupportedGames() const {
+PlainGameList AdvancedMetaEngine::getSupportedGames() const {
if (_singleId != NULL) {
- GameList gl;
+ PlainGameList gl;
const PlainGameDescriptor *g = _gameIds;
while (g->gameId) {
if (0 == scumm_stricmp(_singleId, g->gameId)) {
- gl.push_back(GameDescriptor(g->gameId, g->description));
+ gl.push_back(*g);
return gl;
}
@@ -625,17 +567,17 @@ GameList AdvancedMetaEngine::getSupportedGames() const {
error("Engine %s doesn't have its singleid specified in ids list", _singleId);
}
- return GameList(_gameIds);
+ return PlainGameList(_gameIds);
}
-GameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const {
+PlainGameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const {
// First search the list of supported gameids for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds);
if (g)
- return GameDescriptor(*g);
+ return *g;
// No match found
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions)
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index 5160a99679..326cb79c49 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -41,27 +41,13 @@ class FSList;
* enable detection.
*/
struct ADGameFileDescription {
- const char *fileName; ///< Name of described file.
- uint16 fileType; ///< Optional. Not used during detection, only by engines.
- const char *md5; ///< MD5 of (the beginning of) the described file. Optional. Set to NULL to ignore.
- int32 fileSize; ///< Size of the described file. Set to -1 to ignore.
+ const char *fileName; ///< Name of described file.
+ uint16 fileType; ///< Optional. Not used during detection, only by engines.
+ const char *md5; ///< MD5 of (the beginning of) the described file. Optional. Set to NULL to ignore.
+ int32 fileSize; ///< Size of the described file. Set to -1 to ignore.
};
/**
- * A record describing the properties of a file. Used on the existing
- * files while detecting a game.
- */
-struct ADFileProperties {
- int32 size;
- Common::String md5;
-};
-
-/**
- * A map of all relevant existing files in a game directory while detecting.
- */
-typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ADFilePropertiesMap;
-
-/**
* A shortcut to produce an empty ADGameFileDescription record. Used to mark
* the end of a list of these.
*/
@@ -80,18 +66,18 @@ typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Has
#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, AD_LISTEND}
enum ADGameFlags {
- ADGF_NO_FLAGS = 0,
- ADGF_AUTOGENTARGET = (1 << 20), // automatically generate gameid from extra
- ADGF_UNSTABLE = (1 << 21), // flag to designate not yet officially-supported games that are not fit for public testing
- ADGF_TESTING = (1 << 22), // flag to designate not yet officially-supported games that are fit for public testing
- ADGF_PIRATED = (1 << 23), ///< flag to designate well known pirated versions with cracks
- ADGF_ADDENGLISH = (1 << 24), ///< always add English as language option
- ADGF_MACRESFORK = (1 << 25), ///< the md5 for this entry will be calculated from the resource fork
+ ADGF_NO_FLAGS = 0,
+ ADGF_AUTOGENTARGET = (1 << 20), ///< automatically generate gameid from extra
+ ADGF_UNSTABLE = (1 << 21), ///< flag to designate not yet officially-supported games that are not fit for public testing
+ ADGF_TESTING = (1 << 22), ///< flag to designate not yet officially-supported games that are fit for public testing
+ ADGF_PIRATED = (1 << 23), ///< flag to designate well known pirated versions with cracks
+ ADGF_ADDENGLISH = (1 << 24), ///< always add English as language option
+ ADGF_MACRESFORK = (1 << 25), ///< the md5 for this entry will be calculated from the resource fork
ADGF_USEEXTRAASTITLE = (1 << 26), ///< Extra field value will be used as main game title, not gameid
- ADGF_DROPLANGUAGE = (1 << 27), ///< don't add language to gameid
- ADGF_DROPPLATFORM = (1 << 28), ///< don't add platform to gameid
- ADGF_CD = (1 << 29), ///< add "-cd" to gameid
- ADGF_DEMO = (1 << 30) ///< add "-demo" to gameid
+ ADGF_DROPLANGUAGE = (1 << 27), ///< don't add language to gameid
+ ADGF_DROPPLATFORM = (1 << 28), ///< don't add platform to gameid
+ ADGF_CD = (1 << 29), ///< add "-cd" to gameid
+ ADGF_DEMO = (1 << 30) ///< add "-demo" to gameid
};
struct ADGameDescription {
@@ -112,14 +98,19 @@ struct ADGameDescription {
};
/**
- * A list of pointers to ADGameDescription structs (or subclasses thereof).
+ * A game installation matching an AD game description
*/
-typedef Common::Array<const ADGameDescription *> ADGameDescList;
+struct ADDetectedGame {
+ bool hasUnknownFiles;
+ FilePropertiesMap matchedFiles;
+ const ADGameDescription *desc;
-/**
- * A list of raw game ID strings.
- */
-typedef Common::Array<const char *> ADGameIdList;
+ ADDetectedGame() : desc(nullptr), hasUnknownFiles(false) {}
+ explicit ADDetectedGame(const ADGameDescription *d) : desc(d), hasUnknownFiles(false) {}
+};
+
+/** A list of games detected by the AD */
+typedef Common::Array<ADDetectedGame> ADDetectedGames;
/**
* End marker for a table of ADGameDescription structs. Use this to
@@ -274,11 +265,11 @@ public:
* Returns list of targets supported by the engine.
* Distinguishes engines with single ID
*/
- virtual GameList getSupportedGames() const;
+ PlainGameList getSupportedGames() const override;
- virtual GameDescriptor findGame(const char *gameId) const;
+ PlainGameDescriptor findGame(const char *gameId) const override;
- virtual GameList detectGames(const Common::FSList &fslist) const;
+ DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
@@ -294,8 +285,8 @@ protected:
* An (optional) generic fallback detect function which is invoked
* if the regular MD5 based detection failed to detect anything.
*/
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return 0;
+ virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ return ADDetectedGame();
}
private:
@@ -313,7 +304,7 @@ protected:
* @param extra restrict results to specified extra string (only if kADFlagUseExtraAsHint is set)
* @return list of ADGameDescription pointers corresponding to matched games
*/
- virtual ADGameDescList detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const;
+ virtual ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const;
/**
* Iterates over all ADFileBasedFallback records inside fileBasedFallback.
@@ -327,16 +318,7 @@ protected:
* @param fileBasedFallback a list of ADFileBasedFallback records, zero-terminated
* @param filesProps if not 0, return a map of properties for all detected files here
*/
- const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps = 0) const;
-
- /**
- * Log and print a report that we found an unknown game variant, together with the file
- * names, sizes and MD5 sums.
- */
- void reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps, const ADGameIdList &matchedGameIds = ADGameIdList()) const;
-
- // TODO
- void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const;
+ ADDetectedGame detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback) const;
/**
* Compose a hashmap of all files in fslist.
@@ -345,7 +327,10 @@ protected:
void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName = Common::String()) const;
/** Get the properties (size and MD5) of this file. */
- bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const;
+ bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const;
+
+ /** Convert an AD game description into the shared game description format */
+ DetectedGame toDetectedGame(const ADDetectedGame &adGame) const;
};
#endif
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index e26f5c84fc..39275c4f70 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -220,7 +220,7 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -375,7 +375,11 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
char saveVersion = in->readByte();
if (saveVersion >= 4) {
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ delete in;
+ return SaveStateDescriptor();
+ }
descriptor.setThumbnail(thumbnail);
@@ -417,7 +421,7 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
}
}
-const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
+ADDetectedGame AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
typedef Common::HashMap<Common::String, int32> IntMap;
IntMap allFiles;
bool matchedUsingFilenames = false;
@@ -580,10 +584,10 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
g_system->logMessage(LogMessageType::kWarning, fallbackWarning.c_str());
- return (const ADGameDescription *)&g_fallbackDesc;
+ return ADDetectedGame(&g_fallbackDesc.desc);
}
- return 0;
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(AGI)
diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp
index dbc4ee9145..1847434200 100644
--- a/engines/agos/detection.cpp
+++ b/engines/agos/detection.cpp
@@ -99,7 +99,7 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual GameDescriptor findGame(const char *gameId) const {
+ PlainGameDescriptor findGame(const char *gameId) const override {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h
index 90e5a84829..b9cdce6b99 100644
--- a/engines/agos/detection_tables.h
+++ b/engines/agos/detection_tables.h
@@ -2401,6 +2401,156 @@ static const AGOSGameDescription gameDescriptions[] = {
GF_TALKIE
},
+ // Simon the Sorcerer 2 - Russian Fan with MT-32 hack (25th Anniversary Edition)
+ {
+ {
+ "simon2",
+ "25th Anniversary Edition",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "e26d162e573587f4601b88701292212c", 58851 },
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", 18089 },
+ { "simon2.gme", GAME_GMEFILE, "f1727b15b3e389f0248363d890751ee7", 19695662 },
+ { "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 - Polish with MT-32 hack (25th Anniversary Edition)
+ {
+ {
+ "simon2",
+ "25th Anniversary Edition",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "657fd873f5d0637097ee02315b447e6f", -1},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", -1},
+ { "simon2.gme", GAME_GMEFILE, "212fa5638a76869537d092d4e76524c0", 20037221},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6", -1},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::PL_POL,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE | GF_WAVSFX
+ },
+
+ // Simon the Sorcerer 2 - Hebrew with MT-32 hack (25th Anniversary Edition)
+ {
+ {
+ "simon2",
+ "25th Anniversary Edition",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "952a2b1be23c3c609ba8d988a9a1627d", 53366},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", 18089},
+ { "simon2.gme", GAME_GMEFILE, "40ac2d4763d97a9268023dc6db17e2ce", 20017302},
+ { "stripped.txt", GAME_STRFILE, "de9dbc24158660e153483fa0cf6c3172", 171},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", 513},
+ { NULL, 0, NULL, 0}
+ },
+ Common::HE_ISR,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE | GF_WAVSFX
+ },
+
+ // Simon the Sorcerer 2 - Italian with MT-32 hack (25th Anniversary Edition)
+ {
+ {
+ "simon2",
+ "25th Anniversary Edition",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "3e11d400bea0638f360a724687005cd1", -1},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", -1},
+ { "simon2.gme", GAME_GMEFILE, "510d012bcc5775a8513923163ffe4458", 20066490},
+ { "stripped.txt", GAME_STRFILE, "bea6843fb9f3b2144fcb146d62db0b9a", -1},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE | GF_WAVSFX
+ },
+
+ // Simon the Sorcerer 2 - Czech with MT-32 hack (25th Anniversary Edition)
+ {
+ {
+ "simon2",
+ "25th Anniversary Edition",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "eb8217f9ec4628d12ca606033146c48c", -1},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", -1},
+ { "simon2.gme", GAME_GMEFILE, "50188f9fde0d063c824476972936a52f", 20054555},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6", -1},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::CZ_CZE,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE | GF_WAVSFX
+ },
+
+ // Simon the Sorcerer 2 - Spanish with MT-32 hack (25th Anniversary Edition)
+ {
+ {
+ "simon2",
+ "25th Anniversary Edition",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "268dc322aa73bcf27bb016b8e8ceb889", -1},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", -1},
+ { "simon2.gme", GAME_GMEFILE, "2b997db3c677fb3d2174c73ba2cc53e1", 20049608},
+ { "stripped.txt", GAME_STRFILE, "d13753796bd81bf313a2449f34d8b112", -1},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::ES_ESP,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE | GF_WAVSFX
+ },
+
#ifdef ENABLE_AGOS2
// The Feeble Files - English DOS Demo
{
diff --git a/engines/agos/intern.h b/engines/agos/intern.h
index 3f5c8c519b..afc0cad08e 100644
--- a/engines/agos/intern.h
+++ b/engines/agos/intern.h
@@ -256,7 +256,8 @@ enum GameFeatures {
GF_PLANAR = 1 << 7,
GF_DEMO = 1 << 8,
GF_PACKED = 1 << 9,
- GF_BROKEN_FF_RATING = 1 << 10
+ GF_BROKEN_FF_RATING = 1 << 10,
+ GF_WAVSFX = 1 << 11
};
enum GameFileTypes {
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 3a7158a203..5e28654c41 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -482,20 +482,14 @@ void MidiPlayer::pause(bool b) {
}
void MidiPlayer::setVolume(int musicVol, int sfxVol) {
- if (musicVol < 0)
- musicVol = 0;
- else if (musicVol > 255)
- musicVol = 255;
- if (sfxVol < 0)
- sfxVol = 0;
- else if (sfxVol > 255)
- sfxVol = 255;
+ musicVol = CLIP(musicVol, 0, 255);
+ sfxVol = CLIP(sfxVol, 0, 255);
if (_musicVolume == musicVol && _sfxVolume == sfxVol)
return;
_musicVolume = musicVol;
- _sfxVolume = sfxVol;
+ _sfxVolume = sfxVol;
// Now tell all the channels this.
Common::StackLock lock(_mutex);
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
index 13b5bf761c..ae2412feb4 100644
--- a/engines/agos/sound.cpp
+++ b/engines/agos/sound.cpp
@@ -519,7 +519,7 @@ void Sound::loadSfxTable(const char *gameFilename, uint32 base) {
delete _effects;
const bool dataIsUnsigned = true;
- if (_vm->getPlatform() == Common::kPlatformWindows)
+ if (_vm->getPlatform() == Common::kPlatformWindows || (_vm->getFeatures() & GF_WAVSFX))
_effects = new WavSound(_mixer, gameFilename, base);
else
_effects = new VocSound(_mixer, gameFilename, dataIsUnsigned, base, false);
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
index 533b04fa30..d2f7ac6bd5 100644
--- a/engines/agos/string.cpp
+++ b/engines/agos/string.cpp
@@ -486,7 +486,7 @@ void AGOSEngine::printScreenText(uint vgaSpriteId, uint color, const char *strin
if (_variableArray[141] == 0)
_variableArray[141] = 9;
_variableArray[85] = _variableArray[141] * talkDelay;
-
+
if (_language == Common::HE_ISR)
_variableArray[85] += talkDelay * 2;
} else {
diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp
index 8726ef784a..303fb0cff8 100644
--- a/engines/avalanche/avalanche.cpp
+++ b/engines/avalanche/avalanche.cpp
@@ -39,9 +39,6 @@ AvalancheEngine::AvalancheEngine(OSystem *syst, const AvalancheGameDescription *
_console = new AvalancheConsole(this);
_rnd = new Common::RandomSource("avalanche");
- TimeDate time;
- _system->getTimeAndDate(time);
- _rnd->setSeed(time.tm_sec + time.tm_min + time.tm_hour);
_showDebugLines = false;
_clock = nullptr;
@@ -60,7 +57,6 @@ AvalancheEngine::AvalancheEngine(OSystem *syst, const AvalancheGameDescription *
_help = nullptr;
_highscore = nullptr;
- _platform = gd->desc.platform;
initVariables();
}
@@ -182,10 +178,6 @@ GUI::Debugger *AvalancheEngine::getDebugger() {
return _console;
}
-Common::Platform AvalancheEngine::getPlatform() const {
- return _platform;
-}
-
bool AvalancheEngine::hasFeature(EngineFeature f) const {
return (f == kSupportsSavingDuringRuntime) || (f == kSupportsLoadingDuringRuntime);
}
diff --git a/engines/avalanche/avalanche.h b/engines/avalanche/avalanche.h
index 6eb5e675cc..d50373b07a 100644
--- a/engines/avalanche/avalanche.h
+++ b/engines/avalanche/avalanche.h
@@ -48,10 +48,10 @@
#include "avalanche/mainmenu.h"
#include "avalanche/highscore.h"
+#include "common/error.h"
#include "common/serializer.h"
#include "engines/engine.h"
-#include "engines/advancedDetector.h"
#include "graphics/cursorman.h"
@@ -61,9 +61,7 @@ class RandomSource;
namespace Avalanche {
-struct AvalancheGameDescription {
- ADGameDescription desc;
-};
+struct AvalancheGameDescription;
static const int kSavegameVersion = 2;
@@ -132,7 +130,6 @@ protected:
private:
AvalancheConsole *_console;
- Common::Platform _platform;
public:
// For Thinkabout:
diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp
index def395b77f..7f3d4f88a8 100644
--- a/engines/avalanche/detection.cpp
+++ b/engines/avalanche/detection.cpp
@@ -35,6 +35,10 @@
namespace Avalanche {
+struct AvalancheGameDescription {
+ ADGameDescription desc;
+};
+
uint32 AvalancheEngine::getFeatures() const {
return _gameDescription->desc.flags;
}
@@ -43,6 +47,10 @@ const char *AvalancheEngine::getGameId() const {
return _gameDescription->desc.gameId;
}
+Common::Platform AvalancheEngine::getPlatform() const {
+ return _gameDescription->desc.platform;
+}
+
static const PlainGameDescriptor avalancheGames[] = {
{"avalanche", "Lord Avalot d'Argent"},
{0, 0}
@@ -193,7 +201,12 @@ SaveStateDescriptor AvalancheMetaEngine::querySaveMetaInfos(const char *target,
SaveStateDescriptor desc(slot, description);
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*f);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*f, thumbnail)) {
+ warning("Cannot read thumbnail data, possibly broken savegame");
+ delete f;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
delete f;
diff --git a/engines/avalanche/dropdown.cpp b/engines/avalanche/dropdown.cpp
index 97adfc2581..ba4e452aaa 100644
--- a/engines/avalanche/dropdown.cpp
+++ b/engines/avalanche/dropdown.cpp
@@ -684,9 +684,9 @@ void DropDownMenu::update() {
Common::Point cursorPos = _vm->getMousePos();
while (!_activeMenuItem._activeNow && (cursorPos.y <= 21) && _vm->_holdLeftMouse) {
_menuBar.chooseMenuItem(cursorPos.x);
- do
+ do {
_vm->updateEvents();
- while (_vm->_holdLeftMouse && !_vm->shouldQuit());
+ } while (_vm->_holdLeftMouse && !_vm->shouldQuit());
while (!_vm->shouldQuit()) {
do {
diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h
index 9fb6b9cac3..a9d37c2551 100644
--- a/engines/bbvs/bbvs.h
+++ b/engines/bbvs/bbvs.h
@@ -417,7 +417,7 @@ public:
const char *getSavegameFilename(int num);
bool existsSavegame(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
- static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
+ WARN_UNUSED_RESULT static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true);
void allocSnapshot();
void freeSnapshot();
diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp
index 1b2c644dda..b30c6d3f2d 100644
--- a/engines/bbvs/detection.cpp
+++ b/engines/bbvs/detection.cpp
@@ -124,7 +124,7 @@ SaveStateList BbvsMetaEngine::listSaves(const char *target) const {
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
if (in) {
- if (Bbvs::BbvsEngine::readSaveHeader(in, false, header) == Bbvs::BbvsEngine::kRSHENoError) {
+ if (Bbvs::BbvsEngine::readSaveHeader(in, header) == Bbvs::BbvsEngine::kRSHENoError) {
saveList.push_back(SaveStateDescriptor(slotNum, header.description));
}
delete in;
@@ -142,7 +142,7 @@ SaveStateDescriptor BbvsMetaEngine::querySaveMetaInfos(const char *target, int s
if (in) {
Bbvs::BbvsEngine::SaveHeader header;
Bbvs::BbvsEngine::kReadSaveHeaderError error;
- error = Bbvs::BbvsEngine::readSaveHeader(in, true, header);
+ error = Bbvs::BbvsEngine::readSaveHeader(in, header, false);
delete in;
if (error == Bbvs::BbvsEngine::kRSHENoError) {
SaveStateDescriptor desc(slot, header.description);
diff --git a/engines/bbvs/saveload.cpp b/engines/bbvs/saveload.cpp
index 74c255c860..d4782aad39 100644
--- a/engines/bbvs/saveload.cpp
+++ b/engines/bbvs/saveload.cpp
@@ -27,7 +27,7 @@
namespace Bbvs {
-BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
+WARN_UNUSED_RESULT BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) {
header.version = in->readUint32LE();
if (header.version > BBVS_SAVEGAME_VERSION)
@@ -38,10 +38,8 @@ BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableRead
while (descriptionLen--)
header.description += (char)in->readByte();
- if (loadThumbnail) {
- header.thumbnail = Graphics::loadThumbnail(*in);
- } else {
- Graphics::skipThumbnail(*in);
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
+ return kRSHEIoError;
}
// Not used yet, reserved for future usage
@@ -101,7 +99,7 @@ void BbvsEngine::loadgame(const char *filename) {
SaveHeader header;
- kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
+ kReadSaveHeaderError errorCode = readSaveHeader(in, header);
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index d4c4eeaee3..f9446aae0a 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -22,16 +22,17 @@
#include "bladerunner/actor.h"
-#include "bladerunner/bladerunner.h"
#include "bladerunner/actor_clues.h"
#include "bladerunner/actor_combat.h"
#include "bladerunner/actor_walk.h"
#include "bladerunner/audio_speech.h"
+#include "bladerunner/bladerunner.h"
#include "bladerunner/boundingbox.h"
#include "bladerunner/game_info.h"
#include "bladerunner/items.h"
#include "bladerunner/mouse.h"
#include "bladerunner/movement_track.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/script/scene_script.h"
@@ -51,7 +52,6 @@ Actor::Actor(BladeRunnerEngine *vm, int actorId) {
_walkInfo = new ActorWalk(vm);
_movementTrack = new MovementTrack();
_clues = new ActorClues(vm, (actorId && actorId != 99) ? 2 : 4);
- _bbox = new BoundingBox();
_combatInfo = new ActorCombat(vm);
_friendlinessToOther.resize(_vm->_gameInfo->getActorCount());
@@ -64,7 +64,6 @@ Actor::Actor(BladeRunnerEngine *vm, int actorId) {
Actor::~Actor() {
delete _combatInfo;
- delete _bbox;
delete _clues;
delete _movementTrack;
delete _walkInfo;
@@ -97,6 +96,8 @@ void Actor::setup(int actorId) {
_retiredHeight = 0;
_scale = 1.0f;
+ _timer4RemainDefault = 60000;
+
_movementTrackWalkingToWaypointId = -1;
_movementTrackDelayOnNextWaypoint = -1;
@@ -120,9 +121,6 @@ void Actor::setup(int actorId) {
_movementTrackNextAngle = -1;
_movementTrackNextRunning = false;
- // Timer for exchanging clues
- _timersLeft[4] = 60000;
-
_animationMode = -1;
_screenRectangle = Common::Rect(-1, -1, -1, -1);
@@ -226,6 +224,8 @@ void Actor::timerUpdate(int timerId) {
break;
case 4:
// Exchange clues between actors
+ acquireCluesByRelations();
+ _timersLeft[4] = _timer4RemainDefault;
break;
case 5:
// Actor animation frame timer
@@ -354,7 +354,7 @@ void Actor::setAtXYZ(const Vector3 &position, int facing, bool snapFacing, bool
_vm->_sceneObjects->remove(_id + kSceneObjectOffsetActors);
if (_vm->_scene->getSetId() == _setId) {
- _vm->_sceneObjects->addActor(_id + kSceneObjectOffsetActors, _bbox, &_screenRectangle, true, moving, _isTarget, retired);
+ _vm->_sceneObjects->addActor(_id + kSceneObjectOffsetActors, _bbox, _screenRectangle, true, moving, _isTarget, retired);
}
}
@@ -468,7 +468,7 @@ bool Actor::loopWalkToItem(int itemId, int destinationOffset, int interruptible,
return loopWalk(itemPosition, destinationOffset, interruptible, runFlag, _position, width, 24.0f, a5, isRunningFlag, false);
}
-bool Actor::loopWalkToSceneObject(const char *objectName, int destinationOffset, bool interruptible, bool runFlag, bool a5, bool *isRunningFlag) {
+bool Actor::loopWalkToSceneObject(const Common::String &objectName, int destinationOffset, bool interruptible, bool runFlag, bool a5, bool *isRunningFlag) {
int sceneObject = _vm->_scene->_set->findObject(objectName);
if (sceneObject < 0) {
return true;
@@ -671,6 +671,12 @@ bool Actor::tick(bool forceDraw, Common::Rect *screenRect) {
return isVisible;
}
+void Actor::tickCombat() {
+ if (_id != kActorMcCoy && !_isRetired && _inCombat) {
+ _combatInfo->tick();
+ }
+}
+
bool Actor::draw(Common::Rect *screenRect) {
Vector3 drawPosition(_position.x, -_position.z, _position.y + 2.0);
float drawAngle = M_PI - _facing * (M_PI / 512.0f);
@@ -753,21 +759,21 @@ void Actor::setFacing(int facing, bool halfOrSet) {
void Actor::setBoundingBox(const Vector3 &position, bool retired) {
if (retired) {
- _bbox->setXYZ(position.x - (_retiredWidth / 2.0f),
- position.y,
- position.z - (_retiredWidth / 2.0f),
+ _bbox.setXYZ(position.x - (_retiredWidth / 2.0f),
+ position.y,
+ position.z - (_retiredWidth / 2.0f),
- position.x + (_retiredWidth / 2.0f),
- position.y + _retiredHeight,
- position.z + (_retiredWidth / 2.0f));
+ position.x + (_retiredWidth / 2.0f),
+ position.y + _retiredHeight,
+ position.z + (_retiredWidth / 2.0f));
} else {
- _bbox->setXYZ(position.x - 12.0f,
- position.y + 6.0f,
- position.z - 12.0f,
+ _bbox.setXYZ(position.x - 12.0f,
+ position.y + 6.0f,
+ position.z - 12.0f,
- position.x + 12.0f,
- position.y + 72.0f,
- position.z + 12.0f);
+ position.x + 12.0f,
+ position.y + 72.0f,
+ position.z + 12.0f);
}
}
@@ -813,7 +819,7 @@ void Actor::faceActor(int otherActorId, bool animate) {
faceXYZ(otherActor->_position, animate);
}
-void Actor::faceObject(const char *objectName, bool animate) {
+void Actor::faceObject(const Common::String &objectName, bool animate) {
int objectId = _vm->_scene->findObject(objectName);
if (objectId == -1) {
return;
@@ -880,6 +886,21 @@ void Actor::setFriendlinessToOther(int otherActorId, int friendliness) {
_friendlinessToOther[otherActorId] = friendliness;
}
+bool Actor::checkFriendlinessAndHonesty(int otherActorId) {
+ int honestyDiff = 2 * _friendlinessToOther[otherActorId] - _honesty;
+ int friendlinessRange;
+
+ if (honestyDiff > 30) {
+ friendlinessRange = 100;
+ } else if (honestyDiff >= 0 && honestyDiff <= 30) {
+ friendlinessRange = 50;
+ } else {
+ friendlinessRange = 0;
+ }
+
+ return _vm->_rnd.getRandomNumberRng(1, 100) <= friendlinessRange;
+}
+
void Actor::setHonesty(int honesty) {
_honesty = honesty;
}
@@ -904,16 +925,6 @@ void Actor::setImmunityToObstacles(bool isImmune) {
_isImmuneToObstacles = isImmune;
}
-void Actor::modifyCurrentHP(signed int change) {
- _currentHP = CLIP(_currentHP + change, 0, 100);
- if (_currentHP > 0)
- retire(false, 0, 0, -1);
-}
-
-void Actor::modifyMaxHP(signed int change) {
- _maxHP = CLIP(_maxHP + change, 0, 100);
-}
-
void Actor::modifyCombatAggressiveness(signed int change) {
_combatAggressiveness = CLIP(_combatAggressiveness + change, 0, 100);
}
@@ -955,6 +966,13 @@ void Actor::setTarget(bool target) {
_isTarget = target;
}
+void Actor::setCurrentHP(int hp) {
+ _currentHP = hp;
+ if (hp > 0) {
+ retire(false, 0, 0, -1);
+ }
+}
+
void Actor::setHealth(int hp, int maxHp) {
_currentHP = hp;
_maxHP = maxHp;
@@ -963,18 +981,29 @@ void Actor::setHealth(int hp, int maxHp) {
}
}
-void Actor::combatModeOn(int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int ammoDamage, int a13, int a14) {
+void Actor::modifyCurrentHP(signed int change) {
+ _currentHP = CLIP(_currentHP + change, 0, 100);
+ if (_currentHP > 0) {
+ retire(false, 0, 0, -1);
+ }
+}
+
+void Actor::modifyMaxHP(signed int change) {
+ _maxHP = CLIP(_maxHP + change, 0, 100);
+}
+
+
+void Actor::combatModeOn(int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool unstoppable) {
_animationModeCombatIdle = animationModeCombatIdle;
_animationModeCombatWalk = animationModeCombatWalk;
_animationModeCombatRun = animationModeCombatRun;
_inCombat = true;
if (_id != kActorMcCoy) {
- _combatInfo->combatOn(_id, a2, a3, otherActorId, a5, a9, a10, a11, ammoDamage, a13, a14);
+ _combatInfo->combatOn(_id, initialState, rangedAttack, enemyId, waypointType, fleeRatio, coverRatio, actionRatio, damage, range, unstoppable);
}
stopWalking(false);
changeAnimationMode(_animationModeCombatIdle, false);
- int i;
- for (i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
+ for (int i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
Actor *otherActor = _vm->_actors[i];
if (i != _id && otherActor->_setId == _setId && !otherActor->_isRetired) {
_vm->_aiScripts->otherAgentEnteredCombatMode(i, _id, true);
@@ -989,8 +1018,7 @@ void Actor::combatModeOff() {
_inCombat = false;
stopWalking(false);
changeAnimationMode(kAnimationModeIdle, false);
- int i;
- for (i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
+ for (int i = 0; i < (int)_vm->_gameInfo->getActorCount(); i++) {
Actor *otherActor = _vm->_actors[i];
if (i != _id && otherActor->_setId == _setId && !otherActor->_isRetired) {
_vm->_aiScripts->otherAgentEnteredCombatMode(i, _id, false);
@@ -1002,6 +1030,16 @@ float Actor::distanceFromActor(int otherActorId) {
return (_position - _vm->_actors[otherActorId]->_position).length();
}
+int Actor::angleTo(const Vector3 &target) const {
+ int angle = angle_1024(_position.x, _position.z, target.x, target.z) - _facing;
+ if (angle < -512) {
+ angle += 1024;
+ } else if (angle > 512) {
+ angle -= 1024;
+ }
+ return angle;
+}
+
float Actor::getX() const {
return _position.x;
}
@@ -1014,10 +1052,8 @@ float Actor::getZ() const {
return _position.z;
}
-void Actor::getXYZ(float *x, float *y, float *z) const {
- *x = _position.x;
- *y = _position.y;
- *z = _position.z;
+Vector3 Actor::getXYZ() const {
+ return _position;
}
int Actor::getFacing() const {
@@ -1044,13 +1080,10 @@ int Actor::getGoal() const {
}
void Actor::speechPlay(int sentenceId, bool voiceOver) {
- char name[13];
- sprintf(name, "%02d-%04d%s.AUD", _id, sentenceId, _vm->_languageCode);
- int balance;
+ Common::String name = Common::String::format( "%02d-%04d%s.AUD", _id, sentenceId, _vm->_languageCode.c_str());
- if (voiceOver || _id == BladeRunnerEngine::kActorVoiceOver) {
- balance = 0;
- } else {
+ int balance = 0;
+ if (!voiceOver && _id != BladeRunnerEngine::kActorVoiceOver) {
// Vector3 pos = _vm->_view->_frameViewMatrix * _position;
int screenX = 320; //, screenY = 0;
//TODO: transform to screen space using fov;
@@ -1102,6 +1135,18 @@ void Actor::copyClues(int actorId) {
}
}
+void Actor::acquireCluesByRelations() {
+ if (_setId >= 0 && _setId != kSetFreeSlotG && _setId != _vm->_actors[0]->_setId) {
+ for (int i = 0; i < _vm->_gameInfo->getActorCount(); i++) {
+ if (i != _id && _vm->_actors[i]->_setId == _setId && i && _id
+ && checkFriendlinessAndHonesty(i)
+ && _vm->_actors[i]->checkFriendlinessAndHonesty(_id)) {
+ _clues->acquireCluesByRelations(_id, i);
+ }
+ }
+ }
+}
+
int Actor::soundVolume() const {
float dist = distanceFromView(_vm->_view);
return 35.0f * CLIP(1.0f - (dist / 1200.0f), 0.0f, 1.0f);
@@ -1112,8 +1157,8 @@ int Actor::soundBalance() const {
return 35.0f * (CLIP(screenPosition.x / 640.0f, 0.0f, 1.0f) * 2.0f - 1.0f);
}
-bool Actor::isObstacleBetween(float targetX, float targetZ) {
- return _vm->_sceneObjects->isObstacleBetween(_position.x, _position.z, targetX, targetZ, _position.y, -1);
+bool Actor::isObstacleBetween(const Vector3 &target) {
+ return _vm->_sceneObjects->isObstacleBetween(_position, target, -1);
}
int Actor::findTargetUnderMouse(BladeRunnerEngine *vm, int mouseX, int mouseY) {
@@ -1204,4 +1249,157 @@ bool Actor::walkToNearestPoint(const Vector3 &destination, float distance) {
return false;
}
+void Actor::save(SaveFileWriteStream &f) {
+ f.writeInt(_id);
+ f.writeInt(_setId);
+ f.writeVector3(_position);
+ f.writeInt(_facing);
+ f.writeInt(_targetFacing);
+ f.writeInt(_timer4RemainDefault);
+
+ f.writeInt(_honesty);
+ f.writeInt(_intelligence);
+ f.writeInt(_stability);
+ f.writeInt(_combatAggressiveness);
+ f.writeInt(_goalNumber);
+
+ f.writeInt(_currentHP);
+ f.writeInt(_maxHP);
+
+ f.writeBool(_movementTrackPaused);
+ f.writeInt(_movementTrackNextWaypointId);
+ f.writeInt(_movementTrackNextDelay);
+ f.writeInt(_movementTrackNextAngle);
+ f.writeBool(_movementTrackNextRunning);
+
+ f.writeInt(0); // TODO: _clueType
+ f.writeBool(_isMoving);
+ f.writeBool(_isTarget);
+ f.writeBool(_inCombat);
+ f.writeBool(_isInvisible);
+ f.writeBool(_isRetired);
+ f.writeBool(_isImmuneToObstacles);
+
+ f.writeInt(_animationMode);
+ f.writeInt(_fps);
+ f.writeInt(_frameMs);
+ f.writeInt(_animationId);
+ f.writeInt(_animationFrame);
+
+ f.writeInt(_movementTrackWalkingToWaypointId);
+ f.writeInt(_movementTrackDelayOnNextWaypoint);
+
+ f.writeRect(_screenRectangle);
+ f.writeInt(_retiredWidth);
+ f.writeInt(_retiredHeight);
+ f.writeInt(_damageAnimIfMoving);
+ f.writeInt(0); // TODO: _actorFieldU6
+ f.writeInt(0); // TODO: _actorFieldU7
+ f.writeFloat(_scale);
+
+ for (int i = 0; i < 7; ++i) {
+ f.writeInt(_timersLeft[i]);
+ }
+
+ uint32 now = _vm->getTotalPlayTime(); // TODO: should be last lock time
+ for (int i = 0; i < 7; ++i) {
+ f.writeInt(_timersLast[i] - now);
+ }
+
+ int actorCount = _vm->_gameInfo->getActorCount();
+ for (int i = 0; i != actorCount; ++i) {
+ f.writeInt(_friendlinessToOther[i]);
+ }
+
+ _clues->save(f);
+
+ _movementTrack->save(f);
+
+ _walkInfo->save(f);
+
+ f.writeBoundingBox(_bbox);
+
+ _combatInfo->save(f);
+ f.writeInt(_animationModeCombatIdle);
+ f.writeInt(_animationModeCombatWalk);
+ f.writeInt(_animationModeCombatRun);
+}
+
+void Actor::load(SaveFileReadStream &f) {
+ _id = f.readInt();
+ _setId = f.readInt();
+ _position = f.readVector3();
+ _facing = f.readInt();
+ _targetFacing = f.readInt();
+ _timer4RemainDefault = f.readInt();
+
+ _honesty = f.readInt();
+ _intelligence = f.readInt();
+ _stability = f.readInt();
+ _combatAggressiveness = f.readInt();
+ _goalNumber = f.readInt();
+
+ _currentHP = f.readInt();
+ _maxHP = f.readInt();
+
+ _movementTrackPaused = f.readBool();
+ _movementTrackNextWaypointId = f.readInt();
+ _movementTrackNextDelay = f.readInt();
+ _movementTrackNextAngle = f.readInt();
+ _movementTrackNextRunning = f.readBool();
+
+ f.skip(4); // TODO: _clueType
+ _isMoving = f.readBool();
+ _isTarget = f.readBool();
+ _inCombat = f.readBool();
+ _isInvisible = f.readBool();
+ _isRetired = f.readBool();
+ _isImmuneToObstacles = f.readBool();
+
+ _animationMode = f.readInt();
+ _fps = f.readInt();
+ _frameMs = f.readInt();
+ _animationId = f.readInt();
+ _animationFrame = f.readInt();
+
+ _movementTrackWalkingToWaypointId = f.readInt();
+ _movementTrackDelayOnNextWaypoint = f.readInt();
+
+ _screenRectangle = f.readRect();
+ _retiredWidth = f.readInt();
+ _retiredHeight = f.readInt();
+ _damageAnimIfMoving = f.readInt();
+ f.skip(4); // TODO: _actorFieldU6
+ f.skip(4); // TODO: _actorFieldU7
+ _scale = f.readFloat();
+
+ for (int i = 0; i < 7; ++i) {
+ _timersLeft[i] = f.readInt();
+ }
+
+ uint32 now = _vm->getTotalPlayTime(); // TODO: should be last lock time
+ for (int i = 0; i < 7; ++i) {
+ _timersLast[i] = f.readInt() + now;
+ }
+
+ int actorCount = _vm->_gameInfo->getActorCount();
+ for (int i = 0; i != actorCount; ++i) {
+ _friendlinessToOther[i] = f.readInt();
+ }
+
+ _clues->load(f);
+
+ _movementTrack->load(f);
+
+ _walkInfo->load(f);
+
+ _bbox = f.readBoundingBox();
+
+ _combatInfo->load(f);
+
+ _animationModeCombatIdle = f.readInt();
+ _animationModeCombatWalk = f.readInt();
+ _animationModeCombatRun = f.readInt();
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/actor.h b/engines/bladerunner/actor.h
index af0c14e367..6540c0593a 100644
--- a/engines/bladerunner/actor.h
+++ b/engines/bladerunner/actor.h
@@ -23,6 +23,7 @@
#ifndef BLADERUNNER_ACTOR_H
#define BLADERUNNER_ACTOR_H
+#include "bladerunner/boundingbox.h"
#include "bladerunner/vector.h"
#include "common/array.h"
@@ -36,21 +37,22 @@ class ActorWalk;
class BladeRunnerEngine;
class BoundingBox;
class MovementTrack;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class View;
class Actor {
- friend class ScriptBase;
- friend class KIA;
-
BladeRunnerEngine *_vm;
-private:
- BoundingBox *_bbox;
+public:
+ BoundingBox _bbox;
Common::Rect _screenRectangle;
MovementTrack *_movementTrack;
ActorWalk *_walkInfo;
ActorCombat *_combatInfo;
+ ActorClues *_clues;
+private:
int _honesty;
int _intelligence;
int _stability;
@@ -61,8 +63,6 @@ private:
int _currentHP;
int _maxHP;
- ActorClues *_clues;
-
int _id;
int _setId;
Vector3 _position;
@@ -70,6 +70,8 @@ private:
int _targetFacing;
int _walkboxId;
+ int _timer4RemainDefault;
+
// Flags
bool _isTarget;
bool _isInvisible;
@@ -124,7 +126,7 @@ public:
float getX() const;
float getY() const;
float getZ() const;
- void getXYZ(float *x, float *y, float *z) const;
+ Vector3 getXYZ() const;
int getFacing() const;
int getAnimationMode() const;
@@ -149,7 +151,7 @@ public:
bool walkTo(bool runFlag, const Vector3 &destination, bool a3);
bool loopWalkToActor(int otherActorId, int destinationOffset, int interruptible, bool runFlag, bool a5, bool *isRunningFlag);
bool loopWalkToItem(int itemId, int destinationOffset, int interruptible, bool runFlag, bool a5, bool *isRunningFlag);
- bool loopWalkToSceneObject(const char *objectName, int destinationOffset, bool interruptible, bool runFlag, bool a5, bool *isRunningFlag);
+ bool loopWalkToSceneObject(const Common::String &objectName, int destinationOffset, bool interruptible, bool runFlag, bool a5, bool *isRunningFlag);
bool loopWalkToWaypoint(int waypointId, int destinationOffset, int interruptible, bool runFlag, bool a5, bool *isRunningFlag);
bool loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool interruptible, bool runFlag, bool a5, bool *isRunningFlag);
bool asyncWalkToWaypoint(int waypointId, int destinationOffset, bool runFlag, bool a5);
@@ -157,60 +159,83 @@ public:
void run();
bool tick(bool forceUpdate, Common::Rect *screenRect);
+ void tickCombat();
bool draw(Common::Rect *screenRect);
int getSetId() const;
void setSetId(int setId);
- BoundingBox *getBoundingBox() const { return _bbox; }
- Common::Rect *getScreenRectangle() { return &_screenRectangle; }
+ const BoundingBox &getBoundingBox() const { return _bbox; }
+ const Common::Rect &getScreenRectangle() { return _screenRectangle; }
int getWalkbox() const { return _walkboxId; }
+
bool isRetired() const { return _isRetired; }
bool isTarget() const { return _isTarget; }
void setTarget(bool targetable);
bool isImmuneToObstacles() const { return _isImmuneToObstacles; }
bool inCombat() const { return _inCombat; }
+
bool isMoving() const { return _isMoving; }
void setMoving(bool value) { _isMoving = value; }
+
bool inWalkLoop() const { return _inWalkLoop; }
bool isWalking() const;
bool isRunning() const;
void stopWalking(bool value);
void faceActor(int otherActorId, bool animate);
- void faceObject(const char *objectName, bool animate);
+ void faceObject(const Common::String &objectName, bool animate);
void faceItem(int itemId, bool animate);
void faceWaypoint(int waypointId, bool animate);
void faceXYZ(float x, float y, float z, bool animate);
void faceXYZ(const Vector3 &pos, bool animate);
void faceCurrentCamera(bool animate);
void faceHeading(int heading, bool animate);
- void modifyFriendlinessToOther(int otherActorId, signed int change);
+ void setFacing(int facing, bool halfOrSet = true);
+
+ int getCurrentHP() const { return _currentHP; }
+ int getMaxHP() const { return _maxHP; }
+ void setCurrentHP(int hp);
+ void setHealth(int hp, int maxHp);
+ void modifyCurrentHP(signed int change);
+ void modifyMaxHP(signed int change);
+
+ int getFriendlinessToOther(int otherActorId) const { return _friendlinessToOther[otherActorId]; }
void setFriendlinessToOther(int otherActorId, int friendliness);
+ void modifyFriendlinessToOther(int otherActorId, signed int change);
+ bool checkFriendlinessAndHonesty(int otherActorId);
+
+ int getHonesty() const { return _honesty; }
void setHonesty(int honesty);
+ void modifyHonesty(signed int change);
+
+ int getIntelligence() const { return _intelligence; }
void setIntelligence(int intelligence);
+ void modifyIntelligence(signed int change);
+
+ int getStability() const { return _stability; }
void setStability(int stability);
+ void modifyStability(signed int change);
+
+ int getCombatAggressiveness() const { return _combatAggressiveness; }
void setCombatAggressiveness(int combatAggressiveness);
+ void modifyCombatAggressiveness(signed int change);
+
void setInvisible(bool isInvisible);
void setImmunityToObstacles(bool isImmune);
- void modifyCurrentHP(signed int change);
- void modifyMaxHP(signed int change);
- void modifyCombatAggressiveness(signed int change);
- void modifyHonesty(signed int change);
- void modifyIntelligence(signed int change);
- void modifyStability(signed int change);
+
void setFlagDamageAnimIfMoving(bool value);
- bool getFlagDamageAnimIfMoving() const;
- void setHealth(int hp, int maxHp);
+ bool getFlagDamageAnimIfMoving() const;
void retire(bool isRetired, int width, int height, int retiredByActorId);
- void combatModeOn(int a2, int a3, int a4, int a5, int combatAnimationMode, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14);
+ void combatModeOn(int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool unstoppable);
void combatModeOff();
void setGoal(int goalNumber);
int getGoal() const;
float distanceFromActor(int otherActorId);
+ int angleTo(const Vector3 &target) const;
void speechPlay(int sentenceId, bool voiceOver);
void speechStop();
@@ -221,15 +246,19 @@ public:
void loseClue(int clueId);
bool hasClue(int clueId) const;
void copyClues(int actorId);
+ void acquireCluesByRelations();
int soundVolume() const;
int soundBalance() const;
- bool isObstacleBetween(float targetX, float targetZ);
+ bool isObstacleBetween(const Vector3 &target);
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
static int findTargetUnderMouse(BladeRunnerEngine *vm, int mouseX, int mouseY);
+
private:
- void setFacing(int facing, bool halfOrSet = true);
void setBoundingBox(const Vector3 &position, bool retired);
float distanceFromView(View *view) const;
diff --git a/engines/bladerunner/actor_clues.cpp b/engines/bladerunner/actor_clues.cpp
index 39fbc77d4e..b34e67b46e 100644
--- a/engines/bladerunner/actor_clues.cpp
+++ b/engines/bladerunner/actor_clues.cpp
@@ -21,10 +21,13 @@
*/
#include "bladerunner/actor_clues.h"
+#include "bladerunner/actor.h"
+#include "bladerunner/script/ai_script.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_info.h"
#include "bladerunner/crimes_database.h"
+#include "bladerunner/savefile.h"
#include "common/debug.h"
@@ -87,6 +90,147 @@ bool ActorClues::isAcquired(int clueId) const {
#endif
}
+int ActorClues::getWeight(int clueId) const {
+ int clueIndex = findClueIndex(clueId);
+ if (clueIndex == -1) {
+ return 0;
+ }
+ return _clues[clueIndex].weight;
+}
+
+int ActorClues::getModifier(int actorId, int otherActorId, int clueId) {
+ Actor *actor = _vm->_actors[actorId];
+ int modifier1, modifier2, modifier3, modifier4;
+
+ int friendliness = actor->getFriendlinessToOther(otherActorId);
+ int clueWeight = actor->_clues->getWeight(clueId);
+
+ if (actor->_clues->isFlag2(clueId)) {
+ modifier1 = 100 - actor->getHonesty() - friendliness;
+ } else {
+ modifier1 = 0;
+ }
+ modifier2 = 0;
+ modifier3 = _vm->_aiScripts->callGetFriendlinessModifierIfGetsClue(otherActorId, actorId, clueId);
+
+ for (int i = 0; i < _vm->_gameInfo->getActorCount(); i++) {
+ if (i != actorId && i != otherActorId) {
+ modifier2 += (friendliness - 50) * _vm->_aiScripts->callGetFriendlinessModifierIfGetsClue(i, otherActorId, clueId) / 100;
+ }
+ }
+ modifier4 = _vm->_rnd.getRandomNumberRng(0, (100 - actor->getIntelligence()) / 10);
+
+ if (_vm->_rnd.getRandomNumberRng(0, 1) == 1) {
+ modifier4 = -modifier4;
+ }
+
+ return modifier1 + modifier2 + modifier3 + modifier4 + clueWeight;
+}
+
+static int cluesCompare(const void *p1, const void *p2) {
+ const ActorClues::CluesUS *clue1 = (const ActorClues::CluesUS *)p1;
+ const ActorClues::CluesUS *clue2 = (const ActorClues::CluesUS *)p2;
+
+ if (clue1->modifier > clue2->modifier)
+ return -1;
+
+ return (clue1->modifier < clue2->modifier);
+}
+
+void ActorClues::acquireCluesByRelations(int actorId, int otherActorId) {
+ CluesUS clues1[kClueCount], clues2[kClueCount];
+
+ int count1 = findAcquirableCluesFromActor(actorId, otherActorId, clues1, kClueCount);
+ int count2 = findAcquirableCluesFromActor(otherActorId, actorId, clues2, kClueCount);
+
+ if (count1 || count2) {
+ for (int i = 0; i < count1; i++) {
+ clues1[i].modifier = getModifier(actorId, otherActorId, clues1[i].clueId);
+ }
+ qsort(clues1, count1, sizeof(CluesUS), cluesCompare);
+
+ for (int i = 0; i < count2; i++) {
+ clues2[i].modifier = getModifier(otherActorId, actorId, clues2[i].clueId);
+ }
+ qsort(clues2, count2, sizeof(CluesUS), cluesCompare);
+
+ Actor *actor = _vm->_actors[actorId];
+ Actor *otherActor = _vm->_actors[otherActorId];
+
+ int avgParameters = (otherActor->getHonesty() + otherActor->getIntelligence() + actor->getFriendlinessToOther(otherActorId)) / 3;
+ int clue1count = avgParameters * count1 / 100;
+
+ if (avgParameters >= 50 && !clue1count && count1 == 1) {
+ clue1count = 1;
+ }
+
+ avgParameters = (actor->getHonesty() + actor->getIntelligence() + otherActor->getFriendlinessToOther(actorId)) / 3;
+ int clue2count = avgParameters * count2 / 100;
+
+ if (avgParameters >= 50 && !clue2count && count2 == 1) {
+ clue2count = 1;
+ }
+
+ for (int i = 0; i < clue2count; i++) {
+ bool flag = false;
+ if (otherActor->_clues->isFlag2(clues2[i].clueId)) {
+ avgParameters = (2 * otherActor->getFriendlinessToOther(actorId) + otherActor->getHonesty()) / 3;
+
+ if (avgParameters > 70) {
+ avgParameters = 100;
+ } else if (avgParameters < 30) {
+ avgParameters = 0;
+ }
+ if (_vm->_rnd.getRandomNumberRng(1, 100) <= avgParameters) {
+ flag = true;
+ }
+ }
+
+ actor->_clues->acquire(clues2[i].clueId, flag, otherActorId);
+ }
+
+ for (int i = 0; i < clue1count; i++) {
+ bool flag = false;
+ if (actor->_clues->isFlag2(clues1[i].clueId)) {
+ avgParameters = (2 * actor->getFriendlinessToOther(otherActorId) + actor->getHonesty()) / 3;
+
+ if (avgParameters > 70) {
+ avgParameters = 100;
+ } else if (avgParameters < 30) {
+ avgParameters = 0;
+ }
+ if (_vm->_rnd.getRandomNumberRng(1, 100) <= avgParameters) {
+ flag = true;
+ }
+ }
+
+ otherActor->_clues->acquire(clues1[i].clueId, flag, actorId);
+ }
+ }
+}
+
+int ActorClues::findAcquirableCluesFromActor(int actorId, int targetActorId, CluesUS *list, int size) {
+ Actor *actor = _vm->_actors[actorId];
+ Actor *otherActor = _vm->_actors[targetActorId];
+ int count = 0;
+ int cluesCount = actor->_clues->getCount();
+
+ for (int i = 0; i < cluesCount; i++) {
+ int clueId = actor->_clues->getClueIdByIndex(i);
+
+ if (actor->_clues->isAcquired(clueId)
+ && otherActor->_clues->getWeight(clueId) > 0
+ && !otherActor->_clues->isAcquired(clueId)) {
+ list[count].clueId = clueId;
+ list[count].modifier = 0;
+
+ count++;
+ }
+ }
+
+ return count;
+}
+
int ActorClues::getFromActorId(int clueId) const {
int clueIndex = findClueIndex(clueId);
if (clueIndex == -1) {
@@ -166,6 +310,10 @@ int ActorClues::getCount() const {
return _count;
}
+int ActorClues::getClueIdByIndex(int index) const {
+ return _clues[index].clueId;
+}
+
void ActorClues::removeAll() {
_count = 0;
for (int i = 0; i < _maxCount; ++i) {
@@ -216,6 +364,44 @@ void ActorClues::remove(int index) {
_clues[index].field8 = 0;
}
+void ActorClues::save(SaveFileWriteStream &f) {
+ f.writeInt(_count);
+ f.writeInt(_maxCount);
+ for (int i = 0; i < _count; ++i) {
+ Clue &c = _clues[i];
+ f.writeInt(c.clueId);
+ f.writeInt(c.weight);
+ f.writeInt(c.fromActorId);
+ f.writeInt(c.field3);
+ f.writeInt(c.field4);
+ f.writeInt(c.field5);
+ f.writeInt(c.field6);
+ f.writeInt(c.field7);
+ f.writeInt(c.field8);
+ f.writeByte(c.flags);
+ }
+}
+
+void ActorClues::load(SaveFileReadStream &f) {
+ _count = f.readInt();
+ _maxCount = f.readInt();
+ _clues.clear();
+ _clues.resize(_maxCount);
+ for (int i = 0; i < _count; ++i) {
+ Clue &c = _clues[i];
+ c.clueId = f.readInt();
+ c.weight = f.readInt();
+ c.fromActorId = f.readInt();
+ c.field3 = f.readInt();
+ c.field4 = f.readInt();
+ c.field5 = f.readInt();
+ c.field6 = f.readInt();
+ c.field7 = f.readInt();
+ c.field8 = f.readInt();
+ c.flags = f.readByte();
+ }
+}
+
bool ActorClues::exists(int clueId) const {
return findClueIndex(clueId) != -1;
}
diff --git a/engines/bladerunner/actor_clues.h b/engines/bladerunner/actor_clues.h
index b2b39d8b89..76690329d3 100644
--- a/engines/bladerunner/actor_clues.h
+++ b/engines/bladerunner/actor_clues.h
@@ -28,8 +28,12 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class ActorClues {
+ static const int kClueCount = 288;
+
struct Clue {
int clueId;
int weight;
@@ -40,7 +44,7 @@ class ActorClues {
int field6;
int field7;
int field8;
- unsigned char flags;
+ byte flags;
};
BladeRunnerEngine *_vm;
@@ -50,6 +54,12 @@ class ActorClues {
Common::Array<Clue> _clues;
public:
+ struct CluesUS {
+ int clueId;
+ int modifier;
+ };
+
+public:
ActorClues(BladeRunnerEngine *_vm, int cluesType);
void add(int actorId, int clueId, int unknown, bool acquired, bool unknownFlag, int fromActorId);
@@ -57,6 +67,12 @@ public:
void acquire(int clueId, bool flag2, int fromActorId);
void lose(int clueId);
bool isAcquired(int clueId) const;
+ int getWeight(int clueId) const;
+
+ int getModifier(int actorId, int otherActorId, int clueId);
+
+ void acquireCluesByRelations(int actorId, int otherActorId);
+ int findAcquirableCluesFromActor(int actorId, int targetActorId, CluesUS *list, int size);
int getFromActorId(int clueId) const;
@@ -71,11 +87,12 @@ public:
int getField1(int clueId) const;
int getCount() const;
+ int getClueIdByIndex(int index) const;
void removeAll();
- //savegame
- //loadgame
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
private:
bool exists(int clueId) const;
diff --git a/engines/bladerunner/actor_combat.cpp b/engines/bladerunner/actor_combat.cpp
index 4bd8d17c67..4bcce5d3bf 100644
--- a/engines/bladerunner/actor_combat.cpp
+++ b/engines/bladerunner/actor_combat.cpp
@@ -22,25 +22,673 @@
#include "bladerunner/actor_combat.h"
+#include "bladerunner/actor.h"
+#include "bladerunner/audio_speech.h"
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/combat.h"
+#include "bladerunner/game_constants.h"
+#include "bladerunner/game_info.h"
+#include "bladerunner/movement_track.h"
+#include "bladerunner/savefile.h"
+#include "bladerunner/scene.h"
+#include "bladerunner/scene_objects.h"
+#include "bladerunner/script/ai_script.h"
+#include "bladerunner/set.h"
+#include "bladerunner/settings.h"
+
namespace BladeRunner {
ActorCombat::ActorCombat(BladeRunnerEngine *vm) {
_vm = vm;
+ reset();
}
ActorCombat::~ActorCombat() {
}
-void ActorCombat::hitAttempt() {
+void ActorCombat::setup() {
+ reset();
}
-void ActorCombat::combatOn(int actorId, int a3, int a4, int otherActorId, int a6, int a7, int a8, int a9, int ammoDamage, int a11, int a12) {
+void ActorCombat::combatOn(int actorId, int initialState, bool rangedAttackFlag, int enemyId, int waypointType, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool unstoppable) {
+ _actorId = actorId;
+ _state = initialState;
+ _rangedAttack = rangedAttackFlag;
+ _enemyId = enemyId;
+ _waypointType = waypointType;
+ _damage = damage;
+ _fleeRatioConst = fleeRatio;
+ _coverRatioConst = coverRatio;
+ _actionRatioConst = actionRatio;
+ _fleeRatio = fleeRatio;
+ _coverRatio = coverRatio;
+ _actionRatio = actionRatio;
+ _active = true;
+ if (_rangedAttack) {
+ _range = range;
+ } else {
+ _range = 300;
+ }
+ _unstoppable = unstoppable;
+
+ Actor *actor = _vm->_actors[_actorId];
+
+ _actorPosition = actor->getXYZ();
+ _enemyPosition = _vm->_actors[_enemyId]->getXYZ();
+
+ actor->_movementTrack->flush();
+ actor->stopWalking(false);
+
+ if (_enemyId == kActorMcCoy) {
+ actor->setTarget(true);
+ }
+
+ _actorHp = actor->getCurrentHP();
+
+ _coversWaypointCount = 0;
+ for (int i = 0; i < (int)_vm->_gameInfo->getCoverWaypointCount(); ++i) {
+ if (_vm->_combat->_coverWaypoints[i].type == waypointType && _vm->_combat->_coverWaypoints[i].setId == actor->getSetId()) {
+ ++_coversWaypointCount;
+ }
+ }
+ if (_coversWaypointCount == 0) {
+ _coverRatioConst = 0;
+ _coverRatio = 0;
+ }
+
+ _fleeWaypointsCount = 0;
+ for (int i = 0; i < (int)_vm->_gameInfo->getFleeWaypointCount(); ++i) {
+ if (_vm->_combat->_fleeWaypoints[i].type == waypointType && _vm->_combat->_fleeWaypoints[i].setId == actor->getSetId()) {
+ ++_fleeWaypointsCount;
+ }
+ }
+ if (_fleeWaypointsCount == 0) {
+ _fleeRatioConst = 0;
+ _fleeRatio = 0;
+ }
}
void ActorCombat::combatOff() {
+ _active = false;
+ reset();
}
-void ActorCombat::setup() {
+void ActorCombat::tick() {
+ static int processingCounter = 0;
+
+ if (!_active || processingCounter > 0) {
+ return;
+ }
+
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ if (actor->getSetId() != enemy->getSetId()) {
+ actor->combatModeOff();
+ return;
+ }
+
+ ++processingCounter;
+
+ _actorPosition = actor->getXYZ();
+ _enemyPosition = enemy->getXYZ();
+
+ if (_actionRatioConst >= 0) {
+ _actionRatio = _actionRatioConst;
+ } else {
+ _actionRatio = calculateActionRatio();
+ }
+
+ if (_vm->_combat->findCoverWaypoint(_waypointType, _actorId, _enemyId) != -1) {
+ if (_coverRatioConst >= 0) {
+ _coverRatio = _coverRatioConst;
+ } else {
+ _coverRatio = calculateCoverRatio();
+ }
+ } else {
+ _coverRatio = 0;
+ }
+
+ if (_fleeRatioConst >= 0) {
+ _fleeRatio = _fleeRatioConst;
+ } else {
+ _fleeRatio = calculateFleeRatio();
+ }
+
+ float dist = actor->distanceFromActor(_enemyId);
+ int oldState = _state;
+
+ if (_actionRatio < _fleeRatio || _actionRatio < _coverRatio) {
+ if (_coverRatio >= _fleeRatio && _coverRatio >= _actionRatio) {
+ _state = kActorCombatStateCover;
+ } else {
+ _state = kActorCombatStateFlee;
+ }
+ } else {
+ if (_rangedAttack) {
+ if (dist > _range) {
+ _state = kActorCombatStateApproachRangedAttack;
+ } else {
+ if (actor->isObstacleBetween(_enemyPosition)) {
+ _state = kActorCombatStateUncover;
+ } else {
+ _state = kActorCombatStateRangedAttack;
+ }
+ }
+ } else {
+ if (dist > 36.0f) {
+ _state = kActorCombatStateApproachCloseAttack;
+ } else {
+ _state = kActorCombatStateCloseAttack;
+ }
+ }
+ }
+
+ if (enemy->isRetired()) {
+ _state = kActorCombatStateIdle;
+ }
+
+ if (actor->getAnimationMode() == kAnimationModeHit || actor->getAnimationMode() == kAnimationModeCombatHit) {
+ _state = kActorCombatStateIdle;
+ } else {
+ if (_state != oldState) {
+ actor->stopWalking(false);
+ }
+ }
+ switch (_state) {
+ case kActorCombatStateCover:
+ cover();
+ break;
+ case kActorCombatStateApproachCloseAttack:
+ approachToCloseAttack();
+ break;
+ case kActorCombatStateUncover:
+ uncover();
+ break;
+ case kActorCombatStateAim:
+ aim();
+ break;
+ case kActorCombatStateRangedAttack:
+ rangedAttack();
+ break;
+ case kActorCombatStateCloseAttack:
+ closeAttack();
+ break;
+ case kActorCombatStateFlee:
+ flee();
+ break;
+ case kActorCombatStateApproachRangedAttack:
+ approachToRangedAttack();
+ break;
+ }
+ --processingCounter;
+}
+
+void ActorCombat::hitAttempt() {
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ if (_enemyId == kActorMcCoy && !_vm->playerHasControl() && !_unstoppable) {
+ return;
+ }
+
+ if (actor->isRetired()) {
+ return;
+ }
+
+ int aggressiveness = 0;
+ if (_rangedAttack) {
+ aggressiveness = _rangedAttack == 1 ? getaggressivenessRangedAttack() : 0;
+ } else {
+ aggressiveness = getaggressivenessCloseAttack();
+ }
+
+ if (aggressiveness == 0) {
+ return;
+ }
+
+ int random = _vm->_rnd.getRandomNumberRng(1, 100);
+
+ if (random <= aggressiveness) {
+ if (enemy->isWalking()) {
+ enemy->stopWalking(true);
+ }
+
+ int sentenceId = _vm->_rnd.getRandomNumberRng(0, 1) ? 9000 : 9005;
+ if (enemy->inCombat()) {
+ enemy->changeAnimationMode(22, false);
+ } else {
+ enemy->changeAnimationMode(21, false);
+ }
+
+ int damage = 0;
+ if (_rangedAttack) {
+ damage = getDamageRangedAttack(random, aggressiveness);
+ } else {
+ damage = getDamageCloseAttack(random, aggressiveness);
+ }
+
+ int enemyHp = MAX(enemy->getCurrentHP() - damage, 0);
+ enemy->setCurrentHP(enemyHp);
+
+ if (enemyHp <= 0) {
+ if (!enemy->isRetired()) {
+ if (enemy->inCombat()) {
+ enemy->changeAnimationMode(49, false);
+ } else {
+ enemy->changeAnimationMode(48, false);
+ }
+ sentenceId = 9020;
+ }
+ enemy->retire(true, 6, 3, _actorId);
+ }
+
+ if (_enemyId == kActorMcCoy) {
+ sentenceId += 900;
+ }
+
+ _vm->_audioSpeech->playSpeechLine(_enemyId, sentenceId, 75, enemy->soundBalance(), 99);
+ }
+}
+
+void ActorCombat::save(SaveFileWriteStream &f) {
+ f.writeInt(_actorId);
+ f.writeBool(_active);
+ f.writeInt(_state);
+ f.writeBool(_rangedAttack);
+ f.writeInt(_enemyId);
+ f.writeInt(_waypointType);
+ f.writeInt(_damage);
+ f.writeInt(_fleeRatio);
+ f.writeInt(_coverRatio);
+ f.writeInt(_actionRatio);
+ f.writeInt(_fleeRatioConst);
+ f.writeInt(_coverRatioConst);
+ f.writeInt(_actionRatioConst);
+ f.writeInt(_range);
+ f.writeInt(_unstoppable);
+ f.writeInt(_actorHp);
+ f.writeInt(_fleeingTowards);
+ f.writeVector3(_actorPosition);
+ f.writeVector3(_enemyPosition);
+ f.writeInt(_coversWaypointCount);
+ f.writeInt(_fleeWaypointsCount);
+}
+
+void ActorCombat::load(SaveFileReadStream &f) {
+ _actorId = f.readInt();
+ _active = f.readBool();
+ _state = f.readInt();
+ _rangedAttack = f.readBool();
+ _enemyId = f.readInt();
+ _waypointType = f.readInt();
+ _damage = f.readInt();
+ _fleeRatio = f.readInt();
+ _coverRatio = f.readInt();
+ _actionRatio = f.readInt();
+ _fleeRatioConst = f.readInt();
+ _coverRatioConst = f.readInt();
+ _actionRatioConst = f.readInt();
+ _range = f.readInt();
+ _unstoppable = f.readInt();
+ _actorHp = f.readInt();
+ _fleeingTowards = f.readInt();
+ _actorPosition = f.readVector3();
+ _enemyPosition = f.readVector3();
+ _coversWaypointCount = f.readInt();
+ _fleeWaypointsCount = f.readInt();
+}
+
+void ActorCombat::reset() {
+ _active = false;
+ _actorId = -1;
+ _state = -1;
+ _rangedAttack = false;
+ _enemyId = -1;
+ _waypointType = -1;
+ _damage = 0;
+ _fleeRatio = -1;
+ _coverRatio = -1;
+ _actionRatio = -1;
+ _fleeRatioConst = -1;
+ _coverRatioConst = -1;
+ _actionRatioConst = -1;
+ _actorHp = 0;
+ _range = 300;
+ _unstoppable = false;
+ _actorPosition = Vector3(0.0f, 0.0f, 0.0f);
+ _enemyPosition = Vector3(0.0f, 0.0f, 0.0f);
+ _coversWaypointCount = 0;
+ _fleeWaypointsCount = 0;
+ _fleeingTowards = -1;
+}
+
+void ActorCombat::cover() {
+ Actor *actor = _vm->_actors[_actorId];
+
+ if (actor->isWalking()) {
+ return;
+ }
+
+ if (actor->isObstacleBetween(_enemyPosition)) {
+ faceEnemy();
+ return;
+ }
+
+ int coverWaypointId = _vm->_combat->findCoverWaypoint(_waypointType, _actorId, _enemyId);
+ if (coverWaypointId == -1) {
+ _state = kActorCombatStateIdle;
+ } else {
+ actor->asyncWalkToXYZ(_vm->_combat->_coverWaypoints[coverWaypointId].position, 0, true, 0);
+ }
+}
+
+void ActorCombat::approachToCloseAttack() {
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ float dist = actor->distanceFromActor(_enemyId);
+ if (dist > 36.0f) {
+ if (!actor->isWalking() || enemy->isWalking()) {
+ Vector3 target;
+ if (findClosestPositionToEnemy(target)) {
+ actor->asyncWalkToXYZ(target, 0, dist >= 240.0f, 0);
+ } else {
+ _state = kActorCombatStateCover;
+ }
+ }
+ } else {
+ if (actor->isWalking()) {
+ actor->stopWalking(false);
+ }
+ faceEnemy();
+ _state = kActorCombatStateCloseAttack;
+ }
+}
+
+void ActorCombat::approachToRangedAttack() {
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ float dist = actor->distanceFromActor(_enemyId);
+ if (dist > _range) {
+ if (!actor->isWalking() || enemy->isWalking()) {
+ Vector3 target;
+ if (findClosestPositionToEnemy(target)) {
+ actor->asyncWalkToXYZ(target, 0, dist >= 240.0f, 0);
+ } else {
+ _state = kActorCombatStateCover;
+ }
+ }
+ } else {
+ if (actor->isWalking()) {
+ actor->stopWalking(false);
+ }
+ faceEnemy();
+ _state = kActorCombatStateRangedAttack;
+ }
+}
+
+void ActorCombat::uncover() {
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ if (actor->isObstacleBetween(_enemyPosition)) {
+ actor->asyncWalkToXYZ(enemy->getXYZ(), 16, false, 0);
+ } else {
+ if (actor->isWalking()) {
+ actor->stopWalking(false);
+ }
+ faceEnemy();
+ }
+}
+
+void ActorCombat::aim() {
+ Actor *actor = _vm->_actors[_actorId];
+
+ if (actor->isObstacleBetween(_enemyPosition)) {
+ if (actor->getAnimationMode() != kAnimationModeCombatIdle) {
+ actor->changeAnimationMode(kAnimationModeCombatIdle, false);
+ }
+ } else {
+ faceEnemy();
+ if (actor->getAnimationMode() != kAnimationModeCombatAim) {
+ actor->changeAnimationMode(kAnimationModeCombatAim, false);
+ }
+ }
+}
+
+void ActorCombat::rangedAttack() {
+ Actor *actor = _vm->_actors[_actorId];
+
+ if (actor->isObstacleBetween(_enemyPosition) || (actor->distanceFromActor(_enemyId) > _range)) {
+ _state = kActorCombatStateApproachRangedAttack;
+ } else {
+ faceEnemy();
+ if (actor->getAnimationMode() != kAnimationModeCombatAttack) {
+ if (_enemyId != kActorMcCoy || _vm->playerHasControl() || _unstoppable) {
+ actor->changeAnimationMode(kAnimationModeCombatAttack, false);
+ }
+ }
+ }
+}
+
+void ActorCombat::closeAttack() {
+ Actor *actor = _vm->_actors[_actorId];
+
+ if (actor->isObstacleBetween(_enemyPosition) || (actor->distanceFromActor(_enemyId) > 36.0f)) {
+ _state = kActorCombatStateApproachCloseAttack;
+ } else {
+ faceEnemy();
+ if (actor->getAnimationMode() != kAnimationModeCombatAttack) {
+ if (_enemyId != kActorMcCoy || _vm->playerHasControl() || _unstoppable) {
+ actor->changeAnimationMode(kAnimationModeCombatAttack, false);
+ }
+ }
+ }
+}
+
+void ActorCombat::flee() {
+ Actor *actor = _vm->_actors[_actorId];
+
+ if (_fleeingTowards != -1 && actor->isWalking()) {
+ Vector3 fleeWaypointPosition = _vm->_combat->_fleeWaypoints[_fleeingTowards].position;
+ if (distance(_actorPosition, fleeWaypointPosition) <= 12.0f) {
+ _vm->_aiScripts->fledCombat(_actorId/*, _enemyId*/);
+ actor->setSetId(kSetFreeSlotG);
+ actor->combatModeOff();
+ _fleeingTowards = -1;
+ }
+ } else {
+ int fleeWaypointId = _vm->_combat->findFleeWaypoint(actor->getSetId(), _enemyId, _actorPosition);
+ if (fleeWaypointId == -1) {
+ _state = kActorCombatStateIdle;
+ } else {
+ Vector3 fleeWaypointPosition = _vm->_combat->_fleeWaypoints[fleeWaypointId].position;
+ actor->asyncWalkToXYZ(fleeWaypointPosition, 0, true, 0);
+ _fleeingTowards = fleeWaypointId;
+ }
+ }
+}
+
+void ActorCombat::faceEnemy() {
+ _vm->_actors[_actorId]->setFacing(angle_1024(_actorPosition.x, _actorPosition.z, _enemyPosition.x, _enemyPosition.z), false);
+}
+
+int ActorCombat::getaggressivenessCloseAttack() const{
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ float distance = actor->distanceFromActor(_enemyId);
+
+ if (distance > 36.0f) {
+ return 0;
+ }
+
+ int aggressiveness = 0;
+ if (enemy->isRunning()) {
+ aggressiveness = 11;
+ } else if (enemy->isMoving()) {
+ aggressiveness = 22;
+ } else {
+ aggressiveness = 33;
+ }
+
+ aggressiveness += actor->getCombatAggressiveness() / 3;
+
+ int angle = abs(actor->angleTo(_enemyPosition));
+
+ if (angle > 128) {
+ return false;
+ }
+
+ return aggressiveness + (abs(angle - 128) / 3.7f);
+}
+
+int ActorCombat::getaggressivenessRangedAttack() const {
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ if (actor->isObstacleBetween(_enemyPosition)) {
+ return 0;
+ }
+
+ int distance = MIN(actor->distanceFromActor(_enemyId), 900.0f);
+
+ int aggressiveness = 0;
+ if (enemy->isRunning()) {
+ aggressiveness = 10;
+ } else if (enemy->isMoving()) {
+ aggressiveness = 20;
+ } else {
+ aggressiveness = 30;
+ }
+
+ aggressiveness += actor->getCombatAggressiveness() / 5;
+ return aggressiveness + abs((distance / 30) - 30) + actor->getIntelligence() / 5;
+}
+
+int ActorCombat::getDamageCloseAttack(int min, int max) const {
+ if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 0) {
+ return _damage / 2;
+ }
+ if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 2) {
+ return _damage;
+ }
+ return ((MIN(max - min, 30) * 100.0f / 60.0f) + 50) * _damage / 100;
+}
+
+int ActorCombat::getDamageRangedAttack(int min, int max) const {
+ if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 0) {
+ return _damage / 2;
+ }
+ if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 2) {
+ return _damage;
+ }
+ return ((MIN(max - min, 30) * 100.0f / 60.0f) + 50) * _damage / 100;
+}
+
+int ActorCombat::calculateActionRatio() const {
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ int aggressivenessFactor = actor->getCombatAggressiveness();
+ int actorHpFactor = actor->getCurrentHP();
+ int enemyHpFactor = 100 - enemy->getCurrentHP();
+ int combatFactor = enemy->inCombat() ? 0 : 100;
+ int angleFactor = (100 * abs(enemy->angleTo(_actorPosition))) / 512;
+ int distanceFactor = 2 * (50 - MAX(actor->distanceFromActor(_enemyId) / 12.0f, 50.0f));
+
+ if (_rangedAttack) {
+ return
+ angleFactor * 0.25f +
+ combatFactor * 0.05f +
+ enemyHpFactor * 0.20f +
+ actorHpFactor * 0.10f +
+ aggressivenessFactor * 0.40f;
+ } else {
+ return
+ distanceFactor * 0.20f +
+ angleFactor * 0.10f +
+ combatFactor * 0.10f +
+ enemyHpFactor * 0.15f +
+ actorHpFactor * 0.15f +
+ aggressivenessFactor * 0.30f;
+ }
+}
+
+int ActorCombat::calculateCoverRatio() const {
+ if (_coversWaypointCount == 0) {
+ return 0;
+ }
+
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ int angleFactor = 100 - (100 * abs(enemy->angleTo(_actorPosition))) / 512;
+ int actorHpFactor = 100 - actor->getCurrentHP();
+ int enemyHpFactor = enemy->getCurrentHP();
+ int aggressivenessFactor = 100 - actor->getCombatAggressiveness();
+ int distanceFactor = 2 * MAX(actor->distanceFromActor(_enemyId) / 12.0f, 50.0f);
+
+ if (_rangedAttack) {
+ return
+ angleFactor * 0.40f +
+ enemyHpFactor * 0.05f +
+ actorHpFactor * 0.15f +
+ aggressivenessFactor * 0.50f;
+ } else {
+ return
+ distanceFactor * 0.25f +
+ angleFactor * 0.20f +
+ enemyHpFactor * 0.05f +
+ actorHpFactor * 0.10f +
+ aggressivenessFactor * 0.50f;
+ }
+}
+
+int ActorCombat::calculateFleeRatio() const {
+ if (_fleeWaypointsCount == 0) {
+ return 0;
+ }
+
+ Actor *actor = _vm->_actors[_actorId];
+ Actor *enemy = _vm->_actors[_enemyId];
+
+ int aggressivenessFactor = 100 - actor->getCombatAggressiveness();
+ int actorHpFactor = 100 - actor->getCurrentHP();
+ int combatFactor = enemy->inCombat() ? 100 : 0;
+
+ return
+ combatFactor * 0.2f +
+ actorHpFactor * 0.4f +
+ aggressivenessFactor * 0.4f;
+}
+
+bool ActorCombat::findClosestPositionToEnemy(Vector3 &output) const {
+ output = Vector3();
+
+ Vector3 offsets[] = {
+ Vector3( 0.0f, 0.0f, -28.0f),
+ Vector3( 28.0f, 0.0f, 0.0f),
+ Vector3( 0.0f, 0.0f, 28.0f),
+ Vector3(-28.0f, 0.0f, 0.0f)
+ };
+
+ float min = -1.0f;
+
+ for (int i = 0; i < 4; ++i) {
+ Vector3 test = _enemyPosition + offsets[i];
+ float dist = distance(_actorPosition, test);
+ if ( min == -1.0f || dist < min) {
+ if (!_vm->_sceneObjects->existsOnXZ(_actorId, test.x, test.z, true, true) && _vm->_scene->_set->findWalkbox(test.x, test.z) >= 0) {
+ output = test;
+ min = dist;
+ }
+ }
+ }
+
+ return min >= 0.0f;
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/actor_combat.h b/engines/bladerunner/actor_combat.h
index b7ec93533d..8f36445008 100644
--- a/engines/bladerunner/actor_combat.h
+++ b/engines/bladerunner/actor_combat.h
@@ -28,31 +28,33 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class ActorCombat {
BladeRunnerEngine *_vm;
-// int _actorId;
-// int _combatOn;
-// int _field2;
-// int _field3;
-// int _otherActorId;
-// int _field5;
-// int _field6;
-// int _field7;
-// int _field8;
-// int _field9;
-// int _field10;
-// int _field11;
-// int _field12;
-// int _actorHp;
-// int _field14;
-// int _field15;
- Vector3 actorPosition;
- Vector3 otherActorPosition;
-// int _availableCoversCount;
-// int _availableFleeWaypointsCount;
-// int _field24;
+ int _actorId;
+ bool _active;
+ int _state;
+ bool _rangedAttack;
+ int _enemyId;
+ int _waypointType;
+ int _damage;
+ int _fleeRatio;
+ int _coverRatio;
+ int _actionRatio;
+ int _fleeRatioConst;
+ int _coverRatioConst;
+ int _actionRatioConst;
+ int _actorHp;
+ int _range;
+ bool _unstoppable;
+ Vector3 _actorPosition;
+ Vector3 _enemyPosition;
+ int _coversWaypointCount;
+ int _fleeWaypointsCount;
+ int _fleeingTowards;
public:
ActorCombat(BladeRunnerEngine *vm);
@@ -60,10 +62,41 @@ public:
void setup();
+ void combatOn(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool unstoppable);
+ void combatOff();
+
+ void tick();
+
void hitAttempt();
- void combatOn(int actorId, int a3, int a4, int otherActorId, int a6, int a7, int a8, int a9, int a10, int a11, int a12);
- void combatOff();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
+private:
+ void reset();
+
+ void cover();
+ void approachToCloseAttack();
+ void approachToRangedAttack();
+ void uncover();
+ void aim();
+ void rangedAttack();
+ void closeAttack();
+ void flee();
+
+ void faceEnemy();
+
+ int getaggressivenessCloseAttack() const;
+ int getaggressivenessRangedAttack() const;
+
+ int getDamageCloseAttack(int min, int max) const;
+ int getDamageRangedAttack(int min, int max) const;
+
+ int calculateActionRatio() const;
+ int calculateCoverRatio() const;
+ int calculateFleeRatio() const;
+
+ bool findClosestPositionToEnemy(Vector3 &output) const;
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/actor_dialogue_queue.cpp b/engines/bladerunner/actor_dialogue_queue.cpp
index dbf5598a52..48fcf8a6ab 100644
--- a/engines/bladerunner/actor_dialogue_queue.cpp
+++ b/engines/bladerunner/actor_dialogue_queue.cpp
@@ -26,6 +26,7 @@
#include "bladerunner/actor.h"
#include "bladerunner/audio_speech.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "bladerunner/script/scene_script.h"
@@ -53,7 +54,7 @@ void ActorDialogueQueue::add(int actorId, int sentenceId, int animationMode) {
if (actorId == 0 || actorId == BladeRunnerEngine::kActorVoiceOver) {
animationMode = -1;
}
- if (_entries.size() < 25) {
+ if (_entries.size() < kMaxEntries) {
Entry entry;
entry.isNotPause = true;
entry.isPause = false;
@@ -67,7 +68,7 @@ void ActorDialogueQueue::add(int actorId, int sentenceId, int animationMode) {
}
void ActorDialogueQueue::addPause(int delay) {
- if (_entries.size() < 25) {
+ if (_entries.size() < kMaxEntries) {
Entry entry;
entry.isNotPause = false;
entry.isPause = true;
@@ -159,6 +160,58 @@ void ActorDialogueQueue::tick() {
}
}
+void ActorDialogueQueue::save(SaveFileWriteStream &f) {
+ int count = (int)_entries.size();
+ f.writeInt(count);
+ for (int i = 0; i < count; ++i) {
+ Entry &e = _entries[i];
+ f.writeBool(e.isNotPause);
+ f.writeBool(e.isPause);
+ f.writeInt(e.actorId);
+ f.writeInt(e.sentenceId);
+ f.writeInt(e.animationMode);
+ f.writeInt(e.delay);
+ }
+ f.padBytes((kMaxEntries - count) * 24);
+
+ f.writeBool(_isNotPause);
+ f.writeInt(_actorId);
+ f.writeInt(_sentenceId);
+ f.writeInt(_animationMode);
+ f.writeInt(_animationModePrevious);
+ f.writeBool(_isPause);
+ f.writeInt(_delay);
+ // f.write(_timeLast);
+}
+
+void ActorDialogueQueue::load(SaveFileReadStream &f) {
+ _entries.clear();
+ int count = f.readInt();
+ assert(count <= kMaxEntries);
+ _entries.resize(count);
+ for (int i = 0; i < count; ++i) {
+ Entry &e = _entries[i];
+ e.isNotPause = f.readBool();
+ e.isPause = f.readBool();
+ e.actorId = f.readInt();
+ e.sentenceId = f.readInt();
+ e.animationMode = f.readInt();
+ e.delay = f.readInt();
+ }
+
+ f.skip((kMaxEntries - count) * 24);
+
+ _isNotPause = f.readBool();
+ _actorId = f.readInt();
+ _sentenceId = f.readInt();
+ _animationMode = f.readInt();
+ _animationModePrevious = f.readInt();
+ _isPause = f.readBool();
+ _delay = f.readInt();
+
+ _timeLast = 0;
+}
+
void ActorDialogueQueue::clear() {
_entries.clear();
_isNotPause = false;
@@ -170,4 +223,5 @@ void ActorDialogueQueue::clear() {
_delay = 0;
_timeLast = 0;
}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/actor_dialogue_queue.h b/engines/bladerunner/actor_dialogue_queue.h
index 841ca8a48e..832bcc9dab 100644
--- a/engines/bladerunner/actor_dialogue_queue.h
+++ b/engines/bladerunner/actor_dialogue_queue.h
@@ -22,13 +22,18 @@
#ifndef BLADERUNNER_ACTOR_DIALOGUE_QUEUE_H
#define BLADERUNNER_ACTOR_DIALOGUE_QUEUE_H
+
#include "common/array.h"
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class ActorDialogueQueue {
+ static const int kMaxEntries = 25;
+
struct Entry {
bool isNotPause;
bool isPause;
@@ -61,6 +66,9 @@ public:
void flush(int a1, bool callScript);
void tick();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
void clear();
};
diff --git a/engines/bladerunner/actor_walk.cpp b/engines/bladerunner/actor_walk.cpp
index 16009aa65b..b4587333a1 100644
--- a/engines/bladerunner/actor_walk.cpp
+++ b/engines/bladerunner/actor_walk.cpp
@@ -28,6 +28,7 @@
#include "bladerunner/game_constants.h"
#include "bladerunner/game_info.h"
#include "bladerunner/obstacles.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/set.h"
@@ -238,6 +239,53 @@ void ActorWalk::run(int actorId) {
_vm->_actors[actorId]->changeAnimationMode(animationMode, false);
}
+void ActorWalk::save(SaveFileWriteStream &f) {
+ f.writeInt(_walking);
+ f.writeInt(_running);
+ f.writeVector3(_destination);
+ // _originalDestination is not saved
+ f.writeVector3(_current);
+ f.writeVector3(_next);
+ f.writeInt(_facing);
+
+ assert(_nearActors.size() <= 20);
+ for (Common::HashMap<int, bool>::const_iterator it = _nearActors.begin(); it != _nearActors.end(); ++it) {
+ f.writeInt(it->_key);
+ f.writeBool(it->_value);
+ }
+ f.padBytes(8 * (20 - _nearActors.size()));
+ f.writeInt(_nearActors.size());
+
+ f.writeInt(0); // _notUsed
+ f.writeInt(_status);
+}
+
+void ActorWalk::load(SaveFileReadStream &f) {
+ _walking = f.readInt();
+ _running = f.readInt();
+ _destination = f.readVector3();
+ // _originalDestination is not saved
+ _current = f.readVector3();
+ _next = f.readVector3();
+ _facing = f.readInt();
+
+ int actorId[20];
+ bool isNear[20];
+
+ for (int i = 0; i < 20; ++i) {
+ actorId[i] = f.readInt();
+ isNear[i] = f.readBool();
+ }
+
+ int count = f.readInt();
+ for (int i = 0; i < count; ++i) {
+ _nearActors.setVal(actorId[i], isNear[i]);
+ }
+
+ f.skip(4); // _notUsed
+ _status = f.readInt();
+}
+
bool ActorWalk::isXYZEmpty(float x, float y, float z, int actorId) const {
if (_vm->_scene->_set->findWalkbox(x, z) == -1) {
return true;
diff --git a/engines/bladerunner/actor_walk.h b/engines/bladerunner/actor_walk.h
index f4caa65453..45298e2794 100644
--- a/engines/bladerunner/actor_walk.h
+++ b/engines/bladerunner/actor_walk.h
@@ -29,6 +29,8 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class ActorWalk {
BladeRunnerEngine *_vm;
@@ -60,6 +62,9 @@ public:
void stop(int actorId, bool immediately, int combatAnimationMode, int animationMode);
void run(int actorId);
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
int nextOnPath(int actorId, const Vector3 &from, const Vector3 &to, Vector3 &next) const;
diff --git a/engines/bladerunner/ambient_sounds.cpp b/engines/bladerunner/ambient_sounds.cpp
index 64a85bc46c..81b6174ab9 100644
--- a/engines/bladerunner/ambient_sounds.cpp
+++ b/engines/bladerunner/ambient_sounds.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/audio_player.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_info.h"
+#include "bladerunner/savefile.h"
#include "common/debug.h"
#include "common/system.h"
@@ -68,25 +69,23 @@ void AmbientSounds::addSound(
int panStartMin, int panStartMax,
int panEndMin, int panEndMax,
int priority, int unk) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
sort(volumeMin, volumeMax);
sort(panStartMin, panStartMax);
sort(panEndMin, panEndMax);
addSoundByName(
- name,
- timeMin, timeMax,
- volumeMin, volumeMax,
- panStartMin, panStartMax,
- panEndMin, panEndMax,
- priority, unk
+ _vm->_gameInfo->getSfxTrack(sfxId),
+ timeMin, timeMax,
+ volumeMin, volumeMax,
+ panStartMin, panStartMax,
+ panEndMin, panEndMax,
+ priority, unk
);
}
void AmbientSounds::removeNonLoopingSound(int sfxId, bool stopPlaying) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
- int32 hash = mix_id(name);
+ int32 hash = MIXArchive::getHash(_vm->_gameInfo->getSfxTrack(sfxId));
int index = findNonLoopingTrackByHash(hash);
if (index >= 0) {
removeNonLoopingSoundByIndex(index, stopPlaying);
@@ -104,8 +103,7 @@ void AmbientSounds::addSpeech(int actorId, int sentenceId, int timeMin, int time
sort(panStartMin, panStartMax);
sort(panEndMin, panEndMax);
- char name[13];
- sprintf(name, "%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode);
+ Common::String name = Common::String::format( "%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode.c_str());
addSoundByName(name,
timeMin, timeMax,
volumeMin, volumeMax,
@@ -115,15 +113,12 @@ void AmbientSounds::addSpeech(int actorId, int sentenceId, int timeMin, int time
}
void AmbientSounds::playSound(int sfxId, int volume, int panStart, int panEnd, int priority) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
-
- _vm->_audioPlayer->playAud(name, volume * _ambientVolume / 100, panStart, panEnd, priority, kAudioPlayerOverrideVolume);
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(sfxId), volume * _ambientVolume / 100, panStart, panEnd, priority, kAudioPlayerOverrideVolume);
}
void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, int delay) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
-
- int32 hash = mix_id(name);
+ const Common::String &name = _vm->_gameInfo->getSfxTrack(sfxId);
+ int32 hash = MIXArchive::getHash(name);
if (findLoopingTrackByHash(hash) >= 0) {
return;
@@ -136,8 +131,7 @@ void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, int delay) {
LoopingSound &track = _loopingSounds[i];
track.isActive = true;
- strncpy(track.name, name, sizeof(track.name));
- track.name[sizeof(track.name) - 1] = 0;
+ track.name = name;
track.hash = hash;
track.pan = pan;
track.volume = volume;
@@ -161,8 +155,7 @@ void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, int delay) {
}
void AmbientSounds::adjustLoopingSound(int sfxId, int volume, int pan, int delay) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
- int32 hash = mix_id(name);
+ int32 hash = MIXArchive::getHash(_vm->_gameInfo->getSfxTrack(sfxId));
int index = findLoopingTrackByHash(hash);
if (index >= 0 && _loopingSounds[index].audioPlayerTrack != -1 && _vm->_audioPlayer->isActive(_loopingSounds[index].audioPlayerTrack)) {
@@ -178,8 +171,7 @@ void AmbientSounds::adjustLoopingSound(int sfxId, int volume, int pan, int delay
}
void AmbientSounds::removeLoopingSound(int sfxId, int delay) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
- int32 hash = mix_id(name);
+ int32 hash = MIXArchive::getHash(_vm->_gameInfo->getSfxTrack(sfxId));
int index = findLoopingTrackByHash(hash);
if (index >= 0) {
removeLoopingSoundByIndex(index, delay);
@@ -297,15 +289,12 @@ int AmbientSounds::findLoopingTrackByHash(int32 hash) const {
}
void AmbientSounds::addSoundByName(
- const char *name,
+ const Common::String &name,
int timeMin, int timeMax,
int volumeMin, int volumeMax,
int panStartMin, int panStartMax,
int panEndMin, int panEndMax,
int priority, int unk) {
- if (strlen(name) > 12) {
- error("AmbientSounds::addSoundByName: Overlong name '%s'", name);
- }
int i = findAvailableNonLoopingTrack();
if (i < 0) {
@@ -317,9 +306,8 @@ void AmbientSounds::addSoundByName(
uint32 now = _vm->getTotalPlayTime();
track.isActive = true;
- strncpy(track.name, name, sizeof(track.name));
- track.name[sizeof(track.name) - 1] = 0;
- track.hash = mix_id(name);
+ track.name = name;
+ track.hash = MIXArchive::getHash(name);
track.timeMin = 1000 * timeMin;
track.timeMax = 1000 * timeMax;
track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.timeMin, track.timeMax);
@@ -355,11 +343,83 @@ void AmbientSounds::removeLoopingSoundByIndex(int index, int delay) {
}
}
track.isActive = false;
- track.name[0] = 0;
+ track.name.clear();
track.hash = 0;
track.audioPlayerTrack = -1;
track.volume = 0;
track.pan = 0;
}
+void AmbientSounds::save(SaveFileWriteStream &f) {
+ f.writeBool(false); // TODO: _isDisabled
+
+ for (int i = 0; i != kNonLoopingSounds; ++i) {
+ // 73 bytes per non-looping sound
+ NonLoopingSound &s = _nonLoopingSounds[i];
+ f.writeBool(s.isActive);
+ f.writeStringSz(s.name, 13);
+ f.writeSint32LE(s.hash);
+ f.writeInt(s.audioPlayerTrack);
+ f.writeInt(s.timeMin);
+ f.writeInt(s.timeMax);
+ f.writeUint32LE(s.nextPlayTime);
+ f.writeInt(s.volumeMin);
+ f.writeInt(s.volumeMax);
+ f.writeInt(s.volume);
+ f.writeInt(s.panStartMin);
+ f.writeInt(s.panStartMax);
+ f.writeInt(s.panEndMin);
+ f.writeInt(s.panEndMax);
+ f.writeInt(s.priority);
+ f.padBytes(4); // field_45
+ }
+
+ for (int i = 0; i != kLoopingSounds; ++i) {
+ // 33 bytes per looping sound
+ LoopingSound &s = _loopingSounds[i];
+ f.writeBool(s.isActive);
+ f.writeStringSz(s.name, 13);
+ f.writeSint32LE(s.hash);
+ f.writeInt(s.audioPlayerTrack);
+ f.writeInt(s.volume);
+ f.writeInt(s.pan);
+ }
+}
+
+void AmbientSounds::load(SaveFileReadStream &f) {
+ f.skip(4); // TODO: _isDisabled
+
+ for (int i = 0; i != kNonLoopingSounds; ++i) {
+ // 73 bytes per non-looping sound
+ NonLoopingSound &s = _nonLoopingSounds[i];
+ s.isActive = f.readBool();
+ s.name = f.readStringSz(13);
+ s.hash = f.readSint32LE();
+ s.audioPlayerTrack = f.readInt();
+ s.timeMin = f.readInt();
+ s.timeMax = f.readInt();
+ s.nextPlayTime = f.readUint32LE();
+ s.volumeMin = f.readInt();
+ s.volumeMax = f.readInt();
+ s.volume = f.readInt();
+ s.panStartMin = f.readInt();
+ s.panStartMax = f.readInt();
+ s.panEndMin = f.readInt();
+ s.panEndMax = f.readInt();
+ s.priority = f.readInt();
+ f.skip(4); // field_45
+ }
+
+ for (int i = 0; i != kLoopingSounds; ++i) {
+ // 33 bytes per looping sound
+ LoopingSound &s = _loopingSounds[i];
+ s.isActive = f.readBool();
+ s.name = f.readStringSz(13);
+ s.hash = f.readSint32LE();
+ s.audioPlayerTrack = f.readInt();
+ s.volume = f.readInt();
+ s.pan = f.readInt();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/ambient_sounds.h b/engines/bladerunner/ambient_sounds.h
index e06726b183..de08965a11 100644
--- a/engines/bladerunner/ambient_sounds.h
+++ b/engines/bladerunner/ambient_sounds.h
@@ -25,39 +25,43 @@
#include "audio/audiostream.h"
+#include "common/str.h"
+
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class AmbientSounds {
static const int kNonLoopingSounds = 25;
static const int kLoopingSounds = 3;
struct NonLoopingSound {
- bool isActive;
- char name[13];
- int32 hash;
- int32 audioPlayerTrack;
- int32 timeMin;
- int32 timeMax;
- uint32 nextPlayTime;
- int32 volumeMin;
- int32 volumeMax;
- int32 volume;
- int32 panStartMin;
- int32 panStartMax;
- int32 panEndMin;
- int32 panEndMax;
- int32 priority;
+ bool isActive;
+ Common::String name;
+ int32 hash;
+ int audioPlayerTrack;
+ int timeMin;
+ int timeMax;
+ uint32 nextPlayTime;
+ int volumeMin;
+ int volumeMax;
+ int volume;
+ int panStartMin;
+ int panStartMax;
+ int panEndMin;
+ int panEndMax;
+ int priority;
};
struct LoopingSound {
- bool isActive;
- char name[13];
- int32 hash;
- int audioPlayerTrack;
- int32 volume;
- int pan;
+ bool isActive;
+ Common::String name;
+ int32 hash;
+ int audioPlayerTrack;
+ int volume;
+ int pan;
};
BladeRunnerEngine *_vm;
@@ -103,6 +107,9 @@ public:
int getVolume() const;
void playSample();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
int findAvailableNonLoopingTrack() const;
int findNonLoopingTrackByHash(int32 hash) const;
@@ -119,7 +126,7 @@ private:
// playVolumeAdjustSound
void addSoundByName(
- const char *name,
+ const Common::String &name,
int timeMin, int timeMax,
int volumeMin, int volumeMax,
int panStartMin, int panStartMax,
diff --git a/engines/bladerunner/archive.cpp b/engines/bladerunner/archive.cpp
index 8088e1ac67..c116eeb94f 100644
--- a/engines/bladerunner/archive.cpp
+++ b/engines/bladerunner/archive.cpp
@@ -51,7 +51,7 @@ bool MIXArchive::open(const Common::String &filename) {
_entries.resize(_entryCount);
for (uint16 i = 0; i != _entryCount; ++i) {
- _entries[i].id = _fd.readSint32LE();
+ _entries[i].hash = _fd.readUint32LE();
_entries[i].offset = _fd.readUint32LE();
_entries[i].length = _fd.readUint32LE();
@@ -61,7 +61,7 @@ bool MIXArchive::open(const Common::String &filename) {
// Verify that the entries are sorted by id. Note that id is signed.
if (i > 0) {
- assert(_entries[i].id > _entries[i - 1].id);
+ assert(_entries[i].hash > _entries[i - 1].hash);
}
}
@@ -86,7 +86,7 @@ bool MIXArchive::isOpen() const {
#define ROL(n) ((n << 1) | ((n >> 31) & 1))
-int32 mix_id(const Common::String &name) {
+int32 MIXArchive::getHash(const Common::String &name) {
char buffer[12] = { 0 };
for (uint i = 0; i != name.size() && i < 12u; ++i) {
@@ -103,11 +103,10 @@ int32 mix_id(const Common::String &name) {
id = ROL(id) + t;
}
- return reinterpret_cast<int32&>(id);
+ return id;
}
-static
-int32 tlk_id(const Common::String &name) {
+static uint32 tlk_id(const Common::String &name) {
char buffer[12] = { 0 };
for (uint i = 0; i != name.size() && i < 12u; ++i)
@@ -124,15 +123,15 @@ int32 tlk_id(const Common::String &name) {
return 10000 * actor_id + speech_id;
}
-uint32 MIXArchive::indexForId(int32 id) const {
+uint32 MIXArchive::indexForHash(int32 hash) const {
uint32 lo = 0, hi = _entryCount;
while (lo < hi) {
uint32 mid = lo + (hi - lo) / 2;
- if (id > _entries[mid].id) {
+ if (hash > _entries[mid].hash) {
lo = mid + 1;
- } else if (id < _entries[mid].id) {
+ } else if (hash < _entries[mid].hash) {
hi = mid;
} else {
return mid;
@@ -142,14 +141,15 @@ uint32 MIXArchive::indexForId(int32 id) const {
}
Common::SeekableReadStream *MIXArchive::createReadStreamForMember(const Common::String &name) {
- int32 id;
+ int32 hash;
- if (_isTLK)
- id = tlk_id(name);
- else
- id = mix_id(name);
+ if (_isTLK) {
+ hash = tlk_id(name);
+ } else {
+ hash = MIXArchive::getHash(name);
+ }
- uint32 i = indexForId(id);
+ uint32 i = indexForHash(hash);
if (i == _entryCount) {
return nullptr;
diff --git a/engines/bladerunner/archive.h b/engines/bladerunner/archive.h
index 7bec41f97a..9f7c67920d 100644
--- a/engines/bladerunner/archive.h
+++ b/engines/bladerunner/archive.h
@@ -34,6 +34,8 @@ public:
MIXArchive();
~MIXArchive();
+ static int32 getHash(const Common::String &name);
+
bool open(const Common::String &filename);
void close();
bool isOpen() const;
@@ -50,17 +52,16 @@ private:
uint32 _size;
struct ArchiveEntry {
- int32 id;
+ int32 hash;
uint32 offset;
uint32 length;
};
Common::Array<ArchiveEntry> _entries;
- uint32 indexForId(int32 id) const;
+ uint32 indexForHash(int32 hash) const;
};
-int32 mix_id(const Common::String &name);
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/aud_stream.cpp b/engines/bladerunner/aud_stream.cpp
index 0d4434cbbf..3d14f948d2 100644
--- a/engines/bladerunner/aud_stream.cpp
+++ b/engines/bladerunner/aud_stream.cpp
@@ -133,7 +133,12 @@ int AudStream::getLength() const {
if (_flags & 2) { // stereo
bytesPerSecond *= 2;
}
- return (1000 * _sizeDecompressed) / bytesPerSecond;
+
+ // since everything is 44100, we easily get overflows with ints
+ // thus we must use doubles
+ double res = (double)_sizeDecompressed * 1000.0 / (double)bytesPerSecond;
+
+ return (int32)res;
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_player.cpp b/engines/bladerunner/audio_player.cpp
index e1ef0263b6..5186888dd2 100644
--- a/engines/bladerunner/audio_player.cpp
+++ b/engines/bladerunner/audio_player.cpp
@@ -253,7 +253,7 @@ int AudioPlayer::playAud(const Common::String &name, int volume, int panFrom, in
}
/* Load audio resource and store in cache. Playback will happen directly from there. */
- int32 hash = mix_id(name);
+ int32 hash = MIXArchive::getHash(name);
if (!_cache->findByHash(hash)) {
Common::SeekableReadStream *r = _vm->getResourceStream(name);
if (!r) {
diff --git a/engines/bladerunner/audio_speech.cpp b/engines/bladerunner/audio_speech.cpp
index 69883cbce2..5ffde9db6c 100644
--- a/engines/bladerunner/audio_speech.cpp
+++ b/engines/bladerunner/audio_speech.cpp
@@ -58,12 +58,12 @@ AudioSpeech::~AudioSpeech() {
delete[] _data;
}
-bool AudioSpeech::playSpeech(const char *name, int pan) {
+bool AudioSpeech::playSpeech(const Common::String &name, int pan) {
// debug("AudioSpeech::playSpeech(\"%s\")", name);
Common::ScopedPtr<Common::SeekableReadStream> r(_vm->getResourceStream(name));
if (!r) {
- warning("AudioSpeech::playSpeech: AUD resource \"%s\" not found", name);
+ warning("AudioSpeech::playSpeech: AUD resource \"%s\" not found", name.c_str());
return false;
}
@@ -78,7 +78,7 @@ bool AudioSpeech::playSpeech(const char *name, int pan) {
r->read(_data, r->size());
if (r->err()) {
- warning("AudioSpeech::playSpeech: Error reading resource \"%s\"", name);
+ warning("AudioSpeech::playSpeech: Error reading resource \"%s\"", name.c_str());
return false;
}
@@ -110,14 +110,14 @@ void AudioSpeech::stopSpeech() {
bool AudioSpeech::isPlaying() const {
if (_channel == -1) {
- return false;
+ return false;
}
return _isActive;
}
bool AudioSpeech::playSpeechLine(int actorId, int sentenceId, int volume, int a4, int priority) {
int balance = _vm->_actors[actorId]->soundBalance();
- Common::String name = Common::String::format("%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode);
+ Common::String name = Common::String::format("%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode.c_str());
return _vm->_audioPlayer->playAud(name, _speechVolume * volume / 100, balance, balance, priority, kAudioPlayerOverrideVolume);
}
diff --git a/engines/bladerunner/audio_speech.h b/engines/bladerunner/audio_speech.h
index 010499f480..5406f1d8e5 100644
--- a/engines/bladerunner/audio_speech.h
+++ b/engines/bladerunner/audio_speech.h
@@ -23,6 +23,7 @@
#ifndef BLADERUNNER_AUDIO_SPEECH_H
#define BLADERUNNER_AUDIO_SPEECH_H
+#include "common/str.h"
#include "common/types.h"
namespace BladeRunner {
@@ -44,7 +45,7 @@ public:
AudioSpeech(BladeRunnerEngine *vm);
~AudioSpeech();
- bool playSpeech(const char *name, int balance = 0);
+ bool playSpeech(const Common::String &name, int balance = 0);
void stopSpeech();
bool isPlaying() const;
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index ea663b53bc..fab708cbb8 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -46,6 +46,7 @@
#include "bladerunner/obstacles.h"
#include "bladerunner/overlays.h"
#include "bladerunner/regions.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/screen_effects.h"
@@ -53,6 +54,7 @@
#include "bladerunner/script/ai_script.h"
#include "bladerunner/script/init_script.h"
#include "bladerunner/script/kia_script.h"
+#include "bladerunner/script/police_maze.h"
#include "bladerunner/script/scene_script.h"
#include "bladerunner/settings.h"
#include "bladerunner/shape.h"
@@ -60,9 +62,12 @@
#include "bladerunner/slice_renderer.h"
#include "bladerunner/suspects_database.h"
#include "bladerunner/text_resource.h"
+#include "bladerunner/time.h"
#include "bladerunner/ui/elevator.h"
+#include "bladerunner/ui/end_credits.h"
#include "bladerunner/ui/esper.h"
#include "bladerunner/ui/kia.h"
+#include "bladerunner/ui/scores.h"
#include "bladerunner/ui/spinner.h"
#include "bladerunner/ui/vk.h"
#include "bladerunner/vqa_decoder.h"
@@ -70,8 +75,10 @@
#include "bladerunner/zbuffer.h"
#include "common/array.h"
+#include "common/config-manager.h"
#include "common/error.h"
#include "common/events.h"
+#include "common/savefile.h"
#include "common/system.h"
#include "engines/util.h"
@@ -88,6 +95,9 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des
_windowIsActive = true;
_gameIsRunning = true;
+ _vqaIsPlaying = false;
+ _vqaStopIsRequested = false;
+
_playerLosesControlCounter = 0;
_playerActorIdle = false;
@@ -139,6 +149,7 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des
_lights = nullptr;
_obstacles = nullptr;
_sceneScript = nullptr;
+ _gameTime = nullptr;
_gameInfo = nullptr;
_waypoints = nullptr;
_gameVars = nullptr;
@@ -165,11 +176,14 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst, const ADGameDescription *des
_dialogueMenu = nullptr;
_suspectsDatabase = nullptr;
_kia = nullptr;
+ _endCredits = nullptr;
_spinner = nullptr;
+ _scores = nullptr;
_elevator = nullptr;
_mainFont = nullptr;
_esper = nullptr;
_vk = nullptr;
+ _policeMaze = nullptr;
_mouse = nullptr;
_sliceAnimations = nullptr;
_sliceRenderer = nullptr;
@@ -212,6 +226,13 @@ Common::Error BladeRunnerEngine::run() {
/* TODO: Check for save games and enter KIA */
gameLoop();
+
+ _mouse->disable();
+
+ if (_gameOver) {
+ // autoSaveGame(4, 1); // TODO
+ _endCredits->show();
+ }
}
shutdown();
@@ -224,9 +245,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
_screenEffects = new ScreenEffects(this, 0x8000);
- _combat = new Combat(this);
-
- // TODO: end credits
+ _endCredits = new EndCredits(this);
_actorDialogueQueue = new ActorDialogueQueue(this);
@@ -238,7 +257,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
// TODO: outtake player - but this is done bit differently
- // TODO: police maze
+ _policeMaze = new PoliceMaze(this);
_obstacles = new Obstacles(this);
@@ -254,19 +273,22 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
_surfaceBack.create(640, 480, createRGB555());
_surface4.create(640, 480, createRGB555());
+ _gameTime = new Time(this);
+
r = openArchive("STARTUP.MIX");
if (!r)
return false;
- // TODO: Timer
-
_gameInfo = new GameInfo(this);
if (!_gameInfo)
return false;
r = _gameInfo->open("GAMEINFO.DAT");
- if (!r)
+ if (!r) {
return false;
+ }
+
+ _combat = new Combat(this);
// TODO: Create datetime - not used
@@ -286,7 +308,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
// TODO: Flee waypoints
- _gameVars = new int[_gameInfo->getGlobalVarCount()];
+ _gameVars = new int[_gameInfo->getGlobalVarCount()]();
// TODO: Actor AI DLL init
@@ -348,7 +370,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
// TODO: Set actor ids (redundant?)
- // TODO: Police Maze
+ _policeMaze = new PoliceMaze(this);
_textActorNames = new TextResource(this);
if (!_textActorNames->open("ACTORS"))
@@ -390,7 +412,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
_elevator = new Elevator(this);
- // TODO: Scores
+ _scores = new Scores(this);
_mainFont = new Font(this);
_mainFont->open("KIA6PT.FON", 640, 480, -1, 0, 0x252D);
@@ -415,13 +437,6 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
if (!r)
return false;
- // TODO: Support cdframes
-
- r = _sliceAnimations->openHDFrames();
- if (!r) {
- return false;
- }
-
r = _sliceAnimations->openCoreAnim();
if (!r) {
return false;
@@ -461,8 +476,20 @@ void BladeRunnerEngine::initChapterAndScene() {
_actors[i]->movementTrackNext(true);
}
- _settings->setChapter(1);
- _settings->setNewSetAndScene(_gameInfo->getInitialSetId(), _gameInfo->getInitialSceneId());
+ if (ConfMan.hasKey("boot_param")) {
+ int param = ConfMan.getInt("boot_param"); // CTTTSSS
+ int chapter = param / 1000000;
+ param -= chapter * 1000000;
+ int set = param / 1000;
+ param -= set * 1000;
+ int scene = param;
+
+ _settings->setChapter(chapter);
+ _settings->setNewSetAndScene(set, scene);
+ } else {
+ _settings->setChapter(1);
+ _settings->setNewSetAndScene(_gameInfo->getInitialSetId(), _gameInfo->getInitialSceneId());
+ }
}
void BladeRunnerEngine::shutdown() {
@@ -590,7 +617,11 @@ void BladeRunnerEngine::shutdown() {
// TODO: Delete Flee waypoints
- // TODO: Delete Scores
+ delete _scores;
+ _scores = nullptr;
+
+ delete _endCredits;
+ _endCredits = nullptr;
delete _elevator;
_elevator = nullptr;
@@ -630,8 +661,8 @@ void BladeRunnerEngine::shutdown() {
// TODO: Delete MIXArchives here
- // TODO: Delete Timer
-
+ delete _gameTime;
+ _gameTime = nullptr;
// These are static objects in original game
@@ -644,6 +675,9 @@ void BladeRunnerEngine::shutdown() {
delete _itemPickup;
_itemPickup = nullptr;
+ delete _policeMaze;
+ _policeMaze = nullptr;
+
delete _obstacles;
_obstacles = nullptr;
@@ -744,17 +778,25 @@ void BladeRunnerEngine::gameTick() {
return;
}
- // TODO: Scores
+ if (_scores->isOpen()) {
+ _scores->tick();
+ _ambientSounds->tick();
+ return;
+ }
_actorDialogueQueue->tick();
if (_scene->didPlayerWalkIn()) {
_sceneScript->playerWalkedIn();
}
bool inDialogueMenu = _dialogueMenu->isVisible();
- if (!inDialogueMenu) {
- // TODO: actors combat-tick
+ if (!inDialogueMenu) {
+ for (int i = 0; i < (int)_gameInfo->getActorCount(); ++i) {
+ _actors[i]->tickCombat();
+ }
}
+ _policeMaze->tick();
+
// TODO: Gun range announcements
_zbuffer->clean();
@@ -769,9 +811,6 @@ void BladeRunnerEngine::gameTick() {
(void)backgroundChanged;
blit(_surfaceBack, _surfaceFront);
- // TODO: remove zbuffer draw
- // _surfaceFront.copyRectToSurface(_zbuffer->getData(), 1280, 0, 0, 640, 480);
-
_overlays->tick();
if (!inDialogueMenu) {
@@ -814,14 +853,16 @@ void BladeRunnerEngine::gameTick() {
// TODO: Process AUD
if (_walkSoundId >= 0) {
- const char *name = _gameInfo->getSfxTrack(_walkSoundId);
- _audioPlayer->playAud(name, _walkSoundVolume, _walkSoundBalance, _walkSoundBalance, 50, 0);
+ _audioPlayer->playAud(_gameInfo->getSfxTrack(_walkSoundId), _walkSoundVolume, _walkSoundBalance, _walkSoundBalance, 50, 0);
_walkSoundId = -1;
}
if (_debugger->_viewSceneObjects) {
_debugger->drawSceneObjects();
}
+ if (_debugger->_viewObstacles) {
+ _obstacles->draw();
+ }
blitToScreen(_surfaceFront);
_system->delayMillis(10);
@@ -908,6 +949,13 @@ void BladeRunnerEngine::handleKeyUp(Common::Event &event) {
_speechSkipped = true;
}
+ if (_vqaIsPlaying) {
+ _vqaStopIsRequested = true;
+ _vqaIsPlaying = false;
+
+ return;
+ }
+
// TODO:
if (!playerHasControl() /*|| ActorInWalkingLoop*/) {
return;
@@ -938,7 +986,10 @@ void BladeRunnerEngine::handleKeyUp(Common::Event &event) {
return;
}
- //TODO: scores
+ if (_scores->isOpen()) {
+ return;
+ }
+
switch (event.kbd.keycode) {
case Common::KEYCODE_TAB:
_kia->openLastOpened();
@@ -986,7 +1037,10 @@ void BladeRunnerEngine::handleKeyDown(Common::Event &event) {
return;
}
- //TODO: scores
+ if (_scores->isOpen()) {
+ _scores->handleKeyDown(event.kbd);
+ return;
+ }
switch (event.kbd.keycode) {
case Common::KEYCODE_F1:
@@ -1075,6 +1129,15 @@ void BladeRunnerEngine::handleMouseAction(int x, int y, bool mainButton, bool bu
return;
}
+ if (_scores->isOpen()) {
+ if (buttonDown) {
+ _scores->handleMouseDown(x, y);
+ } else {
+ _scores->handleMouseUp(x, y);
+ }
+ return;
+ }
+
if (_dialogueMenu->waitingForInput()) {
if (mainButton && !buttonDown) {
_dialogueMenu->mouseUp();
@@ -1093,7 +1156,7 @@ void BladeRunnerEngine::handleMouseAction(int x, int y, bool mainButton, bool bu
int exitIndex = _scene->_exits->getRegionAtXY(x, y);
int regionIndex = _scene->_regions->getRegionAtXY(x, y);
- if ((sceneObjectId < kSceneObjectOffsetActors || sceneObjectId >= kSceneObjectOffsetActors) && exitIndex >= 0) {
+ if ((sceneObjectId < kSceneObjectOffsetActors || sceneObjectId >= kSceneObjectOffsetItems) && exitIndex >= 0) {
handleMouseClickExit(exitIndex, x, y, buttonDown);
} else if (regionIndex >= 0) {
handleMouseClickRegion(regionIndex, x, y, buttonDown);
@@ -1183,8 +1246,8 @@ void BladeRunnerEngine::handleMouseClickRegion(int regionId, int x, int y, bool
}
void BladeRunnerEngine::handleMouseClick3DObject(int objectId, bool buttonDown, bool isClickable, bool isTarget) {
- const char *objectName = _scene->objectGetName(objectId);
- debug("Clicked on object %s", objectName);
+ const Common::String &objectName = _scene->objectGetName(objectId);
+ debug("Clicked on object %s", objectName.c_str());
if (_isWalkingInterruptible && objectId != _walkingToObjectId) {
_isWalkingInterruptible = false;
@@ -1217,7 +1280,7 @@ void BladeRunnerEngine::handleMouseClick3DObject(int objectId, bool buttonDown,
_walkingToActorId = -1;
_isInsideScriptObject = true;
- _sceneScript->clickedOn3DObject(objectName, false);
+ _sceneScript->clickedOn3DObject(objectName.c_str(), false);
_isInsideScriptObject = false;
}
} else {
@@ -1226,14 +1289,14 @@ void BladeRunnerEngine::handleMouseClick3DObject(int objectId, bool buttonDown,
}
_playerActor->stopWalking(false);
_playerActor->faceObject(objectName, false);
- _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+ _playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
_settings->decreaseAmmo();
_audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getHitSound()), 100, 0, 0, 90, 0);
- //TODO mouse::randomize(Mouse);
+ _mouse->setMouseJitterUp();
_isInsideScriptObject = true;
- _sceneScript->clickedOn3DObject(objectName, true);
+ _sceneScript->clickedOn3DObject(objectName.c_str(), true);
_isInsideScriptObject = false;
}
}
@@ -1267,11 +1330,11 @@ void BladeRunnerEngine::handleMouseClickEmpty(int x, int y, Vector3 &scenePositi
} else {
_playerActor->faceItem(itemId, false);
}
- _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+ _playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
_settings->decreaseAmmo();
_audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getMissSound()), 100, 0, 0, 90, 0);
- //TODO mouse::randomize(Mouse);
+ _mouse->setMouseJitterUp();
if (actorId > 0) {
_aiScripts->shotAtAndMissed(actorId);
@@ -1362,11 +1425,12 @@ void BladeRunnerEngine::handleMouseClickItem(int itemId, bool buttonDown) {
_playerActor->stopWalking(false);
_playerActor->faceItem(itemId, false);
- _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+ _playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
_settings->decreaseAmmo();
_audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getHitSound()), 100, 0, 0, 90, 0);
- //TODO mouse::randomize(Mouse);
+ _mouse->setMouseJitterUp();
+
_isInsideScriptItem = true;
_sceneScript->clickedOnItem(itemId, true);
_isInsideScriptItem = false;
@@ -1422,22 +1486,21 @@ void BladeRunnerEngine::handleMouseClickActor(int actorId, bool mainButton, bool
}
}
} else {
- if (!_combat->isActive() || actorId == kActorMcCoy || !_actors[actorId]->isTarget() || _actors[actorId]->isRetired() /*|| _mouse->isRandomized()*/) {
+ Actor *actor = _actors[actorId];
+
+ if (!_combat->isActive() || actorId == kActorMcCoy || !actor->isTarget() || actor->isRetired() /*|| _mouse->isRandomized()*/) {
return;
}
_playerActor->stopWalking(false);
_playerActor->faceActor(actorId, false);
- _playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+ _playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
_settings->decreaseAmmo();
- float targetX = _actors[actorId]->getX();
- float targetZ = _actors[actorId]->getZ();
-
- bool missed = _playerActor->isObstacleBetween(targetX, targetZ);
+ bool missed = _playerActor->isObstacleBetween(actor->getXYZ());
_audioPlayer->playAud(_gameInfo->getSfxTrack(missed ? _combat->getMissSound() : _combat->getHitSound()), 100, 0, 0, 90, 0);
- //TODO mouse::randomize(Mouse);
+ _mouse->setMouseJitterUp();
if (missed) {
_aiScripts->shotAtAndMissed(actorId);
@@ -1501,7 +1564,6 @@ bool BladeRunnerEngine::openArchive(const Common::String &name) {
* archive when it runs out of slots. */
error("openArchive: No more archive slots");
- return false;
}
_archives[i].open(name);
@@ -1534,9 +1596,11 @@ Common::SeekableReadStream *BladeRunnerEngine::getResourceStream(const Common::S
if (!_archives[i].isOpen()) {
continue;
}
+
if (false) {
debug("getResource: Searching archive %s for %s.", _archives[i].getName().c_str(), name.c_str());
}
+
Common::SeekableReadStream *stream = _archives[i].createReadStreamForMember(name);
if (stream) {
return stream;
@@ -1573,8 +1637,144 @@ void BladeRunnerEngine::playerGainsControl() {
}
}
-void BladeRunnerEngine::ISez(const char *str) {
- debug("\t%s", str);
+bool BladeRunnerEngine::saveGame(const Common::String &filename, byte *thumbnail) {
+ warning("BladeRunnerEngine::saveGame not finished");
+
+ if (!playerHasControl() || _sceneScript->isInsideScript() || _aiScripts->isInsideScript()) {
+ return false;
+ }
+
+ Common::OutSaveFile *commonSaveFile = getSaveFileManager()->openForSaving(filename, false);
+ if (commonSaveFile->err()) {
+ return false;
+ }
+
+ SaveFileWriteStream s;
+
+ s.padBytes(9600); // TODO: thumbnail
+ s.writeFloat(-1.0f);
+ _settings->save(s);
+ _scene->save(s);
+ _scene->_exits->save(s);
+ _scene->_regions->save(s);
+ _scene->_set->save(s);
+ for (uint i = 0; i != _gameInfo->getGlobalVarCount(); ++i) {
+ s.writeInt(_gameVars[i]);
+ }
+ _music->save(s);
+ // _audioPlayer->save(s) // zero func
+ // _audioSpeech->save(s) // zero func
+ _combat->save(s);
+ _gameFlags->save(s);
+ _items->save(s);
+ _sceneObjects->save(s);
+ _ambientSounds->save(s);
+ _overlays->save(s);
+ _spinner->save(s);
+ _scores->save(s);
+ _dialogueMenu->save(s);
+ _obstacles->save(s);
+ _actorDialogueQueue->save(s);
+ _waypoints->save(s);
+
+ for (uint i = 0; i != _gameInfo->getActorCount(); ++i) {
+ _actors[i]->save(s);
+
+ int animationState, animationFrame, animationStateNext, nextAnimation;
+ _aiScripts->queryAnimationState(i, &animationState, &animationFrame, &animationStateNext, &nextAnimation);
+ s.writeInt(animationState);
+ s.writeInt(animationFrame);
+ s.writeInt(animationStateNext);
+ s.writeInt(nextAnimation);
+ }
+ _actors[kActorVoiceOver]->save(s);
+
+ _policeMaze->save(s);
+ _crimesDatabase->save(s);
+
+ s.finalize();
+ assert(0 && "ok");
+
+ commonSaveFile->writeUint32LE(s.size() + 4);
+ commonSaveFile->write(s.getData(), s.size());
+
+ return !commonSaveFile->err();
+}
+
+void BladeRunnerEngine::loadGame(const Common::String &filename, byte *thumbnail) {
+ warning("BladeRunnerEngine::loadGame not finished");
+
+ if (!playerHasControl() || _sceneScript->isInsideScript() || _aiScripts->isInsideScript()) {
+ return;
+ }
+
+ Common::InSaveFile *commonSaveFile = getSaveFileManager()->openForLoading(filename);
+ if (commonSaveFile->err()) {
+ return;
+ }
+
+ void *buf = malloc(commonSaveFile->size());
+ int dataSize = commonSaveFile->read(buf, commonSaveFile->size());
+
+ SaveFileReadStream s((const byte*)buf, dataSize);
+
+ _ambientSounds->removeAllNonLoopingSounds(true);
+ _ambientSounds->removeAllLoopingSounds(1);
+ _music->stop(2);
+ _audioSpeech->stopSpeech();
+ _actorDialogueQueue->flush(true, false);
+
+ int size = s.readInt();
+
+ if (size != dataSize) {
+ return;
+ }
+
+ s.skip(9600); // thumbnail
+ _settings->load(s);
+ _scene->load(s);
+ _scene->_exits->load(s);
+ _scene->_regions->load(s);
+ _scene->_set->load(s);
+ for (uint i = 0; i != _gameInfo->getGlobalVarCount(); ++i) {
+ _gameVars[i] = s.readInt();
+ }
+ _music->load(s);
+ // _audioPlayer->load(s) // zero func
+ // _audioSpeech->load(s) // zero func
+ _combat->load(s);
+ _gameFlags->load(s);
+ _items->load(s);
+ _sceneObjects->load(s);
+ _ambientSounds->load(s);
+ _overlays->load(s);
+ _spinner->load(s);
+ _scores->load(s);
+ _dialogueMenu->load(s);
+ _obstacles->load(s);
+ _actorDialogueQueue->load(s);
+ _waypoints->load(s);
+
+ for (uint i = 0; i != _gameInfo->getActorCount(); ++i) {
+ _actors[i]->load(s);
+
+ int animationState = s.readInt();
+ int animationFrame = s.readInt();
+ int animationStateNext = s.readInt();
+ int nextAnimation = s.readInt();
+ _aiScripts->setAnimationState(i, animationState, animationFrame, animationStateNext, nextAnimation);
+ }
+ _actors[kActorVoiceOver]->load(s);
+
+ _policeMaze->load(s);
+ _crimesDatabase->load(s);
+
+ _settings->setNewSetAndScene(_settings->getSet(), _settings->getScene());
+ _settings->setChapter(_settings->getChapter());
+}
+
+void BladeRunnerEngine::ISez(const Common::String &str) {
+ debug("\t%s", str.c_str());
}
void BladeRunnerEngine::blitToScreen(const Graphics::Surface &src) {
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index 066e6837cc..fc0abf4e0a 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -63,6 +63,7 @@ class Combat;
class Debugger;
class DialogueMenu;
class Elevator;
+class EndCredits;
class ESPER;
class Font;
class GameFlags;
@@ -75,9 +76,11 @@ class Mouse;
class Music;
class Obstacles;
class Overlays;
+class PoliceMaze;
class Scene;
class SceneObjects;
class SceneScript;
+class Scores;
class Settings;
class Shape;
class SliceAnimations;
@@ -85,6 +88,7 @@ class SliceRenderer;
class Spinner;
class SuspectsDatabase;
class TextResource;
+class Time;
class KIAShapes;
class Vector3;
class View;
@@ -102,10 +106,10 @@ public:
static const int kActorCount = 100;
static const int kActorVoiceOver = kActorCount - 1;
- bool _gameIsRunning;
- bool _windowIsActive;
- int _playerLosesControlCounter;
- const char *_languageCode;
+ bool _gameIsRunning;
+ bool _windowIsActive;
+ int _playerLosesControlCounter;
+ Common::String _languageCode;
ActorDialogueQueue *_actorDialogueQueue;
ScreenEffects *_screenEffects;
@@ -119,6 +123,7 @@ public:
Combat *_combat;
DialogueMenu *_dialogueMenu;
Elevator *_elevator;
+ EndCredits *_endCredits;
ESPER *_esper;
GameFlags *_gameFlags;
GameInfo *_gameInfo;
@@ -131,14 +136,17 @@ public:
Music *_music;
Obstacles *_obstacles;
Overlays *_overlays;
+ PoliceMaze *_policeMaze;
Scene *_scene;
SceneObjects *_sceneObjects;
SceneScript *_sceneScript;
+ Scores *_scores;
Settings *_settings;
SliceAnimations *_sliceAnimations;
SliceRenderer *_sliceRenderer;
Spinner *_spinner;
SuspectsDatabase *_suspectsDatabase;
+ Time *_gameTime;
View *_view;
VK *_vk;
Waypoints *_waypoints;
@@ -176,6 +184,8 @@ public:
int _gameAutoSave;
bool _gameIsLoading;
bool _sceneIsLoading;
+ bool _vqaIsPlaying;
+ bool _vqaStopIsRequested;
int _walkSoundId;
int _walkSoundVolume;
@@ -256,7 +266,12 @@ public:
void playerLosesControl();
void playerGainsControl();
- void ISez(const char *str);
+ bool saveGame(const Common::String &filename, byte *thumbnail);
+ void loadGame(const Common::String &filename, byte *thumbnail);
+ void newGame();
+ void autoSaveGame();
+
+ void ISez(const Common::String &str);
void blitToScreen(const Graphics::Surface &src);
diff --git a/engines/bladerunner/boundingbox.cpp b/engines/bladerunner/boundingbox.cpp
index a1c79a17e7..40b7d4285a 100644
--- a/engines/bladerunner/boundingbox.cpp
+++ b/engines/bladerunner/boundingbox.cpp
@@ -22,6 +22,8 @@
#include "bladerunner/boundingbox.h"
+#include "bladerunner/savefile.h"
+
namespace BladeRunner {
BoundingBox::BoundingBox(float x0, float y0, float z0, float x1, float y1, float z1) {
diff --git a/engines/bladerunner/boundingbox.h b/engines/bladerunner/boundingbox.h
index 11922cbd14..0206f0bbdc 100644
--- a/engines/bladerunner/boundingbox.h
+++ b/engines/bladerunner/boundingbox.h
@@ -27,6 +27,8 @@
namespace BladeRunner {
+class SaveFileWriteStream;
+
class BoundingBox {
Vector3 _vertices[2];
diff --git a/engines/bladerunner/chapters.cpp b/engines/bladerunner/chapters.cpp
index e7404c3c97..16d084b970 100644
--- a/engines/bladerunner/chapters.cpp
+++ b/engines/bladerunner/chapters.cpp
@@ -23,12 +23,15 @@
#include "bladerunner/chapters.h"
#include "bladerunner/bladerunner.h"
+#include "bladerunner/slice_animations.h"
namespace BladeRunner {
bool Chapters::enterChapter(int chapter) {
int id = _resourceIds[chapter];
+ _vm->_sliceAnimations->openFrames(id);
+
if (!_vm->openArchive("A.TLK"))
return false;
diff --git a/engines/bladerunner/combat.cpp b/engines/bladerunner/combat.cpp
index c371f7bedd..e1dc6b1044 100644
--- a/engines/bladerunner/combat.cpp
+++ b/engines/bladerunner/combat.cpp
@@ -22,10 +22,14 @@
#include "bladerunner/combat.h"
-
#include "bladerunner/actor.h"
+#include "bladerunner/audio_speech.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_constants.h"
+#include "bladerunner/game_info.h"
+#include "bladerunner/movement_track.h"
+#include "bladerunner/savefile.h"
+#include "bladerunner/scene_objects.h"
#include "bladerunner/settings.h"
namespace BladeRunner {
@@ -33,6 +37,9 @@ namespace BladeRunner {
Combat::Combat(BladeRunnerEngine *vm) {
_vm = vm;
+ _coverWaypoints.resize(_vm->_gameInfo->getCoverWaypointCount());
+ _fleeWaypoints.resize(_vm->_gameInfo->getFleeWaypointCount());
+
reset();
}
@@ -55,7 +62,7 @@ void Combat::reset() {
void Combat::activate() {
if(_enabled) {
- _vm->_playerActor->combatModeOn(-1, -1, -1, -1, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, _vm->_combat->_ammoDamage[_vm->_settings->getAmmoType()], 0, 0);
+ _vm->_playerActor->combatModeOn(-1, true, -1, -1, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, _vm->_combat->_ammoDamage[_vm->_settings->getAmmoType()], 0, false);
_active = true;
}
}
@@ -97,16 +104,127 @@ void Combat::setMissSound(int ammoType, int column, int soundId) {
_missSoundId[ammoType * 3 + column] = soundId;
}
-int Combat::getHitSound() {
+int Combat::getHitSound() const {
return _hitSoundId[3 * _vm->_settings->getAmmoType() + _vm->_rnd.getRandomNumber(2)];
}
-int Combat::getMissSound() {
+int Combat::getMissSound() const {
return _hitSoundId[3 * _vm->_settings->getAmmoType() + _vm->_rnd.getRandomNumber(2)];
}
void Combat::shoot(int actorId, Vector3 &to, int screenX) {
+ Actor *actor = _vm->_actors[actorId];
+
+ if (actor->isRetired()) {
+ return;
+ }
+
+ int sentenceId = -1;
+
+ /*
+ Distance from center as a percentage:
+ screenX - abs(right + left) / 2
+ distanceFromCenter = 100 * -------------------------------
+ abs(right - left) / 2
+ */
+ const Common::Rect &rect = actor->getScreenRectangle();
+ int distanceFromCenter = CLIP(100 * (screenX - abs((rect.right + rect.left) / 2)) / abs((rect.right - rect.left) / 2), 0, 100);
+
+ int damage = (100 - distanceFromCenter) * _ammoDamage[_vm->_settings->getAmmoType()] / 100;
+
+ int hp = MAX(actor->getCurrentHP() - damage, 0);
+
+ actor->setCurrentHP(hp);
+
+ bool setDamageAnimation = true;
+ if (actor->isWalking() == 1 && !actor->getFlagDamageAnimIfMoving()) {
+ setDamageAnimation = false;
+ }
+ if (actor->_movementTrack->hasNext() && !actor->_movementTrack->isPaused()) {
+ setDamageAnimation = false;
+ }
+ if (setDamageAnimation) {
+ if (actor->isWalking()) {
+ actor->stopWalking(false);
+ }
+ if (actor->getAnimationMode() != kAnimationModeHit && actor->getAnimationMode() != kAnimationModeCombatHit) {
+ actor->changeAnimationMode(kAnimationModeHit, false);
+ sentenceId = _vm->_rnd.getRandomNumberRng(0, 1) ? 9000 : 9005;
+ }
+ }
+
+ if (hp <= 0) {
+ actor->setTarget(false);
+ if (actor->inCombat()) {
+ actor->combatModeOff();
+ }
+ actor->stopWalking(false);
+ actor->changeAnimationMode(48, false);
+ actor->retire(true, 72, 36, kActorMcCoy);
+ actor->setAtXYZ(actor->getXYZ(), actor->getFacing(), true, false, true);
+ _vm->_sceneObjects->setRetired(actorId + kSceneObjectOffsetActors, true);
+ sentenceId = 9020;
+ }
+ if (sentenceId >= 0 && actor->inCombat()) {
+ _vm->_audioSpeech->playSpeechLine(actorId, sentenceId, 75, 0, 99);
+ }
+}
+
+int Combat::findFleeWaypoint(int setId, int enemyId, const Vector3& position) const {
+ float min = -1.0f;
+ int result = -1;
+ for (int i = 0; i < (int)_fleeWaypoints.size(); ++i) {
+ if (setId == _fleeWaypoints[i].setId) {
+ float dist = distance(position, _fleeWaypoints[i].position);
+ if (result == -1 || dist < min) {
+ result = i;
+ min = dist;
+ }
+ }
+ }
+ return result;
+}
+
+int Combat::findCoverWaypoint(int waypointType, int actorId, int enemyId) const {
+ Actor *actor = _vm->_actors[actorId];
+ Actor *enemy = _vm->_actors[enemyId];
+ int result = -1;
+ float min = -1.0f;
+ for (int i = 0; i < (int)_coverWaypoints.size(); ++i) {
+ if (waypointType == _coverWaypoints[i].type && actor->getSetId() == _coverWaypoints[i].setId) {
+ if (_vm->_sceneObjects->isObstacleBetween(_coverWaypoints[i].position, enemy->getXYZ(), enemyId)) {
+ float dist = distance(_coverWaypoints[i].position, actor->getXYZ());
+ if (result == -1 || dist < min) {
+ result = i;
+ min = dist;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+void Combat::save(SaveFileWriteStream &f) {
+ f.writeBool(_active);
+ f.writeBool(_enabled);
+ for (int i = 0; i != kSoundCount; ++i) {
+ f.writeInt(_hitSoundId[i]);
+ }
+ for (int i = 0; i != kSoundCount; ++i) {
+ f.writeInt(_missSoundId[i]);
+ }
+}
+
+void Combat::load(SaveFileReadStream &f) {
+ _active = f.readBool();
+ _enabled = f.readBool();
+ for (int i = 0; i != kSoundCount; ++i) {
+ _hitSoundId[i] = f.readInt();
+ }
+ for (int i = 0; i != kSoundCount; ++i) {
+ _missSoundId[i] = f.readInt();
+ }
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/combat.h b/engines/bladerunner/combat.h
index 21989dac52..e0038d677e 100644
--- a/engines/bladerunner/combat.h
+++ b/engines/bladerunner/combat.h
@@ -23,11 +23,16 @@
#ifndef BLADERUNNER_COMBAT_H
#define BLADERUNNER_COMBAT_H
-namespace BladeRunner {
+#include "bladerunner/vector.h"
-class Vector3;
+#include "common/array.h"
+
+namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
+class Vector3;
class Combat {
static const int kSoundCount = 9;
@@ -36,14 +41,32 @@ class Combat {
bool _active;
bool _enabled;
- int _hitSoundId[kSoundCount];
- int _missSoundId[kSoundCount];
-// int _random1;
-// int _random2;
+ int _hitSoundId[kSoundCount];
+ int _missSoundId[kSoundCount];
+ // int _random1;
+ // int _random2;
public:
int _ammoDamage[3];
+ struct CoverWaypoint {
+ int type;
+ int setId;
+ int sceneId;
+ Vector3 position;
+ };
+
+ struct FleeWaypoint {
+ int type;
+ int setId;
+ int sceneId;
+ Vector3 position;
+ int field7;
+ };
+
+ Common::Array<CoverWaypoint> _coverWaypoints;
+ Common::Array<FleeWaypoint> _fleeWaypoints;
+
public:
Combat(BladeRunnerEngine *vm);
~Combat();
@@ -60,10 +83,16 @@ public:
void setHitSound(int ammoType, int column, int soundId);
void setMissSound(int ammoType, int column, int soundId);
- int getHitSound();
- int getMissSound();
+ int getHitSound() const;
+ int getMissSound() const;
void shoot(int actorId, Vector3 &to, int screenX);
+
+ int findFleeWaypoint(int setId, int enemyId, const Vector3& position) const;
+ int findCoverWaypoint(int waypointType, int actorId, int enemyId) const;
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/crimes_database.cpp b/engines/bladerunner/crimes_database.cpp
index febe408cd9..e9faa22b41 100644
--- a/engines/bladerunner/crimes_database.cpp
+++ b/engines/bladerunner/crimes_database.cpp
@@ -24,11 +24,12 @@
#include "bladerunner/bladerunner.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/text_resource.h"
namespace BladeRunner {
-CrimesDatabase::CrimesDatabase(BladeRunnerEngine *vm, const char *cluesResource, int crimeCount) {
+CrimesDatabase::CrimesDatabase(BladeRunnerEngine *vm, const Common::String &cluesResource, int crimeCount) {
_crimeCount = crimeCount;
_crimes.resize(_crimeCount);
@@ -70,4 +71,17 @@ const char *CrimesDatabase::getClueText(int clueId) const {
return _cluesText->getText(clueId);
}
+void CrimesDatabase::save(SaveFileWriteStream &f) {
+ for (int i = 0; i < _crimeCount; ++i) {
+ uint8 c = _crimes[i];
+ f.writeByte(c);
+ }
+}
+
+void CrimesDatabase::load(SaveFileReadStream &f) {
+ for (int i = 0; i < _crimeCount; ++i) {
+ _crimes[i] = f.readByte();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/crimes_database.h b/engines/bladerunner/crimes_database.h
index 40e46cb356..9bb83f148f 100644
--- a/engines/bladerunner/crimes_database.h
+++ b/engines/bladerunner/crimes_database.h
@@ -28,6 +28,8 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class TextResource;
class CrimesDatabase {
@@ -37,7 +39,7 @@ class CrimesDatabase {
TextResource *_cluesText;
public:
- CrimesDatabase(BladeRunnerEngine *vm, const char *cluesResource, int crimeCount);
+ CrimesDatabase(BladeRunnerEngine *vm, const Common::String &cluesResource, int crimeCount);
~CrimesDatabase();
void setCrime(int clueId, int crimeId);
@@ -47,6 +49,9 @@ public:
int getAssetType(int clueId) const;
const char *getClueText(int clueId) const;
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 5539082187..0355f9d0f5 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/actor.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/boundingbox.h"
+#include "bladerunner/combat.h"
#include "bladerunner/font.h"
#include "bladerunner/game_constants.h"
#include "bladerunner/game_flags.h"
@@ -55,6 +56,8 @@ Debugger::Debugger(BladeRunnerEngine *vm) : GUI::Debugger() {
_vm = vm;
_viewSceneObjects = false;
+ _viewActorsOnly = false;
+ _viewObstacles = false;
_viewUI = false;
_viewZBuffer = false;
@@ -105,8 +108,8 @@ bool Debugger::cmdAnimation(int argc, const char **argv) {
bool Debugger::cmdDraw(int argc, const char **argv) {
if (argc != 2) {
- debugPrintf("Enables debug rendering of scene objects, ui elements, zbuffer or disables debug rendering.\n");
- debugPrintf("Usage: %s (obj | ui | zbuf | reset)\n", argv[0]);
+ debugPrintf("Enables debug rendering of scene objects, obstacles, ui elements, zbuffer or disables debug rendering.\n");
+ debugPrintf("Usage: %s (obj | actors | obstacles | ui | zbuf | reset)\n", argv[0]);
return true;
}
@@ -114,6 +117,13 @@ bool Debugger::cmdDraw(int argc, const char **argv) {
if (arg == "obj") {
_viewSceneObjects = !_viewSceneObjects;
debugPrintf("Drawing scene objects = %i\n", _viewSceneObjects);
+ } else if (arg == "actors") {
+ _viewSceneObjects = !_viewSceneObjects;
+ _viewActorsOnly = _viewSceneObjects;
+ debugPrintf("Drawing scene actors = %i\n", _viewSceneObjects);
+ } else if (arg == "obstacles") {
+ _viewObstacles = !_viewObstacles;
+ debugPrintf("Drawing obstacles = %i\n", _viewObstacles);
} else if (arg == "ui") {
_viewUI = !_viewUI;
debugPrintf("Drawing UI elements = %i\n", _viewUI);
@@ -256,7 +266,6 @@ bool Debugger::cmdPosition(int argc, const char **argv) {
debugPrintf("actorY(%i) = %f\n", actorId, actor->getY());
debugPrintf("actorZ(%i) = %f\n", actorId, actor->getZ());
debugPrintf("actorFacing(%i) = %i\n", actorId, actor->getFacing());
- return true;
}
if (argc == 3) {
@@ -271,11 +280,9 @@ bool Debugger::cmdPosition(int argc, const char **argv) {
return true;
}
- Vector3 position;
- otherActor->getXYZ(&position.x, &position.y, &position.z);
+ Vector3 position = otherActor->getXYZ();
actor->setSetId(otherActor->getSetId());
actor->setAtXYZ(position, otherActor->getFacing());
- return true;
}
if (argc == 7) {
@@ -285,7 +292,6 @@ bool Debugger::cmdPosition(int argc, const char **argv) {
actor->setSetId(setId);
actor->setAtXYZ(position, facing);
- return true;
}
return true;
}
@@ -386,19 +392,22 @@ void Debugger::drawSceneObjects() {
for (int i = 0; i < count; i++) {
SceneObjects::SceneObject *sceneObject = &_vm->_sceneObjects->_sceneObjects[_vm->_sceneObjects->_sceneObjectsSortedByDistance[i]];
- const BoundingBox *bbox = sceneObject->boundingBox;
+ const BoundingBox &bbox = sceneObject->boundingBox;
Vector3 a, b;
- bbox->getXYZ(&a.x, &a.y, &a.z, &b.x, &b.y, &b.z);
+ bbox.getXYZ(&a.x, &a.y, &a.z, &b.x, &b.y, &b.z);
Vector3 pos = _vm->_view->calculateScreenPosition(0.5 * (a + b));
int color;
+ if (_viewActorsOnly && sceneObject->type != kSceneObjectTypeActor)
+ continue;
+
switch (sceneObject->type) {
case kSceneObjectTypeUnknown:
break;
case kSceneObjectTypeActor:
color = 0x7C00; // 11111 00000 00000;
drawBBox(a, b, _vm->_view, &_vm->_surfaceFront, color);
- _vm->_surfaceFront.frameRect(*sceneObject->screenRectangle, color);
+ _vm->_surfaceFront.frameRect(sceneObject->screenRectangle, color);
_vm->_mainFont->drawColor(_vm->_textActorNames->getText(sceneObject->id - kSceneObjectOffsetActors), _vm->_surfaceFront, pos.x, pos.y, color);
break;
case kSceneObjectTypeItem:
@@ -406,7 +415,7 @@ void Debugger::drawSceneObjects() {
char itemText[40];
drawBBox(a, b, _vm->_view, &_vm->_surfaceFront, color);
sprintf(itemText, "item %i", sceneObject->id - kSceneObjectOffsetItems);
- _vm->_surfaceFront.frameRect(*sceneObject->screenRectangle, color);
+ _vm->_surfaceFront.frameRect(sceneObject->screenRectangle, color);
_vm->_mainFont->drawColor(itemText, _vm->_surfaceFront, pos.x, pos.y, color);
break;
case kSceneObjectTypeObject:
@@ -417,13 +426,16 @@ void Debugger::drawSceneObjects() {
color = 0x03E0; // 00000 11111 00000;
}
drawBBox(a, b, _vm->_view, &_vm->_surfaceFront, color);
- _vm->_surfaceFront.frameRect(*sceneObject->screenRectangle, color);
+ _vm->_surfaceFront.frameRect(sceneObject->screenRectangle, color);
_vm->_mainFont->drawColor(_vm->_scene->objectGetName(sceneObject->id - kSceneObjectOffsetObjects), _vm->_surfaceFront, pos.x, pos.y, color);
break;
}
}
}
+ if (_viewActorsOnly)
+ return;
+
//draw regions
for (int i = 0; i < 10; i++) {
Regions::Region *region = &_vm->_scene->_regions->_regions[i];
@@ -481,12 +493,13 @@ void Debugger::drawSceneObjects() {
}
//draw waypoints
- for(int i = 0; i < _vm->_waypoints->_count; i++) {
+ for (int i = 0; i < _vm->_waypoints->_count; i++) {
Waypoints::Waypoint *waypoint = &_vm->_waypoints->_waypoints[i];
- if(waypoint->setId != _vm->_scene->getSetId())
+ if(waypoint->setId != _vm->_scene->getSetId()) {
continue;
+ }
Vector3 pos = waypoint->position;
- Vector3 size = Vector3(5.0f, 5.0f, 5.0f);
+ Vector3 size = Vector3(3.0f, 3.0f, 3.0f);
int color = 0x7FFF; // 11111 11111 11111
drawBBox(pos - size, pos + size, _vm->_view, &_vm->_surfaceFront, color);
Vector3 spos = _vm->_view->calculateScreenPosition(pos);
@@ -495,6 +508,38 @@ void Debugger::drawSceneObjects() {
_vm->_mainFont->drawColor(waypointText, _vm->_surfaceFront, spos.x, spos.y, color);
}
+ //draw combat cover waypoints
+ for (int i = 0; i < (int)_vm->_combat->_coverWaypoints.size(); i++) {
+ Combat::CoverWaypoint *cover = &_vm->_combat->_coverWaypoints[i];
+ if (cover->setId != _vm->_scene->getSetId()) {
+ continue;
+ }
+ Vector3 pos = cover->position;
+ Vector3 size = Vector3(3.0f, 3.0f, 3.0f);
+ int color = 0x7C1F; // 11111 00000 11111
+ drawBBox(pos - size, pos + size, _vm->_view, &_vm->_surfaceFront, color);
+ Vector3 spos = _vm->_view->calculateScreenPosition(pos);
+ char coverText[40];
+ sprintf(coverText, "cover %i", i);
+ _vm->_mainFont->drawColor(coverText, _vm->_surfaceFront, spos.x, spos.y, color);
+ }
+
+ //draw combat flee waypoints
+ for (int i = 0; i < (int)_vm->_combat->_fleeWaypoints.size(); i++) {
+ Combat::FleeWaypoint *flee = &_vm->_combat->_fleeWaypoints[i];
+ if (flee->setId != _vm->_scene->getSetId()) {
+ continue;
+ }
+ Vector3 pos = flee->position;
+ Vector3 size = Vector3(3.0f, 3.0f, 3.0f);
+ int color = 0x03FF; // 00000 11111 11111
+ drawBBox(pos - size, pos + size, _vm->_view, &_vm->_surfaceFront, color);
+ Vector3 spos = _vm->_view->calculateScreenPosition(pos);
+ char fleeText[40];
+ sprintf(fleeText, "flee %i", i);
+ _vm->_mainFont->drawColor(fleeText, _vm->_surfaceFront, spos.x, spos.y, color);
+ }
+
#if 0
//draw aesc
for (uint i = 0; i < _screenEffects->_entries.size(); i++) {
diff --git a/engines/bladerunner/debugger.h b/engines/bladerunner/debugger.h
index bfe4e49b9b..64e312ae20 100644
--- a/engines/bladerunner/debugger.h
+++ b/engines/bladerunner/debugger.h
@@ -41,6 +41,8 @@ class Debugger : public GUI::Debugger{
public:
bool _viewSceneObjects;
+ bool _viewActorsOnly;
+ bool _viewObstacles;
bool _viewUI;
bool _viewZBuffer;
diff --git a/engines/bladerunner/detection_tables.h b/engines/bladerunner/detection_tables.h
index 52627890ea..3c509f4314 100644
--- a/engines/bladerunner/detection_tables.h
+++ b/engines/bladerunner/detection_tables.h
@@ -30,24 +30,18 @@ static const ADGameDescription gameDescriptions[] = {
{
"bladerunner",
0,
- {
- {"STARTUP.MIX", 0, "5643b53306ca7764cf1ec7b79c9630a3", 2312374},
- AD_LISTEND
- },
+ AD_ENTRY1s("STARTUP.MIX", "5643b53306ca7764cf1ec7b79c9630a3", 2312374),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
GUIO0()
},
-
+
// BladeRunner (German)
{
"bladerunner",
0,
- {
- {"STARTUP.MIX", 0, "57d674ed860148a530b7f4957cbe65ec", 2314301},
- AD_LISTEND
- },
+ AD_ENTRY1s("STARTUP.MIX", "57d674ed860148a530b7f4957cbe65ec", 2314301),
Common::DE_DEU,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
@@ -58,10 +52,7 @@ static const ADGameDescription gameDescriptions[] = {
{
"bladerunner",
0,
- {
- {"STARTUP.MIX", 0, "39d1901df50935d58aee252707134952", 2314526},
- AD_LISTEND
- },
+ AD_ENTRY1s("STARTUP.MIX", "39d1901df50935d58aee252707134952", 2314526),
Common::FR_FRA,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
@@ -72,10 +63,7 @@ static const ADGameDescription gameDescriptions[] = {
{
"bladerunner",
0,
- {
- {"STARTUP.MIX", 0, "c7ceb9c691223d25e78516aa519ff504", 2314461},
- AD_LISTEND
- },
+ AD_ENTRY1s("STARTUP.MIX", "c7ceb9c691223d25e78516aa519ff504", 2314461),
Common::IT_ITA,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
@@ -86,10 +74,7 @@ static const ADGameDescription gameDescriptions[] = {
{
"bladerunner",
0,
- {
- {"STARTUP.MIX", 0, "c198b54a5366b88b1734bbca21d3b192", 2678672},
- AD_LISTEND
- },
+ AD_ENTRY1s("STARTUP.MIX", "c198b54a5366b88b1734bbca21d3b192", 2678672),
Common::RU_RUS,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
@@ -100,10 +85,7 @@ static const ADGameDescription gameDescriptions[] = {
{
"bladerunner",
0,
- {
- {"STARTUP.MIX", 0, "54cad53da9e4ae03a85648834ac6765d", 2312976},
- AD_LISTEND
- },
+ AD_ENTRY1s("STARTUP.MIX", "54cad53da9e4ae03a85648834ac6765d", 2312976),
Common::ES_ESP,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
diff --git a/engines/bladerunner/dialogue_menu.cpp b/engines/bladerunner/dialogue_menu.cpp
index 685c8459e0..d9a7c62866 100644
--- a/engines/bladerunner/dialogue_menu.cpp
+++ b/engines/bladerunner/dialogue_menu.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/bladerunner.h"
#include "bladerunner/font.h"
#include "bladerunner/mouse.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/settings.h"
#include "bladerunner/shape.h"
#include "bladerunner/text_resource.h"
@@ -158,7 +159,7 @@ int DialogueMenu::queryInput() {
if (_items[0].isDone) {
_selectedItemIndex = 1;
answer = _items[0].answerValue;
- } else if (_items[0].isDone) {
+ } else if (_items[1].isDone) {
_selectedItemIndex = 0;
answer = _items[1].answerValue;
}
@@ -364,6 +365,54 @@ bool DialogueMenu::waitingForInput() const {
return _waitingForInput;
}
+void DialogueMenu::save(SaveFileWriteStream &f) {
+ f.writeBool(_isVisible);
+ f.writeBool(_waitingForInput);
+ f.writeInt(_selectedItemIndex);
+ f.writeInt(_listSize);
+
+ f.writeInt(_neverRepeatListSize);
+ for (int i = 0; i < 100; ++i) {
+ f.writeInt(_neverRepeatValues[i]);
+ }
+ for (int i = 0; i < 100; ++i) {
+ f.writeBool(_neverRepeatWasSelected[i]);
+ }
+ for (int i = 0; i < 10; ++i) {
+ f.writeStringSz(_items[i].text, 50);
+ f.writeInt(_items[i].answerValue);
+ f.writeInt(_items[i].colorIntensity);
+ f.writeInt(_items[i].priorityPolite);
+ f.writeInt(_items[i].priorityNormal);
+ f.writeInt(_items[i].prioritySurly);
+ f.writeInt(_items[i].isDone);
+ }
+}
+
+void DialogueMenu::load(SaveFileReadStream &f) {
+ _isVisible = f.readBool();
+ _waitingForInput = f.readBool();
+ _selectedItemIndex = f.readInt();
+ _listSize = f.readInt();
+
+ _neverRepeatListSize = f.readInt();
+ for (int i = 0; i < 100; ++i) {
+ _neverRepeatValues[i] = f.readInt();
+ }
+ for (int i = 0; i < 100; ++i) {
+ _neverRepeatWasSelected[i] = f.readBool();
+ }
+ for (int i = 0; i < 10; ++i) {
+ _items[i].text = f.readStringSz(50);
+ _items[i].answerValue = f.readInt();
+ _items[i].colorIntensity = f.readInt();
+ _items[i].priorityPolite = f.readInt();
+ _items[i].priorityNormal = f.readInt();
+ _items[i].prioritySurly = f.readInt();
+ _items[i].isDone = f.readInt();
+ }
+}
+
void DialogueMenu::clear() {
_isVisible = false;
_waitingForInput = false;
diff --git a/engines/bladerunner/dialogue_menu.h b/engines/bladerunner/dialogue_menu.h
index 63e23d8ada..6dfd3efdc6 100644
--- a/engines/bladerunner/dialogue_menu.h
+++ b/engines/bladerunner/dialogue_menu.h
@@ -33,6 +33,8 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class TextResource;
class DialogueMenu {
@@ -96,12 +98,14 @@ public:
void mouseUp();
bool waitingForInput() const;
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
bool showAt(int x, int y);
int getAnswerIndex(int answer) const;
const char *getText(int id) const;
void calculatePosition(int unusedX = 0, int unusedY = 0);
-
void clear();
void reset();
diff --git a/engines/bladerunner/fog.cpp b/engines/bladerunner/fog.cpp
index fff27b0558..cb8235ba64 100644
--- a/engines/bladerunner/fog.cpp
+++ b/engines/bladerunner/fog.cpp
@@ -27,7 +27,6 @@
namespace BladeRunner {
Fog::Fog() {
- _name[0] = 0;
_frameCount = 0;
_animatedParameters = 0;
_fogDensity = 0.0f;
@@ -55,7 +54,9 @@ Fog::~Fog() {
int Fog::readCommon(Common::ReadStream *stream) {
int offset = stream->readUint32LE();
- stream->read(_name, 20);
+ char buf[20];
+ stream->read(buf, sizeof(buf));
+ _name = buf;
_fogColor.r = stream->readFloatLE();
_fogColor.g = stream->readFloatLE();
_fogColor.b = stream->readFloatLE();
@@ -65,7 +66,7 @@ int Fog::readCommon(Common::ReadStream *stream) {
void Fog::readAnimationData(Common::ReadStream *stream, int size) {
_animatedParameters = stream->readUint32LE();
-
+
int floatCount = size / 4;
_animationData = new float[floatCount];
for (int i = 0; i < floatCount; i++) {
diff --git a/engines/bladerunner/fog.h b/engines/bladerunner/fog.h
index 95ac550fd1..e952d24165 100644
--- a/engines/bladerunner/fog.h
+++ b/engines/bladerunner/fog.h
@@ -38,7 +38,8 @@ class Fog {
friend class SetEffects;
protected:
- char _name[20];
+ Common::String _name;
+
int _frameCount;
int _animatedParameters;
Matrix4x3 _matrix;
diff --git a/engines/bladerunner/font.cpp b/engines/bladerunner/font.cpp
index 5ae1c8eedc..d4b0e16515 100644
--- a/engines/bladerunner/font.cpp
+++ b/engines/bladerunner/font.cpp
@@ -120,6 +120,14 @@ void Font::drawColor(const Common::String &text, Graphics::Surface &surface, int
draw(text, surface, x, y);
}
+void Font::drawNumber(int num, Graphics::Surface &surface, int x, int y) const {
+ char buffer[20];
+
+ snprintf(buffer, 20, "%d", num);
+
+ draw(buffer, surface, x, y);
+}
+
int Font::getTextWidth(const Common::String &text) const {
const uint8 *character = (const uint8 *)text.c_str();
diff --git a/engines/bladerunner/font.h b/engines/bladerunner/font.h
index 9302520153..4af25468c6 100644
--- a/engines/bladerunner/font.h
+++ b/engines/bladerunner/font.h
@@ -69,6 +69,7 @@ public:
void draw(const Common::String &text, Graphics::Surface &surface, int x, int y) const;
void drawColor(const Common::String &text, Graphics::Surface &surface, int x, int y, uint16 color);
+ void drawNumber(int num, Graphics::Surface &surface, int x, int y) const;
int getTextWidth(const Common::String &text) const;
int getTextHeight(const Common::String &text) const;
diff --git a/engines/bladerunner/game_constants.h b/engines/bladerunner/game_constants.h
index af4728aaad..79381975f7 100644
--- a/engines/bladerunner/game_constants.h
+++ b/engines/bladerunner/game_constants.h
@@ -535,6 +535,8 @@ enum Flags {
enum Variables {
kVariableChapter = 1,
kVariableChinyen = 2,
+ kVariablePoliceMazeScore = 9,
+ kVariablePoliceMazePS10TargetCounter = 10,
kVariableGenericWalkerAModel = 32,
kVariableGenericWalkerBModel = 33,
kVariableGenericWalkerCModel = 34,
@@ -597,14 +599,17 @@ enum AnimationModes {
kAnimationModeTalk = 3,
kAnimationModeCombatIdle = 4,
kAnimationModeCombatAim = 5,
- kAnimationModeCombatShoot = 6,
+ kAnimationModeCombatAttack = 6,
kAnimationModeCombatWalk = 7,
kAnimationModeCombatRun = 8,
+ kAnimationModeHit = 21,
+ kAnimationModeCombatHit = 22,
kAnimationModeWalkUp = 44,
kAnimationModeWalkDown = 45,
kAnimationModeCombatWalkUp = 46,
kAnimationModeCombatWalkDown = 47,
- kAnimationModeDie = 48, // TODO: check
+ kAnimationModeDie = 48,
+ kAnimationModeCombatDie = 49,
kAnimationModeFeeding = 52,
kAnimationModeSit = 53, // TODO: check
kAnimationModeClimbUp = 64,
@@ -842,6 +847,15 @@ enum Sets {
};
enum GameItems {
+ kItemPoliceMazeTarget1 = 0,
+ kItemPoliceMazeTarget2 = 1,
+ kItemPoliceMazeTarget3 = 2,
+ kItemPoliceMazeTarget4 = 3,
+ kItemPoliceMazeTarget5 = 4,
+ kItemPoliceMazeTarget6 = 5,
+ kItemPoliceMazeTarget7 = 6,
+ kItemPoliceMazeTarget8 = 7,
+ kItemPoliceMazeTarget9 = 8,
kItemChromeDebris = 66,
kItemCandy = 79,
kItemChopstickWrapper = 82,
@@ -871,6 +885,48 @@ enum SceneObjectOffset {
kSceneObjectOffsetObjects = 198
};
+enum ActorCombatStates {
+ kActorCombatStateIdle = 0,
+ kActorCombatStateCover = 1,
+ kActorCombatStateApproachCloseAttack = 2,
+ kActorCombatStateUncover = 3,
+ kActorCombatStateAim = 4,
+ kActorCombatStateRangedAttack = 5,
+ kActorCombatStateCloseAttack = 6,
+ kActorCombatStateFlee = 7,
+ kActorCombatStateApproachRangedAttack = 8
+};
+
+enum PoliceMazeTrackInstruction {
+ kPMTIActivate = -26,
+ kPMTILeave = -25,
+ kPMTIShoot = -24,
+ kPMTIEnemyReset = -23,
+ kPMTIEnemySet = -22,
+ kPMTIFlagReset = -21,
+ kPMTIFlagSet = -20,
+ kPMTIVariableDec = -19,
+ kPMTIVariableInc = -18,
+ kPMTIVariableReset = -17,
+ kPMTIVariableSet = -16,
+ kPMTITargetSet = -15,
+ kPMTI12 = -14,
+ kPMTI13 = -13,
+ kPMTIPausedSet = -12,
+ kPMTIPausedReset = -11,
+ kPMTIPlaySound = -10,
+ kPMTIObstacleReset = -9,
+ kPMTIObstacleSet = -8,
+ kPMTIWaitRandom = -7,
+ kPMTIRotate = -6,
+ kPMTIFacing = -5,
+ kPMTIRestart = -4,
+ kPMTIWait = -3,
+ kPMTIMove = -2,
+ kPMTIPosition = -1,
+ kPMTI26 = 0
+};
+
} // End of namespace BladeRunner
#endif
diff --git a/engines/bladerunner/game_flags.cpp b/engines/bladerunner/game_flags.cpp
index 81fe6a0a4f..6fdcb89363 100644
--- a/engines/bladerunner/game_flags.cpp
+++ b/engines/bladerunner/game_flags.cpp
@@ -22,6 +22,8 @@
#include "bladerunner/game_flags.h"
+#include "bladerunner/savefile.h"
+
#include "common/debug.h"
namespace BladeRunner {
@@ -38,7 +40,7 @@ void GameFlags::setFlagCount(int count) {
assert(count > 0);
_flagCount = count;
- _flags = new uint32[count / 32 + 1];
+ _flags = new uint32[count / 32 + 1]();
for (int i = 0; i <= _flagCount; ++i)
reset(i);
@@ -71,4 +73,16 @@ bool GameFlags::query(int flag) const {
return !!(_flags[flag / 32] & (1 << (flag % 32)));
}
+void GameFlags::save(SaveFileWriteStream &f) {
+ for (int i = 0; i != _flagCount / 32 + 1; ++i) {
+ f.writeUint32LE(_flags[i]);
+ }
+}
+
+void GameFlags::load(SaveFileReadStream &f) {
+ for (int i = 0; i != _flagCount / 32 + 1; ++i) {
+ _flags[i] = f.readUint32LE();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/game_flags.h b/engines/bladerunner/game_flags.h
index 83cbdbc086..837537f689 100644
--- a/engines/bladerunner/game_flags.h
+++ b/engines/bladerunner/game_flags.h
@@ -27,6 +27,9 @@
namespace BladeRunner {
+class SaveFileReadStream;
+class SaveFileWriteStream;
+
class GameFlags {
uint32 *_flags;
int _flagCount;
@@ -40,6 +43,9 @@ public:
void set(int flag);
void reset(int flag);
bool query(int flag) const;
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/game_info.cpp b/engines/bladerunner/game_info.cpp
index db664c0f2d..9dc261bc31 100644
--- a/engines/bladerunner/game_info.cpp
+++ b/engines/bladerunner/game_info.cpp
@@ -31,10 +31,6 @@ namespace BladeRunner {
GameInfo::GameInfo(BladeRunnerEngine *vm) {
_vm = vm;
- _sceneNames = nullptr;
- _sfxTracks = nullptr;
- _musicTracks = nullptr;
- _outtakes = nullptr;
_actorCount = 0;
_playerId = 0;
_flagCount = 0;
@@ -53,18 +49,12 @@ GameInfo::GameInfo(BladeRunnerEngine *vm) {
_fleeWaypointCount = 0;
}
-GameInfo::~GameInfo() {
- delete[] _sceneNames;
- delete[] _sfxTracks;
- delete[] _musicTracks;
- delete[] _outtakes;
-}
-
bool GameInfo::open(const Common::String &name) {
Common::SeekableReadStream *s = _vm->getResourceStream(name);
- if (!s)
+ if (!s) {
return false;
+ }
uint32 unk;
_actorCount = s->readUint32LE(); /* 00 */
@@ -88,25 +78,33 @@ bool GameInfo::open(const Common::String &name) {
(void)unk;
- _sceneNames = new char[_sceneNamesCount][5];
- for (uint32 i = 0; i != _sceneNamesCount; ++i)
- s->read(_sceneNames[i], 5);
+ char buf[9];
+
+ _sceneNames.resize(_sceneNamesCount);
+ for (uint32 i = 0; i != _sceneNamesCount; ++i) {
+ s->read(buf, 5);
+ _sceneNames[i] = buf;
+ }
- _sfxTracks = new char[_sfxTrackCount][13];
+ _sfxTracks.resize(_sfxTrackCount);
for (uint32 i = 0; i != _sfxTrackCount; ++i) {
- s->read(_sfxTracks[i], 9);
- strcat(_sfxTracks[i], ".AUD");
+ s->read(buf, 9);
+ _sfxTracks[i] = buf;
+ _sfxTracks[i] += ".AUD";
}
- _musicTracks = new char[_musicTrackCount][13];
+ _musicTracks.resize(_musicTrackCount);
for (uint32 i = 0; i != _musicTrackCount; ++i) {
- s->read(_musicTracks[i], 9);
- strcat(_musicTracks[i], ".AUD");
+ s->read(buf, 9);
+ _musicTracks[i] = buf;
+ _musicTracks[i] += ".AUD";
}
- _outtakes = new char[_outtakeCount][13];
- for (uint32 i = 0; i != _outtakeCount; ++i)
- s->read(_outtakes[i], 9);
+ _outtakes.resize(_outtakeCount);
+ for (uint32 i = 0; i != _outtakeCount; ++i) {
+ s->read(buf, 9);
+ _outtakes[i] = buf;
+ }
#if BLADERUNNER_DEBUG_CONSOLE
debug("\nScene names\n----------------");
@@ -135,34 +133,38 @@ bool GameInfo::open(const Common::String &name) {
return !err;
}
-const char *GameInfo::getSceneName(int i) const {
+const Common::String &GameInfo::getSceneName(int i) const {
if (i < 0 || i >= (int)_sceneNamesCount) {
warning("GameInfo::getSceneName: unknown id \"%i\"", i);
- return nullptr;
+ static Common::String str("UNKNOWN_SCENE");
+ return str;
}
return _sceneNames[i];
}
-const char *GameInfo::getSfxTrack(int i) const {
+const Common::String &GameInfo::getSfxTrack(int i) const {
if (i < 0 || i >= (int)_sfxTrackCount) {
warning("GameInfo::getSfxTrack: unknown id \"%i\"", i);
- return nullptr;
+ static Common::String str("UNKNOWN_SFX_TRACK");
+ return str;
}
return _sfxTracks[i];
}
-const char *GameInfo::getMusicTrack(int i) const {
+const Common::String &GameInfo::getMusicTrack(int i) const {
if (i < 0 || i >= (int)_musicTrackCount) {
warning("GameInfo::getMusicTrack: unknown id \"%i\"", i);
- return nullptr;
+ static Common::String str("UNKNOWN_MUSIC_TRACK");
+ return str;
}
return _musicTracks[i];
}
-const char *GameInfo::getOuttake(int i) const {
+const Common::String &GameInfo::getOuttake(int i) const {
if (i < 0 || i >= (int)_outtakeCount) {
warning("GameInfo::getOuttake: unknown id \"%i\"", i);
- return nullptr;
+ static Common::String str("UNKNOWN_OUTTAKE");
+ return str;
}
return _outtakes[i];
}
diff --git a/engines/bladerunner/game_info.h b/engines/bladerunner/game_info.h
index bc7fc1eeec..857efa9e0b 100644
--- a/engines/bladerunner/game_info.h
+++ b/engines/bladerunner/game_info.h
@@ -23,6 +23,7 @@
#ifndef BLADERUNNER_GAME_INFO_H
#define BLADERUNNER_GAME_INFO_H
+#include "common/array.h"
#include "common/str.h"
namespace BladeRunner {
@@ -49,14 +50,13 @@ class GameInfo {
uint32 _coverWaypointCount;
uint32 _fleeWaypointCount;
- char (*_sceneNames)[5];
- char (*_sfxTracks)[13];
- char (*_musicTracks)[13];
- char (*_outtakes)[13];
+ Common::Array<Common::String> _sceneNames;
+ Common::Array<Common::String> _sfxTracks;
+ Common::Array<Common::String> _musicTracks;
+ Common::Array<Common::String> _outtakes;
public:
GameInfo(BladeRunnerEngine *vm);
- ~GameInfo();
bool open(const Common::String &name);
@@ -77,10 +77,10 @@ public:
uint32 getCoverWaypointCount() const { return _coverWaypointCount; }
uint32 getFleeWaypointCount() const { return _fleeWaypointCount; }
- const char *getSceneName(int i) const;
- const char *getSfxTrack(int i) const;
- const char *getMusicTrack(int i) const;
- const char *getOuttake(int i) const;
+ const Common::String &getSceneName(int i) const;
+ const Common::String &getSfxTrack(int i) const;
+ const Common::String &getMusicTrack(int i) const;
+ const Common::String &getOuttake(int i) const;
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/item.cpp b/engines/bladerunner/item.cpp
index af7b2ef4c2..2f82fc0b35 100644
--- a/engines/bladerunner/item.cpp
+++ b/engines/bladerunner/item.cpp
@@ -24,6 +24,7 @@
#include "bladerunner/bladerunner.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/slice_renderer.h"
#include "bladerunner/zbuffer.h"
@@ -73,13 +74,17 @@ bool Item::isTarget() const {
return _isTarget;
}
+bool Item::isPoliceMazeEnemy() const {
+ return _isPoliceMazeEnemy;
+}
+
bool Item::tick(Common::Rect *screenRect, bool special) {
if (!_isVisible) {
*screenRect = Common::Rect();
return false;
}
- bool isVisible = false;
+ bool isVisibleFlag = false;
Vector3 position(_position.x, -_position.z, _position.y);
int animationId = _animationId + (special ? 1 : 0);
@@ -88,7 +93,7 @@ bool Item::tick(Common::Rect *screenRect, bool special) {
if (!_screenRectangle.isEmpty()) {
*screenRect = _screenRectangle;
- isVisible = true;
+ isVisibleFlag = true;
} else {
*screenRect = Common::Rect();
}
@@ -120,7 +125,7 @@ bool Item::tick(Common::Rect *screenRect, bool special) {
}
}
- return isVisible;
+ return isVisibleFlag;
}
void Item::setXYZ(Vector3 position) {
@@ -134,7 +139,7 @@ void Item::setXYZ(Vector3 position) {
_depth = screenPosition.z * 25.5f;
}
-void Item::setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisible, bool isPoliceMazeEnemy) {
+void Item::setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag) {
_itemId = itemId;
_setId = setId;
_animationId = animationId;
@@ -143,8 +148,8 @@ void Item::setup(int itemId, int setId, int animationId, Vector3 position, int f
_width = width;
_height = height;
_isTarget = isTargetFlag;
- _isVisible = isVisible;
- _isPoliceMazeEnemy = isPoliceMazeEnemy;
+ _isVisible = isVisibleFlag;
+ _isPoliceMazeEnemy = isPoliceMazeEnemyFlag;
setXYZ(position);
_screenRectangle.bottom = -1;
_screenRectangle.right = -1;
@@ -152,6 +157,15 @@ void Item::setup(int itemId, int setId, int animationId, Vector3 position, int f
_screenRectangle.left = -1;
}
+void Item::spinInWorld() {
+ _isSpinning = true;
+ if (_vm->_rnd.getRandomNumberRng(1, 2) == 1) {
+ _facingChange = -340;
+ } else {
+ _facingChange = 340;
+ }
+}
+
bool Item::isUnderMouse(int mouseX, int mouseY) const {
return _isVisible
&& mouseX >= _screenRectangle.left - 10
@@ -160,4 +174,48 @@ bool Item::isUnderMouse(int mouseX, int mouseY) const {
&& mouseY <= _screenRectangle.bottom + 10;
}
+void Item::save(SaveFileWriteStream &f) {
+ f.writeInt(_setId);
+ f.writeInt(_itemId);
+ f.writeBoundingBox(_boundingBox);
+ f.writeRect(_screenRectangle);
+ f.writeInt(_animationId);
+ f.writeVector3(_position);
+ f.writeInt(_facing);
+ f.writeFloat(_angle);
+ f.writeInt(_width);
+ f.writeInt(_height);
+ f.writeInt(_screenX);
+ f.writeInt(_screenY);
+ f.writeFloat(_depth);
+ f.writeBool(_isTarget);
+ f.writeBool(_isSpinning);
+ f.writeInt(_facingChange);
+ f.writeFloat(0.0f); // _viewAngle
+ f.writeBool(_isVisible);
+ f.writeBool(_isPoliceMazeEnemy);
+}
+
+void Item::load(SaveFileReadStream &f) {
+ _setId = f.readInt();
+ _itemId = f.readInt();
+ _boundingBox = f.readBoundingBox();
+ _screenRectangle = f.readRect();
+ _animationId = f.readInt();
+ _position = f.readVector3();
+ _facing = f.readInt();
+ _angle = f.readFloat();
+ _width = f.readInt();
+ _height = f.readInt();
+ _screenX = f.readInt();
+ _screenY = f.readInt();
+ _depth = f.readFloat();
+ _isTarget = f.readBool();
+ _isSpinning = f.readBool();
+ _facingChange = f.readInt();
+ f.skip(4);
+ _isVisible = f.readBool();
+ _isPoliceMazeEnemy = f.readBool();
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/item.h b/engines/bladerunner/item.h
index 89bec5590b..a6420d1857 100644
--- a/engines/bladerunner/item.h
+++ b/engines/bladerunner/item.h
@@ -32,6 +32,8 @@ namespace BladeRunner {
class BladeRunnerEngine;
class Items;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class Item {
friend class Items;
@@ -65,12 +67,28 @@ public:
void setXYZ(Vector3 position);
void getWidthHeight(int *width, int *height) const;
+ const BoundingBox &getBoundingBox() { return _boundingBox; }
+ const Common::Rect &getScreenRectangle() { return _screenRectangle; }
+ int getFacing() const { return _facing; }
+ void setFacing(int facing) { _facing = facing; }
+
+ void setIsTarget(bool val) { _isTarget = val; }
+
bool isTarget() const;
+ bool isSpinning() const { return _isSpinning; }
+ bool isVisible() const { return _isVisible; }
+ void setVisible(bool val) { _isVisible = val; }
+ bool isPoliceMazeEnemy() const;
+ void setPoliceMazeEnemy(bool val) { _isPoliceMazeEnemy = val; }
+ void spinInWorld();
bool tick(Common::Rect *screenRect, bool special);
- void setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisible, bool isPoliceMazeEnemy);
+ void setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag);
bool isUnderMouse(int mouseX, int mouseY) const;
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
}
diff --git a/engines/bladerunner/item_pickup.h b/engines/bladerunner/item_pickup.h
index 97d98ead36..0328bf428e 100644
--- a/engines/bladerunner/item_pickup.h
+++ b/engines/bladerunner/item_pickup.h
@@ -43,7 +43,7 @@ class ItemPickup {
int _timeLeft;
int _timeLast;
Common::Rect _screenRect;
-
+
public:
ItemPickup(BladeRunnerEngine *vm);
~ItemPickup();
diff --git a/engines/bladerunner/items.cpp b/engines/bladerunner/items.cpp
index 9d9efd6a38..a2cb9da194 100644
--- a/engines/bladerunner/items.cpp
+++ b/engines/bladerunner/items.cpp
@@ -23,6 +23,7 @@
#include "bladerunner/items.h"
#include "bladerunner/game_constants.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/zbuffer.h"
@@ -46,6 +47,13 @@ void Items::getXYZ(int itemId, float *x, float *y, float *z) const {
_items[itemIndex]->getXYZ(x, y, z);
}
+void Items::setXYZ(int itemId, Vector3 position) {
+ int itemIndex = findItem(itemId);
+ assert(itemIndex != -1);
+
+ _items[itemIndex]->setXYZ(position);
+}
+
void Items::getWidthHeight(int itemId, int *width, int *height) const {
int itemIndex = findItem(itemId);
assert(itemIndex != -1);
@@ -67,7 +75,7 @@ void Items::tick() {
}
}
-bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisible, bool isPoliceMazeEnemy, bool addToSetFlag) {
+bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag, bool addToSetFlag) {
if (_items.size() >= 100) {
return false;
}
@@ -78,10 +86,10 @@ bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position,
}
Item *item = _items[itemIndex];
- item->setup(itemId, setId, animationId, position, facing, height, width, isTargetFlag, isVisible, isPoliceMazeEnemy);
+ item->setup(itemId, setId, animationId, position, facing, height, width, isTargetFlag, isVisibleFlag, isPoliceMazeEnemyFlag);
if (addToSetFlag && setId == _vm->_scene->getSetId()) {
- return _vm->_sceneObjects->addItem(itemId + kSceneObjectOffsetItems, &item->_boundingBox, &item->_screenRectangle, isTargetFlag, isVisible);
+ return _vm->_sceneObjects->addItem(itemId + kSceneObjectOffsetItems, item->_boundingBox, item->_screenRectangle, isTargetFlag, isVisibleFlag);
}
return true;
}
@@ -94,7 +102,7 @@ bool Items::addToSet(int setId) {
for (int i = 0; i < itemCount; i++) {
Item *item = _items[i];
if (item->_setId == setId) {
- _vm->_sceneObjects->addItem(item->_itemId + kSceneObjectOffsetItems, &item->_boundingBox, &item->_screenRectangle, item->isTarget(), item->_isVisible);
+ _vm->_sceneObjects->addItem(item->_itemId + kSceneObjectOffsetItems, item->_boundingBox, item->_screenRectangle, item->isTarget(), item->_isVisible);
}
}
return true;
@@ -118,6 +126,15 @@ bool Items::remove(int itemId) {
return true;
}
+void Items::setIsTarget(int itemId, bool val) {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return;
+ }
+ _items[itemIndex]->setIsTarget(val);
+ _vm->_sceneObjects->setIsTarget(itemId + kSceneObjectOffsetItems, val);
+}
+
bool Items::isTarget(int itemId) const {
int itemIndex = findItem(itemId);
if (itemIndex == -1) {
@@ -126,6 +143,87 @@ bool Items::isTarget(int itemId) const {
return _items[itemIndex]->isTarget();
}
+bool Items::isSpinning(int itemId) const {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return false;
+ }
+ return _items[itemIndex]->isSpinning();
+}
+
+bool Items::isVisible(int itemId) const {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return false;
+ }
+ return _items[itemIndex]->isVisible();
+}
+
+bool Items::isPoliceMazeEnemy(int itemId) const {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return false;
+ }
+ return _items[itemIndex]->isTarget();
+}
+
+void Items::setPoliceMazeEnemy(int itemId, bool val) {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return;
+ }
+ _items[itemIndex]->setPoliceMazeEnemy(val);
+}
+
+void Items::setIsObstacle(int itemId, bool val) {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return;
+ }
+ _items[itemIndex]->setVisible(val);
+ _vm->_sceneObjects->setIsClickable(itemId + kSceneObjectOffsetItems, val);
+}
+
+const BoundingBox &Items::getBoundingBox(int itemId) {
+ int itemIndex = findItem(itemId);
+ // if (itemIndex == -1) {
+ // return nullptr;
+ // }
+ return _items[itemIndex]->getBoundingBox();
+}
+
+const Common::Rect &Items::getScreenRectangle(int itemId) {
+ int itemIndex = findItem(itemId);
+ // if (itemIndex == -1) {
+ // return nullptr;
+ // }
+ return _items[itemIndex]->getScreenRectangle();
+}
+
+int Items::getFacing(int itemId) const {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return 0;
+ }
+ return _items[itemIndex]->getFacing();
+}
+
+void Items::setFacing(int itemId, int facing) {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return;
+ }
+ _items[itemIndex]->setFacing(facing);
+}
+
+void Items::spinInWorld(int itemId) {
+ int itemIndex = findItem(itemId);
+ if (itemIndex == -1) {
+ return;
+ }
+ _items[itemIndex]->spinInWorld();
+}
+
int Items::findTargetUnderMouse(int mouseX, int mouseY) const {
int setId = _vm->_scene->getSetId();
for (int i = 0 ; i < (int)_items.size(); ++i) {
@@ -145,4 +243,39 @@ int Items::findItem(int itemId) const {
return -1;
}
+void Items::save(SaveFileWriteStream &f) {
+ int size = (int)_items.size();
+
+ f.writeInt(size);
+ int i;
+ for (i = 0; i != size; ++i) {
+ _items[i]->save(f);
+ }
+
+ // Always write out 100 items
+ for (; i != 100; ++i) {
+ f.padBytes(0x174); // bbox + rect + 18 float fields
+ }
+}
+
+void Items::load(SaveFileReadStream &f) {
+ for (int i = _items.size() - 1; i >= 0; i--) {
+ delete _items.remove_at(i);
+ }
+ _items.resize(f.readInt());
+
+ int size = (int)_items.size();
+
+ int i;
+ for (i = 0; i != size; ++i) {
+ _items[i] = new Item(_vm);
+ _items[i]->load(f);
+ }
+
+ // Always read out 100 items
+ for (; i != 100; ++i) {
+ f.skip(0x174); // bbox + rect + 18 float fields
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/items.h b/engines/bladerunner/items.h
index 1aac82e8da..ce29a77787 100644
--- a/engines/bladerunner/items.h
+++ b/engines/bladerunner/items.h
@@ -30,6 +30,9 @@
namespace BladeRunner {
+class SaveFileReadStream;
+class SaveFileWriteStream;
+
class Items {
BladeRunnerEngine *_vm;
@@ -40,16 +43,33 @@ public:
~Items();
void getXYZ(int itemId, float *x, float *y, float *z) const;
+ void setXYZ(int itemId, Vector3 position);
void getWidthHeight(int itemId, int *width, int *height) const;
void tick();
- bool addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisible, bool isPoliceMazeEnemy, bool addToSetFlag);
+ bool addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag, bool addToSetFlag);
bool addToSet(int itemId);
bool remove(int itemId);
+ void setIsTarget(int itemId, bool val);
bool isTarget(int itemId) const;
+ bool isSpinning(int itemId) const;
+ bool isPoliceMazeEnemy(int itemId) const;
+ void setPoliceMazeEnemy(int itemId, bool val);
+ void setIsObstacle(int itemId, bool val);
+ bool isVisible(int itemId) const;
int findTargetUnderMouse(int mouseX, int mouseY) const;
+ const BoundingBox &getBoundingBox(int itemId);
+ const Common::Rect &getScreenRectangle(int itemId);
+ int getFacing(int itemId) const;
+ void setFacing(int itemId, int facing);
+
+ void spinInWorld(int itemId);
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
int findItem(int itemId) const;
};
diff --git a/engines/bladerunner/light.cpp b/engines/bladerunner/light.cpp
index 615958281a..2231e0460e 100644
--- a/engines/bladerunner/light.cpp
+++ b/engines/bladerunner/light.cpp
@@ -69,7 +69,9 @@ void Light::read(Common::ReadStream *stream, int frameCount, int frame, int anim
int size = stream->readUint32LE();
size = size - 32;
- stream->read(_name, 20);
+ char buf[20];
+ stream->read(buf, sizeof(buf));
+ _name = buf;
_animatedParameters = stream->readUint32LE();
diff --git a/engines/bladerunner/light.h b/engines/bladerunner/light.h
index 1ef9f3082c..31e40e0b45 100644
--- a/engines/bladerunner/light.h
+++ b/engines/bladerunner/light.h
@@ -42,7 +42,8 @@ class Light {
friend class SliceRenderer;
protected:
- char _name[20];
+ Common::String _name;
+
int _frameCount;
int _animated;
int _animatedParameters;
diff --git a/engines/bladerunner/matrix.h b/engines/bladerunner/matrix.h
index 5343eb6b8e..d5922b403f 100644
--- a/engines/bladerunner/matrix.h
+++ b/engines/bladerunner/matrix.h
@@ -57,8 +57,8 @@ inline Matrix3x2 operator*(const Matrix3x2 &a, const Matrix3x2 &b) {
inline Matrix3x2 operator+(const Matrix3x2 &a, Vector2 b) {
Matrix3x2 t(a);
- t(0,2) += b.x;
- t(1,2) += b.y;
+ t(0, 2) += b.x;
+ t(1, 2) += b.y;
return t;
}
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk
index 67827030cd..b0bae4f7bd 100644
--- a/engines/bladerunner/module.mk
+++ b/engines/bladerunner/module.mk
@@ -41,6 +41,7 @@ MODULE_OBJS = \
outtake.o \
overlays.o \
regions.o \
+ savefile.o \
scene.o \
scene_objects.o \
screen_effects.o \
@@ -49,19 +50,24 @@ MODULE_OBJS = \
script/kia_script.o \
script/vk_script.o \
script/esper_script.o \
+ script/police_maze.o \
script/ai_script.o \
script/ai/answering_machine.o \
script/ai/baker.o \
script/ai/blimp_guy.o \
script/ai/bryant.o \
+ script/ai/bullet_bob.o \
script/ai/chew.o \
script/ai/clovis.o \
script/ai/crazylegs.o \
script/ai/dektora.o \
script/ai/desk_clerk.o \
script/ai/dispatcher.o \
+ script/ai/early_q.o \
script/ai/early_q_bartender.o \
script/ai/fish_dealer.o \
+ script/ai/free_slot_a.o \
+ script/ai/free_slot_b.o \
script/ai/gaff.o \
script/ai/general_doll.o \
script/ai/generic_walker_a.o \
@@ -71,6 +77,8 @@ MODULE_OBJS = \
script/ai/governor_kolvig.o \
script/ai/grigorian.o \
script/ai/guzza.o \
+ script/ai/hanoi.o \
+ script/ai/hasan.o \
script/ai/hawkers_barkeep.o \
script/ai/hawkers_parrot.o \
script/ai/holloway.o \
@@ -86,6 +94,7 @@ MODULE_OBJS = \
script/ai/leon.o \
script/ai/lockup_guard.o \
script/ai/lucy.o \
+ script/ai/luther.o \
script/ai/maggie.o \
script/ai/male_announcer.o \
script/ai/marcus.o \
@@ -97,11 +106,13 @@ MODULE_OBJS = \
script/ai/mutant2.o \
script/ai/mutant3.o \
script/ai/newscaster.o \
+ script/ai/officer_grayford.o \
script/ai/officer_leary.o \
script/ai/photographer.o \
script/ai/rachael.o \
script/ai/rajif.o \
script/ai/runciter.o \
+ script/ai/sadik.o \
script/ai/sebastian.o \
script/ai/sergeant_walls.o \
script/ai/shoeshine_man.o \
@@ -235,7 +246,9 @@ MODULE_OBJS = \
slice_renderer.o \
suspects_database.o \
text_resource.o \
+ time.o \
ui/elevator.o \
+ ui/end_credits.o \
ui/esper.o \
ui/kia.o \
ui/kia_log.o \
@@ -248,6 +261,7 @@ MODULE_OBJS = \
ui/kia_section_settings.o \
ui/kia_section_suspects.o \
ui/kia_shapes.o \
+ ui/scores.o \
ui/spinner.o \
ui/ui_check_box.o \
ui/ui_container.o \
diff --git a/engines/bladerunner/mouse.cpp b/engines/bladerunner/mouse.cpp
index 7d67e98de5..093c73fcff 100644
--- a/engines/bladerunner/mouse.cpp
+++ b/engines/bladerunner/mouse.cpp
@@ -51,6 +51,11 @@ Mouse::Mouse(BladeRunnerEngine *vm) {
_disabledCounter = 0;
_lastFrameTime = 0;
_animCounter = 0;
+
+ _randomCountdownX = 0;
+ _randomCountdownY = 0;
+ _randomX = 0;
+ _randomY = 0;
}
Mouse::~Mouse() {
@@ -161,8 +166,55 @@ void Mouse::getXY(int *x, int *y) const {
*y = _y;
}
+void Mouse::setMouseJitterUp() {
+ switch (_vm->_settings->getDifficulty()) {
+ case 0:
+ _randomCountdownX = 2;
+ _randomX = _vm->_rnd.getRandomNumberRng(0, 6) - 3;
+ _randomY = _vm->_rnd.getRandomNumberRng(0, 10) - 20;
+ break;
+
+ case 1:
+ _randomCountdownX = 3;
+ _randomX = _vm->_rnd.getRandomNumberRng(0, 8) - 4;
+ _randomY = _vm->_rnd.getRandomNumberRng(0, 10) - 25;
+ break;
+
+ case 2:
+ _randomCountdownX = 4;
+ _randomX = _vm->_rnd.getRandomNumberRng(0, 10) - 5;
+ _randomY = _vm->_rnd.getRandomNumberRng(0, 10) - 30;
+ break;
+ }
+}
+
+void Mouse::setMouseJitterDown() {
+ switch (_vm->_settings->getDifficulty()) {
+ case 0:
+ _randomCountdownY = 2;
+ _randomX = _vm->_rnd.getRandomNumberRng(0, 6) - 3;
+ _randomY = _vm->_rnd.getRandomNumberRng(10, 20);
+ break;
+
+ case 1:
+ _randomCountdownY = 3;
+ _randomX = _vm->_rnd.getRandomNumberRng(0, 8) - 4;
+ _randomY = _vm->_rnd.getRandomNumberRng(15, 25);
+ break;
+
+ case 2:
+ _randomCountdownY = 4;
+ _randomX = _vm->_rnd.getRandomNumberRng(0, 10) - 5;
+ _randomY = _vm->_rnd.getRandomNumberRng(20, 30);
+ break;
+ }
+}
+
void Mouse::disable() {
++_disabledCounter;
+
+ _randomCountdownX = 0;
+ _randomCountdownY = 0;
}
void Mouse::enable() {
@@ -177,9 +229,24 @@ bool Mouse::isDisabled() const {
void Mouse::draw(Graphics::Surface &surface, int x, int y) {
if (_disabledCounter) {
+ _randomCountdownX = 0;
+ _randomCountdownY = 0;
return;
}
+ if (_randomCountdownX > 0) {
+ _randomCountdownX--;
+ x += _randomX;
+ y += _randomY;
+
+ if (!_randomCountdownX)
+ setMouseJitterDown();
+ } else if (_randomCountdownY > 0){
+ _randomCountdownY--;
+ x += _randomX;
+ y += _randomY;
+ }
+
_x = CLIP(x, 0, surface.w - 1);
_y = CLIP(y, 0, surface.h - 1);
diff --git a/engines/bladerunner/mouse.h b/engines/bladerunner/mouse.h
index 2f33d72583..31ba17a6c3 100644
--- a/engines/bladerunner/mouse.h
+++ b/engines/bladerunner/mouse.h
@@ -46,6 +46,11 @@ class Mouse {
int _lastFrameTime;
int _animCounter;
+ int _randomCountdownX;
+ int _randomCountdownY;
+ int _randomX;
+ int _randomY;
+
public:
Mouse(BladeRunnerEngine *vm);
~Mouse();
@@ -53,6 +58,8 @@ public:
void setCursor(int cursor);
void getXY(int *x, int *y) const;
+ void setMouseJitterUp();
+ void setMouseJitterDown();
void disable();
void enable();
diff --git a/engines/bladerunner/movement_track.cpp b/engines/bladerunner/movement_track.cpp
index 47eb56a098..322d92ef31 100644
--- a/engines/bladerunner/movement_track.cpp
+++ b/engines/bladerunner/movement_track.cpp
@@ -22,6 +22,8 @@
#include "bladerunner/movement_track.h"
+#include "bladerunner/savefile.h"
+
namespace BladeRunner {
MovementTrack::MovementTrack() {
@@ -107,4 +109,32 @@ bool MovementTrack::next(int *waypointId, int *delay, int *angle, bool *run) {
}
}
+void MovementTrack::save(SaveFileWriteStream &f) {
+ f.writeInt(_currentIndex);
+ f.writeInt(_lastIndex);
+ f.writeBool(_hasNext);
+ f.writeBool(_paused);
+ for (int i = 0; i < kSize; ++i) {
+ Entry &e = _entries[i];
+ f.writeInt(e.waypointId);
+ f.writeInt(e.delay);
+ f.writeInt(e.angle);
+ f.writeBool(e.run);
+ }
+}
+
+void MovementTrack::load(SaveFileReadStream &f) {
+ _currentIndex = f.readInt();
+ _lastIndex = f.readInt();
+ _hasNext = f.readBool();
+ _paused = f.readBool();
+ for (int i = 0; i < kSize; ++i) {
+ Entry &e = _entries[i];
+ e.waypointId = f.readInt();
+ e.delay = f.readInt();
+ e.angle = f.readInt();
+ e.run = f.readBool();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/movement_track.h b/engines/bladerunner/movement_track.h
index cba9b690ff..2eab4cdedb 100644
--- a/engines/bladerunner/movement_track.h
+++ b/engines/bladerunner/movement_track.h
@@ -29,6 +29,8 @@ namespace BladeRunner {
class BladeRunnerEngine;
class BoundingBox;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class MovementTrack {
static const int kSize = 100;
@@ -59,7 +61,8 @@ public:
bool hasNext() const;
bool next(int *waypointId, int *delay, int *angle, bool *run);
- //int saveGame();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
private:
void reset();
diff --git a/engines/bladerunner/music.cpp b/engines/bladerunner/music.cpp
index 818d412ba9..05412dd8e0 100644
--- a/engines/bladerunner/music.cpp
+++ b/engines/bladerunner/music.cpp
@@ -26,6 +26,7 @@
#include "bladerunner/aud_stream.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_info.h"
+#include "bladerunner/savefile.h"
#include "common/timer.h"
@@ -167,6 +168,68 @@ void Music::playSample() {
}
}
+void Music::save(SaveFileWriteStream &f) {
+ f.writeBool(_isNextPresent);
+ f.writeBool(_isPlaying);
+ f.writeBool(_isPaused);
+ f.writeStringSz(_current.name, 13);
+ f.writeInt(_current.volume);
+ f.writeInt(_current.pan);
+ f.writeInt(_current.timeFadeIn);
+ f.writeInt(_current.timePlay);
+ f.writeInt(_current.loop);
+ f.writeInt(_current.timeFadeOut);
+ f.writeStringSz(_next.name, 13);
+ f.writeInt(_next.volume);
+ f.writeInt(_next.pan);
+ f.writeInt(_next.timeFadeIn);
+ f.writeInt(_next.timePlay);
+ f.writeInt(_next.loop);
+ f.writeInt(_next.timeFadeOut);
+}
+
+void Music::load(SaveFileReadStream &f) {
+ _isNextPresent = f.readBool();
+ _isPlaying = f.readBool();
+ _isPaused = f.readBool();
+ _current.name = f.readStringSz(13);
+ _current.volume = f.readInt();
+ _current.pan = f.readInt();
+ _current.timeFadeIn = f.readInt();
+ _current.timePlay = f.readInt();
+ _current.loop = f.readInt();
+ _current.timeFadeOut = f.readInt();
+ _next.name = f.readStringSz(13);
+ _next.volume = f.readInt();
+ _next.pan = f.readInt();
+ _next.timeFadeIn = f.readInt();
+ _next.timePlay = f.readInt();
+ _next.loop = f.readInt();
+ _next.timeFadeOut = f.readInt();
+
+ stop(2);
+ if (_isPlaying) {
+ if (_channel == -1) {
+ play(_current.name,
+ _current.volume,
+ _current.pan,
+ _current.timeFadeIn,
+ _current.timePlay,
+ _current.loop,
+ _current.timeFadeOut);
+ } else {
+ _isNextPresent = true;
+ _next.name = _current.name;
+ _next.volume = _current.volume;
+ _next.pan = _current.pan;
+ _next.timeFadeIn = _current.timeFadeIn;
+ _next.timePlay = _current.timePlay;
+ _next.loop = _current.loop;
+ _next.timeFadeOut = _current.timeFadeOut;
+ }
+ }
+}
+
void Music::adjustVolume(int volume, int delay) {
if (_channel >= 0) {
_vm->_audioMixer->adjustVolume(_channel, volume, delay);
diff --git a/engines/bladerunner/music.h b/engines/bladerunner/music.h
index de19942a20..b4dc284def 100644
--- a/engines/bladerunner/music.h
+++ b/engines/bladerunner/music.h
@@ -30,6 +30,8 @@ namespace BladeRunner {
class AudStream;
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class Music {
struct Track {
@@ -47,9 +49,9 @@ class Music {
Common::Mutex _mutex;
int _musicVolume;
int _channel;
- int _isNextPresent;
- int _isPlaying;
- int _isPaused;
+ bool _isNextPresent;
+ bool _isPlaying;
+ bool _isPaused;
Track _current;
Track _next;
byte *_data;
@@ -68,6 +70,9 @@ public:
int getVolume();
void playSample();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
void adjustVolume(int volume, int delay);
void adjustPan(int pan, int delay);
diff --git a/engines/bladerunner/obstacles.cpp b/engines/bladerunner/obstacles.cpp
index 8061e782f2..06c19ad4af 100644
--- a/engines/bladerunner/obstacles.cpp
+++ b/engines/bladerunner/obstacles.cpp
@@ -24,23 +24,42 @@
#include "bladerunner/bladerunner.h"
+#include "bladerunner/savefile.h"
+#include "bladerunner/scene.h" // for debug
+#include "bladerunner/view.h"
+
+#include "common/debug.h"
+
+#define WITHIN_TOLERANCE(a, b) (((a) - 0.009) < (b) && ((a) + 0.009) > (b))
+
namespace BladeRunner {
Obstacles::Obstacles(BladeRunnerEngine *vm) {
_vm = vm;
- _vertices = new Vector2[150];
+ _polygons = new Polygon[kPolygonCount];
+ _polygonsBackup = new Polygon[kPolygonCount];
+ _vertices = new Vector2[kVertexCount];
clear();
}
Obstacles::~Obstacles() {
+ clear();
+
+ delete[] _polygons;
+ _polygons = nullptr;
+
+ delete[] _polygonsBackup;
+ _polygonsBackup = nullptr;
+
delete[] _vertices;
+ _vertices = nullptr;
}
void Obstacles::clear() {
for (int i = 0; i < kPolygonCount; i++) {
_polygons[i].isPresent = false;
_polygons[i].verticeCount = 0;
- for (int j = 0; j < kVertexCount; j++) {
+ for (int j = 0; j < kPolygonVertexCount; j++) {
_polygons[i].vertices[j].x = 0.0f;
_polygons[i].vertices[j].y = 0.0f;
}
@@ -50,7 +69,250 @@ void Obstacles::clear() {
_count = 0;
}
-void Obstacles::add(float x0, float z0, float x1, float z1) {
+#define IN_RANGE(v, start, end) ((start) <= (v) && (v) <= (end))
+
+/*
+ * This function is limited to finding intersections between
+ * horizontal and vertical lines!
+ *
+ * The original implementation is more general but obstacle
+ * polygons only consists of horizontal and vertical lines,
+ * and this is more numerically stable.
+ */
+bool Obstacles::lineLineIntersection(LineSegment a, LineSegment b, Vector2 *intersection) {
+ assert(a.start.x == a.end.x || a.start.y == a.end.y);
+ assert(b.start.x == b.end.x || b.start.y == b.end.y);
+
+ if (a.start.x > a.end.x) SWAP(a.start.x, a.end.x);
+ if (a.start.y > a.end.y) SWAP(a.start.y, a.end.y);
+ if (b.start.x > b.end.x) SWAP(b.start.x, b.end.x);
+ if (b.start.y > b.end.y) SWAP(b.start.y, b.end.y);
+
+ if (a.start.x == a.end.x && b.start.y == b.end.y && IN_RANGE(a.start.x, b.start.x, b.end.x) && IN_RANGE(b.start.y, a.start.y, a.end.y)) {
+ // A is vertical, B is horizontal
+ *intersection = Vector2(a.start.x, b.start.y);
+ return true;
+ }
+
+ if (a.start.y == a.end.y && b.start.x == b.end.x && IN_RANGE(a.start.y, b.start.y, b.end.y) && IN_RANGE(b.start.x, a.start.x, a.end.x)) {
+ // A is horizontal, B is vertical
+ *intersection = Vector2(b.start.x, a.start.y);
+ return true;
+ }
+
+ return false;
+}
+
+bool Obstacles::linePolygonIntersection(LineSegment lineA, VertexType lineAType, Polygon *polyB, Vector2 *intersectionPoint, int *intersectionIndex) {
+ bool hasIntersection = false;
+ float nearestIntersectionDistance = 0.0f;
+
+ for (int i = 0; i != polyB->verticeCount; ++i) {
+ LineSegment lineB;
+ lineB.start = polyB->vertices[i];
+ lineB.end = polyB->vertices[(i+1) % polyB->verticeCount];
+
+ VertexType lineBType = polyB->vertexType[i];
+
+ Vector2 newIntersectionPoint;
+
+ if (lineLineIntersection(lineA, lineB, &newIntersectionPoint)) {
+ if ((lineAType == TOP_RIGHT && lineBType == TOP_LEFT)
+ || (lineAType == BOTTOM_RIGHT && lineBType == TOP_RIGHT)
+ || (lineAType == BOTTOM_LEFT && lineBType == BOTTOM_RIGHT)
+ || (lineAType == TOP_LEFT && lineBType == BOTTOM_LEFT)
+ ) {
+ if (!WITHIN_TOLERANCE(lineB.end.x, intersectionPoint->x)
+ || !WITHIN_TOLERANCE(lineB.end.y, intersectionPoint->y)) {
+ if (newIntersectionPoint != *intersectionPoint) {
+ float newIntersectionDistance = getLength(lineA.start.x, lineA.start.y, newIntersectionPoint.x, newIntersectionPoint.y);
+ if (!hasIntersection || newIntersectionDistance < nearestIntersectionDistance) {
+ hasIntersection = true;
+ nearestIntersectionDistance = newIntersectionDistance;
+ *intersectionPoint = newIntersectionPoint;
+ *intersectionIndex = i;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return hasIntersection;
+}
+
+/*
+ * Polygons vertices are defined in clock-wise order
+ * starting at the top-most, right-most corner.
+ *
+ * When merging two polygons, we start at the top-most, right-most vertex.
+ * The polygon with this vertex starts is the primary polygon.
+ * We follow the edges until we find an intersection with the secondary polygon,
+ * in which case we switch primary and secondary and continue following the new edges.
+ *
+ * Luckily the first two polygons added in RC01 (A, then B) are laid as as below,
+ * making an ideal test case.
+ *
+ * Merge order: (B0,B1) (B1,B2) (B2,J) (J,A2) (A2,A3) (A3,A0) (A0,I) (I,B0)
+ *
+ * 0,0 ---> x
+ * |
+ * | primary
+ * | B 0 ----- 1
+ * | | |
+ * | A 0 --I-- 1 |
+ * | | | | |
+ * | | 3 --J-- 2
+ * | | |
+ * | 3 ----- 2
+ * | secondary
+ * v y
+ */
+
+bool Obstacles::mergePolygons(Polygon &polyA, Polygon &polyB) {
+ bool flagDidMergePolygons = false;
+ Polygon polyMerged;
+ polyMerged.rect = merge(polyA.rect, polyB.rect);
+
+ Polygon *polyPrimary, *polySecondary;
+ if (polyA.rect.y0 < polyB.rect.y0 || (polyA.rect.y0 == polyB.rect.y0 && polyA.rect.x0 < polyB.rect.x0)) {
+ polyPrimary = &polyA;
+ polySecondary = &polyB;
+ } else {
+ polyPrimary = &polyB;
+ polySecondary = &polyA;
+ }
+
+ Vector2 intersectionPoint;
+ LineSegment polyLine;
+ bool flagAddVertexToVertexList = true;
+ bool flagDidFindIntersection = false;
+ int vertIndex = 0;
+
+ Polygon *startingPolygon = polyPrimary;
+ int flagDone = false;
+ while (!flagDone) {
+ VertexType polyPrimaryType;
+
+ polyLine.start = flagDidFindIntersection ? intersectionPoint : polyPrimary->vertices[vertIndex];
+ polyLine.end = polyPrimary->vertices[(vertIndex + 1) % polyPrimary->verticeCount];
+
+ // TODO(madmoose): How does this work when adding a new intersection point?
+ polyPrimaryType = polyPrimary->vertexType[vertIndex];
+
+ if (flagAddVertexToVertexList) {
+ assert(polyMerged.verticeCount < kPolygonVertexCount);
+ polyMerged.vertices[polyMerged.verticeCount] = polyLine.start;
+ polyMerged.vertexType[polyMerged.verticeCount] = polyPrimaryType;
+ polyMerged.verticeCount++;
+ }
+
+ flagAddVertexToVertexList = true;
+ int polySecondaryIntersectionIndex = -1;
+
+ if (linePolygonIntersection(polyLine, polyPrimaryType, polySecondary, &intersectionPoint, &polySecondaryIntersectionIndex)) {
+ if (WITHIN_TOLERANCE(intersectionPoint.x, polyLine.start.x) && WITHIN_TOLERANCE(intersectionPoint.y, polyLine.start.y)) {
+ warning("Set: %d Scene: %d", _vm->_scene->getSetId(), _vm->_scene->getSceneId());
+ assert(0 && "Report instances of this to madmoose!");
+ flagAddVertexToVertexList = false;
+ polyMerged.verticeCount--; // TODO(madmoose): How would this work?
+ } else {
+ // Obstacles::nop
+ }
+ vertIndex = polySecondaryIntersectionIndex;
+ flagDidFindIntersection = true;
+
+ SWAP(polyPrimary, polySecondary);
+
+ flagDidMergePolygons = true;
+ } else {
+ vertIndex = (vertIndex + 1) % polyPrimary->verticeCount;
+ flagDidFindIntersection = false;
+ }
+ if (polyPrimary->vertices[vertIndex] == startingPolygon->vertices[0]) {
+ flagDone = true;
+ }
+ }
+
+ if (flagDidMergePolygons) {
+ *startingPolygon = polyMerged;
+ startingPolygon->isPresent = true;
+ if (startingPolygon == &polyA) {
+ polyB.isPresent = false;
+ } else {
+ polyA.isPresent = false;
+ }
+ }
+
+ return flagDidMergePolygons;
+}
+
+void Obstacles::add(Rect rect) {
+ int polygonIndex = findEmptyPolygon();
+ if (polygonIndex < 0) {
+ return;
+ }
+
+ rect.expand(12.0f);
+ rect.trunc_2_decimals();
+
+ Polygon &poly = _polygons[polygonIndex];
+
+ poly.rect = rect;
+
+ poly.vertices[0] = Vector2(rect.x0, rect.y0);
+ poly.vertexType[0] = TOP_LEFT;
+
+ poly.vertices[1] = Vector2(rect.x1, rect.y0);
+ poly.vertexType[1] = TOP_RIGHT;
+
+ poly.vertices[2] = Vector2(rect.x1, rect.y1);
+ poly.vertexType[2] = BOTTOM_RIGHT;
+
+ poly.vertices[3] = Vector2(rect.x0, rect.y1);
+ poly.vertexType[3] = BOTTOM_LEFT;
+
+ poly.isPresent = true;
+ poly.verticeCount = 4;
+
+restart:
+ for (int i = 0; i < kPolygonCount; ++i) {
+ Polygon &polyA = _polygons[i];
+ if (!polyA.isPresent) {
+ continue;
+ }
+
+ for (int j = i+1; j < kPolygonCount; ++j) {
+ Polygon &polyB = _polygons[j];
+ if (!polyB.isPresent) {
+ continue;
+ }
+
+ if (!overlaps(polyA.rect, polyB.rect)) {
+ continue;
+ }
+
+ if (mergePolygons(polyA, polyB)) {
+ goto restart;
+ }
+ }
+ }
+}
+
+int Obstacles::findEmptyPolygon() const {
+ for (int i = 0; i < kPolygonCount; i++) {
+ if (!_polygons[i].isPresent) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+float Obstacles::getLength(float x0, float z0, float x1, float z1) {
+ if (x0 == x1) {
+ return fabs(z1 - z0);
+ }
+ return fabs(x1 - x0);
}
bool Obstacles::find(const Vector3 &from, const Vector3 &to, Vector3 *next) const {
@@ -59,10 +321,242 @@ bool Obstacles::find(const Vector3 &from, const Vector3 &to, Vector3 *next) cons
return true;
}
+bool Obstacles::findIntersectionNearest(int polygonIndex, Vector2 from, Vector2 to,
+ int *outVertexIndex, float *outDistance, Vector2 *out) const
+{
+ float minDistance = 0.0f;
+ Vector2 minIntersection;
+ int minVertexIndex = -1;
+
+ bool hasDistance = false;
+
+ for (int i = 0; i < _polygons[polygonIndex].verticeCount; ++i) {
+ int nextIndex = (i + 1) % _polygons[polygonIndex].verticeCount;
+ Vector2 *vertices = _polygons[polygonIndex].vertices;
+ Vector2 intersection;
+ bool intersects = lineIntersection(from, to, vertices[i], vertices[nextIndex], &intersection);
+ if (intersects) {
+ float distance2 = distance(from, intersection);
+ if (!hasDistance || distance2 < minDistance) {
+ minDistance = distance2;
+ minIntersection = intersection;
+ minVertexIndex = i;
+ hasDistance = true;
+ }
+ }
+ }
+
+ *outDistance = minDistance;
+ *outVertexIndex = minVertexIndex;
+ *out = minIntersection;
+
+ return minVertexIndex != -1;
+}
+
+bool Obstacles::findIntersectionFarthest(int polygonIndex, Vector2 from, Vector2 to,
+ int *outVertexIndex, float *outDistance, Vector2 *out) const
+{
+ float maxDistance = 0.0f;
+ Vector2 maxIntersection;
+ int maxVertexIndex = -1;
+
+ bool hasDistance = false;
+
+ for (int i = 0; i < _polygons[polygonIndex].verticeCount; ++i) {
+ int nextIndex = (i + 1) % _polygons[polygonIndex].verticeCount;
+ Vector2 *vertices = _polygons[polygonIndex].vertices;
+ Vector2 intersection;
+ bool intersects = lineIntersection(from, to, vertices[i], vertices[nextIndex], &intersection);
+ if (intersects) {
+ float distance2 = distance(from, intersection);
+ if (!hasDistance || distance2 > maxDistance) {
+ maxDistance = distance2;
+ maxIntersection = intersection;
+ maxVertexIndex = i;
+ hasDistance = true;
+ }
+ }
+ }
+
+ *outDistance = maxDistance;
+ *outVertexIndex = maxVertexIndex;
+ *out = maxIntersection;
+
+ return maxVertexIndex != -1;
+}
+
+bool Obstacles::findPolygonVerticeByXZ(int *polygonIndex, int *verticeIndex, int *verticeCount, float x, float z) const {
+ *polygonIndex = -1;
+ *verticeIndex = -1;
+ *verticeCount = -1;
+
+ for (int i = 0; i != kPolygonCount; ++i) {
+ if (!_polygons[i].isPresent || _polygons[i].verticeCount == 0) {
+ continue;
+ }
+
+ for (int j = 0; j != kPolygonVertexCount; ++j) {
+ if (_polygons[i].vertices[j].x == x && _polygons[i].vertices[j].y == z) {
+ *polygonIndex = i;
+ *verticeIndex = j;
+ *verticeCount = _polygons[i].verticeCount;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool Obstacles::findPolygonVerticeByXZWithinTolerance(float x, float z, int *polygonIndex, int *verticeIndex) const {
+ *polygonIndex = -1;
+ *verticeIndex = -1;
+
+ for (int i = 0; i != kPolygonCount; ++i) {
+ if (!_polygons[i].isPresent || _polygons[i].verticeCount == 0) {
+ continue;
+ }
+
+ for (int j = 0; j != kPolygonVertexCount; ++j) {
+ if (WITHIN_TOLERANCE(_polygons[i].vertices[j].x, x)) {
+ if (WITHIN_TOLERANCE(_polygons[i].vertices[j].y, z)) {
+ *polygonIndex = i;
+ *verticeIndex = j;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void Obstacles::clearVertices() {
+ _verticeCount = 0;
+}
+
+void Obstacles::copyVerticesReverse() {
+
+}
+
+void Obstacles::copyVertices() {
+
+}
+
void Obstacles::backup() {
+ for (int i = 0; i != kPolygonCount; ++i) {
+ _polygonsBackup[i].isPresent = false;
+ }
+
+ int count = 0;
+ for (int i = 0; i != kPolygonCount; ++i) {
+ if (_polygons[i].isPresent) {
+ _polygonsBackup[count] = _polygons[i];
+ ++count;
+ }
+ }
+
+ for (int i = 0; i != kPolygonCount; ++i) {
+ _polygons[i] = _polygonsBackup[count];
+ }
+
+ _count = count;
+ _backup = true;
+}
+
+void Obstacles::restore() {
+ for (int i = 0; i != kPolygonCount; ++i) {
+ _polygons[i].isPresent = false;
+ }
+ for (int i = 0; i != kPolygonCount; ++i) {
+ _polygons[i] = _polygonsBackup[i];
+ }
}
-void Obstacles::restore() {}
+void Obstacles::save(SaveFileWriteStream &f) {
+ f.writeBool(_backup);
+ f.writeInt(_count);
+ for (int i = 0; i < _count; ++i) {
+ Polygon &p = _polygonsBackup[i];
+ f.writeBool(p.isPresent);
+ f.writeInt(p.verticeCount);
+ f.writeFloat(p.rect.x0);
+ f.writeFloat(p.rect.y0);
+ f.writeFloat(p.rect.x1);
+ f.writeFloat(p.rect.y1);
+ for (int j = 0; j < kPolygonVertexCount; ++j) {
+ f.writeVector2(p.vertices[j]);
+ }
+ for (int j = 0; j < kPolygonVertexCount; ++j) {
+ f.writeInt(p.vertexType[j]);
+ }
+ }
+ for (int i = 0; i < kVertexCount; ++i) {
+ f.writeVector2(_vertices[i]);
+ }
+ f.writeInt(_verticeCount);
+}
+void Obstacles::load(SaveFileReadStream &f) {
+ for (int i = 0; i < kPolygonCount; ++i) {
+ _polygons[i].isPresent = false;
+ _polygons[i].verticeCount = 0;
+ _polygonsBackup[i].isPresent = false;
+ _polygonsBackup[i].verticeCount = 0;
+ }
+
+ _backup = f.readBool();
+ _count = f.readInt();
+ for (int i = 0; i < _count; ++i) {
+ Polygon &p = _polygonsBackup[i];
+ p.isPresent = f.readBool();
+ p.verticeCount = f.readInt();
+ p.rect.x0 = f.readFloat();
+ p.rect.y0 = f.readFloat();
+ p.rect.x1 = f.readFloat();
+ p.rect.y1 = f.readFloat();
+ for (int j = 0; j < kPolygonVertexCount; ++j) {
+ p.vertices[j] = f.readVector2();
+ }
+ for (int j = 0; j < kPolygonVertexCount; ++j) {
+ p.vertexType[j] = (VertexType)f.readInt();
+ }
+ }
+
+ for (int i = 0; i < kPolygonCount; ++i) {
+ _polygons[i] = _polygonsBackup[i];
+ }
+
+ for (int i = 0; i < kVertexCount; ++i) {
+ _vertices[i] = f.readVector2();
+ }
+ _verticeCount = f.readInt();
+}
+
+void Obstacles::draw() {
+ for (int i = 0; i != kPolygonCount; ++i) {
+ if (!_polygons[i].isPresent) {
+ continue;
+ }
+
+ Vector3 p0 = _vm->_view->calculateScreenPosition(Vector3(
+ _polygons[i].vertices[_polygons[i].verticeCount - 1].x,
+ 0,
+ _polygons[i].vertices[_polygons[i].verticeCount - 1].y
+ ));
+
+ for (int j = 0; j != _polygons[i].verticeCount; ++j) {
+ Vector3 p1 = _vm->_view->calculateScreenPosition(Vector3(
+ _polygons[i].vertices[j].x,
+ 0.0f,
+ _polygons[i].vertices[j].y
+ ));
+
+ _vm->_surfaceFront.drawLine(p0.x, p0.y, p1.x, p1.y, 0x7FE0);
+
+ p0 = p1;
+ }
+ }
+}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/obstacles.h b/engines/bladerunner/obstacles.h
index c2c84c3bfa..25124904ef 100644
--- a/engines/bladerunner/obstacles.h
+++ b/engines/bladerunner/obstacles.h
@@ -23,45 +23,87 @@
#ifndef BLADERUNNER_OBSTACLES_H
#define BLADERUNNER_OBSTACLES_H
+#include "bladerunner/rect.h"
#include "bladerunner/vector.h"
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class Obstacles {
- static const int kPolygonCount = 50;
- static const int kVertexCount = 160;
+ static const int kVertexCount = 150;
+ static const int kPolygonCount = 50;
+ static const int kPolygonVertexCount = 160;
+
+ enum VertexType {
+ BOTTOM_LEFT,
+ TOP_LEFT,
+ TOP_RIGHT,
+ BOTTOM_RIGHT
+ };
+
+ struct LineSegment {
+ Vector2 start;
+ Vector2 end;
+ };
struct Polygon {
- bool isPresent;
- int verticeCount;
- float left;
- float bottom;
- float right;
- float top;
- Vector2 vertices[kVertexCount];
- int vertexType[kVertexCount];
+ bool isPresent;
+ int verticeCount;
+ Rect rect;
+ Vector2 vertices[kPolygonVertexCount];
+ VertexType vertexType[kPolygonVertexCount];
+
+ Polygon() : isPresent(false), verticeCount(0)
+ {}
};
BladeRunnerEngine *_vm;
- Polygon _polygons[kPolygonCount];
- Polygon _polygonsBackup[kPolygonCount];
+ Polygon *_polygons;
+ Polygon *_polygonsBackup;
Vector2 *_vertices;
int _verticeCount;
int _count;
bool _backup;
+ static bool lineLineIntersection(LineSegment a, LineSegment b, Vector2 *intersectionPoint);
+ static bool linePolygonIntersection(LineSegment lineA, VertexType lineAType, Polygon *polyB, Vector2 *intersectionPoint, int *intersectionIndex);
+
+ bool mergePolygons(Polygon &polyA, Polygon &PolyB);
+
public:
Obstacles(BladeRunnerEngine *vm);
~Obstacles();
void clear();
- void add(float x0, float z0, float x1, float z1);
+ void add(Rect rect);
+ void add(float x0, float z0, float x1, float z1) { add(Rect(x0, z0, x1, z1)); }
+ int findEmptyPolygon() const;
+ static float getLength(float x0, float z0, float x1, float z1);
bool find(const Vector3 &from, const Vector3 &to, Vector3 *next) const;
+
+ bool findIntersectionNearest(int polygonIndex, Vector2 from, Vector2 to,
+ int *outVertexIndex, float *outDistance, Vector2 *out) const;
+ bool findIntersectionFarthest(int polygonIndex, Vector2 from, Vector2 to,
+ int *outVertexIndex, float *outDistance, Vector2 *out) const;
+
+ bool findPolygonVerticeByXZ(int *polygonIndex, int *verticeIndex, int *verticeCount, float x, float z) const;
+ bool findPolygonVerticeByXZWithinTolerance(float x, float z, int *polygonIndex, int *verticeIndex) const;
+
+ void clearVertices();
+ void copyVerticesReverse();
+ void copyVertices();
+
void backup();
void restore();
+ void reset();
+
+ void draw();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/overlays.cpp b/engines/bladerunner/overlays.cpp
index b5cb130678..65ba83f15d 100644
--- a/engines/bladerunner/overlays.cpp
+++ b/engines/bladerunner/overlays.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/bladerunner.h"
#include "bladerunner/archive.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/vqa_player.h"
#include "graphics/surface.h"
@@ -56,19 +57,22 @@ Overlays::~Overlays() {
}
int Overlays::play(const Common::String &name, int loopId, bool loopForever, bool startNow, int a6) {
- int id = mix_id(name);
- int index = findById(id);
+ assert(name.size() <= 12);
+
+ int32 hash = MIXArchive::getHash(name);
+ int index = findByHash(hash);
if (index < 0) {
index = findEmpty();
if (index < 0) {
return index;
}
- _videos[index].id = id;
+ _videos[index].loaded = true;
+ _videos[index].name = name;
+ _videos[index].hash = hash;
_videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront);
// repeat forever
_videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr);
- _videos[index].loaded = true;
}
Common::String resourceName = Common::String::format("%s.VQA", name.c_str());
@@ -83,8 +87,7 @@ int Overlays::play(const Common::String &name, int loopId, bool loopForever, boo
}
void Overlays::remove(const Common::String &name) {
- int id = mix_id(name);
- int index = findById(id);
+ int index = findByHash(MIXArchive::getHash(name));
if (index >= 0) {
resetSingle(index);
}
@@ -109,9 +112,9 @@ void Overlays::tick() {
}
}
-int Overlays::findById(int32 id) const {
+int Overlays::findByHash(int32 hash) const {
for (int i = 0; i < kOverlayVideos; ++i) {
- if (_videos[i].loaded && _videos[i].id == id) {
+ if (_videos[i].loaded && _videos[i].hash == hash) {
return i;
}
}
@@ -134,12 +137,44 @@ void Overlays::resetSingle(int i) {
_videos[i].vqaPlayer = nullptr;
}
_videos[i].loaded = false;
- _videos[i].id = 0;
+ _videos[i].hash = 0;
_videos[i].field2 = -1;
+ _videos[i].name.clear();
}
void Overlays::reset() {
_videos.clear();
}
+void Overlays::save(SaveFileWriteStream &f) {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ // 37 bytes per overlay
+ Video &ov = _videos[i];
+
+ f.writeBool(ov.loaded);
+ f.writeInt(0); // vqaPlayer pointer
+ f.writeStringSz(ov.name, 13);
+ f.writeSint32LE(ov.hash);
+ f.writeInt(ov.field0);
+ f.writeInt(ov.field1);
+ f.writeInt(ov.field2);
+ }
+}
+
+void Overlays::load(SaveFileReadStream &f) {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ // 37 bytes per overlay
+ Video &ov = _videos[i];
+
+ ov.loaded = f.readBool();
+ f.skip(4); // vqaPlayer pointer
+ ov.vqaPlayer = nullptr;
+ ov.name = f.readStringSz(13);
+ ov.hash = f.readSint32LE();
+ ov.field0 = f.readInt();
+ ov.field1 = f.readInt();
+ ov.field2 = f.readInt();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/overlays.h b/engines/bladerunner/overlays.h
index 38edf7459b..405acbc264 100644
--- a/engines/bladerunner/overlays.h
+++ b/engines/bladerunner/overlays.h
@@ -33,20 +33,21 @@ struct Surface;
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class VQAPlayer;
-
class Overlays {
static const int kOverlayVideos = 5;
struct Video {
- bool loaded;
- VQAPlayer *vqaPlayer;
- // char name[13];
- int32 id;
- int field0;
- int field1;
- int field2;
+ bool loaded;
+ VQAPlayer *vqaPlayer;
+ Common::String name;
+ int32 hash;
+ int field0;
+ int field1;
+ int field2;
};
BladeRunnerEngine *_vm;
@@ -62,8 +63,11 @@ public:
void removeAll();
void tick();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
- int findById(int32 id) const;
+ int findByHash(int32 hash) const;
int findEmpty() const;
void resetSingle(int i);
diff --git a/engines/bladerunner/rect.h b/engines/bladerunner/rect.h
new file mode 100644
index 0000000000..da01af389d
--- /dev/null
+++ b/engines/bladerunner/rect.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_RECT_H
+#define BLADERUNNER_RECT_H
+
+#include "common/debug.h"
+#include "common/types.h"
+#include "common/util.h"
+
+namespace BladeRunner {
+
+struct Rect {
+ float x0;
+ float y0;
+ float x1;
+ float y1;
+
+ Rect()
+ : x0(0.0f), y0(0.0f), x1(0.0f), y1(0.0f)
+ {}
+ Rect(float x0, float y0, float x1, float y1)
+ : x0(x0), y0(y0), x1(x1), y1(y1)
+ {}
+
+ void expand(float d) {
+ x0 -= d;
+ y0 -= d;
+ x1 += d;
+ y1 += d;
+ }
+
+ void trunc_2_decimals() {
+ x0 = truncf(x0 * 100.0f) / 100.0f;
+ y0 = truncf(y0 * 100.0f) / 100.0f;
+ x1 = truncf(x1 * 100.0f) / 100.0f;
+ y1 = truncf(y1 * 100.0f) / 100.0f;
+ }
+};
+
+inline bool overlaps(const Rect &a, const Rect &b) {
+ return !(a.y1 < b.y0 || a.y0 > b.y1 || a.x0 > b.x1 || a.x1 < b.x0);
+}
+
+inline Rect merge(const Rect &a, const Rect &b) {
+ Rect c;
+ c.x0 = MIN(a.x0, b.x0);
+ c.y0 = MIN(a.y0, b.y0);
+ c.x1 = MAX(a.x1, b.x1);
+ c.y1 = MAX(a.y1, b.y1);
+ return c;
+}
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/regions.cpp b/engines/bladerunner/regions.cpp
index 80dabf2989..f74186240b 100644
--- a/engines/bladerunner/regions.cpp
+++ b/engines/bladerunner/regions.cpp
@@ -22,6 +22,8 @@
#include "bladerunner/regions.h"
+#include "bladerunner/savefile.h"
+
namespace BladeRunner {
Regions::Regions() {
@@ -99,4 +101,22 @@ void Regions::enable() {
_enabled = true;
}
+void Regions::save(SaveFileWriteStream &f) {
+ f.writeBool(_enabled);
+ for (int i = 0; i != 10; ++i) {
+ f.writeRect(_regions[i].rectangle);
+ f.writeInt(_regions[i].type);
+ f.writeInt(_regions[i].present);
+ }
+}
+
+void Regions::load(SaveFileReadStream &f) {
+ _enabled = f.readBool();
+ for (int i = 0; i != 10; ++i) {
+ _regions[i].rectangle = f.readRect();
+ _regions[i].type = f.readInt();
+ _regions[i].present = f.readInt();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/regions.h b/engines/bladerunner/regions.h
index 9868f46ac0..aae3627650 100644
--- a/engines/bladerunner/regions.h
+++ b/engines/bladerunner/regions.h
@@ -30,6 +30,9 @@
namespace BladeRunner {
+class SaveFileReadStream;
+class SaveFileWriteStream;
+
class Regions {
friend class Debugger;
@@ -54,6 +57,9 @@ public:
void setEnabled(bool enabled);
void enable();
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/savefile.cpp b/engines/bladerunner/savefile.cpp
new file mode 100644
index 0000000000..3528a6bb82
--- /dev/null
+++ b/engines/bladerunner/savefile.cpp
@@ -0,0 +1,166 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/savefile.h"
+
+#include "bladerunner/boundingbox.h"
+#include "bladerunner/vector.h"
+
+#include "common/rect.h"
+#include "common/savefile.h"
+
+namespace BladeRunner {
+
+SaveFileWriteStream::SaveFileWriteStream()
+ : MemoryWriteStreamDynamic(DisposeAfterUse::YES) {
+}
+
+void SaveFileWriteStream::debug(char *p) {
+ write(p, strlen(p) + 1);
+}
+
+void SaveFileWriteStream::padBytes(int count) {
+ for (int i = 0; i < count; ++i) {
+ writeByte(0);
+ }
+}
+
+void SaveFileWriteStream::writeInt(int v) {
+ writeUint32LE(v);
+}
+
+void SaveFileWriteStream::writeFloat(int v) {
+ writeFloatLE(v);
+}
+
+void SaveFileWriteStream::writeBool(bool v) {
+ writeUint32LE(v);
+}
+
+void SaveFileWriteStream::writeStringSz(const Common::String &s, int sz) {
+ assert(s.size() < (uint)sz);
+ write(s.begin(), s.size());
+ padBytes((uint)sz - s.size());
+}
+
+void SaveFileWriteStream::writeVector2(const Vector2 &v) {
+ writeFloatLE(v.x);
+ writeFloatLE(v.y);
+}
+
+void SaveFileWriteStream::writeVector3(const Vector3 &v) {
+ writeFloatLE(v.x);
+ writeFloatLE(v.y);
+ writeFloatLE(v.z);
+}
+
+void SaveFileWriteStream::writeRect(const Common::Rect &v) {
+ writeUint32LE(v.left);
+ writeUint32LE(v.top);
+ writeUint32LE(v.right);
+ writeUint32LE(v.bottom);
+}
+
+void SaveFileWriteStream::writeBoundingBox(const BoundingBox &v) {
+ float x0, y0, z0, x1, y1, z1;
+
+ v.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1);
+ writeFloatLE(x0);
+ writeFloatLE(y0);
+ writeFloatLE(z0);
+ writeFloatLE(x1);
+ writeFloatLE(y1);
+ writeFloatLE(z1);
+
+ // Bounding boxes have a lot of extra data that's never actually used
+ for (int i = 0; i != 96; ++i) {
+ writeFloatLE(0.0f);
+ }
+}
+
+SaveFileReadStream::SaveFileReadStream(const byte *dataPtr, uint32 dataSize)
+ : MemoryReadStream(dataPtr, dataSize, DisposeAfterUse::YES) {
+}
+
+int SaveFileReadStream::readInt() {
+ return readUint32LE();
+}
+
+float SaveFileReadStream::readFloat() {
+ return readFloatLE();
+}
+
+bool SaveFileReadStream::readBool() {
+ return readUint32LE();
+}
+
+Common::String SaveFileReadStream::readStringSz(int sz) {
+ char *buf = (char *)malloc(sz);
+ read(buf, sz);
+ Common::String result = buf;
+ free(buf);
+ return result;
+}
+
+Vector2 SaveFileReadStream::readVector2() {
+ Vector2 result;
+ result.x = readFloatLE();
+ result.y = readFloatLE();
+ return result;
+}
+
+Vector3 SaveFileReadStream::readVector3() {
+ Vector3 result;
+ result.x = readFloatLE();
+ result.y = readFloatLE();
+ result.z = readFloatLE();
+ return result;
+}
+
+Common::Rect SaveFileReadStream::readRect() {
+ Common::Rect result;
+ result.left = readUint32LE();
+ result.top = readUint32LE();
+ result.right = readUint32LE();
+ result.bottom = readUint32LE();
+ return result;
+}
+
+BoundingBox SaveFileReadStream::readBoundingBox() {
+ float x0, y0, z0, x1, y1, z1;
+
+ x0 = readFloatLE();
+ y0 = readFloatLE();
+ z0 = readFloatLE();
+ x1 = readFloatLE();
+ y1 = readFloatLE();
+ z1 = readFloatLE();
+
+ // Bounding boxes have a lot of extra data that's never actually used
+ skip(384);
+
+ return BoundingBox(x0, y0, z0, x1, y1, z1);
+}
+
+
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/savefile.h b/engines/bladerunner/savefile.h
new file mode 100644
index 0000000000..4dfdb20bd4
--- /dev/null
+++ b/engines/bladerunner/savefile.h
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_SAVEFILE_H
+#define BLADERUNNER_SAVEFILE_H
+
+#include "common/memstream.h"
+#include "common/types.h"
+
+namespace Common {
+class OutSaveFile;
+class String;
+struct Rect;
+}
+
+namespace BladeRunner {
+
+class Vector2;
+class Vector3;
+class BoundingBox;
+
+class SaveFileWriteStream : public Common::MemoryWriteStreamDynamic {
+public:
+ SaveFileWriteStream();
+
+ void debug(char *p);
+
+ void padBytes(int count);
+
+ void writeInt(int v);
+ void writeFloat(int v);
+ void writeBool(bool v);
+ void writeStringSz(const Common::String &s, int sz);
+ void writeVector2(const Vector2 &v);
+ void writeVector3(const Vector3 &v);
+ void writeRect(const Common::Rect &v);
+ void writeBoundingBox(const BoundingBox &v);
+};
+
+class SaveFileReadStream : public Common::MemoryReadStream {
+public:
+ SaveFileReadStream(const byte *dataPtr, uint32 dataSize);
+
+ int readInt();
+ float readFloat();
+ bool readBool();
+ Common::String readStringSz(int sz);
+ Vector2 readVector2();
+ Vector3 readVector3();
+ Common::Rect readRect();
+ BoundingBox readBoundingBox();
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp
index 123134ed96..fe8dbc7b61 100644
--- a/engines/bladerunner/scene.cpp
+++ b/engines/bladerunner/scene.cpp
@@ -30,11 +30,13 @@
#include "bladerunner/items.h"
#include "bladerunner/overlays.h"
#include "bladerunner/regions.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/screen_effects.h"
#include "bladerunner/set.h"
#include "bladerunner/settings.h"
#include "bladerunner/slice_renderer.h"
+#include "bladerunner/script/police_maze.h"
#include "bladerunner/script/scene_script.h"
#include "bladerunner/ui/spinner.h"
#include "bladerunner/vqa_player.h"
@@ -187,7 +189,8 @@ bool Scene::close(bool isLoadingGame) {
return true;
}
- //_vm->_policeMaze->clear(!isLoadingGame);
+ _vm->_policeMaze->clear(!isLoadingGame);
+
if (isLoadingGame) {
_vm->_sceneScript->playerWalkedOut();
}
@@ -328,7 +331,7 @@ void Scene::loopStartSpecial(int specialLoopMode, int loopId, bool immediately)
}
}
-int Scene::findObject(const char *objectName) {
+int Scene::findObject(const Common::String &objectName) {
return _set->findObject(objectName);
}
@@ -374,7 +377,7 @@ void Scene::objectSetIsTarget(int objectId, bool isTarget, bool sceneLoaded) {
}
}
-const char *Scene::objectGetName(int objectId) {
+const Common::String &Scene::objectGetName(int objectId) {
return _set->objectGetName(objectId);
}
@@ -410,4 +413,37 @@ void Scene::loopEnded(int frame, int loopId) {
void Scene::loopEndedStatic(void *data, int frame, int loopId) {
((Scene *)data)->loopEnded(frame, loopId);
}
+
+void Scene::save(SaveFileWriteStream &f) {
+ f.writeInt(_setId);
+ f.writeInt(_sceneId);
+ f.writeInt(_defaultLoop);
+ f.writeBool(_defaultLoopSet);
+ f.writeBool(_defaultLoopPreloadedSet);
+ f.writeInt(_specialLoopMode);
+ f.writeInt(_specialLoop);
+ f.writeInt(_nextSetId);
+ f.writeInt(_nextSceneId);
+ f.writeInt(_frame);
+ f.writeVector3(_actorStartPosition);
+ f.writeInt(_actorStartFacing);
+ f.writeBool(_playerWalkedIn);
+}
+
+void Scene::load(SaveFileReadStream &f) {
+ _setId = f.readInt();
+ _sceneId = f.readInt();
+ _defaultLoop = f.readInt();
+ _defaultLoopSet = f.readBool();
+ _defaultLoopPreloadedSet = f.readBool();
+ _specialLoopMode = f.readInt();
+ _specialLoop = f.readInt();
+ _nextSetId = f.readInt();
+ _nextSceneId = f.readInt();
+ _frame = f.readInt();
+ _actorStartPosition = f.readVector3();
+ _actorStartFacing = f.readInt();
+ _playerWalkedIn = f.readBool();
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h
index 91cd2ed604..0403cd331e 100644
--- a/engines/bladerunner/scene.h
+++ b/engines/bladerunner/scene.h
@@ -25,11 +25,15 @@
#include "bladerunner/vector.h"
+#include "common/str.h"
+
namespace BladeRunner {
class BladeRunnerEngine;
class BoundingBox;
class Regions;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class Set;
class VQAPlayer;
@@ -80,14 +84,17 @@ public:
bool didPlayerWalkIn() { bool r = _playerWalkedIn; _playerWalkedIn = false; return r; }
- int findObject(const char *objectName);
+ int findObject(const Common::String &objectName);
bool objectSetHotMouse(int objectId);
bool objectGetBoundingBox(int objectId, BoundingBox *boundingBox);
void objectSetIsClickable(int objectId, bool isClickable, bool sceneLoaded);
void objectSetIsObstacle(int objectId, bool isObstacle, bool sceneLoaded, bool updateWalkpath);
void objectSetIsObstacleAll(bool isObstacle, bool sceneLoaded);
void objectSetIsTarget(int objectId, bool isTarget, bool sceneLoaded);
- const char *objectGetName(int objectId);
+ const Common::String &objectGetName(int objectId);
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
private:
void loopEnded(int frame, int loopId);
diff --git a/engines/bladerunner/scene_objects.cpp b/engines/bladerunner/scene_objects.cpp
index 87320a3fa4..30802a8d64 100644
--- a/engines/bladerunner/scene_objects.cpp
+++ b/engines/bladerunner/scene_objects.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/bladerunner.h"
#include "bladerunner/obstacles.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/view.h"
namespace BladeRunner {
@@ -35,9 +36,7 @@ SceneObjects::SceneObjects(BladeRunnerEngine *vm, View *view) {
_count = 0;
- for (int i = 0; i < kSceneObjectCount; ++i) {
- _sceneObjectsSortedByDistance[i] = -1;
- }
+ clear();
}
SceneObjects::~SceneObjects() {
@@ -64,16 +63,16 @@ void SceneObjects::clear() {
_count = 0;
}
-bool SceneObjects::addActor(int sceneObjectId, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isClickable, bool isMoving, bool isTarget, bool isRetired) {
+bool SceneObjects::addActor(int sceneObjectId, const BoundingBox &boundingBox, const Common::Rect &screenRectangle, bool isClickable, bool isMoving, bool isTarget, bool isRetired) {
return addSceneObject(sceneObjectId, kSceneObjectTypeActor, boundingBox, screenRectangle, isClickable, false, 0, isTarget, isMoving, isRetired);
}
-bool SceneObjects::addObject(int sceneObjectId, BoundingBox *boundingBox, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget) {
+bool SceneObjects::addObject(int sceneObjectId, const BoundingBox &boundingBox, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget) {
Common::Rect rect(-1, -1, -1, -1);
- return addSceneObject(sceneObjectId, kSceneObjectTypeObject, boundingBox, &rect, isClickable, isObstacle, unknown1, isTarget, false, false);
+ return addSceneObject(sceneObjectId, kSceneObjectTypeObject, boundingBox, rect, isClickable, isObstacle, unknown1, isTarget, false, false);
}
-bool SceneObjects::addItem(int sceneObjectId, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isTarget, bool isObstacle) {
+bool SceneObjects::addItem(int sceneObjectId, const BoundingBox &boundingBox, const Common::Rect &screenRectangle, bool isTarget, bool isObstacle) {
return addSceneObject(sceneObjectId, kSceneObjectTypeItem, boundingBox, screenRectangle, isObstacle, 0, 0, isTarget, 0, 0);
}
@@ -110,7 +109,7 @@ int SceneObjects::findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget,
if ((findClickables && sceneObject->isClickable) ||
(findObstacles && sceneObject->isObstacle) ||
(findTargets && sceneObject->isTarget)) {
- BoundingBox boundingBox = *sceneObject->boundingBox;
+ BoundingBox boundingBox = sceneObject->boundingBox;
if (sceneObject->type == kSceneObjectTypeActor) {
boundingBox.expand(-4.0, 0.0, -4.0, 4.0, 0.0, 4.0);
@@ -155,7 +154,7 @@ bool SceneObjects::existsOnXZ(int exceptSceneObjectId, float x, float z, bool mo
if (isObstacle && sceneObject->id != exceptSceneObjectId) {
float x1, y1, z1, x2, y2, z2;
- sceneObject->boundingBox->getXYZ(&x1, &y1, &z1, &x2, &y2, &z2);
+ sceneObject->boundingBox.getXYZ(&x1, &y1, &z1, &x2, &y2, &z2);
if (z1 <= zMax && z2 >= zMin && x1 <= xMax && x2 >= xMin) {
return true;
}
@@ -176,7 +175,7 @@ int SceneObjects::findById(int sceneObjectId) const {
return -1;
}
-bool SceneObjects::addSceneObject(int sceneObjectId, SceneObjectType sceneObjectType, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget, bool isMoving, bool isRetired) {
+bool SceneObjects::addSceneObject(int sceneObjectId, SceneObjectType sceneObjectType, const BoundingBox &boundingBox, const Common::Rect &screenRectangle, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget, bool isMoving, bool isRetired) {
int index = findEmpty();
if (index == -1) {
return false;
@@ -194,7 +193,7 @@ bool SceneObjects::addSceneObject(int sceneObjectId, SceneObjectType sceneObject
_sceneObjects[index].isMoving = isMoving;
_sceneObjects[index].isRetired = isRetired;
- float centerZ = (_sceneObjects[index].boundingBox->getZ0() + _sceneObjects[index].boundingBox->getZ1()) / 2.0f;
+ float centerZ = (_sceneObjects[index].boundingBox.getZ0() + _sceneObjects[index].boundingBox.getZ1()) / 2.0f;
float distanceToCamera = fabs(-centerZ - _view->_cameraPosition.y); // y<->z is intentional, not a bug
_sceneObjects[index].distanceToCamera = distanceToCamera;
@@ -246,7 +245,7 @@ bool SceneObjects::isBetween(float sourceX, float sourceZ, float targetX, float
}
float objectX1, objectY1, objectZ1, objectX2, objectY2, objectZ2;
- _sceneObjects[i].boundingBox->getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2);
+ _sceneObjects[i].boundingBox.getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2);
Vector2 intersection;
return lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection)
@@ -255,7 +254,7 @@ bool SceneObjects::isBetween(float sourceX, float sourceZ, float targetX, float
|| lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection);
}
-bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX, float targetZ, float altitude, int exceptSceneObjectId) const {
+bool SceneObjects::isObstacleBetween(const Vector3 &source, const Vector3 &target, int exceptSceneObjectId) const {
for (int i = 0; i < _count; ++i) {
const SceneObject *sceneObject = &_sceneObjects[_sceneObjectsSortedByDistance[i]];
@@ -264,9 +263,9 @@ bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX
}
float objectX1, objectY1, objectZ1, objectX2, objectY2, objectZ2;
- _sceneObjects[i].boundingBox->getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2);
+ sceneObject->boundingBox.getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2);
- if (84.0f <= objectY1 - altitude || 72.0f >= objectY2 - altitude) {
+ if (84.0f <= objectY1 - source.y || 72.0f >= objectY2 - source.y) {
continue;
}
@@ -279,10 +278,10 @@ bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX
objectZ2 = objectZ2 - zAdjustement;
Vector2 intersection;
- if (lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection)
- || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ1), Vector2(objectX2, objectZ2), &intersection)
- || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ2), Vector2(objectX1, objectZ2), &intersection)
- || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection)) {
+ if (lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection)
+ || lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX2, objectZ1), Vector2(objectX2, objectZ2), &intersection)
+ || lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX2, objectZ2), Vector2(objectX1, objectZ2), &intersection)
+ || lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection)) {
return true;
}
}
@@ -320,11 +319,53 @@ void SceneObjects::updateObstacles() {
const SceneObject *sceneObject = &_sceneObjects[index];
if (sceneObject->isObstacle) {
float x0, y0, z0, x1, y1, z1;
- sceneObject->boundingBox->getXYZ(&x0, &y0, &z0, &x1, &y1, &z1);
+ sceneObject->boundingBox.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1);
_vm->_obstacles->add(x0, z0, x1, z1);
}
}
_vm->_obstacles->backup();
}
+void SceneObjects::save(SaveFileWriteStream &f) {
+ f.writeInt(_count);
+ for (int i = 0; i < kSceneObjectCount; ++i) {
+ f.writeInt(_sceneObjects[i].id);
+ f.writeInt(_sceneObjects[i].type);
+ f.writeBoundingBox(_sceneObjects[i].boundingBox);
+ f.writeRect(_sceneObjects[i].screenRectangle);
+ f.writeFloat(_sceneObjects[i].distanceToCamera);
+ f.writeBool(_sceneObjects[i].isPresent);
+ f.writeBool(_sceneObjects[i].isClickable);
+ f.writeBool(_sceneObjects[i].isObstacle);
+ f.writeInt(_sceneObjects[i].unknown1);
+ f.writeBool(_sceneObjects[i].isTarget);
+ f.writeBool(_sceneObjects[i].isMoving);
+ f.writeBool(_sceneObjects[i].isRetired);
+ }
+ for (int i = 0; i < kSceneObjectCount; ++i) {
+ f.writeInt(_sceneObjectsSortedByDistance[i]);
+ }
+}
+
+void SceneObjects::load(SaveFileReadStream &f) {
+ _count = f.readInt();
+ for (int i = 0; i < kSceneObjectCount; ++i) {
+ _sceneObjects[i].id = f.readInt();
+ _sceneObjects[i].type = (SceneObjectType)f.readInt();
+ _sceneObjects[i].boundingBox = f.readBoundingBox();
+ _sceneObjects[i].screenRectangle = f.readRect();
+ _sceneObjects[i].distanceToCamera = f.readFloat();
+ _sceneObjects[i].isPresent = f.readBool();
+ _sceneObjects[i].isClickable = f.readBool();
+ _sceneObjects[i].isObstacle = f.readBool();
+ _sceneObjects[i].unknown1 = f.readInt();
+ _sceneObjects[i].isTarget = f.readBool();
+ _sceneObjects[i].isMoving = f.readBool();
+ _sceneObjects[i].isRetired = f.readBool();
+ }
+ for (int i = 0; i < kSceneObjectCount; ++i) {
+ _sceneObjectsSortedByDistance[i] = f.readInt();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/scene_objects.h b/engines/bladerunner/scene_objects.h
index dbd61b6dc5..a6d552017c 100644
--- a/engines/bladerunner/scene_objects.h
+++ b/engines/bladerunner/scene_objects.h
@@ -30,6 +30,8 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class View;
enum SceneObjectType {
@@ -45,18 +47,18 @@ class SceneObjects {
static const int kSceneObjectCount = 115;
struct SceneObject {
- int id;
- SceneObjectType type;
- const BoundingBox *boundingBox;
- const Common::Rect *screenRectangle;
- float distanceToCamera;
- bool isPresent;
- bool isClickable;
- bool isObstacle;
- int unknown1;
- bool isTarget;
- bool isMoving;
- bool isRetired;
+ int id;
+ SceneObjectType type;
+ BoundingBox boundingBox;
+ Common::Rect screenRectangle;
+ float distanceToCamera;
+ bool isPresent;
+ bool isClickable;
+ bool isObstacle;
+ int unknown1;
+ bool isTarget;
+ bool isMoving;
+ bool isRetired;
};
BladeRunnerEngine *_vm;
@@ -70,9 +72,9 @@ public:
SceneObjects(BladeRunnerEngine *vm, View *view);
~SceneObjects();
- bool addActor(int sceneObjectId, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isClickable, bool isMoving, bool isTarget, bool isRetired);
- bool addObject(int sceneObjectId, BoundingBox *boundingBox, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget);
- bool addItem(int sceneObjectId, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isTarget, bool isObstacle);
+ bool addActor(int sceneObjectId, const BoundingBox &boundingBox, const Common::Rect &screenRectangle, bool isClickable, bool isMoving, bool isTarget, bool isRetired);
+ bool addObject(int sceneObjectId, const BoundingBox &boundingBox, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget);
+ bool addItem(int sceneObjectId, const BoundingBox &boundingBox, const Common::Rect &screenRectangle, bool isTarget, bool isObstacle);
bool remove(int sceneObjectId);
void clear();
int findByXYZ(bool *isClickable, bool *isObstacle, bool *isTarget, Vector3 &position, bool findClickables, bool findObstacles, bool findTargets) const;
@@ -80,16 +82,18 @@ public:
void setMoving(int sceneObjectId, bool isMoving);
void setRetired(int sceneObjectId, bool isRetired);
bool isBetween(float sourceX, float sourceZ, float targetX, float targetZ, int sceneObjectId) const;
- bool isObstacleBetween(float sourceX, float sourceZ, float targetX, float targetZ, float altitude, int exceptSceneObjectId) const;
+ bool isObstacleBetween(const Vector3 &source, const Vector3 &target, int exceptSceneObjectId) const;
void setIsClickable(int sceneObjectId, bool isClickable);
void setIsObstacle(int sceneObjectId, bool isObstacle);
void setIsTarget(int sceneObjectId, bool isTarget);
void updateObstacles();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
private:
int findById(int sceneObjectId) const;
- bool addSceneObject(int sceneObjectId, SceneObjectType sceneObjectType, BoundingBox *boundingBox, Common::Rect *screenRectangle, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget, bool isMoving, bool isRetired);
+ bool addSceneObject(int sceneObjectId, SceneObjectType sceneObjectType, const BoundingBox &boundingBox, const Common::Rect &screenRectangle, bool isClickable, bool isObstacle, uint8 unknown1, bool isTarget, bool isMoving, bool isRetired);
int findEmpty() const;
};
diff --git a/engines/bladerunner/screen_effects.h b/engines/bladerunner/screen_effects.h
index ad0fb5090f..d16f1cf284 100644
--- a/engines/bladerunner/screen_effects.h
+++ b/engines/bladerunner/screen_effects.h
@@ -39,12 +39,12 @@ class ScreenEffects {
public:
struct Entry {
Color256 palette[16];
- uint16 x;
- uint16 y;
- uint16 width;
- uint16 height;
- uint16 z;
- uint8 *data;
+ uint16 x;
+ uint16 y;
+ uint16 width;
+ uint16 height;
+ uint16 z;
+ uint8 *data;
};
BladeRunnerEngine *_vm;
@@ -58,7 +58,7 @@ public:
~ScreenEffects();
void readVqa(Common::SeekableReadStream *stream);
- void getColor(Color256 *outColor, uint16 x, uint16 y, uint16 z) const ;
+ void getColor(Color256 *outColor, uint16 x, uint16 y, uint16 z) const;
//TODO
//bool isAffectingArea(int x, int y, int width, int height, int unk);
diff --git a/engines/bladerunner/script/ai/bullet_bob.cpp b/engines/bladerunner/script/ai/bullet_bob.cpp
new file mode 100644
index 0000000000..87394fa44e
--- /dev/null
+++ b/engines/bladerunner/script/ai/bullet_bob.cpp
@@ -0,0 +1,555 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptBulletBob::AIScriptBulletBob(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 0;
+ _var2 = 6;
+ _var3 = 1;
+ _var4 = 0;
+}
+
+void AIScriptBulletBob::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 0;
+ _var2 = 6;
+ _var3 = 1;
+ _var4 = 0;
+
+ Actor_Set_Goal_Number(kActorBulletBob, 0);
+ Actor_Set_Targetable(kActorBulletBob, 1);
+}
+
+bool AIScriptBulletBob::Update() {
+ if (Game_Flag_Query(289) && Actor_Query_Goal_Number(kActorBulletBob) != 4) {
+ Actor_Set_Goal_Number(kActorBulletBob, 4);
+ }
+ if (Player_Query_Combat_Mode() != 1
+ || Player_Query_Current_Scene() != kSceneRC04
+ || Game_Flag_Query(296)
+ || Global_Variable_Query(kVariableChapter) >= 4) {
+ if (Actor_Query_Goal_Number(kActorBulletBob) == 1 && !Player_Query_Combat_Mode()) {
+ AI_Countdown_Timer_Reset(kActorBulletBob, 2);
+ Game_Flag_Reset(296);
+ Game_Flag_Set(303);
+ Actor_Set_Goal_Number(kActorBulletBob, 0);
+ }
+ } else {
+ AI_Countdown_Timer_Reset(kActorBulletBob, 2);
+ AI_Countdown_Timer_Start(kActorBulletBob, 2, 10);
+ Actor_Set_Goal_Number(kActorBulletBob, 1);
+ Actor_Modify_Friendliness_To_Other(kActorBulletBob, kActorMcCoy, -15);
+ Game_Flag_Set(296);
+ }
+ if (Actor_Query_Goal_Number(kActorBulletBob) != 2 || Game_Flag_Query(295) || _animationState) {
+ if (Game_Flag_Query(303) == 1 && Player_Query_Combat_Mode() == 1 && Actor_Query_Goal_Number(kActorBulletBob) != 4) {
+ Actor_Set_Goal_Number(kActorBulletBob, 2);
+ } else {
+ return false;
+ }
+ } else {
+ Actor_Face_Heading(kActorBulletBob, 208, 0);
+ _animationFrame = 0;
+ _animationState = 2;
+ Actor_Set_Goal_Number(kActorBulletBob, 3);
+ Game_Flag_Set(295);
+ }
+
+ return true;
+}
+
+void AIScriptBulletBob::TimerExpired(int timer) {
+ if (timer != 2 || Actor_Query_Goal_Number(kActorBulletBob) != 1)
+ return; //false;
+
+ Actor_Set_Goal_Number(kActorBulletBob, 2);
+ AI_Countdown_Timer_Reset(kActorBulletBob, 2);
+
+ return; //true;
+}
+
+void AIScriptBulletBob::CompletedMovementTrack() {
+ //return false;
+}
+
+void AIScriptBulletBob::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptBulletBob::ClickedByPlayer() {
+ //return false;
+}
+
+void AIScriptBulletBob::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptBulletBob::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptBulletBob::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptBulletBob::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptBulletBob::ShotAtAndMissed() {
+ // return false;
+}
+
+bool AIScriptBulletBob::ShotAtAndHit() {
+ Global_Variable_Increment(24, 1);
+ if (Global_Variable_Query(24) > 0) {
+ Actor_Set_Targetable(kActorBulletBob, 0);
+ Actor_Set_Goal_Number(kActorBulletBob, 99);
+ _animationFrame = 0;
+ _animationState = 3;
+ Ambient_Sounds_Play_Speech_Sound(2, 9000, 100, 0, 0, 0);
+ Actor_Face_Heading(kActorBulletBob, 281, 0);
+ }
+
+ return false;
+}
+
+void AIScriptBulletBob::Retired(int byActorId) {
+ // return false;
+}
+
+int AIScriptBulletBob::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptBulletBob::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ if (newGoalNumber || Game_Flag_Query(303) != 1 || Player_Query_Current_Scene() != kSceneRC04) {
+ if (newGoalNumber == 1 && !Game_Flag_Query(303) && Player_Query_Current_Scene() == kSceneRC04) {
+ Actor_Says(kActorBulletBob, 120, 37);
+ Actor_Says(kActorMcCoy, 4915, 13);
+ return true;
+ }
+ if (newGoalNumber == 6) {
+ Scene_Exits_Disable();
+ Actor_Force_Stop_Walking(kActorMcCoy);
+ Ambient_Sounds_Play_Speech_Sound(kActorMcCoy, 9900, 100, 0, 0, 0);
+ Actor_Change_Animation_Mode(kActorMcCoy, 48);
+ Actor_Retired_Here(kActorMcCoy, 6, 6, 1, -1);
+ Scene_Exits_Enable();
+ }
+ if (newGoalNumber != 4) {
+ return false;
+ }
+ if (Actor_Clue_Query(kActorMcCoy, 164) != 1) {
+ Delay(2000);
+ Actor_Voice_Over(2100, kActorVoiceOver);
+ Actor_Voice_Over(2110, kActorVoiceOver);
+ Actor_Voice_Over(2120, kActorVoiceOver);
+ Actor_Voice_Over(2130, kActorVoiceOver);
+ }
+ } else {
+ Actor_Says(kActorBulletBob, 140, 16);
+ }
+
+ return true;
+}
+
+bool AIScriptBulletBob::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ if (_var1 == 1) {
+ *animation = 516;
+ if (_var4) {
+ _var4--;
+ } else {
+ if (++_animationFrame == 6) {
+ _var4 = Random_Query(4, 8);
+ }
+ if (_animationFrame == 11) {
+ _var4 = Random_Query(2, 6);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(515)) {
+ _animationFrame = 0;
+ _var1 = 0;
+ _var3 = 2 * Random_Query(0, 1) - 1;
+ _var2 = Random_Query(3, 7);
+ _var4 = Random_Query(0, 4);
+ }
+ }
+ } else if (_var1 == 0) {
+ *animation = 514;
+ if (_var4) {
+ _var4--;
+ } else {
+ _animationFrame += _var3;
+ if (_animationFrame < 0) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(514) - 1;
+ } else if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(514)) {
+ _animationFrame = 0;
+ }
+ if (!--_var2) {
+ _var3 = 2 * Random_Query(0, 1) - 1;
+ _var2 = Random_Query(3, 7);
+ _var4 = Random_Query(0, 4);
+ }
+ if (!_animationFrame) {
+ _var1 = Random_Query(0, 1);
+ }
+ }
+ }
+ break;
+
+ case 1:
+ *animation = 506;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(506)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 2:
+ *animation = 513;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(513)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 506;
+ }
+ if (_animationFrame == 10) {
+ Sound_Play(492, 75, 0, 0, 50);
+ }
+ if (_animationFrame == 5) {
+ Sound_Play(493, 90, 0, 0, 50);
+ Actor_Set_Goal_Number(kActorBulletBob, 6);
+ }
+ break;
+
+ case 3:
+ *animation = 510;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(510) - 1) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(510) - 1;
+ _animationState = 16;
+ Game_Flag_Set(289);
+ }
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ *animation = 525;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(525)) {
+ *animation = 514;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 6:
+ *animation = 517;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(517)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 7:
+ *animation = 518;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(518)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 8:
+ *animation = 519;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(519)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 9:
+ *animation = 520;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(520)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 10:
+ *animation = 521;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(521)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 11:
+ *animation = 522;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(522)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 12:
+ *animation = 523;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(523)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 13:
+ *animation = 524;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(524)) {
+ _animationFrame = 0;
+ _animationState = 6;
+ *animation = 517;
+ }
+ break;
+
+ case 14:
+ *animation = 512;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(512)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 506;
+ }
+ break;
+
+ case 15:
+ if (_var1 == 1) {
+ *animation = 516;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(516)) {
+ _animationFrame += 2;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(516)) {
+ _animationFrame = 0;
+ *animation = _animationNext;
+ _animationState = _animationStateNext;
+ }
+ } else {
+ _animationFrame -= 2;
+ if (_animationFrame <= 0) {
+ _animationFrame = 0;
+ *animation = _animationNext;
+ _animationState = _animationStateNext;
+ }
+ }
+ } else if (_var1 == 0) {
+ *animation = 514;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(514)) {
+ _animationFrame += 2;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(514)) {
+ _animationFrame = 0;
+ *animation = _animationNext;
+ _animationState = _animationStateNext;
+ }
+ } else {
+ _animationFrame -= 2;
+ if (_animationFrame <= 0) {
+ _animationFrame = 0;
+ *animation = _animationNext;
+ _animationState = _animationStateNext;
+ }
+ }
+ }
+ break;
+
+ case 16:
+ *animation = 510;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(510) - 1;
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptBulletBob::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case 0:
+ if (_animationState > 4 || _animationState) {
+ _animationState = 0;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 3:
+ case 9:
+ case 30:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 6;
+ _animationNext = 517;
+ }
+ break;
+
+ case 4:
+ if (_animationState <= 4 && !_animationState) {
+ _animationState = 14;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 6:
+ _animationState = 2;
+ _animationFrame = 0;
+ break;
+
+ case 10:
+ case 31:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 7;
+ _animationNext = 518;
+ }
+ break;
+
+ case 11:
+ case 33:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 9;
+ _animationNext = 520;
+ }
+ break;
+
+ case 21:
+ case 22:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 23:
+ _animationState = 5;
+ _animationFrame = 0;
+ break;
+
+ case 32:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 8;
+ _animationNext = 519;
+ }
+ break;
+
+ case 34:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 10;
+ _animationNext = 521;
+ }
+ break;
+
+ case 35:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 11;
+ _animationNext = 522;
+ }
+ break;
+
+ case 36:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 12;
+ _animationNext = 523;
+ }
+ break;
+
+ case 37:
+ if (_animationState < 6 || _animationState > 13) {
+ _animationState = 15;
+ _animationStateNext = 13;
+ _animationNext = 524;
+ }
+ break;
+
+ case 48:
+ _animationState = 4;
+ _animationFrame = 0;
+ break;
+
+ case 88:
+ _animationState = 16;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(510) - 1;
+ break;
+
+ default:
+ _animationState = 0;
+ _animationFrame = 0;
+ break;
+ }
+ return true;
+}
+
+void AIScriptBulletBob::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptBulletBob::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptBulletBob::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptBulletBob::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/clovis.cpp b/engines/bladerunner/script/ai/clovis.cpp
index 9c8976e02d..58180f3699 100644
--- a/engines/bladerunner/script/ai/clovis.cpp
+++ b/engines/bladerunner/script/ai/clovis.cpp
@@ -56,24 +56,23 @@ bool AIScriptClovis::Update() {
} else if (Global_Variable_Query(kVariableChapter) == 3 && Actor_Query_Goal_Number(kActorClovis) < 350) {
Actor_Set_Goal_Number(kActorClovis, 350);
return true;
- } else if (Global_Variable_Query(kVariableChapter) != 4 || Game_Flag_Query(542)) {
+ } else if (Global_Variable_Query(kVariableChapter) == 4 && !Game_Flag_Query(542)) {
+ Game_Flag_Set(542);
+ Actor_Set_Goal_Number(kActorClovis, 400);
+ return true;
+ } else {
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_Goal_Number(kActorClovis) < 500) {
Actor_Set_Goal_Number(kActorClovis, 500);
}
if (Actor_Query_Goal_Number(kActorClovis) == 511 && Game_Flag_Query(657)) {
Actor_Set_Goal_Number(kActorClovis, 512);
}
- if (Game_Flag_Query(653) != 1 || Game_Flag_Query(696) || Game_Flag_Query(697) != 1) {
- return true;
- } else {
+ if (Game_Flag_Query(653) && !Game_Flag_Query(696) && Game_Flag_Query(697)) {
Actor_Set_Goal_Number(kActorClovis, 517);
Game_Flag_Set(696);
return true;
}
- } else {
- Game_Flag_Set(542);
- Actor_Set_Goal_Number(kActorClovis, 400);
- return true;
+ return false;
}
}
@@ -83,11 +82,11 @@ void AIScriptClovis::TimerExpired(int timer) {
void AIScriptClovis::CompletedMovementTrack() {
switch (Actor_Query_Goal_Number(kActorClovis)) {
- case 100:
+ case 101:
Actor_Set_Goal_Number(kActorClovis, 103);
break;
- case 101:
+ case 102:
Actor_Set_Goal_Number(kActorClovis, 102);
break;
@@ -114,7 +113,7 @@ void AIScriptClovis::ReceivedClue(int clueId, int fromActorId) {
void AIScriptClovis::ClickedByPlayer() {
if (Actor_Query_Goal_Number(kActorClovis) == 599) {
- Actor_Face_Actor(kActorMcCoy, kActorClovis, 1);
+ Actor_Face_Actor(kActorMcCoy, kActorClovis, true);
Actor_Says(kActorMcCoy, 8630, 16);
}
}
@@ -132,14 +131,12 @@ void AIScriptClovis::OtherAgentExitedThisScene(int otherActorId) {
}
void AIScriptClovis::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
- if (Game_Flag_Query(653) != 1 || !Actor_Query_In_Set(kActorMcCoy, kSetKP07)) {
- return; //false;
+ if (Game_Flag_Query(653) && Actor_Query_In_Set(kActorMcCoy, kSetKP07)) {
+ Game_Flag_Set(697);
+ Game_Flag_Set(714);
+ // return true;
}
-
- Game_Flag_Set(697);
- Game_Flag_Set(714);
-
- return; //true;
+ // return false;
}
void AIScriptClovis::ShotAtAndMissed() {
@@ -152,14 +149,14 @@ bool AIScriptClovis::ShotAtAndHit() {
ADQ_Flush();
Actor_Set_Goal_Number(kActorClovis, 599);
shotAnim();
- Actor_Set_Targetable(kActorClovis, 0);
+ Actor_Set_Targetable(kActorClovis, false);
ADQ_Add(kActorMcCoy, 2340, -1);
Music_Stop(3);
} else if (Actor_Query_Goal_Number(kActorClovis) == 513 || Actor_Query_Goal_Number(kActorClovis) == 518) {
ADQ_Flush();
Actor_Set_Goal_Number(kActorClovis, 599);
shotAnim();
- Actor_Set_Targetable(kActorClovis, 0);
+ Actor_Set_Targetable(kActorClovis, false);
Music_Stop(3);
}
}
@@ -167,7 +164,7 @@ bool AIScriptClovis::ShotAtAndHit() {
}
void AIScriptClovis::Retired(int byActorId) {
- if (Game_Flag_Query(653) == 1) {
+ if (Game_Flag_Query(653)) {
if (Actor_Query_In_Set(kActorClovis, kSetKP07)) {
Global_Variable_Decrement(51, 1);
Actor_Set_Goal_Number(kActorClovis, 599);
@@ -175,8 +172,8 @@ void AIScriptClovis::Retired(int byActorId) {
if (!Global_Variable_Query(51)) {
Player_Loses_Control();
Delay(2000);
- Player_Set_Combat_Mode(0);
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -12.0f, -41.58f, 72.0f, 0, 1, 0, 0);
+ Player_Set_Combat_Mode(false);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -12.0f, -41.58f, 72.0f, 0, true, false, 0);
Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
Ambient_Sounds_Remove_All_Looping_Sounds(1);
Game_Flag_Set(579);
@@ -188,40 +185,38 @@ void AIScriptClovis::Retired(int byActorId) {
}
int AIScriptClovis::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
- if (otherActorId != kActorMcCoy)
+ if (otherActorId != kActorMcCoy) {
return 0;
+ }
switch (clueId) {
- case 212:
- case 230:
+ case kClueMcCoyKilledRunciter1:
+ case kClueMcCoyKilledRunciter2:
return 6;
- break;
- case 214:
- case 239:
- case 240:
+ case kClueMcCoyIsABladeRunner:
+ case kClueMcCoyIsStupid:
+ case kClueMcCoyIsAnnoying:
return -2;
- case 215:
- case 217:
- case 218:
- case 219:
- case 220:
- case 221:
- case 241:
+ case kClueMcCoyLetZubenEscape:
+ case kClueMcCoyHelpedIzoIzoIsAReplicant:
+ case kClueMcCoyHelpedDektora:
+ case kClueMcCoyHelpedLucy:
+ case kClueMcCoyHelpedGordo:
+ case kClueMcCoyShotGuzza:
+ case kClueMcCoyIsKind:
return 4;
- case 216:
+ case kClueMcCoyWarnedIzo:
return 2;
- case 222:
+ case kClueMcCoyRetiredZuben:
return -3;
- case 223:
- case 224:
+ case kClueMcCoyRetiredLucy:
+ case kClueMcCoyRetiredDektora:
return -10;
- case 226:
- case 227:
- case 228:
- case 242:
+ case kClueMcCoyRetiredSadik:
+ case kClueMcCoyShotZubenInTheBack:
+ case kClueMcCoyRetiredLutherLance:
+ case kClueMcCoyIsInsane:
return -5;
- default:
- return 0;
}
return 0;
}
@@ -251,30 +246,30 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
case 103:
Actor_Set_Goal_Number(kActorSadik, 107);
Actor_Says(kActorClovis, 10, 15);
- Actor_Says(kActorSadik, 0, 3);
- Actor_Face_Actor(kActorClovis, kActorSadik, 1);
+ Actor_Says(kActorSadik, 0, kAnimationModeTalk);
+ Actor_Face_Actor(kActorClovis, kActorSadik, true);
Actor_Says(kActorClovis, 20, 13);
Actor_Says(kActorClovis, 30, 12);
- Actor_Face_Actor(kActorSadik, kActorClovis, 1);
- Actor_Says(kActorSadik, 10, 3);
+ Actor_Face_Actor(kActorSadik, kActorClovis, true);
+ Actor_Says(kActorSadik, 10, kAnimationModeTalk);
Actor_Says(kActorClovis, 40, 17);
- Actor_Says(kActorSadik, 20, 3);
- Actor_Face_Actor(kActorClovis, 0, 1);
- Actor_Face_Actor(kActorSadik, 0, 1);
+ Actor_Says(kActorSadik, 20, kAnimationModeTalk);
+ Actor_Face_Actor(kActorClovis, kActorMcCoy, true);
+ Actor_Face_Actor(kActorSadik, kActorMcCoy, true);
Actor_Says(kActorClovis, 50, 14);
- Actor_Change_Animation_Mode(kActorClovis, 53);
+ Actor_Change_Animation_Mode(kActorClovis, kAnimationModeSit);
return true;
case 105:
Actor_Says(kActorClovis, 60, 30);
- Actor_Says(kActorSadik, 30, 3);
+ Actor_Says(kActorSadik, 30, kAnimationModeTalk);
Actor_Says(kActorClovis, 70, 30);
Actor_Says(kActorClovis, 80, 30);
Actor_Change_Animation_Mode(kActorClovis, 29);
- Actor_Says(kActorSadik, 40, 3);
- Actor_Says(kActorSadik, 50, 3);
+ Actor_Says(kActorSadik, 40, kAnimationModeTalk);
+ Actor_Says(kActorSadik, 50, kAnimationModeTalk);
Actor_Says(kActorClovis, 90, 13);
- Actor_Face_Current_Camera(5, 1);
+ Actor_Face_Current_Camera(5, true);
Actor_Says(kActorClovis, 100, 17);
Delay(1000);
if (!Game_Flag_Query(48)) {
@@ -343,7 +338,7 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
return true;
case 510:
- if (Game_Flag_Query(653) == 1) {
+ if (Game_Flag_Query(653)) {
Actor_Set_Goal_Number(kActorClovis, 513);
} else {
Actor_Set_Goal_Number(kActorClovis, 511);
@@ -357,26 +352,26 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
return true;
case 512:
- Actor_Says(kActorClovis, 110, 3);
- Actor_Says(kActorMcCoy, 2255, 3);
- Actor_Says(kActorClovis, 120, 3);
- Actor_Says(kActorClovis, 130, 3);
- Actor_Says(kActorClovis, 140, 3);
- Actor_Says(kActorMcCoy, 2260, 3);
- Actor_Says(kActorClovis, 150, 3);
+ Actor_Says(kActorClovis, 110, kAnimationModeTalk);
+ Actor_Says(kActorMcCoy, 2255, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 120, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 130, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 140, kAnimationModeTalk);
+ Actor_Says(kActorMcCoy, 2260, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 150, kAnimationModeTalk);
Actor_Set_Goal_Number(kActorClovis, 513);
return true;
case 513:
Actor_Put_In_Set(kActorClovis, kSetKP07);
- Actor_Set_Targetable(kActorClovis, 1);
- if (Game_Flag_Query(653) == 1) {
+ Actor_Set_Targetable(kActorClovis, true);
+ if (Game_Flag_Query(653)) {
Global_Variable_Set(51, 0);
Global_Variable_Increment(51, 1);
Actor_Set_At_XYZ(kActorClovis, 45.0f, -41.52f, -85.0f, 750);
} else {
Actor_Set_At_XYZ(kActorClovis, 84.85f, -50.56f, -68.87f, 800);
- Actor_Face_Heading(kActorClovis, 1022, 0);
+ Actor_Face_Heading(kActorClovis, 1022, false);
}
someAnim();
return true;
@@ -384,15 +379,15 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
case 514:
Actor_Says(kActorMcCoy, 2345, 16);
Actor_Says(kActorClovis, 170, -1);
- Actor_Says(kActorClovis, 180, 3);
+ Actor_Says(kActorClovis, 180, kAnimationModeTalk);
Actor_Says(kActorMcCoy, 2350, 17);
if (!Game_Flag_Query(714)) {
Actor_Says(kActorMcCoy, 2355, 11);
}
Actor_Says(kActorClovis, 190, -1);
- Actor_Says(kActorClovis, 200, 3);
+ Actor_Says(kActorClovis, 200, kAnimationModeTalk);
Actor_Says(kActorMcCoy, 2360, 18);
- Actor_Says(kActorClovis, 210, 3);
+ Actor_Says(kActorClovis, 210, kAnimationModeTalk);
Actor_Says(kActorClovis, 220, -1);
Actor_Set_Goal_Number(kActorClovis, 515);
return true;
@@ -409,15 +404,15 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
return true;
case 516:
- Actor_Says(kActorMcCoy, 8501, 3);
- Actor_Says(kActorClovis, 1260, 3);
- Actor_Says(kActorMcCoy, 8502, 3);
- Actor_Says(kActorClovis, 1270, 3);
- Actor_Says(kActorMcCoy, 8504, 3);
- Actor_Says(kActorClovis, 1290, 3);
- Actor_Says(kActorMcCoy, 8505, 3);
- Actor_Says(kActorClovis, 1300, 3);
- Actor_Says(kActorClovis, 1310, 3);
+ Actor_Says(kActorMcCoy, 8501, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 1260, kAnimationModeTalk);
+ Actor_Says(kActorMcCoy, 8502, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 1270, kAnimationModeTalk);
+ Actor_Says(kActorMcCoy, 8504, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 1290, kAnimationModeTalk);
+ Actor_Says(kActorMcCoy, 8505, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 1300, kAnimationModeTalk);
+ Actor_Says(kActorClovis, 1310, kAnimationModeTalk);
Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
Ambient_Sounds_Remove_All_Looping_Sounds(1);
Outtake_Play(20, 0, -1);
@@ -440,29 +435,29 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
Global_Variable_Decrement(51, 1);
}
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorDektora, kSetKP07)) {
- Non_Player_Actor_Combat_Mode_On(kActorDektora, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorDektora, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorZuben, kSetKP07)) {
- Non_Player_Actor_Combat_Mode_On(kActorZuben, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorZuben, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorSadik, kSetKP07)) {
- Non_Player_Actor_Combat_Mode_On(kActorSadik, 0, 1, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSadik, kActorCombatStateIdle, true, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorIzo, kSetKP07)) {
- Non_Player_Actor_Combat_Mode_On(kActorIzo, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorIzo, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorGordo, kSetKP07)) {
- Non_Player_Actor_Combat_Mode_On(kActorGordo, 0, 1, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorGordo, kActorCombatStateIdle, true, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorClovis, kSetKP07)) {
- Non_Player_Actor_Combat_Mode_On(kActorClovis, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorClovis, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
return true;
case 518:
Actor_Set_At_XYZ(kActorClovis, 84.85f, -50.56f, -68.87f, 800);
- Actor_Face_Heading(kActorClovis, 1022, 0);
- Actor_Set_Targetable(kActorClovis, 1);
+ Actor_Face_Heading(kActorClovis, 1022, false);
+ Actor_Set_Targetable(kActorClovis, true);
Game_Flag_Set(685);
someAnim();
return true;
@@ -702,7 +697,7 @@ bool AIScriptClovis::UpdateAnimation(int *animation, int *frame) {
if (!_animationFrame && _flag) {
_animationState = 2;
_animationFrame = 0;
- Actor_Change_Animation_Mode(kActorClovis, 53);
+ Actor_Change_Animation_Mode(kActorClovis, kAnimationModeSit);
} else {
_animationFrame++;
if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(241)) {
@@ -1163,11 +1158,11 @@ bool AIScriptClovis::UpdateAnimation(int *animation, int *frame) {
bool AIScriptClovis::ChangeAnimationMode(int mode) {
switch (mode) {
- case 0:
+ case kAnimationModeIdle:
if (!Game_Flag_Query(685)) {
switch (_animationState) {
case 2:
- Actor_Change_Animation_Mode(kActorClovis, 53);
+ Actor_Change_Animation_Mode(kActorClovis, kAnimationModeSit);
break;
case 4:
break;
@@ -1199,17 +1194,17 @@ bool AIScriptClovis::ChangeAnimationMode(int mode) {
_animationFrame = 0;
break;
- case 1:
+ case kAnimationModeWalk:
_animationState = 21;
_animationFrame = 0;
break;
- case 2:
+ case kAnimationModeRun:
_animationState = 22;
_animationFrame = 0;
break;
- case 3:
+ case kAnimationModeTalk:
case 9:
if (Game_Flag_Query(685)) {
_animationFrame = 0;
@@ -1224,7 +1219,7 @@ bool AIScriptClovis::ChangeAnimationMode(int mode) {
}
break;
- case 4:
+ case kAnimationModeCombatIdle:
switch (_animationState) {
case 13:
case 14:
@@ -1244,28 +1239,17 @@ bool AIScriptClovis::ChangeAnimationMode(int mode) {
}
break;
- case 5:
- case 18:
- case 19:
- case 23:
- case 24:
- case 25:
- case 26:
- case 27:
- case 28:
- break;
-
- case 6:
+ case kAnimationModeCombatAttack:
_animationState = 16;
_animationFrame = 0;
break;
- case 7:
+ case kAnimationModeCombatWalk:
_animationState = 21;
_animationFrame = 0;
break;
- case 8:
+ case kAnimationModeCombatRun:
_animationState = 22;
_animationFrame = 0;
break;
@@ -1331,7 +1315,7 @@ bool AIScriptClovis::ChangeAnimationMode(int mode) {
_animationFrame = 0;
break;
- case 21:
+ case kAnimationModeHit:
if ((unsigned int)(_animationState - 13) > 3) {
if ((unsigned int)(_animationState - 32) > 8) {
if (Random_Query(0, 1)) {
@@ -1354,7 +1338,7 @@ bool AIScriptClovis::ChangeAnimationMode(int mode) {
}
break;
- case 22:
+ case kAnimationModeCombatHit:
if (Random_Query(0, 1)) {
_animationState = 17;
} else {
@@ -1379,12 +1363,12 @@ bool AIScriptClovis::ChangeAnimationMode(int mode) {
_animationFrame = Slice_Animation_Query_Number_Of_Frames(226) - 1;
break;
- case 48:
+ case kAnimationModeDie:
_animationState = 41;
_animationFrame = 0;
break;
- case 53:
+ case kAnimationModeSit:
switch (_animationState) {
case 4:
case 5:
@@ -1465,7 +1449,7 @@ void AIScriptClovis::someAnim() {
switch (_animationState) {
case 2:
- Actor_Change_Animation_Mode(kActorClovis, 53);
+ Actor_Change_Animation_Mode(kActorClovis, kAnimationModeSit);
break;
case 4:
break;
diff --git a/engines/bladerunner/script/ai/dektora.cpp b/engines/bladerunner/script/ai/dektora.cpp
index 905c3d16da..28bdf3c83d 100644
--- a/engines/bladerunner/script/ai/dektora.cpp
+++ b/engines/bladerunner/script/ai/dektora.cpp
@@ -280,7 +280,7 @@ void AIScriptDektora::Retired(int byActorId) {
}
if (byActorId == kActorSteele && Actor_Query_In_Set(kActorSteele, kSetHF06) && Actor_Query_In_Set(kActorMcCoy, kSetHF06)) {
- Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, 0, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorMcCoy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
if (Actor_Query_In_Set(kActorDektora, kSetKP07)) {
@@ -290,8 +290,8 @@ void AIScriptDektora::Retired(int byActorId) {
if (!Global_Variable_Query(51)) {
Player_Loses_Control();
Delay(2000);
- Player_Set_Combat_Mode(0);
- Loop_Actor_Walk_To_XYZ(0, -12.0, -41.580002, 72.0, 0, 1, 0, 0);
+ Player_Set_Combat_Mode(false);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -12.0f, -41.58f, 72.0f, 0, true, false, 0);
Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
Ambient_Sounds_Remove_All_Looping_Sounds(1);
Game_Flag_Set(579);
@@ -1095,11 +1095,11 @@ void AIScriptDektora::checkCombat() {
&& Global_Variable_Query(kVariableChapter) == 5
&& Actor_Query_Goal_Number(kActorDektora) != 450) {
if (Global_Variable_Query(kVariableAffectionTowards) == 2) {
- Global_Variable_Set(45, 0);
+ Global_Variable_Set(kVariableAffectionTowards, 0);
}
Actor_Set_Goal_Number(kActorDektora, 450);
- Non_Player_Actor_Combat_Mode_On(kActorDektora, 0, 0, kActorMcCoy, 4, 4, 7, 8, 0, -1, -1, 20, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorDektora, kActorCombatStateIdle, false, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 20, 300, false);
}
}
diff --git a/engines/bladerunner/script/ai/early_q.cpp b/engines/bladerunner/script/ai/early_q.cpp
new file mode 100644
index 0000000000..180493fb6e
--- /dev/null
+++ b/engines/bladerunner/script/ai/early_q.cpp
@@ -0,0 +1,1037 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptEarlyQ::AIScriptEarlyQ(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 1;
+ _flag = false;
+}
+
+void AIScriptEarlyQ::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 1;
+ _flag = 0;
+}
+
+bool AIScriptEarlyQ::Update() {
+ if (Global_Variable_Query(kVariableChapter) != 1 || Game_Flag_Query(490)) {
+ if (Global_Variable_Query(kVariableChapter) != 2 || Game_Flag_Query(491)) {
+ if (Global_Variable_Query(kVariableChapter) != 3 || Game_Flag_Query(564)) {
+ return false;
+ } else {
+ Game_Flag_Set(564);
+ Actor_Put_In_Set(kActorEarlyQ, kSetFreeSlotH);
+ Actor_Set_At_Waypoint(kActorEarlyQ, 40, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 200);
+ }
+ } else {
+ Game_Flag_Set(491);
+ Actor_Put_In_Set(kActorEarlyQ, kSetFreeSlotH);
+ Actor_Set_At_Waypoint(kActorEarlyQ, 40, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 100);
+ }
+ } else {
+ Game_Flag_Set(490);
+ Actor_Put_In_Set(kActorEarlyQ, kSetFreeSlotH);
+ Actor_Set_At_Waypoint(kActorEarlyQ, 40, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 0);
+ }
+
+ return true;
+}
+
+void AIScriptEarlyQ::TimerExpired(int timer) {
+ if (Actor_Query_Goal_Number(kActorEarlyQ) == 221 && !timer) {
+ if (Player_Query_Current_Scene() == 58) {
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 222);
+ } else {
+ Actor_Set_Goal_Number(kActorEarlyQ, 220);
+ }
+ }
+ if (Actor_Query_Goal_Number(kActorEarlyQ) != 205 || timer) {
+ if (Actor_Query_Goal_Number(kActorEarlyQ) == 211 && timer == 1) {
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 1);
+ Player_Loses_Control();
+ Actor_Change_Animation_Mode(kActorEarlyQ, 29);
+ Delay(2500);
+ Actor_Face_Actor(kActorEarlyQ, kActorMcCoy, 1);
+ Actor_Change_Animation_Mode(kActorEarlyQ, 6);
+ Delay(100);
+ _vm->_aiScripts->callChangeAnimationMode(kActorMcCoy, 22);
+ Delay(250);
+ _vm->_aiScripts->callChangeAnimationMode(kActorMcCoy, 48);
+ Actor_Retired_Here(kActorMcCoy, 12, 12, 1, -1);
+ } else {
+ return; //false;
+ }
+ } else {
+ Player_Loses_Control();
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 215);
+ }
+
+ return; //true;
+}
+
+void AIScriptEarlyQ::CompletedMovementTrack() {
+ switch (Actor_Query_Goal_Number(kActorEarlyQ)) {
+ case 0:
+ if (Random_Query(1, 2) == 1) {
+ Actor_Set_Goal_Number(kActorEarlyQ, 1);
+ } else {
+ Actor_Set_Goal_Number(kActorEarlyQ, 2);
+ }
+ break;
+
+ case 1:
+ case 2:
+ Actor_Set_Goal_Number(kActorEarlyQ, 0);
+ break;
+
+ case 100:
+ if (Random_Query(1, 2) != 1) {
+ Actor_Set_Goal_Number(kActorEarlyQ, 102);
+ break;
+ }
+ Actor_Set_Goal_Number(kActorEarlyQ, 101);
+ break;
+
+ case 101:
+ Actor_Set_Goal_Number(kActorEarlyQ, 100);
+ break;
+
+ case 102:
+ Actor_Set_Goal_Number(kActorEarlyQ, 100);
+ break;
+
+ case 201:
+ Game_Flag_Set(569);
+ Player_Set_Combat_Mode(0);
+ Actor_Set_Targetable(kActorEarlyQ, 1);
+ Actor_Set_Goal_Number(kActorEarlyQ, 202);
+ break;
+
+ case 203:
+ Actor_Set_Goal_Number(kActorEarlyQ, 204);
+ break;
+
+ case 222:
+ Actor_Set_Goal_Number(kActorEarlyQ, 223);
+ return; //false;
+
+ case 230:
+ Actor_Set_Goal_Number(kActorEarlyQ, 200);
+ return; //false;
+
+ default:
+ return; //false;
+ }
+
+ return; //true;
+}
+
+void AIScriptEarlyQ::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptEarlyQ::ClickedByPlayer() {
+ //return false;
+}
+
+void AIScriptEarlyQ::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptEarlyQ::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptEarlyQ::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptEarlyQ::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ if (Game_Flag_Query(569) != 1 || otherActorId || combatMode != 1 || Game_Flag_Query(609)) {
+ if (Actor_Query_Goal_Number(kActorEarlyQ) != 211 || otherActorId || combatMode) {
+ return; //false;
+ } else {
+ if (Game_Flag_Query(565) == 1) {
+ Game_Flag_Reset(565);
+ }
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 1);
+ Actor_Set_Goal_Number(kActorEarlyQ, 213);
+ }
+ } else {
+ if (!Game_Flag_Query(565)) {
+ Game_Flag_Set(565);
+ }
+ Game_Flag_Set(609);
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 206);
+ }
+
+ return; //true;
+}
+
+void AIScriptEarlyQ::ShotAtAndMissed() {
+ if (Actor_Query_Goal_Number(kActorEarlyQ) != 211)
+ return; //false;
+
+ Actor_Set_Goal_Number(kActorEarlyQ, 216);
+ return; //true;
+}
+
+bool AIScriptEarlyQ::ShotAtAndHit() {
+ if (Actor_Query_Goal_Number(kActorEarlyQ) < 201 || Actor_Query_Goal_Number(kActorEarlyQ) > 217)
+ return 0;
+
+ Actor_Set_Goal_Number(kActorEarlyQ, 216);
+
+ return true;
+}
+
+void AIScriptEarlyQ::Retired(int byActorId) {
+ // return false;
+}
+
+int AIScriptEarlyQ::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptEarlyQ::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ switch (newGoalNumber) {
+ case 0:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 40, 0);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 1:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 291, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 285, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 292, 30);
+ AI_Movement_Track_Append(kActorEarlyQ, 293, 30);
+ AI_Movement_Track_Append(kActorEarlyQ, 294, 30);
+ AI_Movement_Track_Append(kActorEarlyQ, 295, 30);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 2:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 40, 120);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 100:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 40, 0);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 101:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 291, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 285, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 292, 30);
+ AI_Movement_Track_Append(kActorEarlyQ, 293, 30);
+ AI_Movement_Track_Append(kActorEarlyQ, 294, 30);
+ AI_Movement_Track_Append(kActorEarlyQ, 295, 30);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 102:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 40, 120);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 200:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ Actor_Put_In_Set(kActorEarlyQ, kSetFreeSlotH);
+ Actor_Set_At_Waypoint(kActorEarlyQ, 40, 0);
+ if (Game_Flag_Query(47) == 1 && Game_Flag_Query(592) && Game_Flag_Query(593)) {
+ Actor_Set_Goal_Number(kActorEarlyQ, 220);
+ } else if (Game_Flag_Query(47)) {
+ Actor_Set_Goal_Number(kActorEarlyQ, 230);
+ } else {
+ Actor_Set_Goal_Number(kActorEarlyQ, 220);
+ }
+ break;
+
+ case 201:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 40, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 322, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 354, 0);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 203:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 355, 0);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ Actor_Face_Object(kActorMcCoy, "BAR", 1);
+ break;
+
+ case 205:
+ Loop_Actor_Walk_To_Actor(kActorEarlyQ, 0, 36, 0, 0);
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 0);
+ AI_Countdown_Timer_Start(kActorEarlyQ, 0, 4);
+ break;
+
+ case 206:
+ Player_Set_Combat_Mode(kActorSteele);
+ Actor_Face_Actor(kActorEarlyQ, kActorMcCoy, 1);
+ Actor_Face_Actor(kActorMcCoy, kActorEarlyQ, 1);
+ Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeCombatIdle);
+ _vm->_aiScripts->callChangeAnimationMode(kActorMcCoy, 5);
+ Actor_Says(kActorEarlyQ, 130, 3);
+ Actor_Says(kActorMcCoy, 3400, 5);
+ Actor_Says_With_Pause(kActorEarlyQ, 140, 1.0, 3);
+ Actor_Says_With_Pause(kActorEarlyQ, 150, 1.0, 3);
+ Actor_Says(kActorMcCoy, 3405, 5);
+ Actor_Says(kActorEarlyQ, 160, 3);
+ Actor_Says(kActorMcCoy, 3410, 5);
+ _vm->_aiScripts->callChangeAnimationMode(kActorMcCoy, 4);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, 31.22f, 0.0f, 267.51f, 0, 1, 0, 0);
+ Actor_Set_Goal_Number(kActorEarlyQ, 207);
+ break;
+
+ case 208:
+ if (Game_Flag_Query(374) == 1) {
+ Actor_Set_Goal_Number(kActorEarlyQ, 210);
+ } else {
+ Actor_Set_Goal_Number(kActorEarlyQ, 209);
+ }
+ break;
+
+ case 210:
+ Actor_Set_Targetable(kActorEarlyQ, 0);
+ Game_Flag_Set(606);
+ Delay(3500);
+ Actor_Change_Animation_Mode(kActorEarlyQ, 76);
+ Delay(2000);
+ Actor_Set_At_XYZ(kActorEarlyQ, 109.0, 0.0, 374.0, 0);
+ Actor_Retired_Here(kActorEarlyQ, 12, 12, 1, -1);
+ Actor_Voice_Over(4180, kActorVoiceOver);
+ Scene_Exits_Enable();
+ break;
+
+ case 211:
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 1);
+ AI_Countdown_Timer_Start(kActorEarlyQ, 1, 5);
+ break;
+
+ case 212:
+ Actor_Says(kActorEarlyQ, 0, 3);
+ Actor_Says(kActorEarlyQ, 10, 3);
+ Actor_Says(kActorEarlyQ, 20, 3);
+ Actor_Clue_Lose(kActorMcCoy, 89);
+ Scene_Exits_Enable();
+ Player_Gains_Control();
+ Game_Flag_Set(627);
+ Actor_Set_Goal_Number(kActorHanoi, 220);
+ break;
+
+ case 215:
+ if (Actor_Query_Inch_Distance_From_Actor(kActorMcCoy, kActorEarlyQ) > 36) {
+ Loop_Actor_Walk_To_Actor(kActorEarlyQ, kActorMcCoy, 36, kActorMcCoy, kActorMcCoy);
+ }
+ Actor_Face_Actor(kActorMcCoy, kActorEarlyQ, 1);
+ Actor_Face_Actor(kActorEarlyQ, kActorMcCoy, 1);
+ Actor_Change_Animation_Mode(kActorEarlyQ, 23);
+ Scene_Loop_Start_Special(2, 2, 0);
+ Ambient_Sounds_Play_Sound(582, 50, 99, 0, 0);
+ Actor_Set_Goal_Number(kActorMcCoy, 220);
+ break;
+
+ case 216:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ Actor_Change_Animation_Mode(kActorEarlyQ, 48);
+ Delay(250);
+ Actor_Set_At_XYZ(kActorEarlyQ, 109.0, 0.0, 374.0, 0);
+ Actor_Set_Goal_Number(kActorHanoi, 240);
+ Player_Set_Combat_Mode(0);
+ break;
+
+ case 217:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 354, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 322, 0);
+ AI_Movement_Track_Append(kActorEarlyQ, 40, 0);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 220:
+ if (Player_Query_Current_Set() == 13) {
+ Actor_Set_Goal_Number(kActorEarlyQ, 230);
+ } else {
+ Actor_Put_In_Set(kActorEarlyQ, kSetNR05_NR08);
+ Actor_Set_At_XYZ(kActorEarlyQ, -671.56f, 0.0f, -287.02f, 849);
+ }
+ break;
+
+ case 221:
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 0);
+ AI_Countdown_Timer_Start(kActorEarlyQ, 0, 20);
+ break;
+
+ case 222:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Movement_Track_Append(kActorEarlyQ, 429, 0);
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ case 223:
+ if (Player_Query_Current_Scene() == 58) {
+ Actor_Says(kActorEarlyQ, 670, 3);
+ Actor_Says(kActorEarlyQ, 690, 3);
+ Actor_Set_Goal_Number(kActorDektora, 210);
+ Actor_Set_Goal_Number(kActorEarlyQ, 224);
+ Actor_Set_Goal_Number(kActorHanoi, 230);
+ } else {
+ Actor_Set_Goal_Number(kActorEarlyQ, 220);
+ }
+ break;
+
+ case 224:
+ Game_Flag_Set(620);
+ break;
+
+ case 229:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ AI_Countdown_Timer_Reset(kActorEarlyQ, 0);
+ break;
+
+ case 230:
+ AI_Movement_Track_Flush(kActorEarlyQ);
+ if (Random_Query(1, 3) > 1) {
+ AI_Movement_Track_Append(kActorEarlyQ, 322, Random_Query(15, 30));
+ AI_Movement_Track_Append(kActorEarlyQ, 39, Random_Query(15, 45));
+ AI_Movement_Track_Append(kActorEarlyQ, 40, Random_Query(15, 30));
+ } else {
+ AI_Movement_Track_Append(kActorEarlyQ, 322, Random_Query(5, 15));
+ AI_Movement_Track_Append(kActorEarlyQ, 39, Random_Query(5, 15));
+ AI_Movement_Track_Append(kActorEarlyQ, 40, Random_Query(5, 15));
+ AI_Movement_Track_Append(kActorEarlyQ, 39, Random_Query(5, 15));
+ AI_Movement_Track_Append(kActorEarlyQ, 34, Random_Query(10, 20));
+ }
+ AI_Movement_Track_Repeat(kActorEarlyQ);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool AIScriptEarlyQ::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ if (_var2 == 1) {
+ *animation = 370;
+ if (_var1) {
+ _var1--;
+ } else {
+ if (++_animationFrame == 6) {
+ _var1 = Random_Query(8, 15);
+ }
+ if (_animationFrame < 6) {
+ _var1 = 1;
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(370)) {
+ _animationFrame = 0;
+ _var2 = 0;
+ }
+ }
+ } else if (_var2 == 0) {
+ *animation = 369;
+ if (_var1) {
+ _var1--;
+ if (!Random_Query(0, 6)) {
+ _var3 = -_var3;
+ }
+ } else {
+ _animationFrame += _var3;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(369)) {
+ _animationFrame = 0;
+ }
+ if (_animationFrame < 0) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(369) - 1;
+ }
+ _var1 = Random_Query(0, 1);
+ if (!_animationFrame) {
+ if (!Random_Query(0, 3)) {
+ _var2 = 1;
+ }
+ }
+ if (!_animationFrame || _animationFrame == 5) {
+ if (Random_Query(0, 1)) {
+ _var1 = Random_Query(2, 8);
+ }
+ }
+ }
+ }
+ break;
+
+ case 1:
+ *animation = 381;
+ _animationFrame++;
+ if (_animationFrame == 18) {
+ Ambient_Sounds_Play_Sound(255, 99, 0, 0, 20);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ Actor_Change_Animation_Mode(kActorEarlyQ, 74);
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 382;
+ }
+ break;
+
+ case 2:
+ *animation = 382;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(382)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 3:
+ *animation = 371;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(371)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 0);
+ }
+ break;
+
+ case 4:
+ *animation = 368;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(368) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 5:
+ *animation = 365;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(365)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 6:
+ *animation = 361;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(361)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 7:
+ *animation = 383;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(383)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 384;
+ }
+ break;
+
+ case 8:
+ *animation = 387;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(387)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 9:
+ *animation = 384;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(384)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 10:
+ *animation = 385;
+ if (!_animationFrame && _flag) {
+ _flag = 0;
+ _animationState = 9;
+ _var2 = 0;
+ *animation = 384;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 53);
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(385)) {
+ _animationFrame = 0;
+ }
+ }
+ break;
+
+ case 11:
+ *animation = 386;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(386) - 1) {
+ _animationFrame++;
+ }
+ if (_animationFrame == 1) {
+ Ambient_Sounds_Play_Sound(555, 59, 0, 0, 20);
+ }
+ if (_animationFrame == 8) {
+ Ambient_Sounds_Play_Sound(254, 47, 0, 0, 20);
+ }
+ if (_animationFrame == 11) {
+ Ambient_Sounds_Play_Sound(560, 27, 0, 0, 20);
+ }
+ if (_animationFrame == 14) {
+ Ambient_Sounds_Play_Sound(206, 41, 0, 0, 20);
+ }
+ break;
+
+ case 12:
+ *animation = 360;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(360)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 13:
+ *animation = 362;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(362)) {
+ _animationFrame = 0;
+ _animationState = 12;
+ *animation = 360;
+ }
+ break;
+
+ case 14:
+ *animation = 363;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(363)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 15:
+ *animation = 364;
+ _animationFrame++;
+ if (_animationFrame == 2) {
+ Ambient_Sounds_Play_Sound(12, 60, 0, 0, 20);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(364)) {
+ _animationFrame = 0;
+ _animationState = 12;
+ *animation = 360;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 4);
+ }
+ break;
+
+ case 16:
+ *animation = 366;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(366)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 0);
+ }
+ break;
+
+ case 17:
+ *animation = 367;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(367)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 0);
+ }
+ break;
+
+ case 18:
+ *animation = 366;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(366)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 0);
+ }
+ break;
+
+ case 19:
+ *animation = 367;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(367)) {
+ *animation = 369;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorEarlyQ, 0);
+ }
+ break;
+
+ case 20:
+ *animation = 372;
+ if (!_animationFrame && _flag) {
+ *animation = 369;
+ _animationFrame = 0;
+ _flag = 0;
+ _animationState = 0;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(372)) {
+ _animationFrame = 0;
+ }
+ }
+ break;
+
+ case 21:
+ *animation = 373;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(373)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 22:
+ *animation = 374;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(374)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 23:
+ *animation = 375;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(375)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 24:
+ *animation = 376;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(376)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 25:
+ *animation = 377;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(377)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 26:
+ *animation = 378;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(378)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 27:
+ *animation = 379;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(379)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ case 28:
+ *animation = 380;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(380)) {
+ _animationFrame = 0;
+ _animationState = 20;
+ *animation = 372;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptEarlyQ::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case 0:
+ switch (_animationState) {
+ case 1:
+ Actor_Change_Animation_Mode(kActorEarlyQ, 73);
+ break;
+
+ case 2:
+ Actor_Change_Animation_Mode(kActorEarlyQ, 74);
+ break;
+
+ case 9:
+ Actor_Change_Animation_Mode(kActorEarlyQ, 29);
+ break;
+
+ case 10:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ _flag = 1;
+ break;
+
+ case 12:
+ case 13:
+ case 15:
+ _animationState = 14;
+ _animationFrame = 0;
+ break;
+
+ case 14:
+ return 1;
+
+ default:
+ _animationState = 0;
+ _animationFrame = 0;
+ break;
+ }
+ break;
+
+ case 1:
+ _animationState = 5;
+ _animationFrame = 0;
+ break;
+
+ case 3:
+ _animationState = 20;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 4:
+ if ((unsigned int)(_animationState - 12) > 3 || (_animationState != 12 && _animationState != 13 && _animationState != 15)) {
+ _animationState = 13;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 6:
+ _animationState = 15;
+ _animationFrame = 0;
+ break;
+
+ case 7:
+ _animationState = 6;
+ _animationFrame = 0;
+ break;
+
+ case 12:
+ _animationState = 21;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 13:
+ _animationState = 22;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 14:
+ _animationState = 23;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 15:
+ _animationState = 24;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 16:
+ _animationState = 25;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 17:
+ _animationState = 26;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 18:
+ _animationState = 27;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 19:
+ _animationState = 28;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 21:
+ if ((unsigned int)(_animationState - 12) > 3 || (_animationState != 12 && _animationState != 13 && _animationState != 15)) {
+ if (Random_Query(0, 1)) {
+ _animationState = 16;
+ } else {
+ _animationState = 17;
+ }
+ _animationFrame = 0;
+ } else {
+ if (Random_Query(0, 1)) {
+ _animationState = 18;
+ } else {
+ _animationState = 19;
+ }
+ _animationFrame = 0;
+ }
+ break;
+
+ case 23:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 29:
+ _animationState = 8;
+ _animationFrame = 0;
+ break;
+
+ case 30:
+ _animationState = 10;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 48:
+ _animationState = 4;
+ _animationFrame = 0;
+ break;
+
+ case 53:
+ _animationState = 9;
+ _animationFrame = 0;
+ break;
+
+ case 73:
+ if (_animationState != 1) {
+ _animationState = 1;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 74:
+ if (_animationState != 2) {
+ _animationState = 2;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 76:
+ _animationState = 11;
+ _animationFrame = 0;
+ break;
+
+ case 85:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+
+ default:
+ return true;
+ }
+
+ return true;
+}
+
+void AIScriptEarlyQ::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptEarlyQ::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptEarlyQ::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptEarlyQ::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/free_slot_a.cpp b/engines/bladerunner/script/ai/free_slot_a.cpp
new file mode 100644
index 0000000000..b017a9e3f2
--- /dev/null
+++ b/engines/bladerunner/script/ai/free_slot_a.cpp
@@ -0,0 +1,659 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptFreeSlotA::AIScriptFreeSlotA(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 0;
+ _var2 = 1;
+ _var3 = 0.0f;
+ _var4 = 0.0f; // not initialized in original
+ _var5 = 0.0f; // not initialized in original
+}
+
+void AIScriptFreeSlotA::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 0;
+ _var2 = 1;
+ _var3 = 0.0f;
+ _var4 = 0.0f; // not initialized in original
+ _var5 = 0.0f; // not initialized in original
+
+ World_Waypoint_Set(525, 45, -780.0f, -615.49f, 2611.0f);
+ World_Waypoint_Set(526, 45, -780.0f, -615.49f, 2759.0f);
+}
+
+bool AIScriptFreeSlotA::Update() {
+ switch (Global_Variable_Query(kVariableChapter)) {
+ case 4:
+ if (Actor_Query_Which_Set_In(kActorMcCoy) == kSceneUG02 && Actor_Query_Which_Set_In(kActorFreeSlotA) == kSceneUG02) {
+ int goal = Actor_Query_Goal_Number(kActorFreeSlotA);
+ if ((goal == 302 || goal == 303) && Actor_Query_Inch_Distance_From_Actor(kActorFreeSlotA, kActorMcCoy) <= 48) {
+ Actor_Set_Goal_Number(kActorFreeSlotA, 304);
+ } else if (goal == 309) {
+ float x, y, z;
+
+ Actor_Query_XYZ(kActorMcCoy, &x, &y, &z);
+ _var4 += _var3;
+ if (_var5 < _var4) {
+ _var3 -= 0.2f;
+ } else {
+ _var4 = _var5;
+ Actor_Set_Goal_Number(kActorFreeSlotA, 0);
+ }
+ Actor_Set_At_XYZ(kActorFreeSlotA, x, _var4, z, Actor_Query_Facing_1024(kActorFreeSlotA));
+ }
+ } else {
+ switch (Actor_Query_Goal_Number(kActorFreeSlotA)) {
+ case 306:
+ if (Actor_Query_Which_Set_In(kActorFreeSlotA) == Player_Query_Current_Set()
+ && Actor_Query_Inch_Distance_From_Actor(kActorFreeSlotA, kActorMcCoy) <= 48) {
+ Actor_Set_Goal_Number(kActorFreeSlotA, 308);
+ }
+ break;
+
+ case 308:
+ if (Actor_Query_Which_Set_In(kActorFreeSlotA) != Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorFreeSlotA, 306);
+ }
+ break;
+
+ case 599:
+ if (Actor_Query_Which_Set_In(kActorFreeSlotA) != Player_Query_Current_Set()) {
+ Game_Flag_Reset(631);
+ Game_Flag_Reset(677);
+ Actor_Set_Goal_Number(kActorFreeSlotA, 0);
+ }
+ break;
+
+ default:
+ if (!Game_Flag_Query(631)) {
+ Game_Flag_Set(631);
+ Actor_Set_Goal_Number(kActorFreeSlotA, 306);
+ Actor_Set_Targetable(kActorFreeSlotA, 1);
+ }
+ }
+ }
+ return true;
+
+ case 5:
+ if (Actor_Query_Goal_Number(kActorFreeSlotA) < 400) {
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ Actor_Set_Goal_Number(kActorFreeSlotA, 400);
+ } else if (Actor_Query_Goal_Number(kActorFreeSlotA) == 405 && Actor_Query_Which_Set_In(kActorMcCoy) == kSceneKP05) {
+ Actor_Set_Targetable(kActorFreeSlotA, 1);
+ Actor_Set_Goal_Number(kActorFreeSlotA, 406);
+ }
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void AIScriptFreeSlotA::TimerExpired(int timer) {
+ //return false;
+}
+
+void AIScriptFreeSlotA::CompletedMovementTrack() {
+ switch (Actor_Query_Goal_Number(kActorFreeSlotA)) {
+ case 301:
+ Actor_Set_Goal_Number(kActorFreeSlotA, 302);
+ break;
+
+ case 302:
+ Actor_Set_Goal_Number(kActorFreeSlotA, 303);
+ break;
+
+ case 303:
+ Actor_Set_Goal_Number(kActorFreeSlotA, 300);
+ break;
+
+ case 306:
+ Actor_Set_Goal_Number(kActorFreeSlotA, 307);
+ break;
+
+ case 307:
+ Actor_Set_Goal_Number(kActorFreeSlotA, 306);
+ break;
+
+ case 400:
+ Actor_Set_Goal_Number(kActorFreeSlotA, 405);
+ break;
+
+ case 406:
+ Non_Player_Actor_Combat_Mode_On(kActorFreeSlotA, 0, 0, 0, 8, 4, 7, 8, 0, 0, 100, 5, 300, 0);
+ break;
+
+ default:
+ return; //false;
+ }
+
+ return; //true;
+}
+
+void AIScriptFreeSlotA::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptFreeSlotA::ClickedByPlayer() {
+ if (Actor_Query_Goal_Number(kActorFreeSlotA) != 599) {
+ return; //false;
+ }
+
+ Actor_Face_Actor(kActorMcCoy, kActorFreeSlotA, 1);
+ if (Random_Query(1, 2) == 1) {
+ Actor_Says(kActorMcCoy, 8655, 16);
+ } else {
+ Actor_Says(kActorMcCoy, 8665, 16);
+ }
+}
+
+void AIScriptFreeSlotA::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptFreeSlotA::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptFreeSlotA::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptFreeSlotA::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptFreeSlotA::ShotAtAndMissed() {
+ if (Actor_Query_In_Set(kActorFreeSlotA, kSetUG15) == 1)
+ calcHit();
+}
+
+bool AIScriptFreeSlotA::ShotAtAndHit() {
+ if (Actor_Query_In_Set(kActorFreeSlotA, kSetUG15) == 1) {
+ calcHit();
+ Actor_Set_Goal_Number(kActorFreeSlotA, 305);
+ return true;
+ }
+
+ return false;
+}
+
+void AIScriptFreeSlotA::Retired(int byActorId) {
+ Actor_Set_Goal_Number(kActorFreeSlotA, 599);
+}
+
+int AIScriptFreeSlotA::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptFreeSlotA::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ switch (newGoalNumber) {
+ case 300:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ Actor_Change_Animation_Mode(kActorFreeSlotA, 0);
+ Actor_Set_Targetable(kActorFreeSlotA, 0);
+ break;
+
+ case 301:
+ Actor_Force_Stop_Walking(kActorMcCoy);
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ World_Waypoint_Set(444, 87, -48.75f, 44.66f, 87.57f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 444, 1);
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ break;
+
+ case 302:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ World_Waypoint_Set(444, 87, -237.0f, 48.07f, 208.0f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 444, 1);
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ Actor_Set_Targetable(kActorFreeSlotA, 1);
+ break;
+
+ case 303:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ World_Waypoint_Set(444, 87, 3.52f, 52.28f, 90.68f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 444, 0);
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ break;
+
+ case 304:
+ Player_Loses_Control();
+ Actor_Force_Stop_Walking(kActorMcCoy);
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ Actor_Face_Actor(kActorFreeSlotA, kActorMcCoy, 1);
+ Actor_Change_Animation_Mode(kActorFreeSlotA, 6);
+ Actor_Change_Animation_Mode(kActorMcCoy, 48);
+ break;
+
+ case 305:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ Actor_Set_Targetable(kActorFreeSlotA, 0);
+ Game_Flag_Set(676);
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+
+ case 306:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ processGoal306();
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ break;
+
+ case 307:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ AI_Movement_Track_Append(kActorFreeSlotA, 39, 1);
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ break;
+
+ case 308:
+ Actor_Set_Targetable(kActorFreeSlotA, 1);
+ Non_Player_Actor_Combat_Mode_On(kActorFreeSlotA, 0, 0, 0, 8, 4, 7, 8, 25, 0, 75, 5, 300, 0);
+ break;
+
+ case 309:
+ Actor_Force_Stop_Walking(kActorFreeSlotA);
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ _var4 = 52.46f;
+ _var3 = -4.0f;
+ _var5 = -10.0f;
+ if (_animationState != 7 && _animationState != 8) {
+ _animationState = 7;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 310:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ Actor_Put_In_Set(kActorFreeSlotA, kSetUG15);
+ Actor_Set_At_XYZ(kActorFreeSlotA, 3.52f, 52.28f, 90.68f, 700);
+ Actor_Set_Goal_Number(kActorFreeSlotA, 300);
+ break;
+
+ case 400:
+ AI_Movement_Track_Append(kActorFreeSlotA, 39, 0);
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ break;
+
+ case 406:
+ AI_Movement_Track_Flush(kActorFreeSlotA);
+ AI_Movement_Track_Append(kActorFreeSlotA, 525, 0);
+ AI_Movement_Track_Repeat(kActorFreeSlotA);
+ break;
+
+ case 599:
+ Actor_Set_Health(kActorFreeSlotA, 20, 20);
+ Actor_Set_Friendliness_To_Other(kActorFreeSlotA, kActorMcCoy, 40);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool AIScriptFreeSlotA::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ *animation = 861;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(861)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 1:
+ *animation = 862;
+ if (_var1) {
+ _var1--;
+ } else {
+ _animationFrame += _var2;
+ if (_animationFrame < 8) {
+ _var2 = 1;
+ } else {
+ if (_animationFrame > 8) {
+ _var2 = -1;
+ } else if (Random_Query(0, 4)) {
+ _var2 = -_var2;
+ }
+ }
+ if (_animationFrame >= 7 && _animationFrame <= 9) {
+ _var1 = Random_Query(0, 1);
+ }
+ }
+ break;
+
+ case 2:
+ *animation = 862;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(862) - 1) {
+ *animation = 861;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 3:
+ *animation = 858;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(858)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 4:
+ *animation = 857;
+ _animationFrame++;
+ if (_animationFrame == 1) {
+ int snd;
+ if (Random_Query(1, 2) == 1) {
+ snd = 9010;
+ } else {
+ snd = 9015;
+ }
+ Sound_Play_Speech_Line(64, snd, 75, 0, 99);
+ }
+ if (_animationFrame == 3) {
+ Ambient_Sounds_Play_Sound(438, 99, 0, 0, 20);
+ Actor_Combat_AI_Hit_Attempt(kActorFreeSlotA);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(857)) {
+ _animationState = 0;
+ _animationFrame = 0;
+ Actor_Change_Animation_Mode(kActorFreeSlotA, 4);
+ }
+ break;
+
+ case 5:
+ *animation = 874;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(874) - 1) { // bug? shuld not be '-1'
+ Actor_Change_Animation_Mode(kActorFreeSlotA, 0);
+ }
+ break;
+
+ case 6:
+ if (_animationFrame == 1) {
+ Ambient_Sounds_Play_Sound(437, 99, 0, 0, 20);
+ }
+ *animation = 860;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(860)) {
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorFreeSlotA, 0);
+ }
+ break;
+
+ case 7:
+ *animation = 859;
+ _animationFrame++;
+ if (_animationFrame == 0) {
+ Ambient_Sounds_Play_Sound(439, 99, 0, 0, 25);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(859) - 1) { // bug? shuld not be '-1'
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(859) - 1;
+ _animationState = 8;
+ Actor_Set_Goal_Number(kActorFreeSlotA, 599);
+ }
+ break;
+
+ case 8:
+ *animation = 859;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(859) - 1;
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+ return true;
+}
+
+bool AIScriptFreeSlotA::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case 0:
+ if ((unsigned int)(_animationState - 1) > 1) {
+ _animationState = 0;
+ _animationFrame = 0;
+ } else if (_animationState == 1) {
+ _animationState = 2;
+ }
+ break;
+
+ case 1:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 4:
+ if ((unsigned int)(_animationState - 1) > 1) {
+ _animationState = 0;
+ _animationFrame = 0;
+ } else if (_animationState == 1) {
+ _animationState = 2;
+ }
+ break;
+
+ case 6:
+ _animationState = 4;
+ _animationFrame = 0;
+ break;
+
+ case 7:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 8:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 21:
+ _animationState = 6;
+ _animationFrame = 0;
+ break;
+
+ case 43:
+ _animationState = 1;
+ _animationFrame = 0;
+ break;
+
+ case 48:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+ }
+ return true;
+}
+
+void AIScriptFreeSlotA::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptFreeSlotA::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptFreeSlotA::ReachedMovementTrackWaypoint(int waypointId) {
+ if (Actor_Query_Which_Set_In(kActorFreeSlotA) == kSetUG01) {
+ if (waypointId == 465) {
+ Actor_Change_Animation_Mode(kActorFreeSlotA, 43);
+ }
+ } else if (Actor_Query_Goal_Number(kActorFreeSlotA) == 302) {
+ Actor_Face_Actor(kActorFreeSlotA, kActorMcCoy, 1);
+ }
+
+ return true;
+}
+
+void AIScriptFreeSlotA::FledCombat() {
+ // return false;
+}
+
+void AIScriptFreeSlotA::calcHit() {
+ float x, y, z;
+
+ Actor_Query_XYZ(kActorFreeSlotA, &x, &y, &z);
+
+ if (x >= -30.0f && x < -150.0f) {
+ Game_Flag_Set(677);
+ }
+}
+
+void AIScriptFreeSlotA::processGoal306() {
+ switch (Random_Query(1, 14)) {
+ case 1:
+ AI_Movement_Track_Append(kActorFreeSlotA, 450, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 451, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 450, 0);
+ break;
+
+ case 2:
+ World_Waypoint_Set(463, 74, 144.98f, -50.13f, -175.75f);
+ World_Waypoint_Set(464, 74, 105.6f, -50.13f, -578.46f);
+ World_Waypoint_Set(465, 74, 62.0f, -50.13f, -574.0f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 465, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 5);
+ break;
+
+ case 3:
+ AI_Movement_Track_Append(kActorFreeSlotA, 446, 15);
+ AI_Movement_Track_Append(kActorFreeSlotA, 447, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 449, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 448, 2);
+ AI_Movement_Track_Append(kActorFreeSlotA, 449, 0);
+ break;
+
+ case 4:
+ World_Waypoint_Set(463, 77, -22.7f, 6.39f, 33.12f);
+ World_Waypoint_Set(464, 77, -6.70f, -1.74f, -362.88f);
+ World_Waypoint_Set(465, 77, 164.0f, 11.87f, -1013.0f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 2);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 0);
+ AI_Movement_Track_Append(kActorFreeSlotA, 465, 0);
+ break;
+
+ case 5:
+ AI_Movement_Track_Append(kActorFreeSlotA, 457, 15);
+ AI_Movement_Track_Append(kActorFreeSlotA, 458, 0);
+ AI_Movement_Track_Append(kActorFreeSlotA, 459, 15);
+ break;
+
+ case 6:
+ AI_Movement_Track_Append(kActorFreeSlotA, 460, 15);
+ AI_Movement_Track_Append(kActorFreeSlotA, 461, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 460, 15);
+ break;
+
+ case 7:
+ if (Actor_Query_In_Set(kActorClovis, kSetUG07)) {
+ AI_Movement_Track_Append(kActorFreeSlotA, 39, 10);
+ } else {
+ World_Waypoint_Set(463, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(464, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(465, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 1);
+ }
+ break;
+
+ case 8:
+ World_Waypoint_Set(463, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(464, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(465, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 1);
+ break;
+
+ case 9:
+ World_Waypoint_Set(463, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(464, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(465, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 465, 1);
+ break;
+
+ case 10:
+ World_Waypoint_Set(463, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(464, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(465, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 465, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 1);
+ break;
+
+ case 11:
+ World_Waypoint_Set(463, 82, 91.0f, 156.94f, -498.0f);
+ World_Waypoint_Set(464, 82, -149.0f, 156.94f, -498.0f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 1);
+ break;
+
+ case 12:
+ World_Waypoint_Set(463, 82, 91.0f, 156.94f, -498.0f);
+ World_Waypoint_Set(464, 82, -149.0f, 156.94f, -498.0f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 5);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 1);
+ break;
+
+ case 13:
+ World_Waypoint_Set(463, 82, -152.51f, 277.31f, 311.98f);
+ World_Waypoint_Set(464, 82, -124.51f, 275.08f, 319.98f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 8);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 1);
+ break;
+
+ case 14:
+ World_Waypoint_Set(463, 84, -360.67f, 21.39f, 517.55f);
+ World_Waypoint_Set(464, 84, -250.67f, 21.39f, 477.55f);
+ World_Waypoint_Set(465, 84, -248.67f, 21.39f, -1454.45f);
+ AI_Movement_Track_Append(kActorFreeSlotA, 463, 1);
+ AI_Movement_Track_Append(kActorFreeSlotA, 464, 8);
+ AI_Movement_Track_Append(kActorFreeSlotA, 465, 1);
+ break;
+
+ default:
+ AI_Movement_Track_Append(kActorFreeSlotA, 39, Random_Query(1, 10));
+ break;
+ }
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/free_slot_b.cpp b/engines/bladerunner/script/ai/free_slot_b.cpp
new file mode 100644
index 0000000000..431b27a062
--- /dev/null
+++ b/engines/bladerunner/script/ai/free_slot_b.cpp
@@ -0,0 +1,541 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptFreeSlotB::AIScriptFreeSlotB(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 0;
+ _var2 = 1;
+}
+
+void AIScriptFreeSlotB::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 0;
+ _var2 = 1;
+
+ World_Waypoint_Set(527, 45, -468.46f, -616.58f, 2840.60f);
+ World_Waypoint_Set(528, 45, -1024.46f, -615.49f, 2928.60f);
+ World_Waypoint_Set(529, 45, -1024.46f, -615.49f, 2788.60f);
+}
+
+bool AIScriptFreeSlotB::Update() {
+ if (Global_Variable_Query(kVariableChapter) > 5) {
+ return false;
+ }
+
+ if (Global_Variable_Query(kVariableChapter) == 4) {
+ switch (Actor_Query_Goal_Number(kActorFreeSlotB)) {
+ case 300:
+ Actor_Set_Goal_Number(kActorFreeSlotB, 301);
+ Actor_Set_Targetable(kActorFreeSlotB, 1);
+ break;
+
+ case 301:
+ if (Actor_Query_Which_Set_In(kActorFreeSlotB) == Player_Query_Current_Set()
+ && Actor_Query_Inch_Distance_From_Actor(kActorFreeSlotB, kActorMcCoy) <= 48) {
+ Actor_Set_Goal_Number(kActorFreeSlotB, 302);
+ }
+ break;
+
+ case 302:
+ if (Actor_Query_Which_Set_In(kActorFreeSlotB) != Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorFreeSlotB, 301);
+ }
+ break;
+
+ case 599:
+ if (Actor_Query_Which_Set_In(kActorFreeSlotB) != Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorFreeSlotB, 300);
+ }
+ break;
+
+ default:
+ Actor_Set_Goal_Number(kActorFreeSlotB, 300);
+ break;
+ }
+
+ return false;
+ }
+ if (Actor_Query_Goal_Number(kActorFreeSlotB) < 400) {
+ AI_Movement_Track_Flush(kActorFreeSlotB);
+ Actor_Set_Goal_Number(kActorFreeSlotB, 400);
+ return true;
+ } else {
+ if (Actor_Query_Goal_Number(kActorFreeSlotB) != 405 || Actor_Query_Which_Set_In(kActorMcCoy) != kSetKP02) {
+ if (Actor_Query_Goal_Number(kActorFreeSlotB) == 599) {
+ if (Actor_Query_Which_Set_In(kActorFreeSlotB) != Player_Query_Current_Set()) {
+ Non_Player_Actor_Combat_Mode_Off(kActorFreeSlotB);
+ Actor_Set_Goal_Number(kActorFreeSlotB, 400);
+ return true;
+ }
+ }
+ return false;
+ }
+ Actor_Set_Goal_Number(kActorFreeSlotB, 406);
+ Actor_Set_Targetable(kActorFreeSlotB, 1);
+ return true;
+ }
+}
+
+void AIScriptFreeSlotB::TimerExpired(int timer) {
+ //return false;
+}
+
+void AIScriptFreeSlotB::CompletedMovementTrack() {
+ switch (Actor_Query_Goal_Number(kActorFreeSlotB)) {
+ case 300:
+ Actor_Set_Goal_Number(kActorFreeSlotB, 301);
+ break;
+
+ case 301:
+ Actor_Set_Goal_Number(kActorFreeSlotB, 300);
+ break;
+
+ case 400:
+ Actor_Set_Goal_Number(kActorFreeSlotB, 405);
+ break;
+
+ case 406:
+ Non_Player_Actor_Combat_Mode_On(kActorFreeSlotB, 0, 0, 0, 8, 4, 7, 8, 0, 0, 100, 5, 300, 0);
+ break;
+
+ default:
+ return; //false;
+ }
+
+ return; //true;
+}
+
+void AIScriptFreeSlotB::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptFreeSlotB::ClickedByPlayer() {
+ if (Actor_Query_Goal_Number(kActorFreeSlotB) != 599)
+ return; //false;
+
+ Actor_Face_Actor(kActorMcCoy, kActorFreeSlotB, 1);
+ if (Random_Query(1, 2) == 1) {
+ Actor_Says(kActorMcCoy, 8655, 16);
+ } else {
+ Actor_Says(kActorMcCoy, 8665, 16);
+ }
+}
+
+void AIScriptFreeSlotB::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptFreeSlotB::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptFreeSlotB::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptFreeSlotB::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptFreeSlotB::ShotAtAndMissed() {
+ // return false;
+}
+
+bool AIScriptFreeSlotB::ShotAtAndHit() {
+ return false;
+}
+
+void AIScriptFreeSlotB::Retired(int byActorId) {
+ Actor_Set_Goal_Number(kActorFreeSlotB, 599);
+}
+
+int AIScriptFreeSlotB::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptFreeSlotB::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ switch (newGoalNumber) {
+ case 300:
+ AI_Movement_Track_Flush(kActorFreeSlotB);
+ AI_Movement_Track_Append(kActorFreeSlotB, 39, 2);
+ AI_Movement_Track_Repeat(kActorFreeSlotB);
+ break;
+
+ case 301:
+ AI_Movement_Track_Flush(kActorFreeSlotB);
+ processGoal301();
+ AI_Movement_Track_Repeat(kActorFreeSlotB);
+ break;
+
+ case 302:
+ Actor_Set_Targetable(kActorFreeSlotB, 1);
+ Non_Player_Actor_Combat_Mode_On(kActorFreeSlotB, 0, 0, 0, 8, 4, 7, 8, 25, 0, 75, 5, 300, 0);
+ break;
+
+ case 400:
+ AI_Movement_Track_Append(kActorFreeSlotB, 39, 0);
+ AI_Movement_Track_Repeat(kActorFreeSlotB);
+ break;
+
+ case 406:
+ AI_Movement_Track_Flush(kActorFreeSlotB);
+ AI_Movement_Track_Append(kActorFreeSlotB, 527, 0);
+ AI_Movement_Track_Repeat(kActorFreeSlotB);
+ break;
+
+ case 599:
+ Actor_Set_Health(kActorFreeSlotB, 20, 20);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool AIScriptFreeSlotB::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ *animation = 861;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(861)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 1:
+ *animation = 862;
+ if (_var1) {
+ _var1--;
+ } else {
+ _animationFrame += _var2;
+ if (_animationFrame < 8) {
+ _var2 = 1;
+ } else {
+ if (_animationFrame > 8) {
+ _var2 = -1;
+ } else if (Random_Query(0, 4)) {
+ _var2 = -_var2;
+ }
+ }
+ if (_animationFrame >= 7 && _animationFrame <= 9) {
+ _var1 = Random_Query(0, 1);
+ }
+ }
+ break;
+
+ case 2:
+ *animation = 862;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(862) - 1) {
+ *animation = 861;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 3:
+ *animation = 858;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(858)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 4:
+ *animation = 857;
+ _animationFrame++;
+ if (_animationFrame == 3) {
+ int snd;
+ if (Random_Query(1, 2) == 1) {
+ snd = 9010;
+ } else {
+ snd = 9015;
+ }
+ Sound_Play_Speech_Line(kActorFreeSlotB, snd, 75, 0, 99);
+ }
+ if (_animationFrame == 3) {
+ Actor_Combat_AI_Hit_Attempt(kActorFreeSlotB);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ *animation = 861;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 5:
+ *animation = 874;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(874) - 1) {
+ _animationState = 8;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(874) - 1;
+ }
+ break;
+
+ case 6:
+ if (_animationFrame == 1) {
+ Ambient_Sounds_Play_Sound(437, 99, 0, 0, 20);
+ }
+ *animation = 860;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(860)) {
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorFreeSlotB, 0);
+ }
+ break;
+
+ case 7:
+ *animation = 859;
+ _animationFrame++;
+ if (_animationFrame == 1) {
+ Ambient_Sounds_Play_Sound(439, 99, 0, 0, 25);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(859)) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(859);
+ }
+ _animationState = 8;
+ break;
+
+ case 8:
+ *animation = 859;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(859) - 1;
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+ return true;
+}
+
+bool AIScriptFreeSlotB::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case 0:
+ if ((unsigned int)(_animationState - 1) > 1) {
+ _animationState = 0;
+ _animationFrame = 0;
+ } else if (_animationState == 1) {
+ _animationState = 2;
+ }
+ break;
+
+ case 1:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 4:
+ if ((unsigned int)(_animationState - 1) > 1) {
+ _animationState = 0;
+ _animationFrame = 0;
+ } else if (_animationState == 1) {
+ _animationState = 2;
+ }
+ break;
+
+ case 6:
+ _animationState = 4;
+ _animationFrame = 0;
+ break;
+
+ case 7:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 8:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case 21:
+ _animationState = 6;
+ _animationFrame = 0;
+ break;
+
+ case 43:
+ _animationState = 1;
+ _animationFrame = 0;
+ break;
+
+ case 48:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+ }
+
+ return true;
+}
+
+void AIScriptFreeSlotB::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptFreeSlotB::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptFreeSlotB::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptFreeSlotB::FledCombat() {
+ // return false;
+}
+
+void AIScriptFreeSlotB::processGoal301() {
+ switch (Random_Query(1, 14)) {
+ case 1:
+ AI_Movement_Track_Append(kActorFreeSlotB, 450, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 451, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 450, 0);
+ break;
+
+ case 2:
+ World_Waypoint_Set(466, 74, 144.98f, -50.13f, -175.75f);
+ World_Waypoint_Set(547, 74, 105.6f, -50.13f, -578.46f);
+ World_Waypoint_Set(548, 74, 62.0f, -50.13f, -574.0f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 548, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 5);
+ break;
+
+ case 3:
+ AI_Movement_Track_Append(kActorFreeSlotB, 446, 15);
+ AI_Movement_Track_Append(kActorFreeSlotB, 447, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 449, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 448, 2);
+ AI_Movement_Track_Append(kActorFreeSlotB, 449, 0);
+ break;
+
+ case 4:
+ World_Waypoint_Set(466, 77, -22.70f, 6.39f, 33.12f);
+ World_Waypoint_Set(547, 77, -6.70f, -1.74f, -362.88f);
+ World_Waypoint_Set(548, 77, 164.0f, 11.87f, -1013.0f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 2);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 0);
+ AI_Movement_Track_Append(kActorFreeSlotB, 548, 0);
+ break;
+
+ case 5:
+ AI_Movement_Track_Append(kActorFreeSlotB, 457, 15);
+ AI_Movement_Track_Append(kActorFreeSlotB, 458, 0);
+ AI_Movement_Track_Append(kActorFreeSlotB, 459, 15);
+ break;
+
+ case 6:
+ AI_Movement_Track_Append(kActorFreeSlotB, 460, 15);
+ AI_Movement_Track_Append(kActorFreeSlotB, 461, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 460, 15);
+ break;
+
+ case 7:
+ if (Actor_Query_In_Set(kActorClovis, kSetUG07)) {
+ AI_Movement_Track_Append(kActorFreeSlotB, 39, 10);
+ } else {
+ World_Waypoint_Set(466, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(547, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(548, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 1);
+ }
+ break;
+
+ case 8:
+ World_Waypoint_Set(466, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(547, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(548, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 1);
+ break;
+
+ case 9:
+ World_Waypoint_Set(466, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(547, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(548, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 548, 1);
+ break;
+
+ case 10:
+ World_Waypoint_Set(466, 80, -88.78f, -12.21f, -184.08f);
+ World_Waypoint_Set(547, 80, 250.0f, -12.21f, -342.0f);
+ World_Waypoint_Set(548, 80, -164.78f, -12.21f, -832.08f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 548, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 1);
+ break;
+
+ case 11:
+ World_Waypoint_Set(466, 82, 91.0f, 156.94f, -498.0f);
+ World_Waypoint_Set(547, 82, -149.0f, 156.94f, -498.0f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 1);
+ break;
+
+ case 12:
+ World_Waypoint_Set(466, 82, 91.0f, 156.94f, -498.0f);
+ World_Waypoint_Set(547, 82, -149.0f, 156.94f, -498.0f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 5);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 1);
+ break;
+
+ case 13:
+ World_Waypoint_Set(466, 82, -152.51f, 277.31f, 311.98f);
+ World_Waypoint_Set(547, 82, -124.51f, 275.08f, 319.98f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 8);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 1);
+ break;
+
+ case 14:
+ World_Waypoint_Set(466, 84, -360.67f, 21.39f, 517.55f);
+ World_Waypoint_Set(547, 84, -250.67f, 21.39f, 477.55f);
+ World_Waypoint_Set(548, 84, -248.67f, 21.39f, -1454.45f);
+ AI_Movement_Track_Append(kActorFreeSlotB, 466, 1);
+ AI_Movement_Track_Append(kActorFreeSlotB, 547, 8);
+ AI_Movement_Track_Append(kActorFreeSlotB, 548, 1);
+ break;
+
+ default:
+ AI_Movement_Track_Append(kActorFreeSlotB, 39, Random_Query(1, 10));
+ break;
+ }
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/gaff.cpp b/engines/bladerunner/script/ai/gaff.cpp
index c26f0d907f..c5e629cab0 100644
--- a/engines/bladerunner/script/ai/gaff.cpp
+++ b/engines/bladerunner/script/ai/gaff.cpp
@@ -287,7 +287,7 @@ bool AIScriptGaff::GoalChanged(int currentGoalNumber, int newGoalNumber) {
return true;
case 303:
Actor_Face_Actor(kActorGaff, kActorMcCoy, 1);
- Actor_Change_Animation_Mode(kActorGaff, kAnimationModeCombatShoot);
+ Actor_Change_Animation_Mode(kActorGaff, kAnimationModeCombatAttack);
Sound_Play(27, 100, 0, 0, 50);
Actor_Change_Animation_Mode(kActorMcCoy, 48);
Actor_Retired_Here(kActorMcCoy, 12, 12, 1, -1);
diff --git a/engines/bladerunner/script/ai/generic_walker_a.cpp b/engines/bladerunner/script/ai/generic_walker_a.cpp
index 7acea89c25..0ba48811ed 100644
--- a/engines/bladerunner/script/ai/generic_walker_a.cpp
+++ b/engines/bladerunner/script/ai/generic_walker_a.cpp
@@ -354,8 +354,7 @@ bool AIScriptGenericWalkerA::prepareWalker() {
} else {
model = Random_Query(0, 5);
}
- }
- while (model == Global_Variable_Query(kVariableGenericWalkerBModel) || model == Global_Variable_Query(kVariableGenericWalkerCModel));
+ } while (model == Global_Variable_Query(kVariableGenericWalkerBModel) || model == Global_Variable_Query(kVariableGenericWalkerCModel));
Global_Variable_Set(kVariableGenericWalkerAModel, model);
Game_Flag_Set(kFlagGenericWalkerWaiting);
@@ -459,7 +458,7 @@ bool AIScriptGenericWalkerA::preparePath() {
int waypointEnd = 0;
do {
waypointStart = Random_Query(167, 171);
- } while (waypointEnd == 168 || waypointEnd == 169);
+ } while (waypointStart == 168 || waypointStart == 169);
do {
waypointEnd = Random_Query(167, 171);
} while (waypointEnd == waypointStart || waypointEnd == 168 || waypointEnd == 169);
diff --git a/engines/bladerunner/script/ai/generic_walker_b.cpp b/engines/bladerunner/script/ai/generic_walker_b.cpp
index a2ff58113f..2a6c3a1732 100644
--- a/engines/bladerunner/script/ai/generic_walker_b.cpp
+++ b/engines/bladerunner/script/ai/generic_walker_b.cpp
@@ -330,8 +330,7 @@ bool AIScriptGenericWalkerB::prepareWalker() {
} else {
model = Random_Query(0, 5);
}
- }
- while (model == Global_Variable_Query(kVariableGenericWalkerAModel) || model == Global_Variable_Query(kVariableGenericWalkerCModel));
+ } while (model == Global_Variable_Query(kVariableGenericWalkerAModel) || model == Global_Variable_Query(kVariableGenericWalkerCModel));
Global_Variable_Set(kVariableGenericWalkerBModel, model);
Game_Flag_Set(kFlagGenericWalkerWaiting);
@@ -435,7 +434,7 @@ bool AIScriptGenericWalkerB::preparePath() {
int waypointEnd = 0;
do {
waypointStart = Random_Query(167, 171);
- } while (waypointEnd == 168 || waypointEnd == 169);
+ } while (waypointStart == 168 || waypointStart == 169);
do {
waypointEnd = Random_Query(167, 171);
} while (waypointEnd == waypointStart || waypointEnd == 168 || waypointEnd == 169);
diff --git a/engines/bladerunner/script/ai/generic_walker_c.cpp b/engines/bladerunner/script/ai/generic_walker_c.cpp
index f317d5ad49..5c0478c645 100644
--- a/engines/bladerunner/script/ai/generic_walker_c.cpp
+++ b/engines/bladerunner/script/ai/generic_walker_c.cpp
@@ -331,9 +331,8 @@ bool AIScriptGenericWalkerC::prepareWalker() {
} else {
model = Random_Query(0, 5);
}
- }
// Here is probably bug in original code, because it not using kVariableGenericWalkerBModel but kVariableGenericWalkerCModel
- while (model == Global_Variable_Query(kVariableGenericWalkerAModel) || model == Global_Variable_Query(kVariableGenericWalkerBModel));
+ } while (model == Global_Variable_Query(kVariableGenericWalkerAModel) || model == Global_Variable_Query(kVariableGenericWalkerBModel));
Global_Variable_Set(kVariableGenericWalkerCModel, model);
@@ -438,7 +437,7 @@ bool AIScriptGenericWalkerC::preparePath() {
int waypointEnd = 0;
do {
waypointStart = Random_Query(167, 171);
- } while (waypointEnd == 168 || waypointEnd == 169);
+ } while (waypointStart == 168 || waypointStart == 169);
do {
waypointEnd = Random_Query(167, 171);
} while (waypointEnd == waypointStart || waypointEnd == 168 || waypointEnd == 169);
diff --git a/engines/bladerunner/script/ai/gordo.cpp b/engines/bladerunner/script/ai/gordo.cpp
index fd64112897..c44497176a 100644
--- a/engines/bladerunner/script/ai/gordo.cpp
+++ b/engines/bladerunner/script/ai/gordo.cpp
@@ -1157,7 +1157,7 @@ bool AIScriptGordo::ChangeAnimationMode(int mode) {
break;
}
break;
- case kAnimationModeCombatShoot:
+ case kAnimationModeCombatAttack:
_animationState = 18;
_animationFrame = 0;
break;
diff --git a/engines/bladerunner/script/ai/guzza.cpp b/engines/bladerunner/script/ai/guzza.cpp
index 0f99fa8a46..5a4459535e 100644
--- a/engines/bladerunner/script/ai/guzza.cpp
+++ b/engines/bladerunner/script/ai/guzza.cpp
@@ -728,7 +728,7 @@ bool AIScriptGuzza::ChangeAnimationMode(int mode) {
_animationFrame = 0;
}
break;
- case kAnimationModeCombatShoot:
+ case kAnimationModeCombatAttack:
_animationState = 31;
_animationFrame = 0;
break;
diff --git a/engines/bladerunner/script/ai/hanoi.cpp b/engines/bladerunner/script/ai/hanoi.cpp
new file mode 100644
index 0000000000..4b88be7c5f
--- /dev/null
+++ b/engines/bladerunner/script/ai/hanoi.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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptHanoi::AIScriptHanoi(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 0;
+ _var4 = 1;
+}
+
+void AIScriptHanoi::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 0;
+ _var4 = 1;
+
+ Actor_Set_Goal_Number(kActorHanoi, 0);
+}
+
+bool AIScriptHanoi::Update() {
+ if (Actor_Query_Goal_Number(kActorHolloway) == 240) {
+ AI_Countdown_Timer_Reset(kActorHanoi, 0);
+ }
+ if (Global_Variable_Query(kVariableChapter) == 3 && Actor_Query_Goal_Number(kActorHanoi) < 200) {
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ }
+ if (Player_Query_Current_Scene() != 56 && Actor_Query_Goal_Number(kActorHanoi) == 236) {
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ }
+ if (Player_Query_Current_Scene() == 56
+ && Actor_Query_Goal_Number(kActorHanoi) != 215
+ && Actor_Query_Goal_Number(kActorHanoi) != 230
+ && Actor_Query_Goal_Number(kActorHanoi) != 235
+ && Actor_Query_Goal_Number(kActorHanoi) != 236) {
+ if (Actor_Query_Inch_Distance_From_Waypoint(kActorMcCoy, 364) < 420) {
+ if (Actor_Query_Goal_Number(kActorHanoi) == 210) {
+ Actor_Set_Goal_Number(kActorHanoi, 211);
+ }
+ } else if (Actor_Query_Goal_Number(kActorHanoi) == 211) {
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ }
+ if (Actor_Query_Inch_Distance_From_Waypoint(kActorMcCoy, 361) < 240) {
+ if (Actor_Query_Goal_Number(kActorHanoi) == 210) {
+ Actor_Set_Goal_Number(kActorHanoi, 212);
+ }
+ } else if (Actor_Query_Goal_Number(kActorHanoi) == 212) {
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ }
+ if (Actor_Query_Inch_Distance_From_Actor(kActorMcCoy, kActorHysteriaPatron1) < 120
+ && Actor_Query_Which_Set_In(kActorHanoi) == 55
+ && Actor_Query_Goal_Number(kActorHanoi) != 213) {
+ Actor_Set_Goal_Number(kActorHanoi, 213);
+ }
+ }
+
+ return false;
+}
+
+void AIScriptHanoi::TimerExpired(int timer) {
+ if (timer == 0) {
+ if (Actor_Query_Goal_Number(kActorHanoi) == 215) {
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ return; //true;
+ }
+
+ if (Actor_Query_Goal_Number(kActorHanoi) == 220)
+ return; //false;
+
+ Actor_Set_Goal_Number(kActorHanoi, 202);
+ return; //true;
+ }
+ return; //false;
+}
+
+void AIScriptHanoi::CompletedMovementTrack() {
+ switch (Actor_Query_Goal_Number(kActorHanoi)) {
+ case 235:
+ Actor_Set_Goal_Number(kActorHanoi, 236);
+ break;
+
+ case 240:
+ Actor_Set_Goal_Number(kActorHanoi, 241);
+ break;
+
+ case 202:
+ Actor_Says(kActorHanoi, 130, 3);
+ Actor_Says(kActorDektora, 540, 30);
+ Actor_Set_Goal_Number(kActorHanoi, 203);
+ break;
+
+ case 203:
+ Actor_Face_Actor(kActorHanoi, kActorMcCoy, 1);
+ Actor_Face_Actor(kActorMcCoy, kActorHanoi, 1);
+ Actor_Change_Animation_Mode(kActorHanoi, 23);
+ Actor_Set_Invisible(kActorMcCoy, 1);
+ Actor_Says(kActorMcCoy, 3595, 3);
+ Actor_Says(kActorHanoi, 140, 3);
+ Actor_Set_Goal_Number(kActorHanoi, 220);
+ break;
+
+ case 213:
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ break;
+
+ default:
+ return; //false;
+ }
+
+ return; //true;
+}
+
+void AIScriptHanoi::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptHanoi::ClickedByPlayer() {
+ if (Actor_Query_Goal_Number(kActorHanoi) == 230 || Actor_Query_Goal_Number(kActorHanoi) == 235) {
+ Actor_Face_Actor(kActorMcCoy, kActorHanoi, 1);
+ Actor_Says(kActorMcCoy, 8915, 11);
+
+ if (Actor_Query_Goal_Number(kActorHanoi) == 230) {
+ Actor_Says(kActorHanoi, 210, 3);
+ }
+ }
+}
+
+void AIScriptHanoi::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptHanoi::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptHanoi::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptHanoi::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ if (Player_Query_Current_Scene() != 56 || otherActorId || combatMode != 1) {
+ return; //false;
+ }
+ Player_Set_Combat_Mode(0);
+ Player_Loses_Control();
+ Actor_Set_Goal_Number(kActorHanoi, 220);
+
+ return; //true;
+}
+
+void AIScriptHanoi::ShotAtAndMissed() {
+ // return false;
+}
+
+bool AIScriptHanoi::ShotAtAndHit() {
+ return false;
+}
+
+void AIScriptHanoi::Retired(int byActorId) {
+ // return false;
+}
+
+int AIScriptHanoi::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptHanoi::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ if (!newGoalNumber) {
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append(kActorHanoi, 39, 0);
+ AI_Movement_Track_Repeat(kActorHanoi);
+
+ return true;
+ }
+
+ switch (newGoalNumber) {
+ case 200:
+ AI_Countdown_Timer_Start(kActorHanoi, 0, 45);
+ break;
+
+ case 201:
+ AI_Countdown_Timer_Reset(kActorHanoi, 0);
+ break;
+
+ case 202:
+ if (Actor_Query_Which_Set_In(kActorMcCoy) == kSetNR07 && Actor_Query_In_Set(kActorDektora, kSetNR07)) {
+ Player_Loses_Control();
+ Actor_Put_In_Set(kActorHanoi, kSetNR07);
+ Actor_Set_At_XYZ(kActorHanoi, -102.0f, -73.5f, -233.0f, 0);
+ Async_Actor_Walk_To_Waypoint(kActorMcCoy, 338, 0, 0);
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append(kActorHanoi, 336, 1);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ } else {
+ Actor_Set_Goal_Number(kActorHanoi, 0);
+ }
+ break;
+
+ case 203:
+ if (Actor_Query_Which_Set_In(kActorMcCoy) != kSetNR07) {
+ return false;
+ }
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append(kActorHanoi, 337, 0);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 204:
+ Actor_Says(kActorHanoi, 210, 3);
+ Actor_Change_Animation_Mode(kActorHanoi, 23);
+ break;
+
+ case 210:
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append_With_Facing(kActorHanoi, 362, 0, 300);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 211:
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append_With_Facing(kActorHanoi, 363, 0, 500);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 212:
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append_With_Facing(kActorHanoi, 361, 0, 457);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 213:
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append_With_Facing(kActorHanoi, 365, Random_Query(15, 20), 600);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 215:
+ Actor_Put_In_Set(kActorHanoi, kSetNR03);
+ Actor_Set_At_Waypoint(kActorHanoi, 362, 300);
+ AI_Countdown_Timer_Reset(kActorHanoi, 0);
+ AI_Countdown_Timer_Start(kActorHanoi, 0, 6);
+ break;
+
+ case 220:
+ Game_Flag_Set(604);
+ AI_Countdown_Timer_Reset(kActorHanoi, 0);
+ Player_Loses_Control();
+ Player_Set_Combat_Mode(0);
+ Actor_Force_Stop_Walking(kActorMcCoy);
+ Actor_Change_Animation_Mode(kActorMcCoy, 48);
+ Actor_Set_Invisible(kActorMcCoy, 1);
+ AI_Movement_Track_Flush(kActorHanoi);
+ Actor_Put_In_Set(kActorHanoi, kSetNR01);
+ Actor_Set_At_XYZ(kActorHanoi, -444.0f, 24.0f, -845.0f, 512);
+ Actor_Change_Animation_Mode(kActorHanoi, 78);
+ Set_Enter(kSetNR01, kSetNR01);
+ break;
+
+ case 230:
+ AI_Movement_Track_Flush(kActorHanoi);
+ Actor_Put_In_Set(kActorHanoi, kSetNR05_NR08);
+ Actor_Set_At_XYZ(kActorHanoi, -1387.51f, 0.32f, 288.16f, 292);
+ break;
+
+ case 235:
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append(kActorHanoi, 439, 0);
+ AI_Movement_Track_Append(kActorHanoi, 39, 45);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 236:
+ break;
+
+ case 240:
+ Actor_Put_In_Set(kActorHanoi, kSetNR04);
+ Actor_Set_At_XYZ(kActorHanoi, -47.0f, 0.0f, 334.0f, 535);
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append(kActorHanoi, 549, 0);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ break;
+
+ case 241:
+ Actor_Face_Actor(kActorHanoi, kActorMcCoy, 1);
+ Actor_Change_Animation_Mode(kActorHanoi, 6);
+ Actor_Retired_Here(kActorMcCoy, 12, 12, 1, -1);
+ break;
+
+ case 9999:
+ AI_Movement_Track_Flush(kActorHanoi);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool AIScriptHanoi::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ if (_var2 == 1) {
+ *animation = 649;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(649)) {
+ *animation = 648;
+ _animationFrame = 0;
+ _var2 = 0;
+ }
+ } else if (_var2 == 0) {
+ *animation = 648;
+ if (_var3) {
+ _var3--;
+ if (!Random_Query(0, 6)) {
+ _var4 = -_var4;
+ }
+ } else {
+ _animationFrame += _var4;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(648)) {
+ _animationFrame = 0;
+ }
+ if (_animationFrame < 0) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(648) - 1;
+ }
+ if (_animationFrame == 5 || _animationFrame == 15 || _animationFrame == 11 || !_animationFrame) {
+ _var3 = Random_Query(5, 12);
+ }
+ if (_animationFrame >= 10 && _animationFrame <= 13) {
+ _var3 = Random_Query(0, 1);
+ }
+ if (!_animationFrame) {
+ if (!Random_Query(0, 4)) {
+ _var2 = 1;
+ }
+ }
+ }
+ }
+ break;
+
+ case 1:
+ if (_var2) {
+ *animation = 649;
+ if ( Slice_Animation_Query_Number_Of_Frames(649) < Slice_Animation_Query_Number_Of_Frames(649)) {
+ _animationFrame += 2;
+ } else {
+ _animationFrame -= 2;
+ }
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(649) - 1
+ || _animationFrame <= 0) {
+ _animationFrame = 0;
+ _animationState = _animationStateNext;
+ *animation = _animationNext;
+ }
+ } else {
+ _animationFrame = 0;
+ _animationState = _animationStateNext;
+ *animation = _animationNext;
+ }
+ break;
+
+ case 2:
+ *animation = 657;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(657)) {
+ _animationFrame = 0;
+ _animationState = 3;
+ *animation = 658;
+ }
+ break;
+
+ case 3:
+ *animation = 658;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(658)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 4:
+ *animation = 659;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(659)) {
+ _animationFrame = 0;
+ _animationState = 3;
+ *animation = 658;
+ }
+ break;
+
+ case 5:
+ *animation = 657;
+ _animationFrame--;
+ if (_animationFrame == 0) {
+ _animationState = 0;
+ _animationFrame = 0;
+ *animation = 648;
+ Actor_Face_Actor(kActorMcCoy, kActorHanoi, 1);
+ Actor_Set_Invisible(kActorMcCoy, 0);
+
+ if (Actor_Query_In_Set(kActorHanoi, kSetNR01) == 1) {
+ AI_Movement_Track_Flush(kActorHanoi);
+ AI_Movement_Track_Append(kActorHanoi, 350, 0);
+ AI_Movement_Track_Append(kActorHanoi, 39, 0);
+ AI_Movement_Track_Repeat(kActorHanoi);
+ }
+ }
+ break;
+
+ case 6:
+ *animation = 345;
+ _animationFrame++;
+ if (_animationFrame > 26) {
+ Actor_Change_Animation_Mode(kActorHanoi, 0);
+ _animationState = 0;
+ _animationFrame = 0;
+ *animation = 648;
+ Actor_Set_Goal_Number(kActorMcCoy, 210);
+ Actor_Set_Goal_Number(kActorHanoi, 210);
+ }
+ break;
+
+ case 7:
+ *animation = 645;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(645)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 8:
+ *animation = 642;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(642) - 1) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 9:
+ *animation = 643;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(643) - 1) {
+ Actor_Change_Animation_Mode(kActorHanoi, 4);
+ _animationState = 8;
+ _animationFrame = 0;
+ *animation = 642;
+ Actor_Set_Goal_Number(kActorHanoi, 241);
+ }
+ break;
+
+ case 10:
+ *animation = 644;
+ _animationFrame++;
+ if (_animationFrame == 4) {
+ Ambient_Sounds_Play_Sound(492, 77, 0, 0, 20);
+ }
+ if (_animationFrame == 6) {
+ Ambient_Sounds_Play_Sound(493, 97, 0, 0, 20);
+ }
+ if (_animationFrame == 5) {
+ Actor_Force_Stop_Walking(kActorMcCoy);
+ Actor_Change_Animation_Mode(kActorMcCoy, 48);
+ }
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(*animation) - 1) {
+ Actor_Change_Animation_Mode(kActorHanoi, 4);
+ _animationFrame = 0;
+ _animationState = 8;
+ *animation = 642;
+ }
+ break;
+
+ case 11:
+ *animation = 660;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(660)) {
+ *animation = 648;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 12:
+ *animation = 646;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(646)) {
+ *animation = 642;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 13:
+ *animation = 647;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(647) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 14:
+ *animation = 650;
+ if (!_animationFrame && _var1) {
+ _animationState = 0;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(650)) {
+ _animationFrame = 0;
+ }
+ }
+ break;
+
+ case 15:
+ *animation = 651;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(651)) {
+ _animationFrame = 0;
+ _animationState = 14;
+ *animation = 650;
+ }
+ break;
+
+ case 16:
+ *animation = 652;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(652)) {
+ _animationFrame = 0;
+ _animationState = 14;
+ *animation = 650;
+ }
+ break;
+
+ case 17:
+ *animation = 653;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(653)) {
+ _animationFrame = 0;
+ _animationState = 14;
+ *animation = 650;
+ }
+ break;
+
+ case 18:
+ *animation = 654;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(654)) {
+ _animationFrame = 0;
+ _animationState = 14;
+ *animation = 650;
+ }
+ break;
+
+ case 19:
+ *animation = 655;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(655)) {
+ _animationFrame = 0;
+ _animationState = 14;
+ *animation = 650;
+ }
+ break;
+
+ case 20:
+ *animation = 656;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(656)) {
+ _animationFrame = 0;
+ _animationState = 14;
+ *animation = 650;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptHanoi::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case kAnimationModeIdle:
+ if ((unsigned int)(_animationState - 2) > 1) {
+ _animationState = 0;
+ } else {
+ _animationState = 3;
+ }
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeWalk:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeTalk:
+ if (_animationState == 3) {
+ _animationState = 4;
+ _animationFrame = 0;
+ } else {
+ _animationStateNext = 14;
+ _animationNext = 650;
+ _animationState = 1;
+ }
+ break;
+
+ case kAnimationModeCombatIdle:
+ _animationState = 8;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeCombatAttack:
+ _animationState = 10;
+ _animationFrame = 0;
+ break;
+
+ case 12:
+ _animationStateNext = 15;
+ _animationNext = 651;
+ _animationState = 1;
+ break;
+
+ case 13:
+ _animationStateNext = 16;
+ _animationNext = 652;
+ _animationState = 1;
+ break;
+
+ case 14:
+ _animationStateNext = 17;
+ _animationNext = 653;
+ _animationState = 1;
+ break;
+
+ case 15:
+ _animationStateNext = 18;
+ _animationNext = 654;
+ _animationState = 1;
+ break;
+
+ case 16:
+ _animationStateNext = 18;
+ _animationNext = 654;
+ _animationState = 1;
+ break;
+
+ case 17:
+ _animationStateNext = 20;
+ _animationNext = 656;
+ _animationState = 1;
+ break;
+
+ case kAnimationModeHit:
+ case kAnimationModeCombatHit:
+ _animationState = 12;
+ _animationFrame = 0;
+ break;
+
+ case 23:
+ if (_animationState != 3 && _animationState != 4) {
+ Actor_Set_Invisible(kActorMcCoy, true);
+ _animationState = 2;
+ _animationFrame = 0;
+ } else {
+ _animationState = 5;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(657) - 1;
+ }
+ break;
+
+ case kAnimationModeDie:
+ _animationState = 13;
+ _animationFrame = 0;
+ break;
+
+ case 71:
+ _animationState = 9;
+ _animationFrame = 0;
+ break;
+
+ case 78:
+ _animationState = 6;
+ _animationFrame = 16;
+ break;
+ }
+
+ return true;
+}
+
+void AIScriptHanoi::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptHanoi::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptHanoi::ReachedMovementTrackWaypoint(int waypointId) {
+ if (waypointId == 365) {
+ Actor_Face_Actor(kActorHanoi, kActorHysteriaPatron1, true);
+ }
+
+ return true;
+}
+
+void AIScriptHanoi::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/hasan.cpp b/engines/bladerunner/script/ai/hasan.cpp
new file mode 100644
index 0000000000..ed2ebc717f
--- /dev/null
+++ b/engines/bladerunner/script/ai/hasan.cpp
@@ -0,0 +1,315 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptHasan::AIScriptHasan(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 6;
+ _var2 = 1;
+ _var3 = 0;
+ _var4 = 0;
+ _var5 = 0;
+ _var6 = 0;
+}
+
+void AIScriptHasan::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 6;
+ _var2 = 1;
+ _var3 = 0;
+ _var4 = 0;
+ _var5 = 0;
+ _var6 = 0;
+
+ Actor_Put_In_Set(kActorHasan, 0);
+ Actor_Set_At_XYZ(kActorHasan, -214.0f, 0.0f, -1379.0f, 371);
+ Actor_Set_Goal_Number(kActorHasan, 0);
+}
+
+bool AIScriptHasan::Update() {
+ if (Global_Variable_Query(kVariableChapter) != 3 || Actor_Query_Goal_Number(kActorHasan) >= 300)
+ return false;
+
+ Actor_Set_Goal_Number(kActorHasan, 300);
+ return true;
+}
+
+void AIScriptHasan::TimerExpired(int timer) {
+ //return false;
+}
+
+void AIScriptHasan::CompletedMovementTrack() {
+ //return false;
+}
+
+void AIScriptHasan::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptHasan::ClickedByPlayer() {
+ //return false;
+}
+
+void AIScriptHasan::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptHasan::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptHasan::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptHasan::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptHasan::ShotAtAndMissed() {
+ // return false;
+}
+
+bool AIScriptHasan::ShotAtAndHit() {
+ return false;
+}
+
+void AIScriptHasan::Retired(int byActorId) {
+ // return false;
+}
+
+int AIScriptHasan::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptHasan::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ if (newGoalNumber == 300) {
+ Actor_Put_In_Set(kActorHasan, kSetFreeSlotH);
+ Actor_Set_At_Waypoint(kActorHasan, 40, 0);
+ }
+ return false;
+}
+
+bool AIScriptHasan::UpdateAnimation(int *animation, int *frame) {
+ if (_var4) {
+ _var4--;
+ }
+ if (_var5) {
+ _var5--;
+ }
+
+ switch (_animationState) {
+ case 0:
+ if (_var6 == 1) {
+ *animation = 922;
+ if (_var3) {
+ _var3--;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(922)) {
+ _animationFrame = 0;
+ _var6 = 0;
+ *animation = 921;
+ _var1 = Random_Query(6, 14);
+ _var2 = 2 * Random_Query(0, 1) - 1;
+ _var4 = Random_Query(40, 60);
+ }
+ if (_animationFrame >= 10 && _animationFrame <= 14) {
+ _var3 = Random_Query(0, 1);
+ }
+ }
+ } else if (_var6 == 2) {
+ *animation = 923;
+ if (_var3) {
+ _var3--;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(923)) {
+ _animationFrame = 0;
+ _var6 = 0;
+ *animation = 921;
+ _var1 = Random_Query(6, 14);
+ _var2 = 2 * Random_Query(0, 1) - 1;
+ _var5 = Random_Query(40, 60);
+ }
+ if (_animationFrame == 14) {
+ _var3 = Random_Query(3, 10);
+ }
+ if (_animationFrame == 23) {
+ _var3 = Random_Query(0, 4);
+ }
+ }
+ } else if (_var6 == 0) {
+ *animation = 921;
+ if (_var3) {
+ _var3--;
+ } else {
+ _animationFrame += _var2;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(921)) {
+ _animationFrame = 0;
+ }
+ if (_animationFrame < 0) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(921) - 1;
+ }
+ if (!--_var1) {
+ _var2 = 2 * Random_Query(0, 1) - 1;
+ _var1 = Random_Query(6, 14);
+ _var3 = Random_Query(0, 4);
+ }
+ if (!_animationFrame) {
+ _var6 = Random_Query(0, 2);
+ }
+ if (_var6 == 1 && _var4) {
+ _var6 = 0;
+ }
+ if (_var6 == 2 && _var5) {
+ _var6 = 0;
+ }
+ }
+ }
+ break;
+
+ case 1:
+ *animation = 925;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(925)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 2:
+ *animation = 926;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(926)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 925;
+ }
+ break;
+
+ case 3:
+ *animation = 927;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(927)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 925;
+ }
+ break;
+
+ case 4:
+ *animation = 928;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(928)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 925;
+ }
+ break;
+
+ case 5:
+ *animation = 929;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(929)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 925;
+ }
+ break;
+
+ case 6:
+ *animation = 930;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(930)) {
+ _animationFrame = 0;
+ _animationState = 1;
+ *animation = 925;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptHasan::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case 0:
+ _animationState = 0;
+ _var6 = 0;
+ _animationFrame = 0;
+ break;
+
+ case 3:
+ _animationState = 1;
+ _var6 = 0;
+ _animationFrame = 0;
+ break;
+
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ _animationState = 6;
+ _var6 = 0;
+ _animationFrame = 0;
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
+void AIScriptHasan::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptHasan::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptHasan::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptHasan::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/hysteria_patron1.cpp b/engines/bladerunner/script/ai/hysteria_patron1.cpp
index 44278ac5e9..6eadd74976 100644
--- a/engines/bladerunner/script/ai/hysteria_patron1.cpp
+++ b/engines/bladerunner/script/ai/hysteria_patron1.cpp
@@ -34,7 +34,7 @@ void AIScriptHysteriaPatron1::Initialize() {
_animationNext = 0;
Actor_Put_In_Set(kActorHysteriaPatron1, kSetNR03);
- Actor_Set_At_XYZ(kActorHysteriaPatron1, 50.0f, -6.5900002f, -1030.0f, 524);
+ Actor_Set_At_XYZ(kActorHysteriaPatron1, 50.0f, -6.59f, -1030.0f, 524);
}
bool AIScriptHysteriaPatron1::Update() {
diff --git a/engines/bladerunner/script/ai/leon.cpp b/engines/bladerunner/script/ai/leon.cpp
index fad9da3cfb..fdcb538f0a 100644
--- a/engines/bladerunner/script/ai/leon.cpp
+++ b/engines/bladerunner/script/ai/leon.cpp
@@ -386,7 +386,7 @@ bool AIScriptLeon::ChangeAnimationMode(int mode) {
_animationFrame = 0;
var_45EDAC = 0;
break;
- case kAnimationModeCombatShoot:
+ case kAnimationModeCombatAttack:
_animationState = 10;
_animationFrame = 0;
break;
diff --git a/engines/bladerunner/script/ai/lucy.cpp b/engines/bladerunner/script/ai/lucy.cpp
index aebeac7322..464f228179 100644
--- a/engines/bladerunner/script/ai/lucy.cpp
+++ b/engines/bladerunner/script/ai/lucy.cpp
@@ -227,7 +227,7 @@ void AIScriptLucy::Retired(int byActorId) {
if ((byActorId == kActorSteele || byActorId == kActorMcCoy)
&& Actor_Query_In_Set(kActorSteele, kSetHF06)
&& Actor_Query_In_Set(kActorMcCoy, kSetHF06)) {
- Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, 0, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorMcCoy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
if (Query_Difficulty_Level() && byActorId == kActorMcCoy && Game_Flag_Query(46)) {
Global_Variable_Increment(2, 200);
@@ -861,10 +861,10 @@ void AIScriptLucy::checkCombat() {
&& Global_Variable_Query(kVariableChapter) == 5
&& Actor_Query_Goal_Number(kActorLucy) != 450) {
if (Global_Variable_Query(kVariableAffectionTowards) == 3) {
- Global_Variable_Set(45, 0);
+ Global_Variable_Set(kVariableAffectionTowards, 0);
}
Actor_Set_Goal_Number(kActorLucy, 450);
- Non_Player_Actor_Combat_Mode_On(kActorLucy, 0, 0, 0, 4, 0, 1, 2, -1, 0, 0, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorLucy, kActorCombatStateIdle, false, kActorMcCoy, 4, kAnimationModeIdle, kAnimationModeWalk, kAnimationModeRun, -1, 0, 0, 10, 300, false);
}
}
diff --git a/engines/bladerunner/script/ai/luther.cpp b/engines/bladerunner/script/ai/luther.cpp
new file mode 100644
index 0000000000..21df880d64
--- /dev/null
+++ b/engines/bladerunner/script/ai/luther.cpp
@@ -0,0 +1,439 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptLuther::AIScriptLuther(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _flag = false;
+}
+
+void AIScriptLuther::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _flag = false;
+
+ Actor_Put_In_Set(kActorLuther, kSetUG16);
+ Actor_Set_At_XYZ(kActorLuther, 176.91f, -40.67f, 225.92f, 486);
+ Actor_Set_Goal_Number(kActorLuther, 400);
+ Actor_Set_Targetable(kActorLuther, 1);
+}
+
+bool AIScriptLuther::Update() {
+ if (!Actor_Query_Is_In_Current_Set(kActorLuther)
+ || Player_Query_Combat_Mode() != 1
+ || Global_Variable_Query(29)
+ || Game_Flag_Query(596)
+ || Global_Variable_Query(kVariableChapter) != 4) {
+ if (Actor_Query_Goal_Number(kActorLuther) == 400 && Actor_Query_Goal_Number(kActorLuther) != 499) {
+ Actor_Set_Goal_Number(kActorLuther, 401);
+ } else if (Actor_Query_Goal_Number(kActorLuther) == 494) {
+ Actor_Set_Goal_Number(kActorLuther, 495);
+ ChangeAnimationMode(48);
+ } else if (Actor_Query_Goal_Number(kActorLuther) != 495 || Game_Flag_Query(587)) {
+ if (Actor_Query_Goal_Number(kActorLuther) != 497
+ || Global_Variable_Query(29) >= 2
+ || Game_Flag_Query(568)) {
+ if (Actor_Query_Goal_Number(kActorLuther) != 497
+ || Global_Variable_Query(29) <= 1
+ || Game_Flag_Query(568)) {
+ if (Actor_Query_Goal_Number(kActorLuther) == 498) {
+ Game_Flag_Set(595);
+ Actor_Set_Goal_Number(kActorLuther, 499);
+ Actor_Set_Targetable(kActorLuther, 0);
+ } else {
+ return false;
+ }
+ } else {
+ Actor_Set_Targetable(kActorLuther, 0);
+ Actor_Set_Goal_Number(kActorLuther, 498);
+ Actor_Set_Targetable(kActorLuther, 0);
+ }
+ } else {
+ Game_Flag_Set(568);
+ ChangeAnimationMode(50);
+ ChangeAnimationMode(48);
+ Actor_Set_Goal_Number(kActorLuther, 498);
+ Actor_Set_Targetable(kActorLuther, 0);
+ Scene_Loop_Set_Default(5);
+ Scene_Loop_Start_Special(2, 4, 1);
+ Ambient_Sounds_Play_Sound(559, 50, 0, 0, 99);
+ Ambient_Sounds_Remove_Looping_Sound(516, 1);
+ }
+ } else {
+ AI_Countdown_Timer_Reset(kActorLuther, 2);
+ AI_Countdown_Timer_Start(kActorLuther, 2, 5);
+ Actor_Set_Goal_Number(kActorLuther, 496);
+ Game_Flag_Set(587);
+ }
+ } else {
+ Actor_Says(kActorMcCoy, 5720, 12);
+ Actor_Says(kActorLuther, 80, 13);
+ Actor_Says(kActorLance, 40, 12);
+ Game_Flag_Set(596);
+ }
+
+ return false;
+}
+
+void AIScriptLuther::TimerExpired(int timer) {
+ if (timer != 2)
+ return; //false;
+
+ AI_Countdown_Timer_Reset(kActorLuther, 2);
+ Actor_Set_Goal_Number(kActorLuther, 497);
+
+ return; //true;
+}
+
+void AIScriptLuther::CompletedMovementTrack() {
+ if (Actor_Query_Goal_Number(kActorLuther) != 401)
+ return; //false;
+
+ Actor_Set_Goal_Number(kActorLuther, 402);
+
+ return; //true;
+}
+
+void AIScriptLuther::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptLuther::ClickedByPlayer() {
+ //return false;
+}
+
+void AIScriptLuther::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptLuther::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptLuther::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptLuther::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptLuther::ShotAtAndMissed() {
+ // return false;
+}
+
+bool AIScriptLuther::ShotAtAndHit() {
+ if (Actor_Query_Which_Set_In(kActorLuther) == 19) {
+ Actor_Set_Health(kActorLuther, 50, 50);
+ }
+ Global_Variable_Increment(29, 1);
+ Music_Stop(2);
+ if (Global_Variable_Query(29) <= 0) {
+ return false;
+ }
+ if (!Game_Flag_Query(560)) {
+ Game_Flag_Set(557);
+ }
+ Actor_Set_Goal_Number(kActorLuther, 494);
+
+ return true;
+}
+
+void AIScriptLuther::Retired(int byActorId) {
+ Actor_Set_Goal_Number(kActorLuther, 599);
+}
+
+int AIScriptLuther::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptLuther::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ switch (newGoalNumber) {
+ case 401:
+ AI_Movement_Track_Flush(kActorLuther);
+ AI_Movement_Track_Append(kActorLuther, 39, 20);
+ AI_Movement_Track_Append_With_Facing(kActorLuther, 368, 120, 486);
+ AI_Movement_Track_Append(kActorLuther, 40, 10);
+ AI_Movement_Track_Repeat(kActorLuther);
+ break;
+
+ case 402:
+ Actor_Set_Goal_Number(kActorLuther, 401);
+ break;
+
+ case 403:
+ AI_Movement_Track_Flush(kActorLuther);
+ break;
+
+ case 499:
+ Actor_Set_Goal_Number(kActorLuther, 599);
+ break;
+ }
+
+ return false;
+}
+
+bool AIScriptLuther::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ *animation = 346;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(346) - 1) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 1:
+ *animation = 348;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(348) - 1) {
+ *animation = 346;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorLuther, 0);
+ }
+ break;
+
+ case 2:
+ if (!_animationFrame && _flag) {
+ *animation = 346;
+ _animationState = 0;
+ } else {
+ *animation = 349;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(349) - 1) {
+ _animationFrame = 0;
+ }
+ }
+ break;
+
+ case 3:
+ *animation = 350;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(350) - 1) {
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 349;
+ }
+ break;
+
+ case 4:
+ *animation = 351;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(351) - 1) {
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 349;
+ }
+ break;
+
+ case 5:
+ *animation = 352;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(352) - 1) {
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 349;
+ }
+ break;
+
+ case 6:
+ *animation = 353;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(353) - 1) {
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 349;
+ }
+ break;
+
+ case 7:
+ *animation = 354;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(354) - 1) {
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 349;
+ }
+ break;
+
+ case 8:
+ *animation = 355;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(355) - 1) {
+ _animationFrame = 0;
+ _animationState = 2;
+ *animation = 349;
+ }
+ break;
+
+ case 9:
+ *animation = 356;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(356) - 1) {
+ *animation = 346;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorLuther, 0);
+ }
+ break;
+
+ case 10:
+ *animation = 357;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(357) - 1) {
+ Actor_Change_Animation_Mode(kActorLuther, 50);
+ *animation = 358;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 11:
+ *animation = 358;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(358) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 12:
+ *animation = 359;
+ if (_animationFrame == 12) {
+ Ambient_Sounds_Play_Sound(557, 59, 0, 0, 20);
+ }
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(*animation) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptLuther::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case 0:
+ if ((unsigned int)(_animationState - 2) > 6) {
+ _animationState = 0;
+ _animationFrame = 0;
+ } else {
+ _flag = 1;
+ }
+ break;
+
+ case 3:
+ _animationState = 2;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 6:
+ _animationState = 9;
+ _animationFrame = 0;
+ break;
+
+ case 12:
+ _animationState = 3;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 13:
+ _animationState = 4;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 14:
+ _animationState = 5;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 15:
+ _animationState = 6;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 16:
+ _animationState = 7;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 17:
+ _animationState = 8;
+ _animationFrame = 0;
+ _flag = 0;
+ break;
+
+ case 23:
+ _animationState = 1;
+ _animationFrame = 0;
+ break;
+
+ case 48:
+ _animationState = 12;
+ _animationFrame = 0;
+ break;
+
+ case 50:
+ _animationState = 11;
+ _animationFrame = 0;
+ break;
+ }
+
+ return true;
+}
+
+void AIScriptLuther::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptLuther::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptLuther::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptLuther::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/mccoy.cpp b/engines/bladerunner/script/ai/mccoy.cpp
index 554de0cd80..1e3dff8c1b 100644
--- a/engines/bladerunner/script/ai/mccoy.cpp
+++ b/engines/bladerunner/script/ai/mccoy.cpp
@@ -242,22 +242,22 @@ bool AIScriptMcCoy::ShotAtAndHit() {
void AIScriptMcCoy::Retired(int byActorId) {
if (byActorId == kActorSteele && Actor_Query_In_Set(kActorSteele, kSetHF06)) {
if (Actor_Query_In_Set(kActorDektora, kSetHF06) && Actor_Query_Goal_Number(kActorDektora) != 599) {
- Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, kActorDektora, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorDektora, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
} else if (Actor_Query_In_Set(kActorLucy, kSetHF06) && Actor_Query_Goal_Number(kActorLucy) != 599) {
- Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, kActorLucy, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorLucy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
}
if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerLeary, kSetHF05) && Actor_Query_In_Set(kActorDektora, kSetHF05) && Actor_Query_Goal_Number(kActorDektora) != 599) {
- Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorDektora, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorDektora, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerGrayford, kSetHF05) && Actor_Query_In_Set(kActorDektora, kSetHF05) && Actor_Query_Goal_Number(kActorDektora) != 599) {
- Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorDektora, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorDektora, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerLeary, kSetHF05) && Actor_Query_In_Set(kActorLucy, kSetHF05) && Actor_Query_Goal_Number(kActorLucy) != 599) {
- Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorLucy, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorLucy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerGrayford, kSetHF05) && Actor_Query_In_Set(kActorLucy, kSetHF05) && Actor_Query_Goal_Number(kActorLucy) != 599) {
- Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorLucy, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorLucy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
}
}
@@ -307,7 +307,7 @@ bool AIScriptMcCoy::GoalChanged(int currentGoalNumber, int newGoalNumber) {
return true;
case 230:
dword_45A0FC = Actor_Query_Goal_Number(kActorSteele) == 215;
- Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeCombatShoot);
+ Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeCombatAttack);
return true;
case 220:
Actor_Change_Animation_Mode(kActorMcCoy, 75);
@@ -412,7 +412,7 @@ bool AIScriptMcCoy::GoalChanged(int currentGoalNumber, int newGoalNumber) {
case 400:
Actor_Set_Health(kActorMcCoy, 50, 50);
Game_Flag_Set(373);
- v5 = Global_Variable_Query(45);
+ v5 = Global_Variable_Query(kVariableAffectionTowards);
if (v5 == 1) {
Actor_Modify_Friendliness_To_Other(kActorSteele, kActorMcCoy, 3);
} else if (v5 == 2) {
@@ -428,14 +428,14 @@ bool AIScriptMcCoy::GoalChanged(int currentGoalNumber, int newGoalNumber) {
if (Actor_Query_Friendliness_To_Other(kActorSteele, kActorMcCoy) < Actor_Query_Friendliness_To_Other(kActorClovis, kActorMcCoy)) {
Game_Flag_Set(653);
}
- v7 = Global_Variable_Query(45);
+ v7 = Global_Variable_Query(kVariableAffectionTowards);
if (v7 == 1) {
if (Game_Flag_Query(653)) {
- Global_Variable_Set(45, 0);
+ Global_Variable_Set(kVariableAffectionTowards, 0);
}
} else if (v7 == 2 || v7 == 3) {
if (!Game_Flag_Query(653)) {
- Global_Variable_Set(45, 0);
+ Global_Variable_Set(kVariableAffectionTowards, 0);
}
}
if (!Game_Flag_Query(653)) {
@@ -1382,7 +1382,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
break;
}
break;
- case kAnimationModeCombatShoot:
+ case kAnimationModeCombatAttack:
_animationState = 21;
_animationFrame = 0;
break;
@@ -1503,7 +1503,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
}
}
break;
- case 21:
+ case kAnimationModeHit:
switch (_animationState) {
case 14:
case 15:
@@ -1520,7 +1520,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
}
_animationFrame = 0;
break;
- case 16:
+ default:
if (Random_Query(0, 1) == 1) {
_animationState = 26;
} else {
@@ -1530,7 +1530,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
break;
}
break;
- case 22:
+ case kAnimationModeCombatHit:
if (Random_Query(0, 1) == 1) {
_animationState = 23;
} else {
@@ -1587,7 +1587,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
_animationState = 41;
_animationFrame = 0;
break;
- case 48:
+ case kAnimationModeDie:
switch (_animationState) {
case 14:
case 15:
@@ -1610,7 +1610,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
break;
}
break;
- case 49:
+ case kAnimationModeCombatDie:
_animationState = 28;
_animationFrame = 0;
break;
@@ -1622,7 +1622,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
_animationState = 55;
_animationFrame = 0;
break;
- case 53:
+ case kAnimationModeSit:
if (_animationState != 60 && (Player_Query_Current_Set() == kSetNR03 || Player_Query_Current_Set() == kSetNR05_NR08)) {
_animationState = 60;
_animationFrame = 0;
diff --git a/engines/bladerunner/script/ai/mutant1.cpp b/engines/bladerunner/script/ai/mutant1.cpp
index 9ecaf9d80e..eb1c0562af 100644
--- a/engines/bladerunner/script/ai/mutant1.cpp
+++ b/engines/bladerunner/script/ai/mutant1.cpp
@@ -83,7 +83,7 @@ bool AIScriptMutant1::Update() {
case 410:
if (Actor_Query_Which_Set_In(kActorMutant1) != Player_Query_Current_Set()) {
- Non_Player_Actor_Combat_Mode_Off(70);
+ Non_Player_Actor_Combat_Mode_Off(kActorMutant1);
Actor_Set_Goal_Number(kActorMutant1, 403);
}
break;
@@ -326,28 +326,23 @@ bool AIScriptMutant1::GoalChanged(int currentGoalNumber, int newGoalNumber) {
case 410:
switch (Actor_Query_Which_Set_In(kActorMutant1)) {
case kSetUG01:
- Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 11, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG04:
case kSetUG05:
case kSetUG06:
- Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 10, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG07:
- Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 12, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 12, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG10:
- Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
- break;
-
case kSetUG12:
- Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
- break;
case kSetUG14:
- Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
}
return true;
diff --git a/engines/bladerunner/script/ai/mutant2.cpp b/engines/bladerunner/script/ai/mutant2.cpp
index 6a51c710dd..6317311088 100644
--- a/engines/bladerunner/script/ai/mutant2.cpp
+++ b/engines/bladerunner/script/ai/mutant2.cpp
@@ -305,25 +305,19 @@ bool AIScriptMutant2::GoalChanged(int currentGoalNumber, int newGoalNumber) {
case 410:
switch (Actor_Query_Which_Set_In(kActorMutant2)) {
case kSetUG01:
- Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 11, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant2, kActorCombatStateIdle, false, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG04:
case kSetUG05:
case kSetUG06:
- Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 10, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant2, kActorCombatStateIdle, false, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG10:
- Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
- break;
-
case kSetUG12:
- Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
- break;
-
case kSetUG14:
- Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant2, kActorCombatStateIdle, false, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
}
return true;
diff --git a/engines/bladerunner/script/ai/mutant3.cpp b/engines/bladerunner/script/ai/mutant3.cpp
index 76a9a0edff..db161d8d5a 100644
--- a/engines/bladerunner/script/ai/mutant3.cpp
+++ b/engines/bladerunner/script/ai/mutant3.cpp
@@ -316,24 +316,19 @@ bool AIScriptMutant3::GoalChanged(int currentGoalNumber, int newGoalNumber) {
case 410:
switch (Actor_Query_Which_Set_In(kActorMutant3)) {
case kSetUG01:
- Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 11, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant3, kActorCombatStateIdle, false, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG04:
case kSetUG05:
case kSetUG06:
- Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 10, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant3, kActorCombatStateIdle, false, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
case kSetUG10:
- Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
- break;
case kSetUG12:
- Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
- break;
-
case kSetUG14:
- Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorMutant3, kActorCombatStateIdle, false, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
break;
}
break;
@@ -342,6 +337,7 @@ bool AIScriptMutant3::GoalChanged(int currentGoalNumber, int newGoalNumber) {
AI_Movement_Track_Flush(kActorMutant3);
AI_Movement_Track_Append(kActorMutant3, 39, 100);
AI_Movement_Track_Repeat(kActorMutant3);
+ break;
case 599:
AI_Movement_Track_Flush(kActorMutant3);
diff --git a/engines/bladerunner/script/ai/officer_grayford.cpp b/engines/bladerunner/script/ai/officer_grayford.cpp
new file mode 100644
index 0000000000..a1f9b11f9b
--- /dev/null
+++ b/engines/bladerunner/script/ai/officer_grayford.cpp
@@ -0,0 +1,1422 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptOfficerGrayford::AIScriptOfficerGrayford(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 0;
+}
+
+void AIScriptOfficerGrayford::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 0;
+
+ Actor_Put_In_Set(kActorOfficerGrayford, kSetFreeSlotG);
+ Actor_Set_At_Waypoint(kActorOfficerGrayford, 39, 0);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 0);
+}
+
+bool AIScriptOfficerGrayford::Update() {
+ if (Global_Variable_Query(kVariableChapter) == 4 && Actor_Query_Goal_Number(kActorOfficerGrayford) < 300) {
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 300);
+ } else if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_Goal_Number(kActorOfficerGrayford) < 400) {
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 400);
+ } else if (!Game_Flag_Query(177)
+ && Actor_Query_Goal_Number(kActorOfficerGrayford) > 102
+ && Actor_Query_Goal_Number(kActorOfficerGrayford) < 110) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 110);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 0) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 1);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 10) {
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 0);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 102) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 103);
+ } else if (Game_Flag_Query(629)) {
+ AI_Movement_Track_Unpause(kActorGenwalkerA);
+ AI_Movement_Track_Unpause(kActorGenwalkerB);
+ AI_Movement_Track_Unpause(kActorGenwalkerC);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 310
+ && Actor_Query_Which_Set_In(kActorOfficerGrayford) != Player_Query_Current_Set()) {
+ Non_Player_Actor_Combat_Mode_Off(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 599
+ && Actor_Query_Which_Set_In(kActorOfficerGrayford) != Player_Query_Current_Set()) {
+ Actor_Set_Health(kActorOfficerGrayford, 50, 50);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 305) {
+ switch (Actor_Query_Which_Set_In(kActorOfficerGrayford)) {
+ case kSetRC03:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 18, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetUG01:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetUG04:
+ case kSetUG05:
+ case kSetUG06:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetUG08:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 13, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetUG10:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetUG12:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 16, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetUG14:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 17, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetMA07:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 7, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetNR01:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 3, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetDR01_DR02_DR04:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 0, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetBB01:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 1, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ case kSetCT11:
+ if (Actor_Query_Which_Set_In(kActorOfficerGrayford) == Player_Query_Current_Set()) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 310);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 5, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
+ }
+ break;
+
+ }
+ }
+ return false;
+}
+
+void AIScriptOfficerGrayford::TimerExpired(int timer) {
+ if (timer == 2) {
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+ if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 104) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 105);
+ } else if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 105) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 104);
+ }
+ }
+}
+
+void AIScriptOfficerGrayford::CompletedMovementTrack() {
+ switch (Actor_Query_Goal_Number(kActorOfficerGrayford)) {
+ case 1:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 2);
+ break;
+
+ case 2:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 3);
+ break;
+
+ case 3:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 4);
+ break;
+
+ case 4:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 5);
+ break;
+
+ case 5:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 6);
+ break;
+
+ case 6:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 7);
+ break;
+
+ case 7:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 8);
+ break;
+
+ case 8:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 9);
+ break;
+
+ case 9:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 10);
+ break;
+
+ case 104:
+ case 105:
+ if (Random_Query(0, 2)) {
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 43);
+ } else {
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+ AI_Countdown_Timer_Start(kActorOfficerGrayford, 2, Random_Query(6, 12));
+ }
+ Actor_Face_Waypoint(kActorOfficerGrayford, 97, true);
+ // return false;
+ break;
+
+ case 305:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 306);
+ break;
+
+ case 307:
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateIdle, true, kActorMcCoy, 12, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 15, 300, false);
+ break;
+
+ case 308:
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, kAnimationModeCombatIdle);
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ break;
+
+ }
+
+ // return true;
+}
+
+void AIScriptOfficerGrayford::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptOfficerGrayford::ClickedByPlayer() {
+ switch (Actor_Query_Goal_Number(kActorOfficerGrayford)) {
+ case 1:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 99);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ if (Random_Query(1, 2) == 1) {
+ Actor_Says(kActorMcCoy, 5075, 14);
+ } else {
+ Actor_Says(kActorMcCoy, 4515, 13);
+ Actor_Says(kActorOfficerGrayford, 230, 13);
+ }
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 1);
+ break;
+
+ case 2:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 99);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ if (Random_Query(1, 2) == 1) {
+ Actor_Says(kActorMcCoy, 5075, 14);
+ } else {
+ Actor_Says(kActorMcCoy, 4515, 13);
+ Actor_Says(kActorOfficerGrayford, 330, 13);
+ }
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 2);
+ break;
+
+ case 3:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 99);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ if (Random_Query(1, 2) == 1) {
+ Actor_Says(kActorMcCoy, 5075, 14);
+ } else {
+ Actor_Says(kActorMcCoy, 5075, 14); // bug in the original? Matches the above statement
+ }
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 3);
+ break;
+
+ case 4:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 99);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ if (Random_Query(1, 2) == 1) {
+ Actor_Says(kActorMcCoy, 5075, 14);
+ Actor_Says(kActorOfficerGrayford, 160, 13);
+ } else {
+ Actor_Says(kActorMcCoy, 4515, 13);
+ Actor_Says(kActorOfficerGrayford, 330, 13);
+ }
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 4);
+ break;
+
+ case 7:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 99);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Says(kActorMcCoy, 4515, 14);
+ Actor_Says(kActorOfficerGrayford, 330, 13);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 7);
+ break;
+
+ case 8:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 99);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ Actor_Says(kActorMcCoy, 5075, 13);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 8);
+ break;
+
+ case 104:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 199);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Says(kActorMcCoy, 1005, kAnimationModeTalk);
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+ if (_animationState == 35 || _animationState == 34) {
+ _animationState = 37;
+ _animationFrame = 0;
+ }
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ Actor_Says(kActorOfficerGrayford, 190, 19);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 104);
+ break;
+
+ case 105:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 199);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Says(kActorMcCoy, 1005, kAnimationModeTalk);
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+ if (_animationState == 35 || _animationState == 34) {
+ _animationState = 37;
+ _animationFrame = 0;
+ }
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, 1);
+ Actor_Says(kActorOfficerGrayford, 190, 19);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 105);
+ break;
+
+ default:
+ return; //false;
+ break;
+ }
+
+ return; //true;
+}
+
+void AIScriptOfficerGrayford::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptOfficerGrayford::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptOfficerGrayford::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptOfficerGrayford::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptOfficerGrayford::ShotAtAndMissed() {
+ // return false;
+}
+
+bool AIScriptOfficerGrayford::ShotAtAndHit() {
+ if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 307)
+ Actor_Set_Health(kActorOfficerGrayford, 50, 50);
+
+ return false;
+}
+
+void AIScriptOfficerGrayford::Retired(int byActorId) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 599);
+ Game_Flag_Set(607);
+}
+
+int AIScriptOfficerGrayford::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptOfficerGrayford::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ switch (newGoalNumber) {
+ case 1:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 82, Random_Query(5, 20));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 2:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 76, Random_Query(10, 20));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 3:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 77, Random_Query(5, 15));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 4:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 78, Random_Query(5, 15));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 5:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 6:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 79, Random_Query(5, 15));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 7:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 80, 1);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 8:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 81, Random_Query(5, 15));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 9:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 82, Random_Query(5, 15));
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 101:
+ Player_Loses_Control();
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Put_In_Set(kActorOfficerGrayford, kSetDR01_DR02_DR04);
+ Actor_Set_At_Waypoint(kActorOfficerGrayford, 110, 0);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Loop_Actor_Walk_To_Waypoint(kActorOfficerGrayford, 111, 0, false, true);
+
+ _animationState = 23;
+ _animationFrame = kActorMcCoy;
+
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+
+ if (Game_Flag_Query(713)) {
+ Actor_Set_Goal_Number(kActorMcCoy, 500);
+ } else {
+ Actor_Says(kActorMcCoy, 960, 15);
+ Actor_Says(kActorMcCoy, 965, 18);
+ _animationState = 24;
+ }
+ return true;
+
+ case 102:
+ return true;
+
+ case 103:
+ Actor_Says(kActorOfficerGrayford, 120, 19);
+ Actor_Says_With_Pause(kActorMcCoy, 970, 0.2f, 13);
+ Actor_Says(kActorMcCoy, 975, 12);
+
+ if (Actor_Clue_Query(kActorMcCoy, kClueMorajiInterview) == 1) {
+ Actor_Says(kActorMcCoy, 980, 16);
+ Actor_Says_With_Pause(kActorOfficerGrayford, 130, 0.1f, 13);
+ Actor_Says(kActorMcCoy, 985, 14);
+ Actor_Says_With_Pause(kActorMcCoy, 990, 0.0f, 17);
+ Actor_Says_With_Pause(kActorOfficerGrayford, 140, 1.0f, 16);
+ Actor_Says_With_Pause(kActorOfficerGrayford, 150, 0.0f, 17);
+ Actor_Says(kActorOfficerGrayford, 160, 15);
+ Actor_Says_With_Pause(kActorMcCoy, 995, 0.3f, 14);
+ }
+
+ Player_Gains_Control();
+
+ if (Actor_Query_Goal_Number(kActorMoraji) == 23) {
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMoraji, 1);
+ } else {
+ Actor_Face_Waypoint(kActorOfficerGrayford, 97, 1);
+ }
+
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 43);
+
+ if (Player_Query_Current_Scene() == 28) {
+ Actor_Says(kActorOfficerGrayford, 170, kAnimationModeTalk);
+ }
+ return true;
+
+ case 104:
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 112, 0);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 105:
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 113, 0);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 106:
+ Actor_Face_Actor(kActorMcCoy, kActorOfficerGrayford, true);
+ Actor_Says(kActorMcCoy, 1000, 14);
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Countdown_Timer_Reset(kActorOfficerGrayford, 2);
+
+ if (_animationState == 35 || _animationState == 34) {
+ _animationState = 37;
+ _animationFrame = 0;
+ }
+
+ Actor_Face_Actor(kActorOfficerGrayford, kActorMcCoy, true);
+ Actor_Says(kActorOfficerGrayford, 180, 18);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, currentGoalNumber);
+ break;
+
+ case 110:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 0);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ AI_Movement_Track_Flush(kActorMoraji);
+ AI_Movement_Track_Append(kActorMoraji, 41, 0);
+ AI_Movement_Track_Repeat(kActorMoraji);
+ return true;
+
+ case 300:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 305:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ switch (Random_Query(1, 10)) {
+ case 1:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 398, 15);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 399, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 400, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 401, 0);
+ AI_Movement_Track_Append_With_Facing(kActorOfficerGrayford, 402, 3, 276);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 403, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 404, 15);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 2:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 385, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 242, 2);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 386, 2);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 387, 15);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 3:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 390, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 391, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 392, 5);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 345, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 393, 15);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 4:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 381, 15);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 382, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 383, 15);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 382, 3);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 384, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 5:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 388, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 389, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 6:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 385, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 242, 2);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 386, 2);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 387, 15);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 7:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 394, 15);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 395, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 396, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 397, 15);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 396, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 395, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 430, 15);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 8:
+ switch (Random_Query(1, 7)) {
+ case 1:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 302, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 407, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 408, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ break; // and go to case 9 below
+
+ case 2:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 536, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 537, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 538, 5);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 537, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 536, 0);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ break; // and go to case 9 below
+
+ case 3:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 296, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 409, 2);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 296, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ break; // and go to case 9 below
+
+ case 4:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 411, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 412, 5);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 411, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ break; // and go to case 9 below
+
+ case 5:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 413, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 414, 0);
+ AI_Movement_Track_Append_With_Facing(kActorOfficerGrayford, 431, 0, 1017);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 432, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ break; // and go to case 9 below
+
+ case 6:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 415, 0);
+ AI_Movement_Track_Append_With_Facing(kActorOfficerGrayford, 416, 0, 620);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 417, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 418, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ break; // and go to case 9 below
+
+ case 7:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 405, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 406, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return false;
+
+ }
+ // fall through
+ // TODO bug in the game? there should be nothing track related after AI_Movement_Track_Repeat
+
+ case 9:
+ if (Random_Query(0, 1)) {
+ AI_Movement_Track_Append(kActorOfficerGrayford, 433, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 434, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 435, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ } else {
+ AI_Movement_Track_Append(kActorOfficerGrayford, 420, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 422, 2);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 421, 1);
+ AI_Movement_Track_Append_With_Facing(kActorOfficerGrayford, 422, 4, 182);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 420, 10);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ // TODO bug in the game? Same code bellow looks like a case 10 and are from set 84 whereas upper one are from set 81
+ AI_Movement_Track_Append(kActorOfficerGrayford, 310, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 307, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 309, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 310, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ }
+ return false;
+
+ case 10:
+ AI_Movement_Track_Append(kActorOfficerGrayford, 310, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 307, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 309, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 310, 0);
+ AI_Movement_Track_Append(kActorOfficerGrayford, 35, 30);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return false;
+
+ }
+ return false;
+
+ case 306:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 305);
+ return true;
+
+ case 307:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append_With_Facing(kActorOfficerGrayford, 419, 0, 512);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 308:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ AI_Movement_Track_Append_Run(kActorOfficerGrayford, 440, 0);
+ AI_Movement_Track_Append_Run(kActorOfficerGrayford, 441, 0);
+ AI_Movement_Track_Repeat(kActorOfficerGrayford);
+ return true;
+
+ case 399:
+ AI_Movement_Track_Flush(kActorOfficerGrayford);
+ Actor_Put_In_Set(kActorOfficerGrayford, kSetTB02_TB03);
+ Actor_Set_At_XYZ(kActorOfficerGrayford, -173.89f, 0.0f, 2084.22f, 859);
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, kAnimationModeCombatIdle);
+ return true;
+
+ case 599:
+ _animationState = 32;
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(624) - 1;
+ return true;
+
+ }
+ return false;
+}
+
+bool AIScriptOfficerGrayford::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ if (!_var1) {
+ *animation = 625;
+ }
+ if (_var1 == 1) {
+ *animation = 626;
+ }
+ if (_var1 == 2) {
+ *animation = 627;
+ }
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ _animationFrame = 0;
+ _var1 = 0;
+ if (!Random_Query(0, 1)) {
+ _var1 = Random_Query(1, 2);
+ }
+ }
+ break;
+
+ case 1:
+ *animation = 618;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(618)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 2:
+ *animation = 619;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(619)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 5:
+ *animation = 611;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(611)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 6:
+ *animation = 610;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(610)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 9:
+ if (!_animationFrame && _var2) {
+ *animation = 625;
+ _animationState = 0;
+ _var1 = 0;
+ _var2 = 0;
+ } else {
+ *animation = 629;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(629)) {
+ _animationFrame = 0;
+ _animationState = Random_Query(9, 11);
+ }
+ }
+ break;
+
+ case 10:
+ *animation = 630;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(630)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 11:
+ *animation = 631;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(631)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 12:
+ *animation = 632;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(632)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 13:
+ *animation = 633;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(633)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 14:
+ *animation = 634;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(634)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 15:
+ *animation = 635;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(635)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 16:
+ *animation = 636;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(636)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 17:
+ *animation = 637;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(637)) {
+ _animationFrame = 0;
+ _animationState = 9;
+ *animation = 629;
+ }
+ break;
+
+ case 18:
+ case 19:
+ *animation = 605;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(605)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 20:
+ *animation = 615;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(615)) {
+ _animationFrame = 0;
+ _animationState = 19;
+ }
+ break;
+
+ case 21:
+ *animation = 616;
+ _animationFrame++;
+ if (_animationFrame == 11) {
+ Ambient_Sounds_Play_Sound(556, 25, 0, 0, 25);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ *animation = 625;
+ _animationFrame = 0;
+ _animationState = 0;
+ _var1 = 0;
+ if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 101) {
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 102);
+ }
+ }
+ break;
+
+ case 22:
+ *animation = 617;
+ _animationFrame++;
+ if (_animationFrame == 3) {
+ int snd;
+ if (Random_Query(1, 2) == 1) {
+ snd = 9010;
+ } else {
+ snd = 9015;
+ }
+ Sound_Play_Speech_Line(kActorOfficerGrayford, snd, 75, 0, 99);
+ }
+ if (_animationFrame == 5) {
+ Actor_Combat_AI_Hit_Attempt(kActorOfficerGrayford);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(617)) {
+ _animationState = 19;
+ _animationFrame = 0;
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 4);
+ }
+ break;
+
+ case 23:
+ *animation = 617;
+ if (_animationFrame < 2) {
+ _animationFrame++;
+ }
+ break;
+
+ case 24:
+ *animation = 617;
+ _animationFrame--;
+ if (_animationFrame < 0) {
+ _animationFrame = 0;
+ _animationState = 21;
+ *animation = 616;
+ }
+ break;
+
+ case 27:
+ *animation = 608;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(608) - 1) {
+ _animationFrame = 0;
+ _animationState = 19;
+ *animation = 625;
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 4);
+ }
+ break;
+
+ case 28:
+ *animation = 609;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(609) - 1) {
+ _animationFrame = 0;
+ _animationState = 19;
+ *animation = 625;
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 4);
+ }
+ break;
+
+ case 29:
+ *animation = 622;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(622) - 1) {
+ *animation = 605;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 0);
+ }
+ break;
+
+ case 30:
+ *animation = 623;
+ _animationFrame++;
+ if (_animationFrame > Slice_Animation_Query_Number_Of_Frames(623) - 1) {
+ *animation = 605;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 0);
+ }
+ break;
+
+ case 31:
+ *animation = 612;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(612) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 32:
+ *animation = 624;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(624) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 34:
+ *animation = 639;
+ if (_var3) {
+ _var3--;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(639)) {
+ if (Random_Query(0, 1)) {
+ *animation = 641;
+ _animationState = 37;
+ } else {
+ *animation = 638;
+ _animationState = 35;
+ }
+ _animationFrame = 0;
+ } else {
+ if (_animationFrame == 12) {
+ _var3 = Random_Query(5, 18);
+ }
+ }
+ }
+ break;
+
+ case 35:
+ *animation = 638;
+ if (_var3) {
+ _var3--;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(638)) {
+ if (Random_Query(0, 1)) {
+ *animation = 641;
+ _animationState = 37;
+ } else {
+ *animation = 639;
+ _animationState = 34;
+ }
+ _animationFrame = 0;
+ } else {
+ if (_animationFrame == 10) {
+ _var3 = Random_Query(5, 18);
+ }
+ }
+ }
+ break;
+
+ case 36:
+ *animation = 640;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(640)) {
+ _animationFrame = 0;
+ _animationState = 34;
+ *animation = 639;
+ }
+ break;
+
+ case 37:
+ *animation = 641;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(641)) {
+ *animation = 625;
+ _animationState = 0;
+ _animationFrame = 0;
+
+ switch (Actor_Query_Goal_Number(kActorOfficerGrayford)) {
+ case 103:
+ case 104:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 105);
+ break;
+
+ case 105:
+ Actor_Set_Goal_Number(kActorOfficerGrayford, 104);
+ break;
+ }
+ }
+ break;
+
+ default:
+ *animation = 399;
+ break;
+ }
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptOfficerGrayford::ChangeAnimationMode(int mode) {
+ switch (mode) {
+ case kAnimationModeIdle:
+ switch (_animationState) {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ _var2 = 1;
+ break;
+
+ case 18:
+ {
+ int tmp = _animationFrame;
+ Actor_Change_Animation_Mode(kActorOfficerGrayford, 4);
+ _animationFrame = tmp;
+ _animationState = 19;
+ break;
+ }
+
+ case 19:
+ _animationState = 21;
+ _animationFrame = 0;
+ break;
+
+ case 20:
+ case 21:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ return true;
+
+ default:
+ _animationState = 0;
+ _animationFrame = 0;
+ break;
+ }
+ break;
+
+ case kAnimationModeWalk:
+ if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 101) {
+ _animationState = 6;
+ _animationFrame = 0;
+ } else if (_animationState != 1) {
+ _animationState = 1;
+ _animationFrame = 0;
+ }
+ break;
+
+ case kAnimationModeRun:
+ if (Actor_Query_Goal_Number(kActorOfficerGrayford) == 101) {
+ _animationState = 5;
+ _animationFrame = 0;
+ } else if (_animationState != 2) {
+ _animationState = 2;
+ _animationFrame = 0;
+ }
+ break;
+
+ case kAnimationModeTalk:
+ if (_animationState != 36 && _animationState != 34) {
+ _animationState = 9;
+ _animationFrame = 0;
+ _var2 = 0;
+ }
+ break;
+
+ case kAnimationModeCombatIdle:
+ switch (_animationState) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ _animationState = 19;
+ _animationFrame = 0;
+ break;
+
+ case 19:
+ case 20:
+ case 22:
+ case 24:
+ return true;
+
+ case 23:
+ _animationState = 24;
+ _animationFrame = 0;
+ break;
+
+ default:
+ _animationState = 20;
+ _animationFrame = 0;
+ }
+ break;
+
+ case kAnimationModeCombatAim:
+ _animationState = 23;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeCombatAttack:
+ _animationFrame = 0;
+ _animationState = 22;
+ break;
+
+ case kAnimationModeCombatWalk:
+ _animationState = 6;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeCombatRun:
+ _animationState = 5;
+ _animationFrame = 0;
+ break;
+
+ case 12:
+ _animationState = 10;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 13:
+ _animationState = 11;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 14:
+ _animationState = 12;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 15:
+ _animationState = 13;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 16:
+ _animationState = 14;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 17:
+ _animationState = 15;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 18:
+ _animationState = 16;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case 19:
+ _animationState = 17;
+ _animationFrame = 0;
+ _var2 = 0;
+ break;
+
+ case kAnimationModeHit:
+ switch (_animationState) {
+ case 19:
+ case 20:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ if (Random_Query(0, 1)) {
+ _animationState = 27;
+ } else {
+ _animationState = 28;
+ }
+ _animationFrame = 0;
+ break;
+
+ case 21:
+ if (Random_Query(0, 1)) {
+ _animationState = 29;
+ } else {
+ _animationState = 30;
+ }
+ _animationFrame = 0;
+ break;
+ }
+ break;
+
+ case kAnimationModeCombatHit:
+ if (Random_Query(0, 1)) {
+ _animationState = 27;
+ } else {
+ _animationState = 28;
+ }
+ _animationFrame = 0;
+ break;
+
+ case 43:
+ _animationState = 36;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeWalkUp:
+ _animationState = 3;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeWalkDown:
+ _animationState = 4;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeCombatWalkUp:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeCombatWalkDown:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+
+ case kAnimationModeDie:
+ switch (_animationState) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 7:
+ _animationState = 20;
+ _animationFrame = 0;
+ break;
+
+ case 5:
+ case 6:
+ return true;
+
+ default:
+ _animationState = 32;
+ _animationFrame = 0;
+ break;
+ }
+ break;
+
+ case 58:
+ _animationState = 18;
+ _animationFrame = 0;
+ break;
+
+ }
+
+ return true;
+}
+
+void AIScriptOfficerGrayford::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptOfficerGrayford::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptOfficerGrayford::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptOfficerGrayford::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/officer_leary.cpp b/engines/bladerunner/script/ai/officer_leary.cpp
index b18ba0869f..0adbe7c1c0 100644
--- a/engines/bladerunner/script/ai/officer_leary.cpp
+++ b/engines/bladerunner/script/ai/officer_leary.cpp
@@ -979,7 +979,7 @@ bool AIScriptOfficerLeary::ChangeAnimationMode(int mode) {
break;
}
break;
- case kAnimationModeCombatShoot:
+ case kAnimationModeCombatAttack:
_animationState = 24;
_animationFrame = 0;
break;
diff --git a/engines/bladerunner/script/ai/rajif.cpp b/engines/bladerunner/script/ai/rajif.cpp
index 2ac6a5bed5..26cf41282f 100644
--- a/engines/bladerunner/script/ai/rajif.cpp
+++ b/engines/bladerunner/script/ai/rajif.cpp
@@ -115,7 +115,7 @@ bool AIScriptRajif::UpdateAnimation(int *animation, int *frame) {
if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(751)) {
_animationFrame = 0;
}
- } else {
+ } else { // bug in original. Both branches are equal
*animation = 751;
_animationFrame++;
if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(751)) {
diff --git a/engines/bladerunner/script/ai/sadik.cpp b/engines/bladerunner/script/ai/sadik.cpp
new file mode 100644
index 0000000000..9fdb889b6c
--- /dev/null
+++ b/engines/bladerunner/script/ai/sadik.cpp
@@ -0,0 +1,1039 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/script/ai_script.h"
+
+namespace BladeRunner {
+
+AIScriptSadik::AIScriptSadik(BladeRunnerEngine *vm) : AIScriptBase(vm) {
+ _flag = 0;
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 0;
+ _var4 = 1;
+}
+
+void AIScriptSadik::Initialize() {
+ _animationFrame = 0;
+ _animationState = 0;
+ _animationStateNext = 0;
+ _animationNext = 0;
+
+ _flag = 0;
+ _var1 = 0;
+ _var2 = 0;
+ _var3 = 0;
+ _var4 = 1;
+
+ Actor_Put_In_Set(kActorSadik, kSetFreeSlotA);
+ Actor_Set_At_Waypoint(kActorSadik, 33, 0);
+ Actor_Set_Goal_Number(kActorSadik, 100);
+}
+
+bool AIScriptSadik::Update() {
+ if (Global_Variable_Query(kVariableChapter) != 2 || Player_Query_Current_Scene() != 10 || Game_Flag_Query(391)) {
+ if (_var1) {
+ Sound_Play(_var1, 100, 0, 0, 50);
+ _var1 = 0;
+ }
+ if (Global_Variable_Query(kVariableChapter) == 3 && Actor_Query_Goal_Number(kActorSadik) < 200) {
+ Actor_Set_Goal_Number(kActorSadik, 200);
+ }
+ if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_Goal_Number(kActorSadik) < 400) {
+ Actor_Set_Goal_Number(kActorSadik, 400);
+ }
+ if (Actor_Query_Goal_Number(kActorSadik) == 411) {
+ if (Game_Flag_Query(657)) {
+ Actor_Set_Goal_Number(kActorSadik, 412);
+ }
+ }
+ return false;
+ } else {
+ Actor_Set_Goal_Number(kActorSadik, 101);
+ Actor_Set_Targetable(kActorSadik, 1);
+ Game_Flag_Set(391);
+ Game_Flag_Set(406);
+ return true;
+ }
+}
+
+void AIScriptSadik::TimerExpired(int timer) {
+ if (!timer) {
+ AI_Countdown_Timer_Reset(kActorSadik, 0);
+
+ switch (Actor_Query_Goal_Number(kActorSadik)) {
+ case 302:
+ Actor_Set_Goal_Number(kActorSadik, 305);
+ break;
+
+ case 303:
+ Actor_Set_Goal_Number(kActorSadik, 305);
+ break;
+
+ case 307:
+ Actor_Set_Goal_Number(kActorSadik, 308);
+ break;
+ }
+ }
+}
+
+void AIScriptSadik::CompletedMovementTrack() {
+ switch (Actor_Query_Goal_Number(kActorSadik)) {
+ case 301:
+ Actor_Set_Goal_Number(kActorSadik, 302);
+ break;
+
+ case 101:
+ Actor_Set_Goal_Number(kActorSadik, 102);
+ break;
+
+ case 104:
+ Actor_Set_Goal_Number(kActorSadik, 105);
+ break;
+
+ case 105:
+ Actor_Set_Goal_Number(kActorSadik, 106);
+ break;
+
+ default:
+ return; //false;
+ }
+
+ return; //true;
+}
+
+void AIScriptSadik::ReceivedClue(int clueId, int fromActorId) {
+ //return false;
+}
+
+void AIScriptSadik::ClickedByPlayer() {
+ if (Actor_Query_Goal_Number(kActorSadik) == 599) {
+ Actor_Face_Actor(kActorMcCoy, kActorSadik, 1);
+ Actor_Says(kActorMcCoy, 8580, 16);
+ }
+}
+
+void AIScriptSadik::EnteredScene(int sceneId) {
+ // return false;
+}
+
+void AIScriptSadik::OtherAgentEnteredThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptSadik::OtherAgentExitedThisScene(int otherActorId) {
+ // return false;
+}
+
+void AIScriptSadik::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
+ // return false;
+}
+
+void AIScriptSadik::ShotAtAndMissed() {
+ if (Actor_Query_Goal_Number(kActorSadik) == 414 || Actor_Query_Goal_Number(kActorSadik) == 416) {
+ Game_Flag_Set(714);
+ if (Actor_Query_Which_Set_In(kActorSadik) != 48) {
+ Actor_Set_Goal_Number(kActorSadik, 418);
+ Scene_Exits_Disable();
+ }
+ }
+}
+
+bool AIScriptSadik::ShotAtAndHit() {
+ if (Actor_Query_Goal_Number(kActorSadik) == 301) {
+ if (Game_Flag_Query(48)) {
+ Actor_Set_Health(kActorSadik, 60, 60);
+ } else {
+ Actor_Set_Health(kActorSadik, 40, 40);
+ }
+ return true;
+ } else {
+ if (Actor_Query_Goal_Number(kActorSadik) == 414 || Actor_Query_Goal_Number(kActorSadik) == 416) {
+ Game_Flag_Set(714);
+ if (Actor_Query_Which_Set_In(kActorSadik) != 48) {
+ Actor_Set_Goal_Number(kActorSadik, 418);
+ Scene_Exits_Disable();
+ }
+ }
+ return false;
+ }
+}
+
+void AIScriptSadik::Retired(int byActorId) {
+ if ((Actor_Query_Goal_Number(kActorSadik) == 418 || Actor_Query_Goal_Number(kActorSadik) == 450)
+ && Actor_Query_Which_Set_In(kActorSadik) != 48) {
+ Scene_Exits_Enable();
+ }
+ if (Actor_Query_In_Set(kActorSadik, kSetKP07)) {
+ Global_Variable_Decrement(51, 1);
+ Actor_Set_Goal_Number(kActorSadik, 599);
+
+ if (!Global_Variable_Query(51)) {
+ Player_Loses_Control();
+ Delay(2000);
+ Player_Set_Combat_Mode(0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -12.0f, -41.58f, 72.0f, 0, 1, 0, 0);
+ Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
+ Ambient_Sounds_Remove_All_Looping_Sounds(1);
+ Game_Flag_Set(579);
+ Game_Flag_Reset(653);
+ Set_Enter(kSetKP05_KP06, kSetKP03);
+ return; //true;
+ }
+ }
+
+ Actor_Set_Goal_Number(kActorSadik, 599);
+
+ return; //false;
+}
+
+int AIScriptSadik::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
+ return 0;
+}
+
+bool AIScriptSadik::GoalChanged(int currentGoalNumber, int newGoalNumber) {
+ switch (newGoalNumber) {
+ case 100:
+ AI_Movement_Track_Flush(kActorSadik);
+ AI_Movement_Track_Append(kActorSadik, 33, 0);
+ AI_Movement_Track_Repeat(kActorSadik);
+ return true;
+
+ case 101:
+ AI_Movement_Track_Flush(kActorSadik);
+ AI_Movement_Track_Append_Run(kActorSadik, 131, 0);
+ AI_Movement_Track_Append_Run(kActorSadik, 132, 0);
+ AI_Movement_Track_Append_Run(kActorSadik, 133, 0);
+ AI_Movement_Track_Repeat(kActorSadik);
+ return true;
+
+ case 102:
+ AI_Movement_Track_Flush(kActorSadik);
+ AI_Movement_Track_Append(kActorSadik, 313, 0);
+ AI_Movement_Track_Repeat(kActorSadik);
+ Game_Flag_Set(509);
+ return true;
+
+ case 103:
+ Actor_Set_Immunity_To_Obstacles(kActorSadik, 1);
+ Actor_Face_Heading(kActorSadik, kActorMcCoy, kActorMcCoy);
+ _animationState = 32;
+ _animationFrame = -1;
+ Actor_Change_Animation_Mode(kActorMcCoy, 48);
+ return true;
+
+ case 104:
+ Actor_Set_Goal_Number(kActorMcCoy, 100);
+ AI_Movement_Track_Flush(kActorSadik);
+ AI_Movement_Track_Append(kActorSadik, 314, 0);
+ AI_Movement_Track_Append_Run(kActorSadik, 317, 0);
+ AI_Movement_Track_Repeat(kActorSadik);
+ return true;
+
+ case 105:
+ Actor_Change_Animation_Mode(kActorSadik, 62);
+ return true;
+
+ case 106:
+ Actor_Face_Heading(kActorSadik, 100, 0);
+ Actor_Change_Animation_Mode(kActorSadik, 63);
+ Actor_Set_Goal_Number(kActorClovis, 101);
+ Actor_Set_Immunity_To_Obstacles(kActorSadik, 0);
+ return true;
+
+ case 107:
+ _var1 = 0;
+ return false;
+
+ case 200:
+ Actor_Put_In_Set(kActorSadik, kSetFreeSlotA);
+ Actor_Set_At_Waypoint(kActorSadik, 33, 0);
+ Actor_Set_Goal_Number(kActorMcCoy, 199);
+ return true;
+
+ case 300:
+ Actor_Put_In_Set(kActorSadik, kSetUG18);
+ Actor_Set_At_XYZ(kActorSadik, 111.89f, 0.0f, 408.42f, 0);
+ Actor_Change_Animation_Mode(kActorSadik, 4);
+ return true;
+
+ case 301:
+ Actor_Set_Targetable(kActorSadik, 1);
+ World_Waypoint_Set(436, 89, -356.11f, 0.0f, 652.42f);
+ AI_Movement_Track_Flush(kActorSadik);
+ AI_Movement_Track_Append_Run(kActorSadik, 436, 0);
+ AI_Movement_Track_Repeat(kActorSadik);
+ return true;
+
+ case 302:
+ Actor_Set_Targetable(kActorSadik, 0);
+ return true;
+
+ case 303:
+ AI_Countdown_Timer_Reset(kActorSadik, 0);
+ AI_Countdown_Timer_Start(kActorSadik, 0, 5);
+ return true;
+
+ case 304:
+ Actor_Set_Targetable(kActorSadik, 0);
+ AI_Countdown_Timer_Reset(kActorSadik, 0);
+ return true;
+
+ case 305:
+ case 306:
+ case 310:
+ return true;
+
+ case 307:
+ Sound_Play(12, 100, 0, 0, 50);
+ AI_Countdown_Timer_Start(kActorSadik, 0, 2);
+ return true;
+
+ case 308:
+ if (Player_Query_Current_Scene() == 102) {
+ Actor_Force_Stop_Walking(kActorMcCoy);
+ Actor_Change_Animation_Mode(kActorSadik, 6);
+ Sound_Play(12, 100, 0, 0, 50);
+ Actor_Change_Animation_Mode(kActorMcCoy, 48);
+ Actor_Retired_Here(kActorMcCoy, 6, 6, 1, -1);
+ }
+ return true;
+
+ case 309:
+ AI_Countdown_Timer_Reset(kActorSadik, 0);
+ return true;
+
+ case 400:
+ Actor_Set_Goal_Number(kActorSadik, 410);
+ return true;
+
+ case 410:
+ if (Game_Flag_Query(653) == 1) {
+ Actor_Set_Goal_Number(kActorSadik, 414);
+ } else {
+ Actor_Set_Goal_Number(kActorSadik, 411);
+ }
+ return true;
+
+ case 411:
+ Actor_Put_In_Set(kActorSadik, kSetKP05_KP06);
+ Actor_Set_At_XYZ(kActorSadik, -1134.0f, 0.0f, 73.45f, 398);
+ Actor_Set_Goal_Number(kActorClovis, 513);
+ Actor_Set_Goal_Number(kActorMaggie, 411);
+ return true;
+
+ case 412:
+ Actor_Says(kActorSadik, 60, 3);
+ Actor_Says(kActorMcCoy, 2240, 3);
+ Actor_Says(kActorSadik, 70, 3);
+ Actor_Says(kActorSadik, 80, 3);
+ Actor_Says(kActorMcCoy, 2245, 3);
+ Actor_Says(kActorSadik, 90, 3);
+ Actor_Says(kActorSadik, 100, 3);
+ Actor_Says(kActorMcCoy, 2250, 3);
+ Actor_Set_Goal_Number(kActorSadik, 413);
+ return true;
+
+ case 413:
+ Loop_Actor_Walk_To_XYZ(kActorSadik, -1062.0f, 0.0f, 219.0f, 0, 0, 1, 0);
+ Actor_Set_Targetable(kActorSadik, 1);
+ Non_Player_Actor_Combat_Mode_On(kActorSadik, kActorCombatStateIdle, true, kActorMcCoy, 9, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 15, 300, false);
+ Actor_Set_Goal_Number(kActorSadik, 450);
+ return true;
+
+ case 414:
+ Actor_Put_In_Set(kActorSadik, kSetKP05_KP06);
+ Actor_Set_At_XYZ(kActorSadik, -961.0f, 0.0f, -778.0f, 150);
+ Actor_Set_Targetable(kActorSadik, 1);
+ return true;
+
+ case 415:
+ Actor_Says(kActorSadik, 110, 3);
+ Actor_Says(kActorMcCoy, 2290, 3);
+ Actor_Says(kActorSadik, 310, 3);
+ Actor_Says(kActorMcCoy, 2300, 3);
+ if (Game_Flag_Query(48)) {
+ Actor_Says(kActorSadik, 180, 3);
+ Actor_Says(kActorSadik, 190, 3);
+ Actor_Says(kActorMcCoy, 2310, 3);
+ Actor_Says(kActorSadik, 200, 3);
+ } else {
+ Actor_Says(kActorSadik, 140, 3);
+ Actor_Says(kActorSadik, 150, 3);
+ Actor_Says(kActorMcCoy, 2305, 3);
+ Actor_Says(kActorSadik, 160, 3);
+ Actor_Says(kActorSadik, 170, 3);
+ }
+ Actor_Says(kActorMcCoy, 2315, 3);
+ Actor_Says(kActorSadik, 210, 3);
+ Actor_Says(kActorSadik, 220, 3);
+ Actor_Says(kActorSadik, 230, 3);
+ Actor_Says(kActorSadik, 240, 3);
+ Actor_Says(kActorSadik, 250, 3);
+ Actor_Says(kActorSadik, 260, 3);
+ Actor_Set_Goal_Number(kActorSadik, 416);
+ return true;
+
+ case 416:
+ Loop_Actor_Walk_To_XYZ(kActorSadik, -961.0f, 0.0f, -778.0f, 0, 0, 0, 0);
+ Actor_Face_Heading(kActorSadik, 150, 0);
+ return true;
+
+ case 417:
+ Actor_Face_Actor(kActorSadik, kActorMcCoy, 1);
+ Actor_Says(kActorSadik, 320, 3);
+ Loop_Actor_Walk_To_XYZ(kActorSadik, -857.0f, 0.0f, -703.0f, 0, 0, 1, 0);
+ Actor_Says(kActorMcCoy, 2330, 3);
+ Actor_Says(kActorSadik, 330, 3);
+ Actor_Says(kActorMcCoy, 2335, 3);
+ Actor_Says(kActorSadik, 340, 3);
+ Actor_Set_Goal_Number(kActorSadik, 416);
+ return true;
+
+ case 418:
+ Game_Flag_Reset(653);
+ Actor_Set_Goal_Number(kActorClovis, 518);
+ Non_Player_Actor_Combat_Mode_On(kActorSadik, kActorCombatStateIdle, true, kActorMcCoy, 9, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 15, 300, false);
+ return true;
+
+ case 419:
+ Actor_Put_In_Set(kActorSadik, kSetKP07);
+ Actor_Set_At_XYZ(kActorSadik, -12.0f, -41.58f, 72.0f, 0);
+ return true;
+
+ case 420:
+ case 450:
+ return true;
+ }
+ return false;
+}
+
+bool AIScriptSadik::UpdateAnimation(int *animation, int *frame) {
+ switch (_animationState) {
+ case 0:
+ if (_var2 == 1) {
+ *animation = 329;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(329)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _var2 = 0;
+ }
+ } else if (_var2 == 0) {
+ *animation = 328;
+ if (_var3) {
+ _var3--;
+ if (!Random_Query(0, 6)) {
+ _var4 = -_var4;
+ }
+ } else {
+ _animationFrame += _var4;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(328)) {
+ _animationFrame = 0;
+ }
+ if (_animationFrame < 0) {
+ _animationFrame = Slice_Animation_Query_Number_Of_Frames(328) - 1;
+ }
+ if (!Random_Query(0, 4)) {
+ _var3 = 1;
+ }
+ if (!_animationFrame || _animationFrame == 8) {
+ _var3 = Random_Query(2, 8);
+ }
+ if (!Random_Query(0, 2)) {
+ if (!_animationFrame) {
+ _var2 = 1;
+ _var3 = 0;
+ *animation = 329;
+ }
+ }
+ }
+ }
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ switch (_animationState) {
+ case 1:
+ *animation = 323;
+ break;
+ case 2:
+ *animation = 324;
+ break;
+ case 3:
+ *animation = 317;
+ break;
+ case 4:
+ *animation = 318;
+ break;
+ case 6:
+ *animation = 340;
+ break;
+ case 5:
+ *animation = 339;
+ break;
+ }
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 7:
+ *animation = 312;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(312)) {
+ _animationFrame = 0;
+ }
+ break;
+
+ case 8:
+ *animation = 313;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(313)) {
+ _animationFrame = 0;
+ _animationState = 7;
+ *animation = 312;
+ Actor_Change_Animation_Mode(kActorSadik, 4);
+ }
+ break;
+
+ case 9:
+ *animation = 314;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(314)) {
+ _animationFrame = 0;
+ _animationState = 7;
+ *animation = 312;
+ Actor_Change_Animation_Mode(kActorSadik, 4);
+ }
+ break;
+
+ case 10:
+ *animation = 325;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(325)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ }
+ break;
+
+ case 11:
+ *animation = 326;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(326)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ }
+ break;
+
+ case 12:
+ *animation = 315;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(315)) {
+ _animationFrame = 0;
+ _animationState = 7;
+ *animation = 312;
+ Actor_Change_Animation_Mode(kActorSadik, 4);
+ }
+ break;
+
+ case 13:
+ *animation = 316;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(316)) {
+ _animationFrame = 0;
+ _animationState = 7;
+ *animation = 312;
+ Actor_Change_Animation_Mode(kActorSadik, 4);
+ }
+ break;
+
+ case 14:
+ *animation = 327;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(327) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 15:
+ *animation = 327;
+ if (_animationFrame < Slice_Animation_Query_Number_Of_Frames(327) - 1) {
+ _animationFrame++;
+ }
+ break;
+
+ case 16:
+ *animation = 320;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(320)) {
+ _animationFrame = 0;
+ _animationState = 7;
+ *animation = 312;
+ }
+ break;
+
+ case 17:
+ *animation = 321;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(321)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 18:
+ *animation = 322;
+ _animationFrame++;
+ if (_animationFrame == 5) {
+ int snd;
+ if (Random_Query(1, 2) == 1) {
+ snd = 9010;
+ } else {
+ snd = 9015;
+ }
+ Sound_Play_Speech_Line(8, snd, 75, 0, 99);
+ }
+ if (_animationFrame == 7) {
+ Actor_Combat_AI_Hit_Attempt(kActorSadik);
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(322)) {
+ _animationFrame = 0;
+ _animationState = 7;
+ *animation = 312;
+ Actor_Change_Animation_Mode(kActorSadik, 4);
+ }
+ break;
+
+ case 19:
+ *animation = 331;
+ if (!_animationFrame && _flag) {
+ *animation = 328;
+ _animationState = 0;
+ _flag = 0;
+ } else {
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(331)) {
+ _animationFrame = 0;
+ }
+ }
+ break;
+
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ switch (_animationState) {
+ case 20:
+ *animation = 332;
+ break;
+ case 21:
+ *animation = 333;
+ break;
+ case 22:
+ *animation = 334;
+ break;
+ case 23:
+ *animation = 335;
+ break;
+ case 24:
+ *animation = 336;
+ break;
+ case 25:
+ *animation = 337;
+ break;
+ default:
+ *animation = 338;
+ break;
+ }
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ _animationFrame = 0;
+ _animationState = 19;
+ *animation = 331;
+ }
+ break;
+
+ case 27:
+ *animation = 330;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(330)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ }
+ break;
+
+ case 28:
+ *animation = 341;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(341)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 29:
+ *animation = 342;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(342)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ }
+ break;
+
+ case 30:
+ *animation = 343;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(343)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ }
+ break;
+
+ case 31:
+ *animation = 344;
+ _animationFrame++;
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(344)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ }
+ break;
+
+ case 32:
+ *animation = 345;
+ _animationFrame++;
+ if (_animationFrame == 23) {
+ _var1 = 201;
+ }
+ if (_animationFrame >= 25) {
+ _animationFrame = 0;
+ _animationState = 0;
+ *animation = 328;
+ Actor_Set_Goal_Number(kActorSadik, 104);
+ }
+ break;
+
+ case 33:
+ *animation = 344;
+ _animationFrame++;
+ if (Actor_Query_Goal_Number(kActorSadik) == 105) {
+ if (_animationFrame == 4) {
+ _var1 = 221;
+ }
+ if (_animationFrame == 6) {
+ Actor_Change_Animation_Mode(0, 21);
+ }
+ }
+ if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ if (Actor_Query_Goal_Number(kActorSadik) == 105) {
+ Actor_Change_Animation_Mode(kActorSadik, 63);
+ }
+ }
+ break;
+
+ case 34:
+ *animation = 343;
+ _animationFrame++;
+ if (_animationFrame == 4) {
+ if (Actor_Query_Goal_Number(kActorSadik) == 105) {
+ Actor_Change_Animation_Mode(0, 48);
+ _var1 = 222;
+ } else {
+ Actor_Change_Animation_Mode(0, 68);
+ _var1 = 223;
+ }
+ }
+
+ if (_animationFrame >= 15) {
+ *animation = 328;
+ _animationFrame = 0;
+ _animationState = 0;
+ Actor_Change_Animation_Mode(kActorSadik, 0);
+ if (Actor_Query_Goal_Number(kActorSadik) == 105) {
+ AI_Movement_Track_Flush(kActorSadik);
+ AI_Movement_Track_Append(kActorSadik, 318, 0);
+ AI_Movement_Track_Repeat(kActorSadik);
+ } else {
+ if (Actor_Query_Goal_Number(kActorSadik) == 106) {
+ Actor_Change_Animation_Mode(kActorSadik, 63);
+ }
+ }
+ }
+ break;
+
+ default:
+ *animation = 406;
+ _animationFrame = 0;
+ break;
+ }
+
+ *frame = _animationFrame;
+
+ return true;
+}
+
+bool AIScriptSadik::ChangeAnimationMode(int mode) {
+ Actor_Set_Frame_Rate_FPS(kActorSadik, -2);
+
+ switch (mode) {
+ case 0:
+ switch (_animationState) {
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ _flag = 1;
+ break;
+ case 30:
+ case 31:
+ return 1;
+ default:
+ _animationState = 0;
+ _animationFrame = 0;
+ _var3 = 0;
+ break;
+ }
+ break;
+
+ case 1:
+ _animationFrame = 0;
+ _animationState = 1;
+ break;
+
+ case 2:
+ _animationFrame = 0;
+ _animationState = 2;
+ break;
+
+ case 3:
+ _animationState = 20;
+ _animationFrame = 0;
+ break;
+
+ case 4:
+ switch (_animationState) {
+ case 0:
+ _animationFrame = 0;
+ _animationState = 16;
+ break;
+ case 3:
+ case 4:
+ _animationState = 7;
+ _animationFrame = 0;
+ break;
+ case 7:
+ case 16:
+ case 18:
+ return true;
+ case 17:
+ _animationFrame = 0;
+ _animationState = 7;
+ break;
+ default:
+ _animationFrame = 0;
+ _animationState = 16;
+ break;
+ }
+ break;
+
+ case 5:
+ case 9:
+ case 10:
+ case 11:
+ case 19:
+ case 20:
+ return true;
+
+ case 6:
+ _animationFrame = 0;
+ _animationState = 18;
+ break;
+
+ case 7:
+ _animationFrame = 0;
+ _animationState = 3;
+ break;
+
+ case 8:
+ _animationFrame = 0;
+ _animationState = 4;
+ break;
+
+ case 12:
+ _animationState = 20;
+ _animationFrame = 0;
+ break;
+
+ case 13:
+ _animationState = 21;
+ _animationFrame = 0;
+ break;
+
+ case 14:
+ _animationState = 22;
+ _animationFrame = 0;
+ break;
+
+ case 15:
+ _animationState = 23;
+ _animationFrame = 0;
+ break;
+
+ case 16:
+ _animationState = 24;
+ _animationFrame = 0;
+ break;
+
+ case 17:
+ _animationState = 25;
+ _animationFrame = 0;
+ break;
+
+ case 18:
+ _animationState = 26;
+ _animationFrame = 0;
+ break;
+
+ case 21:
+ switch (_animationState) {
+ case 7:
+ case 8:
+ case 9:
+ case 16:
+ case 17:
+ case 18:
+ if (Random_Query(0, 1)) {
+ _animationState = 13;
+ } else {
+ _animationState = 12;
+ }
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ if (Random_Query(0, 1)) {
+ _animationState = 11;
+ } else {
+ _animationState = 10;
+ }
+ break;
+ }
+ _animationFrame = 0;
+ break;
+
+ case 22:
+ if (Random_Query(0, 1)) {
+ _animationState = 12;
+ } else {
+ _animationState = 13;
+ }
+ _animationFrame = 0;
+ break;
+
+ case 23:
+ _animationState = 27;
+ _animationFrame = 0;
+ break;
+
+ case 48:
+ _animationState = 14;
+ _animationFrame = 0;
+ break;
+
+ case 62:
+ if (Actor_Query_Goal_Number(kActorSadik) != 105 && Actor_Query_Goal_Number(kActorSadik) != 106) {
+ _animationState = 31;
+ _animationFrame = 0;
+ } else {
+ _animationState = 33;
+ _animationFrame = 0;
+ }
+ break;
+
+ case 63:
+ if (Actor_Query_Goal_Number(kActorSadik) != 105 && Actor_Query_Goal_Number(kActorSadik) != 106) {
+ _animationState = 30;
+ _animationFrame = 2;
+ } else {
+ _animationState = 34;
+ _animationFrame = 2;
+ }
+ break;
+ }
+ return true;
+}
+
+void AIScriptSadik::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ *animationState = _animationState;
+ *animationFrame = _animationFrame;
+ *animationStateNext = _animationStateNext;
+ *animationNext = _animationNext;
+}
+
+void AIScriptSadik::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ _animationState = animationState;
+ _animationFrame = animationFrame;
+ _animationStateNext = animationStateNext;
+ _animationNext = animationNext;
+}
+
+bool AIScriptSadik::ReachedMovementTrackWaypoint(int waypointId) {
+ return true;
+}
+
+void AIScriptSadik::FledCombat() {
+ // return false;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai/steele.cpp b/engines/bladerunner/script/ai/steele.cpp
index e51a14a8ca..ff2afa1ec3 100644
--- a/engines/bladerunner/script/ai/steele.cpp
+++ b/engines/bladerunner/script/ai/steele.cpp
@@ -419,7 +419,7 @@ bool AIScriptSteele::ShotAtAndHit() {
Actor_Set_Goal_Number(kActorSteele, 271);
if (/* !a1 && */ Actor_Query_In_Set(kActorSteele, kSetHF06))
- Non_Player_Actor_Combat_Mode_On(1, 3, 1, 0, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorMcCoy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
return false;
}
diff --git a/engines/bladerunner/script/ai/taffy_patron.cpp b/engines/bladerunner/script/ai/taffy_patron.cpp
index c7fa3a7165..0bf6861d12 100644
--- a/engines/bladerunner/script/ai/taffy_patron.cpp
+++ b/engines/bladerunner/script/ai/taffy_patron.cpp
@@ -95,13 +95,13 @@ bool AIScriptTaffyPatron::GoalChanged(int currentGoalNumber, int newGoalNumber)
case 250:
Actor_Put_In_Set(kActorTaffyPatron, kSetNR01);
- Actor_Set_At_XYZ(kActorTaffyPatron, -170.39999, 23.68, -850.0, 324);
- Async_Actor_Walk_To_XYZ(kActorTaffyPatron, -390.0, 31.549999, -429.0, 24, 1);
+ Actor_Set_At_XYZ(kActorTaffyPatron, -170.4f, 23.68f, -850.0f, 324);
+ Async_Actor_Walk_To_XYZ(kActorTaffyPatron, -390.0f, 31.55f, -429.0f, 24, 1);
return true;
case 255:
Actor_Put_In_Set(kActorTaffyPatron, kSetNR01);
- Actor_Set_At_XYZ(kActorTaffyPatron, -170.39999, 23.68, -850.0, 324);
+ Actor_Set_At_XYZ(kActorTaffyPatron, -170.4f, 23.68f, -850.0f, 324);
Actor_Change_Animation_Mode(kActorTaffyPatron, 48);
return true;
diff --git a/engines/bladerunner/script/ai/zuben.cpp b/engines/bladerunner/script/ai/zuben.cpp
index 9fe6aa2f10..58cea9d39d 100644
--- a/engines/bladerunner/script/ai/zuben.cpp
+++ b/engines/bladerunner/script/ai/zuben.cpp
@@ -152,7 +152,7 @@ void AIScriptZuben::CompletedMovementTrack() {
Set_Enter(kSetCT06, kSceneCT06);
}
if (Actor_Query_Goal_Number(kActorZuben) == 21) {
- Non_Player_Actor_Combat_Mode_On(kActorZuben, 0, 0, kActorMcCoy, 6, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 15, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorZuben, kActorCombatStateIdle, false, kActorMcCoy, 6, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 15, 300, false);
}
int goal = Actor_Query_Goal_Number(kActorZuben);
if (goal == 200) {
@@ -977,7 +977,7 @@ bool AIScriptZuben::ChangeAnimationMode(int mode) {
break;
}
break;
- case kAnimationModeCombatShoot:
+ case kAnimationModeCombatAttack:
_animationState = 8;
_animationFrame = 0;
break;
diff --git a/engines/bladerunner/script/ai_script.cpp b/engines/bladerunner/script/ai_script.cpp
index 7b28e2db3d..b328824de1 100644
--- a/engines/bladerunner/script/ai_script.cpp
+++ b/engines/bladerunner/script/ai_script.cpp
@@ -22,9 +22,8 @@
#include "bladerunner/script/ai_script.h"
-#include "bladerunner/bladerunner.h"
-
#include "bladerunner/actor.h"
+#include "bladerunner/bladerunner.h"
namespace BladeRunner {
@@ -47,17 +46,24 @@ AIScripts::AIScripts(BladeRunnerEngine *vm, int actorCount) {
_AIScripts[kActorClovis] = new AIScriptClovis(_vm); // 5
_AIScripts[kActorLucy] = new AIScriptLucy(_vm); // 6
_AIScripts[kActorIzo] = new AIScriptIzo(_vm); // 7
+ _AIScripts[kActorSadik] = new AIScriptSadik(_vm); // 8
_AIScripts[kActorCrazylegs] = new AIScriptCrazylegs(_vm); // 9
+ _AIScripts[kActorLuther] = new AIScriptLuther(_vm); // 10
_AIScripts[kActorGrigorian] = new AIScriptGrigorian(_vm); // 11
_AIScripts[kActorTransient] = new AIScriptTransient(_vm); // 12
_AIScripts[kActorLance] = new AIScriptLance(_vm); // 13
+ _AIScripts[kActorBulletBob] = new AIScriptBulletBob(_vm); // 14
_AIScripts[kActorRunciter] = new AIScriptRunciter(_vm); // 15
_AIScripts[kActorInsectDealer] = new AIScriptInsectDealer(_vm); // 16
_AIScripts[kActorTyrellGuard] = new AIScriptTyrellGuard(_vm); // 17
+ _AIScripts[kActorEarlyQ] = new AIScriptEarlyQ(_vm); // 18
_AIScripts[kActorZuben] = new AIScriptZuben(_vm); // 19
+ _AIScripts[kActorHasan] = new AIScriptHasan(_vm); // 20
_AIScripts[kActorMarcus] = new AIScriptMarcus(_vm); // 21
_AIScripts[kActorMia] = new AIScriptMia(_vm); // 22
_AIScripts[kActorOfficerLeary] = new AIScriptOfficerLeary(_vm); // 23
+ _AIScripts[kActorOfficerGrayford] = new AIScriptOfficerGrayford(_vm); // 24
+ _AIScripts[kActorHanoi] = new AIScriptHanoi(_vm); // 25
_AIScripts[kActorBaker] = new AIScriptBaker(_vm); // 26
_AIScripts[kActorDeskClerk] = new AIScriptDeskClerk(_vm); // 27
_AIScripts[kActorHowieLee] = new AIScriptHowieLee(_vm); // 28
@@ -96,6 +102,8 @@ AIScripts::AIScripts(BladeRunnerEngine *vm, int actorCount) {
_AIScripts[kActorNewscaster] = new AIScriptNewscaster(_vm); // 61
_AIScripts[kActorLeon] = new AIScriptLeon(_vm); // 62
_AIScripts[kActorMaleAnnouncer] = new AIScriptMaleAnnouncer(_vm); // 63
+ _AIScripts[kActorFreeSlotA] = new AIScriptFreeSlotA(_vm); // 64
+ _AIScripts[kActorFreeSlotB] = new AIScriptFreeSlotB(_vm); // 65
_AIScripts[kActorMaggie] = new AIScriptMaggie(_vm); // 66
_AIScripts[kActorGenwalkerA] = new AIScriptGenericWalkerA(_vm); // 67
_AIScripts[kActorGenwalkerB] = new AIScriptGenericWalkerB(_vm); // 68
@@ -324,4 +332,43 @@ void AIScripts::changeAnimationMode(int actor, int mode) {
_inScriptCounter--;
}
+void AIScripts::fledCombat(int actor) {
+ if (actor >= _actorCount) {
+ return;
+ }
+
+ _inScriptCounter++;
+ if (_AIScripts[actor]) {
+ _AIScripts[actor]->FledCombat();
+ }
+ _inScriptCounter--;
+}
+
+void AIScripts::setAnimationState(int actor, int animationState, int animationFrame, int animationStateNext, int animationNext) {
+ if (actor >= _actorCount) {
+ return;
+ }
+
+ _inScriptCounter++;
+ if (_AIScripts[actor]) {
+ _AIScripts[actor]->SetAnimationState(animationState, animationFrame, animationStateNext, animationNext);
+ }
+ _inScriptCounter--;
+}
+
+
+void AIScripts::queryAnimationState(int actor, int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
+ if (actor >= _actorCount) {
+ return;
+ }
+
+ _inScriptCounter++;
+ if (_AIScripts[actor]) {
+ _AIScripts[actor]->FledCombat();
+ _AIScripts[actor]->QueryAnimationState(animationState, animationFrame, animationStateNext, animationNext);
+ }
+ _inScriptCounter--;
+}
+
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai_script.h b/engines/bladerunner/script/ai_script.h
index 32bbce092f..9cafa28039 100644
--- a/engines/bladerunner/script/ai_script.h
+++ b/engines/bladerunner/script/ai_script.h
@@ -61,7 +61,7 @@ public:
virtual bool GoalChanged(int currentGoalNumber, int newGoalNumber) = 0;
virtual bool UpdateAnimation(int *animation, int *frame) = 0;
virtual bool ChangeAnimationMode(int mode) = 0;
- virtual void QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *nextAnimation) = 0;
+ virtual void QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) = 0;
virtual void SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) = 0;
virtual bool ReachedMovementTrackWaypoint(int waypointId) = 0;
virtual void FledCombat() = 0;
@@ -189,10 +189,22 @@ DECLARE_SCRIPT(Izo)
void modifyWaypoints();
END_SCRIPT
+DECLARE_SCRIPT(Sadik)
+ int _var1;
+ int _var2;
+ int _var3;
+ int _var4;
+ bool _flag;
+END_SCRIPT
+
DECLARE_SCRIPT(Crazylegs)
bool _flag;
END_SCRIPT
+DECLARE_SCRIPT(Luther)
+ bool _flag;
+END_SCRIPT
+
DECLARE_SCRIPT(Grigorian)
int var_45CA10;
int var_45CA14;
@@ -204,6 +216,13 @@ END_SCRIPT
DECLARE_SCRIPT(Lance)
END_SCRIPT
+DECLARE_SCRIPT(BulletBob)
+ int _var1;
+ int _var2;
+ int _var3;
+ int _var4;
+END_SCRIPT
+
DECLARE_SCRIPT(Runciter)
int var_45CD78;
int var_45CD7C;
@@ -225,6 +244,13 @@ DECLARE_SCRIPT(TyrellGuard)
bool _flag1;
END_SCRIPT
+DECLARE_SCRIPT(EarlyQ)
+ int _var1;
+ int _var2;
+ int _var3;
+ bool _flag;
+END_SCRIPT
+
DECLARE_SCRIPT(Zuben)
int _var_45D258;
int _var_45D25C;
@@ -235,6 +261,15 @@ DECLARE_SCRIPT(Zuben)
void dialogue();
END_SCRIPT
+DECLARE_SCRIPT(Hasan)
+ int _var1;
+ int _var2;
+ int _var3;
+ int _var4;
+ int _var5;
+ int _var6;
+END_SCRIPT
+
DECLARE_SCRIPT(Marcus)
END_SCRIPT
@@ -250,6 +285,19 @@ DECLARE_SCRIPT(OfficerLeary)
bool sub_431420();
END_SCRIPT
+DECLARE_SCRIPT(OfficerGrayford)
+ int _var1;
+ int _var2;
+ int _var3;
+END_SCRIPT
+
+DECLARE_SCRIPT(Hanoi)
+ int _var1;
+ int _var2;
+ int _var3;
+ int _var4;
+END_SCRIPT
+
DECLARE_SCRIPT(Baker)
END_SCRIPT
@@ -411,6 +459,24 @@ END_SCRIPT
DECLARE_SCRIPT(MaleAnnouncer)
END_SCRIPT
+DECLARE_SCRIPT(FreeSlotA)
+ int _var1;
+ int _var2;
+ float _var3;
+ float _var4;
+ float _var5;
+
+ void calcHit();
+ void processGoal306();
+END_SCRIPT
+
+DECLARE_SCRIPT(FreeSlotB)
+ int _var1;
+ int _var2;
+
+ void processGoal301();
+END_SCRIPT
+
DECLARE_SCRIPT(Maggie)
int var_45F3F8;
int var_45F3FC;
@@ -500,8 +566,16 @@ public:
bool reachedMovementTrackWaypoint(int actor, int waypointId);
void updateAnimation(int actor, int *animation, int *frame);
void changeAnimationMode(int actor, int mode);
+ void queryAnimationState(int actor, int *animationState, int *animationFrame, int *animationStateNext, int *animationNext);
+ void setAnimationState(int actor, int animationState, int animationFrame, int animationStateNext, int animationNext);
+ void fledCombat(int actor);
bool isInsideScript() const { return _inScriptCounter > 0; }
+
+ void callChangeAnimationMode(int actor, int mode) { _AIScripts[actor]->ChangeAnimationMode(mode); }
+ int callGetFriendlinessModifierIfGetsClue(int actor, int otherActorId, int clueId) {
+ return _AIScripts[actor]->GetFriendlinessModifierIfGetsClue(otherActorId, clueId);
+ }
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/police_maze.cpp b/engines/bladerunner/script/police_maze.cpp
new file mode 100644
index 0000000000..a85fa07451
--- /dev/null
+++ b/engines/bladerunner/script/police_maze.cpp
@@ -0,0 +1,603 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/bladerunner.h"
+#include "bladerunner/game_constants.h"
+#include "bladerunner/items.h"
+#include "bladerunner/mouse.h"
+#include "bladerunner/savefile.h"
+#include "bladerunner/scene.h"
+#include "bladerunner/scene_objects.h"
+#include "bladerunner/script/police_maze.h"
+#include "bladerunner/script/scene_script.h"
+
+namespace BladeRunner {
+
+PoliceMaze::PoliceMaze(BladeRunnerEngine *vm) : ScriptBase(vm) {
+ reset();
+
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ _tracks[i] = new PoliceMazeTargetTrack(vm);
+ }
+}
+
+PoliceMaze::~PoliceMaze() {
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ delete _tracks[i];
+ }
+
+ reset();
+}
+
+void PoliceMaze::reset() {
+ _isPaused = false;
+ _isActive = false;
+ _isEnding = false;
+
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ _tracks[i] = 0;
+ }
+
+ _pm_var1 = 0;
+ _pm_var2 = 0;
+}
+
+void PoliceMaze::clear(bool isLoadingGame) {
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ if (_tracks[i]->isPresent()) {
+ _tracks[i]->clear(isLoadingGame);
+ }
+ }
+}
+
+void PoliceMaze::activate() {
+ _isActive = true;
+ _isEnding = false;
+}
+
+void PoliceMaze::setPauseState(bool state) {
+ warning("PAUSE: %d", state);
+ _isPaused = state;
+
+ uint32 t = _vm->getTotalPlayTime();
+
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ _tracks[i]->setTime(t);
+ }
+}
+
+void PoliceMaze::tick() {
+ if (_isPaused) {
+ return;
+ }
+
+ if (_vm->_scene->getSetId() != kSetPS10_PS11_PS12_PS13) {
+ return;
+ }
+
+ if (_isEnding) {
+ _isActive = false;
+ return;
+ }
+
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ _tracks[i]->tick();
+ }
+
+ bool notFound = true;
+ for (int i = 0; i < kNumMazeTracks; i++) {
+ if (!_tracks[i]->isPaused()) {
+ notFound = false;
+ break;
+ }
+ }
+
+ if (notFound && _isActive && !_isEnding) {
+ _isActive = false;
+ _isEnding = true;
+
+ if (_vm->_scene->getSceneId() == kScenePS13) {
+ Actor_Voice_Over(320, kActorAnsweringMachine);
+ } else {
+ Actor_Voice_Over(310, kActorAnsweringMachine);
+ }
+ }
+}
+
+void PoliceMaze::save(SaveFileWriteStream &f) {
+ f.writeBool(_isPaused);
+ f.writeBool(_isActive);
+ f.writeBool(_isEnding);
+ for (int i = 0; i < kNumMazeTracks; ++i) {
+ _tracks[i]->save(f);
+ }
+}
+
+void PoliceMaze::load(SaveFileReadStream &f) {
+ _isPaused = f.readBool();
+ _isActive = f.readBool();
+ _isEnding = f.readBool();
+ for (int i = 0; i < kNumMazeTracks; ++i) {
+ _tracks[i]->load(f);
+ }
+}
+
+PoliceMazeTargetTrack::PoliceMazeTargetTrack(BladeRunnerEngine *vm) : ScriptBase(vm) {
+ reset();
+}
+
+PoliceMazeTargetTrack::~PoliceMazeTargetTrack() {
+ reset();
+}
+
+void PoliceMazeTargetTrack::reset() {
+ _isPresent = false;
+ _itemId = -1;
+ _pointCount = 0;
+ _data = nullptr;
+ _dataIndex = 0;
+ _timeLeftUpdate = 0;
+ _timeLeftWait = 0;
+ _time = 0;
+ _isWaiting = false;
+ _isMoving = false;
+ _pointIndex = 0;
+ _pointTarget = 0;
+ _isRotating = false;
+ _angleTarget = 0;
+ _angleDelta = 0;
+ _isPaused = true;
+}
+
+void PoliceMazeTargetTrack::clear(bool isLoadingGame) {
+ reset();
+}
+
+void PoliceMazeTargetTrack::add(int trackId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, const int *instructions, bool isActive) {
+ _data = (const int *)instructions;
+
+ if (true /* !GameIsLoading */) { // TODO: FIXME
+ _itemId = trackId;
+ _pointCount = steps;
+ _dataIndex = 0;
+
+ double coef = 1.0f / (long double)steps;
+
+ double coefX = (endX - startX) * coef;
+ double coefY = (endY - startY) * coef;
+ double coefZ = (endZ - startZ) * coef;
+
+ for (int i = 0; i < steps - 1; i++) {
+ _points[i].x = i * coefX + startX;
+ _points[i].y = i * coefY + startY;
+ _points[i].z = i * coefZ + startZ;
+ }
+
+ _points[steps - 1].x = endX;
+ _points[steps - 1].y = endY;
+ _points[steps - 1].z = endZ;
+
+ _isPaused = !isActive;
+ }
+ _isPresent = true;
+}
+
+bool PoliceMazeTargetTrack::tick() {
+ if (!_isPresent) {
+ return false;
+ }
+
+ uint32 oldTime = _time;
+ _time = _vm->getTotalPlayTime();
+ int32 timeDiff = _time - oldTime;
+ _timeLeftUpdate -= timeDiff;
+
+ if (_timeLeftUpdate > 0) {
+ return false;
+ }
+
+ _timeLeftUpdate = 66;
+
+ if (_isPaused) {
+ return false;
+ }
+
+ if (_isWaiting) {
+ _timeLeftWait -= timeDiff;
+
+ if (_timeLeftWait > 0) {
+ return true;
+ }
+
+ _isWaiting = false;
+ _timeLeftWait = 0;
+ }
+
+ if (_vm->_items->isSpinning(_itemId)) {
+ return true;
+ }
+
+ if (_isRotating) {
+ float angle = _vm->_items->getFacing(_itemId) + _angleDelta;
+
+ if (_angleDelta > 0) {
+ if (angle >= _angleTarget) {
+ angle = _angleTarget;
+ _isRotating = false;
+ }
+ } else if (_angleDelta < 0) {
+ if (angle <= _angleTarget) {
+ angle = _angleTarget;
+ _isRotating = false;
+ }
+ } else {
+ _isRotating = false;
+ }
+
+ _vm->_items->setFacing(_itemId, angle);
+
+ if (_isRotating)
+ return false;
+ }
+
+ bool advancePoint = false;
+
+ if (_isMoving) {
+ if (_pointIndex < _pointTarget) {
+ _pointIndex++;
+ advancePoint = true;
+ } else if (_pointIndex > _pointTarget) {
+ _pointIndex--;
+ advancePoint = true;
+ } else {
+ _isMoving = 0;
+ }
+ }
+
+ if (advancePoint) {
+ _vm->_items->setXYZ(_itemId, _points[_pointIndex]);
+ readdObject(_itemId);
+
+ return true;
+ }
+
+ bool cont = true;
+
+ while (cont) {
+ _dataIndex++;
+
+ debug ("ItemId %3i, pos %3i, instruction %3i", _itemId, _dataIndex - 1, _data[_dataIndex - 1]);
+
+ switch (_data[_dataIndex - 1]) {
+ case kPMTIActivate:
+ {
+ int variableId = _data[_dataIndex++];
+ int maxValue = _data[_dataIndex++];
+
+ if (Global_Variable_Query(variableId) >= maxValue) {
+ setPaused();
+ cont = false;
+ } else {
+ cont = true;
+ }
+ break;
+ }
+
+ case kPMTILeave:
+ if (!_vm->_items->isPoliceMazeEnemy(_itemId) && _vm->_items->isTarget(_itemId)) {
+ Police_Maze_Increment_Score(1);
+ }
+ break;
+
+ case kPMTIShoot:
+ {
+ int soundId = _data[_dataIndex++];
+ _dataIndex++; // second argument is not used
+
+ if (_vm->_items->isTarget(_itemId)) {
+ Sound_Play(soundId, 90, 0, 0, 50);
+ Police_Maze_Decrement_Score(1);
+ Actor_Force_Stop_Walking(kActorMcCoy);
+
+ if (Player_Query_Combat_Mode()) {
+ Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeCombatHit);
+ } else {
+ Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeHit);
+ }
+
+ int snd;
+
+ if (Random_Query(1, 2) == 1) {
+ snd = 9900;
+ } else {
+ snd = 9905;
+ }
+ Sound_Play_Speech_Line(kActorMcCoy, snd, 75, 0, 99);
+
+ _vm->_mouse->setMouseJitterDown();
+ }
+
+ cont = false;
+ break;
+ }
+
+ case kPMTIEnemyReset:
+ {
+ int itemId = _data[_dataIndex++];
+ _vm->_items->setPoliceMazeEnemy(itemId, false);
+ break;
+ }
+
+ case kPMTIEnemySet:
+ {
+ int itemId = _data[_dataIndex++];
+ _vm->_items->setPoliceMazeEnemy(itemId, true);
+ break;
+ }
+
+ case kPMTIFlagReset:
+ {
+ int gameFlagId = _data[_dataIndex++];
+ Game_Flag_Reset(gameFlagId);
+ break;
+ }
+
+ case kPMTIFlagSet:
+ {
+ int gameFlagId = _data[_dataIndex++];
+ Game_Flag_Set(gameFlagId);
+ break;
+ }
+
+ case kPMTIVariableDec:
+ {
+ int variableId = _data[_dataIndex++];
+ Global_Variable_Decrement(variableId, 1);
+ break;
+ }
+
+ case kPMTIVariableInc:
+ {
+ int variableId = _data[_dataIndex++];
+ int maxValue = _data[_dataIndex++];
+ if (Global_Variable_Query(variableId) < maxValue) {
+ Global_Variable_Increment(variableId, 1);
+ }
+ break;
+ }
+
+ case kPMTIVariableReset:
+ {
+ int variableId = _data[_dataIndex++];
+ Global_Variable_Reset(variableId);
+ break;
+ }
+
+ case kPMTIVariableSet:
+ {
+ int variableId = _data[_dataIndex++];
+ int value = _data[_dataIndex++];
+ Global_Variable_Set(variableId, value);
+ break;
+ }
+
+ case kPMTITargetSet:
+ {
+ int itemId = _data[_dataIndex++];
+ int value = _data[_dataIndex++];
+ _vm->_items->setIsTarget(itemId, value);
+ break;
+ }
+
+ case kPMTI12:
+ {
+ int trackId1 = _data[_dataIndex++];
+ int trackId2 = _data[_dataIndex++];
+ int trackId3 = _data[_dataIndex++];
+
+ switch (Random_Query(1, 3)) {
+ case 1:
+ _vm->_policeMaze->_tracks[trackId1]->resetPaused();
+ break;
+
+ case 2:
+ _vm->_policeMaze->_tracks[trackId2]->resetPaused();
+ break;
+
+ case 3:
+ _vm->_policeMaze->_tracks[trackId3]->resetPaused();
+ break;
+ }
+
+ break;
+ }
+
+ case kPMTI13:
+ {
+ int trackId1 = _data[_dataIndex++];
+ int trackId2 = _data[_dataIndex++];
+
+ if (Random_Query(1, 2) == 1) {
+ _vm->_policeMaze->_tracks[trackId1]->resetPaused();
+ } else {
+ _vm->_policeMaze->_tracks[trackId2]->resetPaused();
+ }
+ break;
+ }
+
+ case kPMTIPausedSet:
+ {
+ int trackId = _data[_dataIndex++];
+ _vm->_policeMaze->_tracks[trackId]->setPaused();
+ break;
+ }
+
+ case kPMTIPausedReset:
+ {
+ int trackId = _data[_dataIndex++];
+ _vm->_policeMaze->_tracks[trackId]->resetPaused();
+ break;
+ }
+
+ case kPMTIPlaySound:
+ {
+ int soundId = _data[_dataIndex++];
+ int volume = _data[_dataIndex++];
+ Sound_Play(soundId, volume, 0, 0, 50);
+ break;
+ }
+
+ case kPMTIObstacleReset:
+ {
+ int itemId = _data[_dataIndex++];
+ _vm->_items->setIsObstacle(itemId, 0);
+ break;
+ }
+
+ case kPMTIObstacleSet:
+ {
+ int itemId = _data[_dataIndex++];
+ _vm->_items->setIsObstacle(itemId, 1);
+ break;
+ }
+
+ case kPMTIWaitRandom:
+ {
+ int randomMin = _data[_dataIndex++];
+ int randomMax = _data[_dataIndex++];
+ _timeLeftWait = Random_Query(randomMin, randomMax);
+ _isWaiting = true;
+
+ cont = false;
+ break;
+ }
+
+ case kPMTIRotate:
+ _angleTarget = _data[_dataIndex++];
+ _angleDelta = _data[_dataIndex++];
+ _isRotating = true;
+
+ cont = false;
+ break;
+
+ case kPMTIFacing:
+ {
+ int angle = _data[_dataIndex++];
+ _vm->_items->setFacing(_itemId, angle);
+ break;
+ }
+
+ case kPMTIRestart:
+ _dataIndex = 0;
+
+ cont = false;
+ break;
+
+ case kPMTIWait:
+ _timeLeftWait = _data[_dataIndex++];
+ _isWaiting = true;
+
+ cont = false;
+ break;
+
+ case kPMTIMove:
+ _pointTarget = _data[_dataIndex++];
+ _isMoving = true;
+
+ cont = false;
+ break;
+
+ case kPMTIPosition:
+ _pointIndex = _data[_dataIndex++];
+ _isMoving = false;
+ _vm->_items->setXYZ(_itemId, _points[_pointIndex]);
+ readdObject(_itemId);
+ break;
+
+ default:
+ return false;
+ }
+
+ if (_isPaused || _isWaiting) {
+ cont = false;
+ }
+ }
+
+ return true;
+}
+
+void PoliceMazeTargetTrack::readdObject(int itemId) {
+ if (_vm->_sceneObjects->remove(itemId + kSceneObjectOffsetItems)) {
+ const BoundingBox &boundingBox = _vm->_items->getBoundingBox(itemId);
+ const Common::Rect &screenRect = _vm->_items->getScreenRectangle(itemId);
+ bool targetable = _vm->_items->isTarget(itemId);
+ bool obstacle = _vm->_items->isVisible(itemId);
+
+ _vm->_sceneObjects->addItem(itemId + kSceneObjectOffsetItems, boundingBox, screenRect, targetable, obstacle);
+ }
+}
+
+void PoliceMazeTargetTrack::save(SaveFileWriteStream &f) {
+ f.writeBool(_isPresent);
+ f.writeInt(_itemId);
+ f.writeInt(_pointCount);
+ f.writeInt(_dataIndex);
+ f.writeBool(_isWaiting);
+ f.writeBool(_isMoving);
+ f.writeInt(_pointIndex);
+ f.writeInt(_pointTarget);
+ f.writeBool(_isRotating);
+ f.writeInt(_angleTarget);
+ f.writeInt(_angleDelta);
+ f.writeBool(_isPaused);
+
+ for (int i = 0; i < kNumTrackPoints; ++i) {
+ f.writeVector3(_points[i]);
+ }
+
+ f.writeInt(_timeLeftUpdate);
+ f.writeInt(_timeLeftWait);
+}
+
+void PoliceMazeTargetTrack::load(SaveFileReadStream &f) {
+ _isPresent = f.readBool();
+ _itemId = f.readInt();
+ _pointCount = f.readInt();
+ _dataIndex = f.readInt();
+ _isWaiting = f.readBool();
+ _isMoving = f.readBool();
+ _pointIndex = f.readInt();
+ _pointTarget = f.readInt();
+ _isRotating = f.readBool();
+ _angleTarget = f.readInt();
+ _angleDelta = f.readInt();
+ _isPaused = f.readBool();
+
+ for (int i = 0; i < kNumTrackPoints; ++i) {
+ _points[i] = f.readVector3();
+ }
+
+ _timeLeftUpdate = f.readInt();
+ _timeLeftWait = f.readInt();
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/police_maze.h b/engines/bladerunner/script/police_maze.h
new file mode 100644
index 0000000000..725fbd4319
--- /dev/null
+++ b/engines/bladerunner/script/police_maze.h
@@ -0,0 +1,106 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_SCRIPT_POLICE_MAZE_H
+#define BLADERUNNER_SCRIPT_POLICE_MAZE_H
+
+#include "bladerunner/script/script.h"
+#include "bladerunner/vector.h"
+
+namespace BladeRunner {
+
+enum {
+ kNumMazeTracks = 64,
+ kNumTrackPoints = 100
+};
+
+class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
+
+class PoliceMazeTargetTrack : ScriptBase {
+ uint32 _time;
+ bool _isPresent;
+ int _itemId;
+ int _pointCount;
+ Vector3 _points[kNumTrackPoints];
+ const int *_data;
+ int _dataIndex;
+ int32 _timeLeftUpdate;
+ int32 _timeLeftWait;
+ bool _isWaiting;
+ int _isMoving;
+ int _pointIndex;
+ int _pointTarget;
+ bool _isRotating;
+ int _angleTarget;
+ int _angleDelta;
+ bool _isPaused;
+
+public:
+ PoliceMazeTargetTrack(BladeRunnerEngine *vm);
+ ~PoliceMazeTargetTrack();
+
+ void reset();
+ void clear(bool isLoadingGame);
+ void add(int trackId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, const int *instructions, bool isActive);
+
+ bool tick();
+ bool isPresent() const { return _isPresent; }
+ void setPaused() { _isPaused = true; }
+ void resetPaused() { _isPaused = false; }
+ bool isPaused() const { return _isPaused; }
+ void setTime(uint32 t) { _time = t; }
+
+ void readdObject(int itemId);
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+};
+
+class PoliceMaze : ScriptBase {
+ bool _isPaused;
+ bool _isActive;
+ bool _isEnding;
+ int _pm_var1;
+ int _pm_var2;
+
+public:
+ PoliceMazeTargetTrack *_tracks[kNumMazeTracks];
+
+public:
+ PoliceMaze(BladeRunnerEngine *vm);
+ ~PoliceMaze();
+
+ void tick();
+ void reset();
+ void clear(bool isLoadingGame);
+ void setPauseState(bool state);
+ void activate();
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/script/scene/ct07.cpp b/engines/bladerunner/script/scene/ct07.cpp
index 2eb7805c44..ebbe604b65 100644
--- a/engines/bladerunner/script/scene/ct07.cpp
+++ b/engines/bladerunner/script/scene/ct07.cpp
@@ -89,7 +89,7 @@ void SceneScriptCT07::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
void SceneScriptCT07::PlayerWalkedIn() {
Player_Gains_Control();
- Non_Player_Actor_Combat_Mode_On(kActorZuben, 0, 0, kActorMcCoy, 2, 4, 7, 8, 0, 0, 100, 15, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorZuben, kActorCombatStateIdle, false, kActorMcCoy, 2, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 15, 300, false);
Game_Flag_Set(516);
Actor_Face_Actor(kActorMcCoy, kActorZuben, true);
}
diff --git a/engines/bladerunner/script/scene/ct11.cpp b/engines/bladerunner/script/scene/ct11.cpp
index 63d114ebfb..49dd417ae1 100644
--- a/engines/bladerunner/script/scene/ct11.cpp
+++ b/engines/bladerunner/script/scene/ct11.cpp
@@ -54,7 +54,7 @@ void SceneScriptCT11::SceneLoaded() {
Unobstacle_Object("BOX SOUTH 1", true);
if (Global_Variable_Query(kVariableChapter) < 4) {
if (!Game_Flag_Query(645)) {
- Item_Add_To_World(115, 951, 33, 640.21002f, 30.0f, 470.0f, 512, 12, 12, false, true, false, true);
+ Item_Add_To_World(115, 951, 33, 640.21f, 30.0f, 470.0f, 512, 12, 12, false, true, false, true);
Scene_2D_Region_Add(0, 505, 316, 513, 321);
Game_Flag_Set(725);
}
@@ -99,15 +99,15 @@ bool SceneScriptCT11::ClickedOnItem(int itemId, bool a2) {
bool SceneScriptCT11::ClickedOnExit(int exitId) {
if (exitId == 0) {
- if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, 121.0f, 9.6800003f, -42.0f, 0, 1, false, 0)) {
+ if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, 121.0f, 9.68f, -42.0f, 0, 1, false, 0)) {
Game_Flag_Set(304);
Set_Enter(31, kSceneCT09);
}
return true;
}
if (exitId == 1) {
- if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -300.0f, 9.6800003f, 66.0f, 0, 1, false, 0)) {
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -400.0f, 9.6800003f, -70.0f, 0, 1, false, 0);
+ if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -300.0f, 9.68f, 66.0f, 0, 1, false, 0)) {
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -400.0f, 9.68f, -70.0f, 0, 1, false, 0);
Game_Flag_Set(86);
Set_Enter(4, kSceneCT12);
}
diff --git a/engines/bladerunner/script/scene/ct12.cpp b/engines/bladerunner/script/scene/ct12.cpp
index 859b065b37..88bbd4645a 100644
--- a/engines/bladerunner/script/scene/ct12.cpp
+++ b/engines/bladerunner/script/scene/ct12.cpp
@@ -138,7 +138,7 @@ bool SceneScriptCT12::ClickedOnItem(int itemId, bool a2) {
bool SceneScriptCT12::ClickedOnExit(int exitId) {
if (exitId == 0) {
- if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -419.14999f, -6.5f, 696.94f, 0, 1, false, 0)) {
+ if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -419.15f, -6.5f, 696.94f, 0, 1, false, 0)) {
Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
Game_Flag_Set(88);
Set_Enter(4, kSceneCT01);
diff --git a/engines/bladerunner/script/scene/dr02.cpp b/engines/bladerunner/script/scene/dr02.cpp
index cbdb1ddcd7..c416fe2ff2 100644
--- a/engines/bladerunner/script/scene/dr02.cpp
+++ b/engines/bladerunner/script/scene/dr02.cpp
@@ -32,7 +32,7 @@ void SceneScriptDR02::InitializeScene() {
} else if (Game_Flag_Query(264)) {
Setup_Scene_Information(-1258.0f, 7.18f, -314.0f, 400);
} else {
- Setup_Scene_Information(168.78f, 0.16f, -775.71997f, 193);
+ Setup_Scene_Information(168.78f, 0.16f, -775.72f, 193);
}
Scene_Exit_Add_2D_Exit(0, 605, 0, 639, 479, 1);
Scene_Exit_Add_2D_Exit(1, 222, 176, 279, 314, 0);
diff --git a/engines/bladerunner/script/scene/dr04.cpp b/engines/bladerunner/script/scene/dr04.cpp
index 21933aaae7..fd7316536d 100644
--- a/engines/bladerunner/script/scene/dr04.cpp
+++ b/engines/bladerunner/script/scene/dr04.cpp
@@ -247,7 +247,7 @@ void SceneScriptDR04::PlayerWalkedIn() {
Loop_Actor_Walk_To_XYZ(kActorMcCoy, -851.0f, 71.64f, 647.0f, 0, 0, false, 0);
Actor_Face_Heading(kActorMcCoy, 0, false);
Loop_Actor_Travel_Stairs(kActorMcCoy, 7, 0, 0);
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -774.85f, 7.18f, 386.67001f, 0, 0, false, 0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -774.85f, 7.18f, 386.67f, 0, 0, false, 0);
Actor_Set_Immunity_To_Obstacles(kActorMcCoy, false);
Footstep_Sound_Override_Off();
}
diff --git a/engines/bladerunner/script/scene/dr06.cpp b/engines/bladerunner/script/scene/dr06.cpp
index ebc19bce41..393cdc3184 100644
--- a/engines/bladerunner/script/scene/dr06.cpp
+++ b/engines/bladerunner/script/scene/dr06.cpp
@@ -26,9 +26,9 @@ namespace BladeRunner {
void SceneScriptDR06::InitializeScene() {
if (Game_Flag_Query(230)) {
- Setup_Scene_Information(-733.57001f, 136.60001f, -968.64001f, 0);
+ Setup_Scene_Information(-733.57f, 136.6f, -968.64f, 0);
} else {
- Setup_Scene_Information(-707.57001f, 136.60001f, -1132.64f, 472);
+ Setup_Scene_Information(-707.57f, 136.6f, -1132.64f, 472);
}
Scene_Exit_Add_2D_Exit(0, 601, 11, 639, 479, 1);
if (Global_Variable_Query(kVariableChapter) > 3 && Game_Flag_Query(715)) {
diff --git a/engines/bladerunner/script/scene/hf01.cpp b/engines/bladerunner/script/scene/hf01.cpp
index ce36b91e31..d75c381f35 100644
--- a/engines/bladerunner/script/scene/hf01.cpp
+++ b/engines/bladerunner/script/scene/hf01.cpp
@@ -90,9 +90,9 @@ bool SceneScriptHF01::ClickedOn3DObject(const char *objectName, bool a2) {
bool SceneScriptHF01::ClickedOnActor(int actorId) {
int v1;
- if (Global_Variable_Query(45) == 2) {
+ if (Global_Variable_Query(kVariableAffectionTowards) == 2) {
v1 = kActorDektora;
- } else if (Global_Variable_Query(45) == 3) {
+ } else if (Global_Variable_Query(kVariableAffectionTowards) == 3) {
v1 = kActorLucy;
} else {
v1 = -1;
@@ -295,15 +295,15 @@ void SceneScriptHF01::PlayerWalkedIn() {
Actor_Set_At_XYZ(kActorOfficerLeary, 8.2f, 8.0f, -346.67f, 1021);
Actor_Put_In_Set(kActorOfficerGrayford, 37);
Actor_Set_At_XYZ(kActorOfficerGrayford, 51.21f, 8.0f, -540.78f, 796);
- Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 0, 100, 300, 0);
- Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 0, 100, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 0, 100, 300, false);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 0, 100, 300, false);
}
if (!Game_Flag_Query(165) && Actor_Query_Goal_Number(kActorCrazylegs) != 2) {
- if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallLucy1) && Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+ if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallLucy1) && Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
Actor_Put_In_Set(kActorLucy, 37);
Actor_Set_At_XYZ(kActorLucy, -5.0f, 8.0f, -622.0f, 419);
Actor_Set_Targetable(kActorLucy, true);
- } else if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallDektora1) && Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+ } else if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallDektora1) && Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
Actor_Put_In_Set(kActorDektora, 37);
Actor_Set_At_XYZ(kActorDektora, -5.0f, 8.0f, -622.0f, 419);
Actor_Set_Targetable(kActorDektora, true);
diff --git a/engines/bladerunner/script/scene/hf03.cpp b/engines/bladerunner/script/scene/hf03.cpp
index 09bf589bb7..e3b01df4f8 100644
--- a/engines/bladerunner/script/scene/hf03.cpp
+++ b/engines/bladerunner/script/scene/hf03.cpp
@@ -96,8 +96,8 @@ void SceneScriptHF03::sub_401C80() {
Actor_Says(kActorLucy, 210, 13);
Actor_Says(kActorMcCoy, 1655, 15);
Actor_Modify_Friendliness_To_Other(kActorLucy, kActorMcCoy, Random_Query(9, 10));
- if (Actor_Query_Friendliness_To_Other(kActorLucy, kActorMcCoy) > 59 && !Global_Variable_Query(45)) {
- Global_Variable_Set(45, 3);
+ if (Actor_Query_Friendliness_To_Other(kActorLucy, kActorMcCoy) > 59 && Global_Variable_Query(kVariableAffectionTowards) == 0) {
+ Global_Variable_Set(kVariableAffectionTowards, 3);
Actor_Says(kActorLucy, 940, 14);
Actor_Says(kActorMcCoy, 6780, 11);
Actor_Says(kActorLucy, 950, 12);
diff --git a/engines/bladerunner/script/scene/hf05.cpp b/engines/bladerunner/script/scene/hf05.cpp
index ff497ebbe8..c96f852973 100644
--- a/engines/bladerunner/script/scene/hf05.cpp
+++ b/engines/bladerunner/script/scene/hf05.cpp
@@ -114,7 +114,7 @@ bool SceneScriptHF05::ClickedOn3DObject(const char *objectName, bool a2) {
ADQ_Add(kActorVoiceOver, 940, -1);
Ambient_Sounds_Play_Sound(147, 50, 99, 0, 0);
Delay(1500);
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, 181.53999f, 40.630001f, 388.09f, 0, 0, true, 0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, 181.54f, 40.63f, 388.09f, 0, 0, true, 0);
Actor_Face_Heading(kActorMcCoy, 0, false);
Actor_Change_Animation_Mode(kActorMcCoy, 23);
Actor_Clue_Lose(kActorMcCoy, kClueBomb);
@@ -163,7 +163,7 @@ bool SceneScriptHF05::ClickedOnExit(int exitId) {
return true;
}
if (exitId == 2) {
- if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, 277.0f, 40.631f, 410.0f, 0, 1, false, 0) && !Game_Flag_Query(684)) {
+ if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, 277.0f, 40.63f, 410.0f, 0, 1, false, 0) && !Game_Flag_Query(684)) {
Game_Flag_Set(529);
Set_Enter(42, kSceneHF06);
}
@@ -483,10 +483,10 @@ void SceneScriptHF05::sub_403738() {
}
int SceneScriptHF05::sub_404858() {
- if (Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+ if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
return kActorDektora;
}
- if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+ if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
return kActorLucy;
}
return -1;
@@ -494,15 +494,15 @@ int SceneScriptHF05::sub_404858() {
void SceneScriptHF05::sub_4042E4() {
Actor_Force_Stop_Walking(kActorMcCoy);
- Actor_Put_In_Set(kActorOfficerLeary, 41);
- Actor_Set_At_XYZ(kActorOfficerLeary, 430.39999f, 40.630001f, -258.17999f, 300);
- Actor_Put_In_Set(kActorOfficerGrayford, 41);
- Actor_Set_At_XYZ(kActorOfficerGrayford, 526.40002f, 37.18f, -138.17999f, 300);
+ Actor_Put_In_Set(kActorOfficerLeary, kSetHF05);
+ Actor_Set_At_XYZ(kActorOfficerLeary, 430.4f, 40.63f, -258.18f, 300);
+ Actor_Put_In_Set(kActorOfficerGrayford, kSetHF05);
+ Actor_Set_At_XYZ(kActorOfficerGrayford, 526.4f, 37.18f, -138.18f, 300);
ADQ_Flush();
ADQ_Add(kActorOfficerGrayford, 260, -1);
Player_Loses_Control();
- Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 100, 100, 1200, 1);
- return Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 100, 100, 300, 1);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 100, 1200, true);
+ Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 100, 300, true);
}
void SceneScriptHF05::sub_403F0C() {
diff --git a/engines/bladerunner/script/scene/hf06.cpp b/engines/bladerunner/script/scene/hf06.cpp
index 7a41c9eda2..49ea1d81d2 100644
--- a/engines/bladerunner/script/scene/hf06.cpp
+++ b/engines/bladerunner/script/scene/hf06.cpp
@@ -180,12 +180,13 @@ void SceneScriptHF06::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
void SceneScriptHF06::PlayerWalkedIn() {
if (Game_Flag_Query(662)) {
- int actorId;
- if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+ int actorId = -1;
+ if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
actorId = kActorLucy;
- } else {
- actorId = Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599 ? kActorDektora : -1;
- }
+ } else if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+ actorId = kActorDektora;
+ }
+
if (actorId != -1) {
Actor_Put_In_Set(actorId, 42);
if (Game_Flag_Query(559)) {
@@ -267,7 +268,7 @@ void SceneScriptHF06::sub_401EF4() {
Sound_Play(562, 50, 0, 0, 50);
Game_Flag_Set(559);
Scene_Exits_Disable();
- Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, actorId, 15, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, actorId, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
}
void SceneScriptHF06::sub_4023E0() {
diff --git a/engines/bladerunner/script/scene/hf07.cpp b/engines/bladerunner/script/scene/hf07.cpp
index e9fe2f05fd..b653cfd08a 100644
--- a/engines/bladerunner/script/scene/hf07.cpp
+++ b/engines/bladerunner/script/scene/hf07.cpp
@@ -142,11 +142,11 @@ void SceneScriptHF07::DialogueQueueFlushed(int a1) {
}
int SceneScriptHF07::sub_401864() {
- if (Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(3) != 599) {
- return 3;
+ if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(3) != 599) {
+ return kActorDektora;
}
- if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(6) != 599) {
- return 6;
+ if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(6) != 599) {
+ return kActorLucy;
}
return -1;
}
diff --git a/engines/bladerunner/script/scene/kp05.cpp b/engines/bladerunner/script/scene/kp05.cpp
index 9b080aceb0..99fa6c33fa 100644
--- a/engines/bladerunner/script/scene/kp05.cpp
+++ b/engines/bladerunner/script/scene/kp05.cpp
@@ -158,7 +158,7 @@ void SceneScriptKP05::PlayerWalkedIn() {
Actor_Says(kActorMcCoy, 2220, 3);
Actor_Says(kActorSteele, 620, 15);
Actor_Says(kActorSteele, 630, 17);
- Non_Player_Actor_Combat_Mode_On(kActorSteele, 0, 1, kActorMcCoy, 9, 4, 7, 8, 0, -1, -1, 20, 240, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateIdle, true, kActorMcCoy, 9, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 20, 240, false);
}
}
diff --git a/engines/bladerunner/script/scene/ma04.cpp b/engines/bladerunner/script/scene/ma04.cpp
index 5f1b41e998..ead9f1946d 100644
--- a/engines/bladerunner/script/scene/ma04.cpp
+++ b/engines/bladerunner/script/scene/ma04.cpp
@@ -176,9 +176,9 @@ bool SceneScriptMA04::ClickedOn2DRegion(int region) {
Overlay_Remove("MA04OVER");
Delay(500);
if (Game_Flag_Query(653)) {
- if (Global_Variable_Query(45) == 2) {
+ if (Global_Variable_Query(kVariableAffectionTowards) == 2) {
phoneCallWithDektora();
- } else if (Global_Variable_Query(45) == 3) {
+ } else if (Global_Variable_Query(kVariableAffectionTowards) == 3) {
phoneCallWithLucy();
} else {
phoneCallWithClovis();
diff --git a/engines/bladerunner/script/scene/nr01.cpp b/engines/bladerunner/script/scene/nr01.cpp
index 171cea52d8..fd7c9911d0 100644
--- a/engines/bladerunner/script/scene/nr01.cpp
+++ b/engines/bladerunner/script/scene/nr01.cpp
@@ -384,7 +384,7 @@ void SceneScriptNR01::PlayerWalkedIn() {
if (Actor_Query_Goal_Number(kActorGordo) == 230) {
Scene_Exits_Disable();
Actor_Set_Goal_Number(kActorGordo, 231);
- Non_Player_Actor_Combat_Mode_On(kActorGordo, 0, 1, kActorMcCoy, 3, 4, 7, 8, -1, -1, -1, 20, 300, 0);
+ Non_Player_Actor_Combat_Mode_On(kActorGordo, kActorCombatStateIdle, true, kActorMcCoy, 3, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 20, 300, false);
}
} else if (Game_Flag_Query(545)) {
Game_Flag_Reset(545);
diff --git a/engines/bladerunner/script/scene/nr04.cpp b/engines/bladerunner/script/scene/nr04.cpp
index 18583f0d75..00aee0b4ad 100644
--- a/engines/bladerunner/script/scene/nr04.cpp
+++ b/engines/bladerunner/script/scene/nr04.cpp
@@ -187,7 +187,7 @@ void SceneScriptNR04::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
Delay(2500);
Actor_Says(kActorEarlyQ, 290, 3);
sub_401DB0();
- //return true;
+ //return true;
break;
case 213:
Actor_Clue_Acquire(kActorMcCoy, kClueDektorasDressingRoom, 0, kActorEarlyQ);
diff --git a/engines/bladerunner/script/scene/nr09.cpp b/engines/bladerunner/script/scene/nr09.cpp
index fd4faeccb0..7f786e17c8 100644
--- a/engines/bladerunner/script/scene/nr09.cpp
+++ b/engines/bladerunner/script/scene/nr09.cpp
@@ -107,7 +107,7 @@ void SceneScriptNR09::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
void SceneScriptNR09::PlayerWalkedIn() {
if (Game_Flag_Query(614)) {
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -704.07001f, 0.35f, 623.04f, 0, 0, false, 0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -704.07f, 0.35f, 623.04f, 0, 0, false, 0);
Game_Flag_Reset(614);
}
//return false;
diff --git a/engines/bladerunner/script/scene/nr11.cpp b/engines/bladerunner/script/scene/nr11.cpp
index 95ef4b7d84..5c4f4c141c 100644
--- a/engines/bladerunner/script/scene/nr11.cpp
+++ b/engines/bladerunner/script/scene/nr11.cpp
@@ -140,7 +140,7 @@ bool SceneScriptNR11::ClickedOn3DObject(const char *objectName, bool a2) {
} else {
Actor_Says(kActorMcCoy, 3840, 18);
Delay(1000);
- if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 59 && !Global_Variable_Query(45)) {
+ if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 59 && Global_Variable_Query(kVariableAffectionTowards) == 0) {
Music_Play(21, 35, 0, 3, -1, 0, 0);
}
Loop_Actor_Walk_To_XYZ(kActorDektora, -135.0f, 0.33f, -267.0f, 0, 0, false, 0);
@@ -164,8 +164,8 @@ bool SceneScriptNR11::ClickedOn3DObject(const char *objectName, bool a2) {
Actor_Says(kActorMcCoy, 3870, 3);
Actor_Says(kActorDektora, 1070, 14);
Actor_Modify_Friendliness_To_Other(kActorDektora, kActorMcCoy, 5);
- if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 55 && !Global_Variable_Query(45)) {
- Global_Variable_Set(45, 2);
+ if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 55 && Global_Variable_Query(kVariableAffectionTowards) == 0) {
+ Global_Variable_Set(kVariableAffectionTowards, 2);
Actor_Says(kActorDektora, 1130, 17);
Actor_Says(kActorMcCoy, 6365, 12);
Actor_Says(kActorDektora, 1140, 14);
diff --git a/engines/bladerunner/script/scene/ps10.cpp b/engines/bladerunner/script/scene/ps10.cpp
index d45a4b8e67..3957ee1c7d 100644
--- a/engines/bladerunner/script/scene/ps10.cpp
+++ b/engines/bladerunner/script/scene/ps10.cpp
@@ -24,8 +24,301 @@
namespace BladeRunner {
+enum PoliceMazePS10Tracks {
+ kPoliceMazePS10Track1 = 0,
+ kPoliceMazePS10Track2 = 1,
+ kPoliceMazePS10Track3 = 2,
+ kPoliceMazePS10Track4 = 3,
+ kPoliceMazePS10Track5 = 4,
+ kPoliceMazePS10Track6 = 5,
+ kPoliceMazePS10Track7 = 6,
+ kPoliceMazePS10Track8 = 7,
+ kPoliceMazePS10Track9 = 8
+};
+
+static int kPoliceMazePS10TargetCount = 20;
+
+static const int *getPoliceMazePS10TrackData1() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget1,
+ kPMTIObstacleReset, kItemPoliceMazeTarget2,
+ kPMTIFacing, 989,
+ kPMTIPosition, 0,
+ kPMTITargetSet, kItemPoliceMazeTarget1, 1,
+ kPMTITargetSet, kItemPoliceMazeTarget2, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget1,
+ kPMTIWaitRandom, 3000, 5000,
+ kPMTIObstacleSet, kItemPoliceMazeTarget1,
+ kPMTIPlaySound, 159, 100,
+ kPMTIMove, 14,
+ kPMTIWait, 1000,
+ kPMTIRotate, 740, 80,
+ kPMTIEnemySet, kItemPoliceMazeTarget1,
+ kPMTIWait, 0,
+ kPMTIRotate, 488, 80,
+ kPMTIWait, 1000,
+ kPMTIShoot, 27, 33,
+ kPMTIWait, 0,
+ kPMTIRotate, 740, 80,
+ kPMTIPausedReset, kPoliceMazePS10Track2,
+ kPMTIObstacleReset, kItemPoliceMazeTarget1,
+ kPMTIObstacleSet, kItemPoliceMazeTarget2,
+ kPMTIPausedSet, kPoliceMazePS10Track1,
+ kPMTIPosition, 0,
+ kPMTIRestart
+ };
+
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData2() {
+ static int trackData[] = {
+ kPMTIFacing, 740,
+ kPMTIPosition, 0,
+ kPMTIEnemySet, kItemPoliceMazeTarget2,
+ kPMTIMove, 69,
+ kPMTIWait, 500,
+ kPMTIObstacleReset, kItemPoliceMazeTarget2,
+ kPMTIPausedReset, kPoliceMazePS10Track5,
+ kPMTIPausedSet, kPoliceMazePS10Track2,
+ kPMTIPosition, 0,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData3() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget3,
+ kPMTIFacing, 993,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 3000, 5000,
+ kPMTIObstacleSet, kItemPoliceMazeTarget3,
+ kPMTIPlaySound, 159, 100,
+ kPMTITargetSet, kItemPoliceMazeTarget3, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget3,
+ kPMTIMove, 5,
+ kPMTIWait, 1000,
+ kPMTIEnemySet, kItemPoliceMazeTarget3,
+ kPMTIRotate, 233, 80,
+ kPMTIWait, 0,
+ kPMTIRotate, 491, 80,
+ kPMTIWait, 500,
+ kPMTIShoot, 27, 33,
+ kPMTIWait, 500,
+ kPMTIRotate, 233, 80,
+ kPMTIWait, 0,
+ kPMTIRotate, 993, 80,
+ kPMTIPlaySound, 34, 33,
+ kPMTIMove, 0,
+ kPMTIObstacleReset, kItemPoliceMazeTarget3,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData4() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget4,
+ kPMTIFacing, 993,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 3000, 6000,
+ kPMTIObstacleSet, kItemPoliceMazeTarget4,
+ kPMTIPlaySound, 159, 100,
+ kPMTITargetSet, kItemPoliceMazeTarget4, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget4,
+ kPMTIMove, 34,
+ kPMTIWait, 500,
+ kPMTIRotate, 491, 80,
+ kPMTIMove, 0,
+ kPMTILeave,
+ kPMTIObstacleReset, kItemPoliceMazeTarget4,
+ kPMTIPausedReset, kPoliceMazePS10Track8,
+ kPMTIPausedSet, kPoliceMazePS10Track4,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData5() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget5,
+ kPMTIFacing, 0,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 4000, 6000,
+ kPMTIObstacleSet, kItemPoliceMazeTarget5,
+ kPMTIPlaySound, 159, 100,
+ kPMTITargetSet, kItemPoliceMazeTarget5, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget5,
+ kPMTIMove, 5,
+ kPMTIWait, 1000,
+ kPMTIRotate, 512, 100,
+ kPMTIWait, 2000,
+ kPMTIRotate, 0, -100,
+ kPMTIPlaySound, 34, 33,
+ kPMTIMove, 0,
+ kPMTILeave,
+ kPMTIObstacleReset, kItemPoliceMazeTarget5,
+ kPMTIPausedReset, kPoliceMazePS10Track1,
+ kPMTIPausedSet, kPoliceMazePS10Track5,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData6() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget6,
+ kPMTIFacing, 999,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 4000, 6000,
+ kPMTIObstacleSet, kItemPoliceMazeTarget6,
+ kPMTIPlaySound, 159, 100,
+ kPMTITargetSet, kItemPoliceMazeTarget6, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget6,
+ kPMTIMove, 7,
+ kPMTIWait, 500,
+ kPMTIEnemySet, kItemPoliceMazeTarget6,
+ kPMTIRotate, 750, 80,
+ kPMTIWait, 0,
+ kPMTIRotate, 500, 80,
+ kPMTIWait, 1000,
+ kPMTIShoot, 27, 33,
+ kPMTIWait, 0,
+ kPMTIRotate, 750, 80,
+ kPMTIWait, 0,
+ kPMTIRotate, 999, 80,
+ kPMTIPlaySound, 34, 33,
+ kPMTIMove, 0,
+ kPMTIObstacleReset, kItemPoliceMazeTarget6,
+ kPMTIPausedReset, kPoliceMazePS10Track7,
+ kPMTIPausedReset, kPoliceMazePS10Track9,
+ kPMTIPausedSet, kPoliceMazePS10Track6,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData7() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget7,
+ kPMTIFacing, 264,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 3000, 6000,
+ kPMTITargetSet, kItemPoliceMazeTarget7, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget7,
+ kPMTIObstacleSet, kItemPoliceMazeTarget7,
+ kPMTIMove, 89,
+ kPMTIWaitRandom, 4000, 8000,
+ kPMTIFacing, 776,
+ kPMTIMove, 0,
+ kPMTILeave,
+ kPMTIObstacleReset, kItemPoliceMazeTarget7,
+ kPMTIPausedSet, kPoliceMazePS10Track7,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData8() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget8,
+ kPMTIFacing, 993,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 4000, 6000,
+ kPMTIObstacleSet, kItemPoliceMazeTarget8,
+ kPMTIPlaySound, 159, 100,
+ kPMTITargetSet, kItemPoliceMazeTarget8, 1,
+ kPMTIEnemyReset, kItemPoliceMazeTarget8,
+ kPMTIMove, 34,
+ kPMTIWait, 500,
+ kPMTIEnemySet, kItemPoliceMazeTarget8,
+ kPMTIRotate, 491, 80,
+ kPMTIMove, 20,
+ kPMTIWait, 0,
+ kPMTIShoot, 27, 33,
+ kPMTIMove, 0,
+ kPMTIObstacleReset, kItemPoliceMazeTarget8,
+ kPMTIPausedReset, kPoliceMazePS10Track4,
+ kPMTIPausedSet, kPoliceMazePS10Track8,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
+static const int *getPoliceMazePS10TrackData9() {
+ static int trackData[] = {
+ kPMTIActivate, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIVariableInc, kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount,
+ kPMTIObstacleReset, kItemPoliceMazeTarget9,
+ kPMTIFacing, 738,
+ kPMTIPosition, 0,
+ kPMTIWaitRandom, 2000, 5000,
+ kPMTITargetSet, kItemPoliceMazeTarget9, 1,
+ kPMTIEnemySet, kItemPoliceMazeTarget9,
+ kPMTIObstacleSet, kItemPoliceMazeTarget9,
+ kPMTIPlaySound, 0, 33,
+ kPMTIMove, 23,
+ kPMTIPlaySound, 0, 33,
+ kPMTIWait, 200,
+ kPMTIPlaySound, 32, 33,
+ kPMTIRotate, 498, 100,
+ kPMTIPlaySound, 0, 33,
+ kPMTIWait, 100,
+ kPMTIShoot, 27, 33,
+ kPMTIPlaySound, 32, 33,
+ kPMTIMove, 35,
+ kPMTIPlaySound, 32, 33,
+ kPMTIWait, 100,
+ kPMTIShoot, 27, 33,
+ kPMTIPlaySound, 0, 33,
+ kPMTIMove, 23,
+ kPMTIPlaySound, 32, 33,
+ kPMTIWait, 100,
+ kPMTIShoot, 27, 33,
+ kPMTIPlaySound, 32, 33,
+ kPMTIRotate, 758, 100,
+ kPMTIPlaySound, 32, 33,
+ kPMTIMove, 89,
+ kPMTIPlaySound, 0, 33,
+ kPMTIWaitRandom, 4000, 6000,
+ kPMTITargetSet, kItemPoliceMazeTarget9, 1,
+ kPMTIEnemySet, kItemPoliceMazeTarget9,
+ kPMTIFacing, 216,
+ kPMTIPlaySound, 32, 33,
+ kPMTIMove, 69,
+ kPMTIWait, 100,
+ kPMTIPlaySound, 32, 33,
+ kPMTIRotate, 498, 100,
+ kPMTIWait, 100,
+ kPMTIShoot, 27, 33,
+ kPMTIPlaySound, 0, 33,
+ kPMTIRotate, 216, 100,
+ kPMTIPlaySound, 32, 33,
+ kPMTIMove, 0,
+ kPMTIObstacleReset, kItemPoliceMazeTarget9,
+ kPMTIPausedSet, kPoliceMazePS10Track9,
+ kPMTIRestart
+ };
+ return trackData;
+}
+
void SceneScriptPS10::InitializeScene() {
- Police_Maze_Set_Pause_State(1);
+ Police_Maze_Set_Pause_State(true);
if (Game_Flag_Query(15)) {
float x = World_Waypoint_Query_X(4);
float y = World_Waypoint_Query_Y(4);
@@ -38,30 +331,20 @@ void SceneScriptPS10::InitializeScene() {
Ambient_Sounds_Remove_All_Non_Looping_Sounds(0);
Ambient_Sounds_Add_Looping_Sound(387, 50, 1, 1);
Ambient_Sounds_Add_Looping_Sound(54, 50, 1, 1);
- Ambient_Sounds_Add_Sound(1, 10, 50, 16, 25, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(389, 5, 50, 16, 25, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(390, 6, 50, 16, 25, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(443, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(444, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(445, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(446, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(303, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(304, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(305, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(306, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(307, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
- Ambient_Sounds_Add_Sound(308, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
-}
-
-static int track_data_0[] = {-26, 10, 20, -18, 10, 20, -9, 0, -9, 1,-5, 989, -1, 0, -15, 0, 1, -15, 1, 1,-23, 0, -7, 3000, 5000, -8, 0, -10, 159, 100,-2, 14, -3, 1000, -6, 740, 80, -22, 0, -3,0, -6, 488, 80, -3, 1000, -24, 27, 33, -3, 0, -6, 740, 80, -11, 1, -9, 0, -8, 1, -12, 0, -1, 0, -4};
-static int track_data_1[] = {-5, 740, -1, 0, -22, 1, -2, 69, -3, 500, -9, 1, -11, 4, -12, 1, -1, 0, -4};
-static int track_data_2[] = {-26, 10, 20, -18, 10, 20, -9, 2, -5, 993, -1, 0, -7, 3000, 5000, -8, 2, -10, 159, 100, -15, 2, 1, -23, 2, -2, 5, -3, 1000, -22, 2, -6, 233, 80, -3, 0, -6, 491, 80, -3, 500, -24, 27, 33, -3, 500, -6, 233, 80, -3, 0, -6, 993, 80, -10, 34, 33, -2, 0, -9, 2, -4};
-static int track_data_3[] = {-26, 10, 20, -18, 10, 20, -9, 3, -5, 993, -1, 0, -7, 3000, 6000, -8, 3, -10, 159, 100, -15, 3, 1, -23, 3, -2, 34, -3, 500, -6, 491, 80, -2, 0, -25, -9, 3, -11, 7, -12, 3, -4};
-static int track_data_4[] = {-26, 10, 20, -18, 10, 20, -9, 4, -5, 0, -1, 0, -7, 4000, 6000, -8, 4, -10, 159, 100, -15, 4, 1, -23, 4, -2, 5, -3, 1000, -6, 512, 100, -3, 2000, -6, 0, -100, -10, 34, 33, -2, 0, -25, -9, 4, -11, 0, -12, 4, -4};
-static int track_data_5[] = {-26, 10, 20, -18, 10, 20, -9, 5, -5, 999, -1, 0, -7, 4000, 6000, -8, 5, -10, 159, 100, -15, 5, 1, -23, 5, -2, 7, -3, 500, -22, 5, -6, 750, 80, -3, 0, -6, 500, 80, -3, 1000, -24, 27, 33, -3, 0, -6, 750, 80, -3, 0, -6, 999, 80, -10, 34, 33, -2, 0, -9, 5, -11, 6, -11, 8, -12, 5, -4};
-static int track_data_6[] = {-26, 10, 20, -18, 10, 20, -9, 6, -5, 264, -1, 0, -7, 3000, 6000, -15, 6, 1, -23, 6, -8, 6, -2, 89, -7, 4000, 8000, -5, 776, -2, 0, -25, -9, 6, -12, 6, -4};
-static int track_data_7[] = {-26, 10, 20, -18, 10, 20, -9, 7, -5, 993, -1, 0, -7, 4000, 6000, -8, 7, -10, 159, 100, -15, 7, 1, -23, 7, -2, 34, -3, 500, -22, 7, -6, 491, 80, -2, 20, -3, 0, -24, 27, 33, -2, 0, -9, 7, -11, 3, -12, 7, -4};
-static int track_data_8[] = {-26, 10, 20, -18, 10, 20, -9, 8, -5, 738, -1, 0, -7, 2000, 5000, -15, 8, 1, -22, 8, -8, 8, -10, 0, 33, -2, 23, -10, 0, 33, -3, 200, -10, 32, 33, -6, 498, 100, -10, 0, 33, -3, 100, -24, 27, 33, -10, 32, 33, -2, 35, -10, 32, 33, -3, 100, -24, 27, 33, -10, 0, 33, -2, 23, -10, 32, 33, -3, 100, -24, 27, 33, -10, 32, 33, -6, 758, 100, -10, 32, 33, -2, 89, -10, 0, 33, -7, 4000, 6000, -15, 8, 1, -22, 8, -5, 216, -10, 32, 33, -2, 69, -3, 100, -10, 32, 33, -6, 498, 100, -3, 100, -24, 27, 33, -10, 0, 33, -6, 216, 100, -10, 32, 33, -2, 0, -9, 8, -12, 8, -4};
+ Ambient_Sounds_Add_Sound( 1, 10, 50, 16, 25, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(389, 5, 50, 16, 25, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(390, 6, 50, 16, 25, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(443, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(444, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(445, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(446, 2, 100, 14, 16, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(303, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(304, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(305, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(306, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(307, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
+ Ambient_Sounds_Add_Sound(308, 5, 100, 17, 27, -100, 100, -101, -101, 0, 0);
+}
void SceneScriptPS10::SceneLoaded() {
Obstacle_Object("PARKMETR01", true);
@@ -85,26 +368,26 @@ void SceneScriptPS10::SceneLoaded() {
Unclickable_Object("PARKMETR16");
Unobstacle_Object("E.SM.WIRE01", true);
if (!Query_System_Currently_Loading_Game()) {
- Item_Add_To_World(0, 443, 14, -240.0f, -80.74f, 145.0f, 989, 72, 36, true, false, false, true);
- Item_Add_To_World(1, 443, 14, -240.0f, -8.74f, 145.0f, 740, 72, 36, true, false, false, true);
- Item_Add_To_World(2, 445, 14, -165.0f, 111.53f, -10.0f, 993, 72, 36, true, false, false, true);
- Item_Add_To_World(3, 447, 14, -125.0f, 160.0f, -10.0f, 993, 72, 36, true, false, false, true);
- Item_Add_To_World(4, 441, 14, -246.71f, 205.51f, -20.0f, 0, 72, 36, true, false, false, true);
- Item_Add_To_World(5, 445, 14, -27.69f, -86.92f, 434.0f, 999, 72, 36, true, false, false, true);
- Item_Add_To_World(6, 441, 14, -347.15f, 7.68f, -20.0f, 264, 72, 36, true, false, false, true);
- Item_Add_To_World(7, 449, 14, -51.0f, 160.0f, -10.0f, 993, 72, 36, true, false, false, true);
- Item_Add_To_World(8, 445, 14, 39.0f, 9.16f, -20.0f, 738, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget1, 443, 14, -240.0f, -80.74f, 145.0f, 989, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget2, 443, 14, -240.0f, -8.74f, 145.0f, 740, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget3, 445, 14, -165.0f, 111.53f, -10.0f, 993, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget4, 447, 14, -125.0f, 160.0f, -10.0f, 993, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget5, 441, 14, -246.71f, 205.51f, -20.0f, 0, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget6, 445, 14, -27.69f, -86.92f, 434.0f, 999, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget7, 441, 14, -347.15f, 7.68f, -20.0f, 264, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget8, 449, 14, -51.0f, 160.0f, -10.0f, 993, 72, 36, true, false, false, true);
+ Item_Add_To_World(kItemPoliceMazeTarget9, 445, 14, 39.0f, 9.16f, -20.0f, 738, 72, 36, true, false, false, true);
}
- Police_Maze_Target_Track_Add(0, -240.0f, -80.74f, 145.0f, -240.0f, -8.74f, 145.0f, 15, track_data_0, false);
- Police_Maze_Target_Track_Add(1, -240.0f, -8.74f, 145.0f, -450.0f, -8.74f, 145.0f, 70, track_data_1, false);
- Police_Maze_Target_Track_Add(2, -165.0f, 111.53f, -10.0f, -165.0f, 167.53f, -10.0f, 6, track_data_2, true);
- Police_Maze_Target_Track_Add(3, -125.0f, 160.0f, -10.0f, -51.0f, 160.0f, -10.0f, 35, track_data_3, false);
- Police_Maze_Target_Track_Add(4, -246.71f, 205.51f, -20.0f, -246.71f, 241.51f, -20.0f, 6, track_data_4, true);
- Police_Maze_Target_Track_Add(5, -27.69f, -86.92f, 434.0f, -27.69f, -18.92f, 434.0f, 8, track_data_5, true);
- Police_Maze_Target_Track_Add(6, -347.15f, 7.68f, -20.0f, 39.0f, 9.16f, -20.0f, 90, track_data_6, false);
- Police_Maze_Target_Track_Add(7, -51.0f, 160.0f, -10.0f, -125.0f, 160.0f, -10.0f, 35, track_data_7, true);
- Police_Maze_Target_Track_Add(8, 39.0f, 9.16f, -20.0f, -347.15f, 7.68f, -20.0f, 90, track_data_8, false);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget1, -240.0f, -80.74f, 145.0f, -240.0f, -8.74f, 145.0f, 15, getPoliceMazePS10TrackData1(), false);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget2, -240.0f, -8.74f, 145.0f, -450.0f, -8.74f, 145.0f, 70, getPoliceMazePS10TrackData2(), false);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget3, -165.0f, 111.53f, -10.0f, -165.0f, 167.53f, -10.0f, 6, getPoliceMazePS10TrackData3(), true);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget4, -125.0f, 160.0f, -10.0f, -51.0f, 160.0f, -10.0f, 35, getPoliceMazePS10TrackData4(), false);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget5, -246.71f, 205.51f, -20.0f, -246.71f, 241.51f, -20.0f, 6, getPoliceMazePS10TrackData5(), true);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget6, -27.69f, -86.92f, 434.0f, -27.69f, -18.92f, 434.0f, 8, getPoliceMazePS10TrackData6(), true);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget7, -347.15f, 7.68f, -20.0f, 39.0f, 9.16f, -20.0f, 90, getPoliceMazePS10TrackData7(), false);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget8, -51.0f, 160.0f, -10.0f, -125.0f, 160.0f, -10.0f, 35, getPoliceMazePS10TrackData8(), true);
+ Police_Maze_Target_Track_Add(kItemPoliceMazeTarget9, 39.0f, 9.16f, -20.0f, -347.15f, 7.68f, -20.0f, 90, getPoliceMazePS10TrackData9(), false);
Preload(441);
Preload(442);
Preload(443);
@@ -132,13 +415,13 @@ bool SceneScriptPS10::ClickedOnActor(int actorId) {
bool SceneScriptPS10::ClickedOnItem(int itemId, bool a2) {
if (Player_Query_Combat_Mode()) {
switch (itemId) {
- case 3:
+ case kItemPoliceMazeTarget4:
Sound_Play(4, 50, 0, 0, 50);
break;
- case 4:
+ case kItemPoliceMazeTarget5:
Sound_Play(555, 50, 0, 0, 50);
break;
- case 6:
+ case kItemPoliceMazeTarget7:
Sound_Play(555, 50, 0, 0, 50);
break;
default:
@@ -146,34 +429,34 @@ bool SceneScriptPS10::ClickedOnItem(int itemId, bool a2) {
break;
}
Item_Spin_In_World(itemId);
- if (itemId == 0) {
- Item_Flag_As_Non_Target(0);
- Item_Flag_As_Non_Target(1);
+ if (itemId == kItemPoliceMazeTarget1) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget1);
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget2);
}
- if (itemId == 1) {
- Item_Flag_As_Non_Target(0);
- Item_Flag_As_Non_Target(1);
+ if (itemId == kItemPoliceMazeTarget2) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget1);
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget2);
}
- if (itemId == 2) {
- Item_Flag_As_Non_Target(2);
+ if (itemId == kItemPoliceMazeTarget3) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget3);
}
- if (itemId == 3) {
- Item_Flag_As_Non_Target(3);
+ if (itemId == kItemPoliceMazeTarget4) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget4);
}
- if (itemId == 4) {
- Item_Flag_As_Non_Target(4);
+ if (itemId == kItemPoliceMazeTarget5) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget5);
}
- if (itemId == 5) {
- Item_Flag_As_Non_Target(5);
+ if (itemId == kItemPoliceMazeTarget6) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget6);
}
- if (itemId == 6) {
- Item_Flag_As_Non_Target(6);
+ if (itemId == kItemPoliceMazeTarget7) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget7);
}
- if (itemId == 7) {
- Item_Flag_As_Non_Target(7);
+ if (itemId == kItemPoliceMazeTarget8) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget8);
}
- if (itemId == 8) {
- Item_Flag_As_Non_Target(8);
+ if (itemId == kItemPoliceMazeTarget9) {
+ Item_Flag_As_Non_Target(kItemPoliceMazeTarget9);
} else {
Item_Flag_As_Non_Target(itemId);
}
@@ -185,12 +468,12 @@ bool SceneScriptPS10::ClickedOnItem(int itemId, bool a2) {
bool SceneScriptPS10::ClickedOnExit(int exitId) {
if (exitId == 1) {
- if (!Loop_Actor_Walk_To_Waypoint(kActorMcCoy, 6, 12, 1, false)) {
+ if (!Loop_Actor_Walk_To_Waypoint(kActorMcCoy, 6, 12, true, false)) {
Game_Flag_Set(14);
- sub_402238();
- Global_Variable_Decrement(9, 20 - Global_Variable_Query(10));
- Global_Variable_Set(10, 20);
- Set_Enter(14, kScenePS11);
+ removeTargets();
+ Global_Variable_Decrement(kVariablePoliceMazeScore, kPoliceMazePS10TargetCount - Global_Variable_Query(kVariablePoliceMazePS10TargetCounter));
+ Global_Variable_Set(kVariablePoliceMazePS10TargetCounter, kPoliceMazePS10TargetCount);
+ Set_Enter(kSetPS10_PS11_PS12_PS13, kScenePS11);
}
return true;
}
@@ -210,18 +493,18 @@ void SceneScriptPS10::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
void SceneScriptPS10::PlayerWalkedIn() {
if (Game_Flag_Query(15)) {
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -352.09f, -9.23f, 267.95f, 0, 0, true, 0);
- Police_Maze_Set_Pause_State(0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -352.09f, -9.23f, 267.95f, 0, false, true, 0);
+ Police_Maze_Set_Pause_State(false);
Game_Flag_Reset(15);
//return true;
return;
} else {
Player_Set_Combat_Mode(true);
- Loop_Actor_Walk_To_Waypoint(kActorMcCoy, 5, 0, 0, true);
- Actor_Says(kActorAnsweringMachine, 280, 3);
- Actor_Says(kActorAnsweringMachine, 290, 3);
- Actor_Says(kActorAnsweringMachine, 300, 3);
- Police_Maze_Set_Pause_State(0);
+ Loop_Actor_Walk_To_Waypoint(kActorMcCoy, 5, 0, false, true);
+ Actor_Says(kActorAnsweringMachine, 280, kAnimationModeTalk);
+ Actor_Says(kActorAnsweringMachine, 290, kAnimationModeTalk);
+ Actor_Says(kActorAnsweringMachine, 300, kAnimationModeTalk);
+ Police_Maze_Set_Pause_State(false);
//return true;
return;
}
@@ -233,16 +516,16 @@ void SceneScriptPS10::PlayerWalkedOut() {
void SceneScriptPS10::DialogueQueueFlushed(int a1) {
}
-void SceneScriptPS10::sub_402238() {
- Item_Remove_From_World(0);
- Item_Remove_From_World(1);
- Item_Remove_From_World(2);
- Item_Remove_From_World(3);
- Item_Remove_From_World(4);
- Item_Remove_From_World(5);
- Item_Remove_From_World(6);
- Item_Remove_From_World(7);
- Item_Remove_From_World(8);
+void SceneScriptPS10::removeTargets() {
+ Item_Remove_From_World(kItemPoliceMazeTarget1);
+ Item_Remove_From_World(kItemPoliceMazeTarget2);
+ Item_Remove_From_World(kItemPoliceMazeTarget3);
+ Item_Remove_From_World(kItemPoliceMazeTarget4);
+ Item_Remove_From_World(kItemPoliceMazeTarget5);
+ Item_Remove_From_World(kItemPoliceMazeTarget6);
+ Item_Remove_From_World(kItemPoliceMazeTarget7);
+ Item_Remove_From_World(kItemPoliceMazeTarget8);
+ Item_Remove_From_World(kItemPoliceMazeTarget9);
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/scene/ps11.cpp b/engines/bladerunner/script/scene/ps11.cpp
index 1aa227b022..e6311b3ca1 100644
--- a/engines/bladerunner/script/scene/ps11.cpp
+++ b/engines/bladerunner/script/scene/ps11.cpp
@@ -254,7 +254,7 @@ void SceneScriptPS11::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
}
void SceneScriptPS11::PlayerWalkedIn() {
- Police_Maze_Set_Pause_State(0);
+ Police_Maze_Set_Pause_State(false);
}
void SceneScriptPS11::PlayerWalkedOut() {
diff --git a/engines/bladerunner/script/scene/ps12.cpp b/engines/bladerunner/script/scene/ps12.cpp
index 7db642891e..d4d771a94f 100644
--- a/engines/bladerunner/script/scene/ps12.cpp
+++ b/engines/bladerunner/script/scene/ps12.cpp
@@ -25,7 +25,7 @@
namespace BladeRunner {
void SceneScriptPS12::InitializeScene() {
- Police_Maze_Set_Pause_State(1);
+ Police_Maze_Set_Pause_State(true);
if (Game_Flag_Query(16)) {
Scene_Loop_Start_Special(0, 0, 0);
Scene_Loop_Set_Default(1);
@@ -96,9 +96,9 @@ void SceneScriptPS12::SceneLoaded() {
}
Police_Maze_Target_Track_Add(29, -691.8f, -9.06f, 587.67f, -649.11f, -9.06f, 587.71f, 6, track_data_29, true);
Police_Maze_Target_Track_Add(30, -679.6f, -45.4f, 721.05f, -679.6f, -1.4f, 721.05f, 6, track_data_30, true);
- Police_Maze_Target_Track_Add(31, -414.04f, -8.98f, 711.917f, -459.54f, -8.99f, 707.81f, 6, track_data_31, false);
+ Police_Maze_Target_Track_Add(31, -414.04f, -8.98f, 711.91f, -459.54f, -8.99f, 707.81f, 6, track_data_31, false);
Police_Maze_Target_Track_Add(32, -440.0f, -8.97f, 1137.0f, -430.0f, -8.97f, 921.0f, 6, track_data_32, false);
- Police_Maze_Target_Track_Add(33, -764.92f, -0.84f, 950.21997f, -722.92f, -0.84f, 950.22f, 6, track_data_33, false);
+ Police_Maze_Target_Track_Add(33, -764.92f, -0.84f, 950.22f, -722.92f, -0.84f, 950.22f, 6, track_data_33, false);
Police_Maze_Target_Track_Add(34, -696.0f, -5.7f, 1185.0f, -635.0f, -5.7f, 1185.0f, 20, track_data_34, false);
Police_Maze_Target_Track_Add(35, -635.0f, -5.7f, 1165.0f, -620.0f, -8.63f, 1366.0f, 10, track_data_35, false);
Police_Maze_Target_Track_Add(36, -620.0f, -8.63f, 1366.0f, -595.0f, -8.63f, 1366.0f, 10, track_data_36, false);
@@ -270,7 +270,7 @@ void SceneScriptPS12::PlayerWalkedIn() {
Loop_Actor_Walk_To_XYZ(kActorMcCoy, -546.0f, -9.06f, 570.0f, 0, 1, false, 0);
Game_Flag_Reset(16);
}
- Police_Maze_Set_Pause_State(0);
+ Police_Maze_Set_Pause_State(false);
}
void SceneScriptPS12::PlayerWalkedOut() {
diff --git a/engines/bladerunner/script/scene/ps13.cpp b/engines/bladerunner/script/scene/ps13.cpp
index 83f99faf4f..f525d48137 100644
--- a/engines/bladerunner/script/scene/ps13.cpp
+++ b/engines/bladerunner/script/scene/ps13.cpp
@@ -25,7 +25,7 @@
namespace BladeRunner {
void SceneScriptPS13::InitializeScene() {
- Police_Maze_Set_Pause_State(1);
+ Police_Maze_Set_Pause_State(true);
if (Game_Flag_Query(18)) {
Scene_Loop_Start_Special(0, 0, 0);
Scene_Loop_Set_Default(1);
@@ -99,7 +99,7 @@ void SceneScriptPS13::SceneLoaded() {
Item_Add_To_World(51, 443, 14, -24.0f, 102.0f, 1625.0f, 823, 72, 36, true, false, false, true);
Item_Add_To_World(52, 449, 14, 180.0f, -72.7f, 1605.0f, 305, 72, 36, true, false, false, true);
Item_Add_To_World(53, 443, 14, 127.79f, 14.56f, 1703.03f, 356, 72, 36, true, false, false, true);
- Item_Add_To_World(54, 443, 14, 136.37f, -6.84f, 1425.4301f, 512, 72, 36, true, false, false, true);
+ Item_Add_To_World(54, 443, 14, 136.37f, -6.84f, 1425.43f, 512, 72, 36, true, false, false, true);
Item_Add_To_World(55, 441, 14, 77.83f, -79.8f, 1520.5f, 327, 72, 36, true, false, false, true);
Item_Add_To_World(56, 441, 14, 77.83f, -7.8f, 1520.5f, 327, 72, 36, true, false, false, true);
Item_Add_To_World(57, 443, 14, -88.0f, -8.8f, 1520.5f, 327, 72, 36, true, false, false, true);
@@ -115,7 +115,7 @@ void SceneScriptPS13::SceneLoaded() {
Police_Maze_Target_Track_Add(51, -24.0f, 102.0f, 1625.0f, -24.0f, 138.0f, 1625.0f, 10, track_data_51, false);
Police_Maze_Target_Track_Add(52, 180.0f, -72.7f, 1605.0f, 180.0f, -0.7f, 1605.0f, 10, track_data_52, false);
Police_Maze_Target_Track_Add(53, 127.79f, 14.56f, 1703.03f, -56.07f, 1.89f, 1589.04f, 6, track_data_53, false);
- Police_Maze_Target_Track_Add(54, 136.37f, -6.84f, 1425.4301f, 117.55f, -6.84f, 1442.09f, 4, track_data_54, false);
+ Police_Maze_Target_Track_Add(54, 136.37f, -6.84f, 1425.43f, 117.55f, -6.84f, 1442.09f, 4, track_data_54, false);
Police_Maze_Target_Track_Add(55, 77.83f, -79.8f, 1520.5f, 77.83f, -7.8f, 1520.5f, 15, track_data_55, false);
Police_Maze_Target_Track_Add(56, 77.83f, -7.8f, 1520.5f, -88.0f, -8.8f, 1520.5f, 15, track_data_56, false);
Police_Maze_Target_Track_Add(57, -88.0f, -8.8f, 1520.5f, -88.0f, -80.8f, 1520.5f, 15, track_data_57, false);
@@ -255,7 +255,7 @@ void SceneScriptPS13::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
}
void SceneScriptPS13::PlayerWalkedIn() {
- Police_Maze_Set_Pause_State(0);
+ Police_Maze_Set_Pause_State(false);
}
void SceneScriptPS13::PlayerWalkedOut() {
diff --git a/engines/bladerunner/script/scene/rc01.cpp b/engines/bladerunner/script/scene/rc01.cpp
index 867e3bd661..db89807022 100644
--- a/engines/bladerunner/script/scene/rc01.cpp
+++ b/engines/bladerunner/script/scene/rc01.cpp
@@ -74,6 +74,8 @@ void SceneScriptRC01::InitializeScene() {
// Global_Variable_Set(kVariableChapter, 2);
// Chapter_Enter(2, kSetRC03, kSceneRC03);
+ Set_Enter(14, 73);
+
#endif
if (!Game_Flag_Query(kFlagIntroPlayed)) {
diff --git a/engines/bladerunner/script/scene/tb05.cpp b/engines/bladerunner/script/scene/tb05.cpp
index b3299292f1..a7797414d6 100644
--- a/engines/bladerunner/script/scene/tb05.cpp
+++ b/engines/bladerunner/script/scene/tb05.cpp
@@ -52,10 +52,10 @@ void SceneScriptTB05::SceneLoaded() {
Clickable_Object("MONITOR05");
Unclickable_Object("SMUDGE_GLASS01");
if (!Actor_Clue_Query(kActorMcCoy, kClueDragonflyEarring)) {
- Item_Add_To_World(76, 940, 72, 76.160004f, 147.36f, -235.14999f, 0, 6, 6, false, true, false, true);
+ Item_Add_To_World(76, 940, 72, 76.16f, 147.36f, -235.15f, 0, 6, 6, false, true, false, true);
}
if (!Actor_Clue_Query(kActorMcCoy, kClueTyrellSalesPamphlet1) && !Actor_Clue_Query(kActorMcCoy, kClueTyrellSalesPamphlet2) && (Game_Flag_Query(kFlagGordoIsReplicant) || Game_Flag_Query(kFlagLucyIsReplicant))) {
- Item_Add_To_World(119, 972, 72, 129.00999f, 147.12f, -162.98f, 0, 8, 8, false, true, false, true);
+ Item_Add_To_World(119, 972, 72, 129.01f, 147.12f, -162.98f, 0, 8, 8, false, true, false, true);
}
}
diff --git a/engines/bladerunner/script/scene/ug02.cpp b/engines/bladerunner/script/scene/ug02.cpp
index c6b96c65a5..f8f1e84578 100644
--- a/engines/bladerunner/script/scene/ug02.cpp
+++ b/engines/bladerunner/script/scene/ug02.cpp
@@ -153,9 +153,9 @@ bool SceneScriptUG02::ClickedOnExit(int exitId) {
Loop_Actor_Travel_Stairs(kActorMcCoy, 4, 0, 0);
Footstep_Sound_Override_Off();
int v3 = Player_Query_Combat_Mode();
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -96.57f, 74.870003f, -271.28f, 0, 0, v3, 0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -96.57f, 74.87f, -271.28f, 0, 0, v3, 0);
int v4 = Player_Query_Combat_Mode();
- Loop_Actor_Walk_To_XYZ(kActorMcCoy, -95.0f, 74.870003f, -503.0f, 0, 0, v4, 0);
+ Loop_Actor_Walk_To_XYZ(kActorMcCoy, -95.0f, 74.87f, -503.0f, 0, 0, v4, 0);
Game_Flag_Set(315);
Set_Enter(74, kSceneUG01);
}
diff --git a/engines/bladerunner/script/scene/ug05.cpp b/engines/bladerunner/script/scene/ug05.cpp
index c3996dca37..3348ebbfb6 100644
--- a/engines/bladerunner/script/scene/ug05.cpp
+++ b/engines/bladerunner/script/scene/ug05.cpp
@@ -222,10 +222,10 @@ void SceneScriptUG05::DialogueQueueFlushed(int a1) {
}
int SceneScriptUG05::sub_4021B0() {
- if (Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+ if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
return kActorDektora;
}
- if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+ if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
return kActorLucy;
}
return -1;
diff --git a/engines/bladerunner/script/scene/ug07.cpp b/engines/bladerunner/script/scene/ug07.cpp
index 9a586407fc..4a256b02c7 100644
--- a/engines/bladerunner/script/scene/ug07.cpp
+++ b/engines/bladerunner/script/scene/ug07.cpp
@@ -119,7 +119,7 @@ bool SceneScriptUG07::ClickedOnExit(int exitId) {
Actor_Set_At_XYZ(kActorClovis, 118.02f, -12.21f, -154.0f, 768);
Player_Set_Combat_Mode(true);
Actor_Face_Actor(kActorMcCoy, kActorClovis, true);
- Loop_Actor_Walk_To_XYZ(kActorClovis, 98.019997f, -12.21f, -154.0f, 0, 0, false, 0);
+ Loop_Actor_Walk_To_XYZ(kActorClovis, 98.02f, -12.21f, -154.0f, 0, 0, false, 0);
Actor_Face_Actor(kActorClovis, kActorMcCoy, true);
Actor_Set_Goal_Number(kActorMcCoy, 301);
Actor_Face_Heading(kActorMcCoy, 0, true);
diff --git a/engines/bladerunner/script/scene/ug15.cpp b/engines/bladerunner/script/scene/ug15.cpp
index 8477e5b46f..3503992457 100644
--- a/engines/bladerunner/script/scene/ug15.cpp
+++ b/engines/bladerunner/script/scene/ug15.cpp
@@ -26,9 +26,9 @@ namespace BladeRunner {
void SceneScriptUG15::InitializeScene() {
if (Game_Flag_Query(353)) {
- Setup_Scene_Information(-25.0f, 26.309999f, -434.0f, 520);
+ Setup_Scene_Information(-25.0f, 26.31f, -434.0f, 520);
} else if (Game_Flag_Query(153)) {
- Setup_Scene_Information(-17.0f, 26.309999f, -346.0f, 711);
+ Setup_Scene_Information(-17.0f, 26.31f, -346.0f, 711);
} else if (Game_Flag_Query(355)) {
Setup_Scene_Information(-18.0f, 48.07f, 62.0f, 650);
} else {
diff --git a/engines/bladerunner/script/scene/ug18.cpp b/engines/bladerunner/script/scene/ug18.cpp
index cafe42654a..05ef4559fb 100644
--- a/engines/bladerunner/script/scene/ug18.cpp
+++ b/engines/bladerunner/script/scene/ug18.cpp
@@ -110,7 +110,7 @@ bool SceneScriptUG18::ClickedOnItem(int itemId, bool a2) {
bool SceneScriptUG18::ClickedOnExit(int exitId) {
if (exitId == 0) {
- if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -684.712f, 0.0f, 171.59f, 0, 1, false, 0)) {
+ if (!Loop_Actor_Walk_To_XYZ(kActorMcCoy, -684.71f, 0.0f, 171.59f, 0, 1, false, 0)) {
Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
Ambient_Sounds_Remove_All_Looping_Sounds(1);
Game_Flag_Set(435);
@@ -323,9 +323,8 @@ void SceneScriptUG18::sub_402734() {
}
void SceneScriptUG18::sub_402DE8() {
-
if (Player_Query_Agenda()) {
- if (Global_Variable_Query(45) > 1 || Player_Query_Agenda() == 2) {
+ if (Global_Variable_Query(kVariableAffectionTowards) > 1 || Player_Query_Agenda() == 2) {
sub_403114();
} else {
sub_402F8C();
diff --git a/engines/bladerunner/script/scene_script.cpp b/engines/bladerunner/script/scene_script.cpp
index 01fe3e3b1e..ff43853044 100644
--- a/engines/bladerunner/script/scene_script.cpp
+++ b/engines/bladerunner/script/scene_script.cpp
@@ -161,8 +161,10 @@ void SceneScript::initializeScene() {
}
void SceneScript::sceneLoaded() {
+ _vm->_sceneIsLoading = true;
_inScriptCounter++;
_currentScript->SceneLoaded();
+ _vm->_sceneIsLoading = false;
_inScriptCounter--;
}
diff --git a/engines/bladerunner/script/scene_script.h b/engines/bladerunner/script/scene_script.h
index 54047ed8a8..51cac52db6 100644
--- a/engines/bladerunner/script/scene_script.h
+++ b/engines/bladerunner/script/scene_script.h
@@ -385,7 +385,7 @@ DECLARE_SCRIPT(PS09)
END_SCRIPT
DECLARE_SCRIPT(PS10)
- void sub_402238();
+ void removeTargets();
END_SCRIPT
DECLARE_SCRIPT(PS11)
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 2aca6db9d3..3c68717116 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -45,6 +45,7 @@
#include "bladerunner/set_effects.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
+#include "bladerunner/script/police_maze.h"
#include "bladerunner/slice_animations.h"
#include "bladerunner/slice_renderer.h"
#include "bladerunner/suspects_database.h"
@@ -52,6 +53,7 @@
#include "bladerunner/ui/elevator.h"
#include "bladerunner/ui/esper.h"
#include "bladerunner/ui/kia.h"
+#include "bladerunner/ui/scores.h"
#include "bladerunner/ui/spinner.h"
#include "bladerunner/ui/vk.h"
#include "bladerunner/vector.h"
@@ -130,7 +132,7 @@ void ScriptBase::Actor_Face_Heading(int actorId, int heading, bool animate) {
}
int ScriptBase::Actor_Query_Friendliness_To_Other(int actorId, int otherActorId) {
- return _vm->_actors[actorId]->_friendlinessToOther[otherActorId];
+ return _vm->_actors[actorId]->getFriendlinessToOther(otherActorId);
}
void ScriptBase::Actor_Modify_Friendliness_To_Other(int actorId, int otherActorId, signed int change) {
@@ -158,27 +160,27 @@ void ScriptBase::Actor_Set_Combat_Aggressiveness(int actorId, int combatAggressi
}
int ScriptBase::Actor_Query_Current_HP(int actorId) {
- return _vm->_actors[actorId]->_currentHP;
+ return _vm->_actors[actorId]->getCurrentHP();
}
int ScriptBase::Actor_Query_Max_HP(int actorId) {
- return _vm->_actors[actorId]->_maxHP;
+ return _vm->_actors[actorId]->getMaxHP();
}
int ScriptBase::Actor_Query_Combat_Aggressiveness(int actorId) {
- return _vm->_actors[actorId]->_combatAggressiveness;
+ return _vm->_actors[actorId]->getCombatAggressiveness();
}
int ScriptBase::Actor_Query_Honesty(int actorId) {
- return _vm->_actors[actorId]->_honesty;
+ return _vm->_actors[actorId]->getHonesty();
}
int ScriptBase::Actor_Query_Intelligence(int actorId) {
- return _vm->_actors[actorId]->_intelligence;
+ return _vm->_actors[actorId]->getIntelligence();
}
int ScriptBase::Actor_Query_Stability(int actorId) {
- return _vm->_actors[actorId]->_stability;
+ return _vm->_actors[actorId]->getStability();
}
void ScriptBase::Actor_Modify_Current_HP(int actorId, signed int change) {
@@ -218,8 +220,8 @@ void ScriptBase::Actor_Combat_AI_Hit_Attempt(int actorId) {
_vm->_actors[actorId]->_combatInfo->hitAttempt();
}
-void ScriptBase::Non_Player_Actor_Combat_Mode_On(int actorId, int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int a12, int a13, int a14) {
- _vm->_actors[actorId]->combatModeOn(a2, a3, otherActorId, a5, animationModeCombatIdle, animationModeCombatWalk, animationModeCombatRun, a9, a10, a11, a12, a13, a14);
+void ScriptBase::Non_Player_Actor_Combat_Mode_On(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool unstoppable) {
+ _vm->_actors[actorId]->combatModeOn(initialState, rangedAttack, enemyId, waypointType, animationModeCombatIdle, animationModeCombatWalk, animationModeCombatRun, fleeRatio, coverRatio, actionRatio, damage, range, unstoppable);
}
void ScriptBase::Non_Player_Actor_Combat_Mode_Off(int actorId) {
@@ -680,15 +682,20 @@ void ScriptBase::Item_Remove_From_World(int itemId) {
}
void ScriptBase::Item_Spin_In_World(int itemId) {
- warning("Item_Spin_In_World(%d)", itemId);
+ _vm->_items->spinInWorld(itemId);
+ if (_vm->_items->isPoliceMazeEnemy(itemId)) {
+ Police_Maze_Increment_Score(1);
+ } else {
+ Police_Maze_Decrement_Score(1);
+ }
}
void ScriptBase::Item_Flag_As_Target(int itemId) {
- warning("Item_Flag_As_Target(%d)", itemId);
+ _vm->_items->setIsTarget(itemId, true);
}
void ScriptBase::Item_Flag_As_Non_Target(int itemId) {
- warning("Item_Flag_As_Non_Target(%d)", itemId);
+ _vm->_items->setIsTarget(itemId, false);
}
void ScriptBase::Item_Pickup_Spin_Effect(int animationId, int x, int y) {
@@ -723,8 +730,9 @@ int ScriptBase::Animation_Skip_To_Frame() {
void ScriptBase::Delay(int miliseconds) {
Player_Loses_Control();
int endTime = _vm->getTotalPlayTime() + miliseconds;
- while ((int)_vm->getTotalPlayTime() < endTime)
+ while ((int)_vm->getTotalPlayTime() < endTime) {
_vm->gameTick();
+ }
Player_Gains_Control();
}
@@ -825,8 +833,7 @@ int ScriptBase::Random_Query(int min, int max) {
}
void ScriptBase::Sound_Play(int id, int volume, int panFrom, int panTo, int priority) {
- const char *name = _vm->_gameInfo->getSfxTrack(id);
- _vm->_audioPlayer->playAud(name, volume, panFrom, panTo, priority);
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(id), volume, panFrom, panTo, priority);
}
void ScriptBase::Sound_Play_Speech_Line(int actorId, int sentenceId, int volume, int a4, int priority) {
@@ -892,8 +899,7 @@ void ScriptBase::Footstep_Sound_Override_Off() {
}
bool ScriptBase::Music_Play(int musicId, int volume, int pan, int timeFadeIn, int timePlay, int loop, int timeFadeOut) {
- const char *musicName = _vm->_gameInfo->getMusicTrack(musicId);
- return _vm->_music->play(musicName, volume, pan, timeFadeIn, timePlay, loop, timeFadeOut);
+ return _vm->_music->play(_vm->_gameInfo->getMusicTrack(musicId), volume, pan, timeFadeIn, timePlay, loop, timeFadeOut);
}
void ScriptBase::Music_Adjust(int volume, int pan, int delay) {
@@ -1075,31 +1081,56 @@ float ScriptBase::World_Waypoint_Query_Z(int waypointId) {
return _vm->_waypoints->getZ(waypointId);
}
-void ScriptBase::Combat_Cover_Waypoint_Set_Data(int combatCoverId, int type, int setId, int sceneId, float x, float y, float z) {
- //TODO
- warning("Combat_Cover_Waypoint_Set_Data(%d, %d, %d, %d, %f, %f, %f)", combatCoverId, type, setId, sceneId, x, y, z);
+void ScriptBase::Combat_Cover_Waypoint_Set_Data(int coverWaypointId, int type, int setId, int sceneId, float x, float y, float z) {
+ assert(coverWaypointId < (int)_vm->_combat->_coverWaypoints.size());
+
+ _vm->_combat->_coverWaypoints[coverWaypointId].type = type;
+ _vm->_combat->_coverWaypoints[coverWaypointId].setId = setId;
+ _vm->_combat->_coverWaypoints[coverWaypointId].sceneId = sceneId;
+ _vm->_combat->_coverWaypoints[coverWaypointId].position.x = x;
+ _vm->_combat->_coverWaypoints[coverWaypointId].position.y = y;
+ _vm->_combat->_coverWaypoints[coverWaypointId].position.z = z;
}
-void ScriptBase::Combat_Flee_Waypoint_Set_Data(int combatFleeWaypointId, int type, int setId, int sceneId, float x, float y, float z, int a8) {
- //TODO
- warning("Combat_Cover_Waypoint_Set_Data(%d, %d, %d, %d, %f, %f, %f, %d)", combatFleeWaypointId, type, setId, sceneId, x, y, z, a8);
+void ScriptBase::Combat_Flee_Waypoint_Set_Data(int fleeWaypointId, int type, int setId, int sceneId, float x, float y, float z, int a8) {
+ assert(fleeWaypointId < (int)_vm->_combat->_fleeWaypoints.size());
+
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].type = type;
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].setId = setId;
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].sceneId = sceneId;
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].position.x = x;
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].position.y = y;
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].position.z = z;
+ _vm->_combat->_fleeWaypoints[fleeWaypointId].field7 = a8;
}
-void ScriptBase::Police_Maze_Target_Track_Add(int itemId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, signed int data[], bool a10) {
- //TODO
- warning("Police_Maze_Target_Track_Add(%d, %f, %f, %f, %f, %f, %f, %d, %p, %d)", itemId, startX, startY, startZ, endX, endY, endZ, steps, (void *)data, a10);
+void ScriptBase::Police_Maze_Target_Track_Add(int itemId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, const int* instructions, bool isActive) {
+ _vm->_policeMaze->_tracks[itemId]->add(itemId, startX, startY, startZ, endX, endY, endZ, steps, instructions, isActive);
+ _vm->_policeMaze->activate();
+}
+
+int ScriptBase::Police_Maze_Query_Score() {
+ return Global_Variable_Query(kVariablePoliceMazeScore);
+}
+void ScriptBase::Police_Maze_Zero_Score() {
+ Global_Variable_Reset(kVariablePoliceMazeScore);
}
-// ScriptBase::Police_Maze_Query_Score
-// ScriptBase::Police_Maze_Zero_Score
-// ScriptBase::Police_Maze_Increment_Score
-// ScriptBase::Police_Maze_Decrement_Score
-// ScriptBase::Police_Maze_Set_Score
+void ScriptBase::Police_Maze_Increment_Score(int delta) {
+ Global_Variable_Set(kVariablePoliceMazeScore, Global_Variable_Query(kVariablePoliceMazeScore) + delta);
+}
-void ScriptBase::Police_Maze_Set_Pause_State(int a1) {
- //TODO
- warning("Police_Maze_Set_Pause_State(%d)", a1);
+void ScriptBase::Police_Maze_Decrement_Score(int delta) {
+ Global_Variable_Set(kVariablePoliceMazeScore, Global_Variable_Query(kVariablePoliceMazeScore) - delta);
+}
+
+void ScriptBase::Police_Maze_Set_Score(int value) {
+ Global_Variable_Set(kVariablePoliceMazeScore, value);
+}
+
+void ScriptBase::Police_Maze_Set_Pause_State(bool state) {
+ _vm->_policeMaze->setPauseState(state);
}
void ScriptBase::CDB_Set_Crime(int clueId, int crimeId) {
@@ -1181,18 +1212,15 @@ int ScriptBase::Elevator_Activate(int elevatorId) {
}
void ScriptBase::View_Score_Board() {
- //TODO
- warning("View_Score_Board()");
+ _vm->_scores->open();
}
-int ScriptBase::Query_Score(int a0) {
- warning("Query_Score(%d)", a0);
-
- return 0;
+int ScriptBase::Query_Score(int index) {
+ return _vm->_scores->query(index);
}
-void ScriptBase::Set_Score(int a0, int a1) {
- warning("Set_Score(%d, %d)", a0, a1);
+void ScriptBase::Set_Score(int index, int value) {
+ _vm->_scores->set(index, value);
}
void ScriptBase::Give_McCoy_Ammo(int ammoType, int ammo) {
@@ -1221,10 +1249,8 @@ bool ScriptBase::Query_System_Currently_Loading_Game() {
void ScriptBase::Actor_Retired_Here(int actorId, int width, int height, int retired, int retiredByActorId) {
Actor *actor = _vm->_actors[actorId];
- Vector3 actorPosition;
- actor->getXYZ(&actorPosition.x, &actorPosition.y, &actorPosition.z);
actor->retire(retired, width, height, retiredByActorId);
- actor->setAtXYZ(actorPosition, actor->getFacing(), true, false, true);
+ actor->setAtXYZ(actor->getXYZ(), actor->getFacing(), true, false, true);
_vm->_sceneObjects->setRetired(actorId + kSceneObjectOffsetActors, true);
}
diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h
index 7faf3886b2..09c372d009 100644
--- a/engines/bladerunner/script/script.h
+++ b/engines/bladerunner/script/script.h
@@ -23,16 +23,18 @@
#ifndef BLADERUNNER_SCRIPT_H
#define BLADERUNNER_SCRIPT_H
-#include "common/str.h"
-
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_constants.h"
+#include "common/str.h"
+
namespace BladeRunner {
class BladeRunnerEngine;
class ScriptBase {
+friend class SceneScript;
+
protected:
BladeRunnerEngine *_vm;
@@ -78,7 +80,7 @@ protected:
void Actor_Set_Flag_Damage_Anim_If_Moving(int actorId, bool value);
bool Actor_Query_Flag_Damage_Anim_If_Moving(int actorId);
void Actor_Combat_AI_Hit_Attempt(int actorId);
- void Non_Player_Actor_Combat_Mode_On(int actorId, int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int a12, int a13, int a14);
+ void Non_Player_Actor_Combat_Mode_On(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool unstoppable);
void Non_Player_Actor_Combat_Mode_Off(int actorId);
void Actor_Set_Health(int actorId, int hp, int maxHp);
void Actor_Set_Targetable(int actorId, bool targetable);
@@ -205,15 +207,15 @@ protected:
float World_Waypoint_Query_X(int waypointId);
float World_Waypoint_Query_Y(int waypointId);
float World_Waypoint_Query_Z(int waypointId);
- void Combat_Cover_Waypoint_Set_Data(int combatCoverId, int a2, int setId, int a4, float x, float y, float z);
- void Combat_Flee_Waypoint_Set_Data(int combatFleeWaypointId, int a2, int setId, int a4, float x, float y, float z, int a8);
- void Police_Maze_Target_Track_Add(int itemId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, signed int data[], bool a10);
- // Police_Maze_Query_Score
- // Police_Maze_Zero_Score
- // Police_Maze_Increment_Score
- // Police_Maze_Decrement_Score
- // Police_Maze_Set_Score
- void Police_Maze_Set_Pause_State(int a1);
+ void Combat_Cover_Waypoint_Set_Data(int coverWaypointId, int a2, int setId, int a4, float x, float y, float z);
+ void Combat_Flee_Waypoint_Set_Data(int fleeWaypointId, int a2, int setId, int a4, float x, float y, float z, int a8);
+ void Police_Maze_Target_Track_Add(int itemId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, const int* instructions, bool isActive);
+ int Police_Maze_Query_Score();
+ void Police_Maze_Zero_Score();
+ void Police_Maze_Increment_Score(int delta);
+ void Police_Maze_Decrement_Score(int delta);
+ void Police_Maze_Set_Score(int value);
+ void Police_Maze_Set_Pause_State(bool state);
void CDB_Set_Crime(int clueId, int crimeId);
void CDB_Set_Clue_Asset_Type(int clueId, int assetType);
void SDB_Set_Actor(int suspectId, int actorId);
diff --git a/engines/bladerunner/script/vk_script.cpp b/engines/bladerunner/script/vk_script.cpp
index 8a7ddb26eb..eef5f5bdaf 100644
--- a/engines/bladerunner/script/vk_script.cpp
+++ b/engines/bladerunner/script/vk_script.cpp
@@ -1209,12 +1209,12 @@ void VKScript::askDektora(int questionId) {
VK_Play_Speech_Line(kActorDektora, 1520, 0.5f);
VK_Play_Speech_Line(kActorMcCoy, 7840, 0.5f);
VK_Subject_Reacts(20, -1, 9, 10);
- VK_Play_Speech_Line(kActorDektora, 1540, 0.80000001f);
+ VK_Play_Speech_Line(kActorDektora, 1540, 0.8f);
VK_Play_Speech_Line(kActorDektora, 1550, 0.5f);
} else {
VK_Play_Speech_Line(kActorDektora, 1560, 0.5f);
VK_Subject_Reacts(25, 13, -3, 0);
- VK_Play_Speech_Line(kActorDektora, 1570, 0.80000001f);
+ VK_Play_Speech_Line(kActorDektora, 1570, 0.8f);
VK_Play_Speech_Line(kActorDektora, 1580, 0.5f);
}
break;
@@ -1234,7 +1234,7 @@ void VKScript::askDektora(int questionId) {
VK_Subject_Reacts(25, -1, 9, 0);
} else {
VK_Subject_Reacts(25, 14, -2, 0);
- VK_Play_Speech_Line(kActorDektora, 1630, 0.89999998f);
+ VK_Play_Speech_Line(kActorDektora, 1630, 0.9f);
VK_Play_Speech_Line(kActorDektora, 1640, 0.5f);
}
break;
@@ -1274,7 +1274,7 @@ void VKScript::askDektora(int questionId) {
VK_Play_Speech_Line(kActorDektora, 1740, 0.5f);
VK_Play_Speech_Line(kActorMcCoy, 7805, 0.5f);
VK_Eye_Animates(2);
- VK_Play_Speech_Line(kActorDektora, 1750, 0.89999998f);
+ VK_Play_Speech_Line(kActorDektora, 1750, 0.9f);
VK_Play_Speech_Line(kActorDektora, 1760, 0.5f);
break;
case 7455:
diff --git a/engines/bladerunner/set.cpp b/engines/bladerunner/set.cpp
index fe10c189b6..ac026a4d76 100644
--- a/engines/bladerunner/set.cpp
+++ b/engines/bladerunner/set.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_constants.h"
#include "bladerunner/lights.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/set_effects.h"
#include "bladerunner/slice_renderer.h"
@@ -67,8 +68,10 @@ bool Set::open(const Common::String &name) {
_objectCount = s->readUint32LE();
assert(_objectCount <= 85);
+ char buf[20];
for (int i = 0; i < _objectCount; ++i) {
- s->read(_objects[i].name, 20);
+ s->read(buf, sizeof(buf));
+ _objects[i].name = buf;
float x0, y0, z0, x1, y1, z1;
x0 = s->readFloatLE();
@@ -82,6 +85,7 @@ bool Set::open(const Common::String &name) {
_objects[i].isObstacle = s->readByte();
_objects[i].isClickable = s->readByte();
_objects[i].isHotMouse = 0;
+ _objects[i].unknown1 = 0;
_objects[i].isTarget = 0;
s->skip(4);
@@ -94,7 +98,9 @@ bool Set::open(const Common::String &name) {
for (int i = 0; i < _walkboxCount; ++i) {
float x, z;
- s->read(_walkboxes[i].name, 20);
+ s->read(buf, sizeof(buf));
+ _walkboxes[i].name = buf;
+
_walkboxes[i].altitude = s->readFloatLE();
_walkboxes[i].vertexCount = s->readUint32LE();
@@ -129,7 +135,7 @@ bool Set::open(const Common::String &name) {
void Set::addObjectsToScene(SceneObjects *sceneObjects) const {
for (int i = 0; i < _objectCount; i++) {
- sceneObjects->addObject(i + kSceneObjectOffsetObjects, &_objects[i].bbox, _objects[i].isClickable, _objects[i].isObstacle, _objects[i].unknown1, _objects[i].isTarget);
+ sceneObjects->addObject(i + kSceneObjectOffsetObjects, _objects[i].bbox, _objects[i].isClickable, _objects[i].isObstacle, _objects[i].unknown1, _objects[i].isTarget);
}
}
@@ -207,15 +213,14 @@ int Set::findWalkbox(float x, float z) const {
return result;
}
-int Set::findObject(const char *objectName) const {
- int i;
- for (i = 0; i < (int)_objectCount; i++) {
- if (scumm_stricmp(objectName, _objects[i].name) == 0) {
+int Set::findObject(const Common::String &objectName) const {
+ for (int i = 0; i < _objectCount; ++i) {
+ if (objectName.compareToIgnoreCase(_objects[i].name) == 0) {
return i;
}
}
- debug("Set::findObject didn't find \"%s\"", objectName);
+ debug("Set::findObject didn't find \"%s\"", objectName.c_str());
return -1;
}
@@ -256,7 +261,7 @@ void Set::objectSetIsTarget(int objectId, bool isTarget) {
_objects[objectId].isTarget = isTarget;
}
-const char *Set::objectGetName(int objectId) const {
+const Common::String &Set::objectGetName(int objectId) const {
return _objects[objectId].name;
}
@@ -327,4 +332,74 @@ int Set::getWalkboxSoundRunLeft(int walkboxId) const {
int Set::getWalkboxSoundRunRight(int walkboxId) const {
return getWalkboxSoundWalkRight(walkboxId);
}
+
+void Set::save(SaveFileWriteStream &f) {
+ f.writeBool(_loaded);
+ f.writeInt(_objectCount);
+ f.writeInt(_walkboxCount);
+
+ for (int i = 0; i != _objectCount; ++i) {
+ f.writeStringSz(_objects[i].name, 20);
+ f.writeBoundingBox(_objects[i].bbox);
+ f.writeBool(_objects[i].isObstacle);
+ f.writeBool(_objects[i].isClickable);
+ f.writeBool(_objects[i].isHotMouse);
+ f.writeInt(_objects[i].unknown1);
+ f.writeBool(_objects[i].isTarget);
+ }
+
+ for (int i = 0; i != _walkboxCount; ++i) {
+ f.writeStringSz(_walkboxes[i].name, 20);
+ f.writeFloat(_walkboxes[i].altitude);
+ f.writeInt(_walkboxes[i].vertexCount);
+ for (int j = 0; j != 8; ++j) {
+ f.writeVector3(_walkboxes[i].vertices[j]);
+
+ // In BLADE.EXE vertices are a vec5
+ f.writeInt(0);
+ f.writeInt(0);
+ }
+ }
+
+ for (int i = 0; i != 85; ++i) {
+ f.writeInt(_walkboxStepSound[i]);
+ }
+
+ f.writeInt(_footstepSoundOverride);
+}
+
+void Set::load(SaveFileReadStream &f) {
+ _loaded = f.readBool();
+ _objectCount = f.readInt();
+ _walkboxCount = f.readInt();
+
+ for (int i = 0; i != _objectCount; ++i) {
+ _objects[i].name = f.readStringSz(20);
+ _objects[i].bbox = f.readBoundingBox();
+ _objects[i].isObstacle = f.readBool();
+ _objects[i].isClickable = f.readBool();
+ _objects[i].isHotMouse = f.readBool();
+ _objects[i].unknown1 = f.readInt();
+ _objects[i].isTarget = f.readBool();
+ }
+
+ for (int i = 0; i != _walkboxCount; ++i) {
+ _walkboxes[i].name = f.readStringSz(20);
+ _walkboxes[i].altitude = f.readFloat();
+ _walkboxes[i].vertexCount = f.readInt();
+ for (int j = 0; j != 8; ++j) {
+ _walkboxes[i].vertices[j] = f.readVector3();
+
+ // In BLADE.EXE vertices are a vec5
+ f.skip(8);
+ }
+ }
+
+ for (int i = 0; i != 85; ++i) {
+ _walkboxStepSound[i] = f.readInt();
+ }
+
+ _footstepSoundOverride = f.readInt();
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/set.h b/engines/bladerunner/set.h
index a6e7e9f3df..c6c1081196 100644
--- a/engines/bladerunner/set.h
+++ b/engines/bladerunner/set.h
@@ -32,28 +32,30 @@ namespace BladeRunner {
class BladeRunnerEngine;
-class VQADecoder;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class SetEffects;
class SceneObjects;
+class VQADecoder;
class Set {
friend class Debugger;
struct Object {
- char name[20];
- BoundingBox bbox;
- uint8 isObstacle;
- uint8 isClickable;
- uint8 isHotMouse;
- uint8 isTarget;
- uint8 unknown1;
+ Common::String name;
+ BoundingBox bbox;
+ uint8 isObstacle;
+ uint8 isClickable;
+ uint8 isHotMouse;
+ uint8 isTarget;
+ uint8 unknown1;
};
struct Walkbox {
- char name[20];
- float altitude;
- int vertexCount;
- Vector3 vertices[8];
+ Common::String name;
+ float altitude;
+ int vertexCount;
+ Vector3 vertices[8];
};
BladeRunnerEngine *_vm;
@@ -82,23 +84,27 @@ public:
float getAltitudeAtXZ(float x, float z, bool *inWalkbox) const;
int findWalkbox(float x, float z) const;
- int findObject(const char *objectName) const;
+ int findObject(const Common::String &objectName) const;
bool objectSetHotMouse(int objectId) const;
bool objectGetBoundingBox(int objectId, BoundingBox *boundingBox) const;
void objectSetIsClickable(int objectId, bool isClickable);
void objectSetIsObstacle(int objectId, bool isObstacle);
void objectSetIsTarget(int objectId, bool isTarget);
- const char *objectGetName(int objectId) const;
+ const Common::String &objectGetName(int objectId) const;
void setWalkboxStepSound(int walkboxId, int soundId);
void setFoodstepSoundOverride(int soundId);
void resetFoodstepSoundOverride();
+
int getWalkboxSoundWalkLeft(int walkboxId) const;
int getWalkboxSoundWalkRight(int walkboxId) const;
int getWalkboxSoundRunLeft(int walkboxId) const;
int getWalkboxSoundRunRight(int walkboxId) const;
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
static bool isXZInWalkbox(float x, float z, const Walkbox &walkbox);
};
diff --git a/engines/bladerunner/set_effects.cpp b/engines/bladerunner/set_effects.cpp
index 5c7b2487a8..3d46e41e7b 100644
--- a/engines/bladerunner/set_effects.cpp
+++ b/engines/bladerunner/set_effects.cpp
@@ -104,7 +104,7 @@ void SetEffects::setFadeDensity(float density) {
_fadeDensity = density;
}
-void SetEffects::setFogColor(const char *fogName, float r, float g, float b) {
+void SetEffects::setFogColor(const Common::String &fogName, float r, float g, float b) {
Fog *fog = findFog(fogName);
if (fog == nullptr) {
return;
@@ -115,7 +115,7 @@ void SetEffects::setFogColor(const char *fogName, float r, float g, float b) {
fog->_fogColor.b = b;
}
-void SetEffects::setFogDensity(const char *fogName, float density) {
+void SetEffects::setFogDensity(const Common::String &fogName, float density) {
Fog *fog = findFog(fogName);
if (fog == nullptr) {
return;
@@ -151,7 +151,7 @@ void SetEffects::calculateColor(Vector3 viewPosition, Vector3 position, float *o
outColor->b = outColor->b * (1.0f - _fadeDensity) + _fadeColor.b * _fadeDensity;
}
-Fog *SetEffects::findFog(const char *fogName) const {
+Fog *SetEffects::findFog(const Common::String &fogName) const {
if (!_fogs) {
return nullptr;
}
@@ -159,7 +159,7 @@ Fog *SetEffects::findFog(const char *fogName) const {
Fog *fog = _fogs;
while (fog != nullptr) {
- if (strcmp(fogName, fog->_name) == 0) {
+ if (fogName.compareTo(fog->_name) == 0) {
break;
}
fog = fog->_next;
diff --git a/engines/bladerunner/set_effects.h b/engines/bladerunner/set_effects.h
index 81d7b93149..6bd139c4d6 100644
--- a/engines/bladerunner/set_effects.h
+++ b/engines/bladerunner/set_effects.h
@@ -53,13 +53,13 @@ public:
void setFadeColor(float r, float g, float b);
void setFadeDensity(float density);
- void setFogColor(const char *fogName, float r, float g, float b);
- void setFogDensity(const char *fogName, float density);
+ void setFogColor(const Common::String &fogName, float r, float g, float b);
+ void setFogDensity(const Common::String &fogName, float density);
void calculateColor(Vector3 viewPosition, Vector3 position, float *outCoeficient, Color *outColor) const;
private:
- Fog *findFog(const char *fogName) const;
+ Fog *findFog(const Common::String &fogName) const;
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/settings.cpp b/engines/bladerunner/settings.cpp
index a5540fcb04..071adf6dd5 100644
--- a/engines/bladerunner/settings.cpp
+++ b/engines/bladerunner/settings.cpp
@@ -22,10 +22,14 @@
#include "bladerunner/settings.h"
+#include "bladerunner/actor.h"
#include "bladerunner/ambient_sounds.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/chapters.h"
+#include "bladerunner/game_constants.h"
+#include "bladerunner/game_info.h"
#include "bladerunner/music.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "common/debug.h"
@@ -39,14 +43,23 @@ Settings::Settings(BladeRunnerEngine *vm) {
_playerAgenda = 1;
_chapter = 1;
+ _scene = -1;
+ _set = -1;
+ _unk0 = 0;
_gamma = 1.0f;
+ _ammoType = 0;
+ _ammoAmounts[0] = 1;
+ _ammoAmounts[1] = 0;
+ _ammoAmounts[2] = 0;
+
+ // The remaining fields are not reset in BLADE.EXE
_chapterChanged = false;
_newChapter = -1;
_newScene = -1;
_newSet = -1;
- _startingGame = true;
+ _startingGame = false;
_loadingGame = false;
_fullHDFrames = true;
@@ -83,8 +96,9 @@ bool Settings::openNewScene() {
_vm->_scene->close(!_loadingGame && !_startingGame);
}
if (_chapterChanged) {
- if (_vm->_chapters->hasOpenResources())
+ if (_vm->_chapters->hasOpenResources()) {
_vm->_chapters->closeResources();
+ }
int newChapter = _newChapter;
_chapterChanged = false;
@@ -103,8 +117,23 @@ bool Settings::openNewScene() {
return false;
}
+ _set = newSet;
+ _scene = newScene;
+
if (!_loadingGame && currentSet != newSet) {
- // TODO: Reset actors for new set
+ for (int i = 0; i < (int)_vm->_gameInfo->getActorCount(); ++i) {
+ Actor *actor = _vm->_actors[i];
+ if (i != kActorMcCoy && actor->getSetId() == currentSet) {
+ if (!actor->isRetired()) {
+ actor->stopWalking(false);
+ actor->movementTrackWaypointReached();
+ }
+ if (actor->inCombat()) {
+ actor->setSetId(kSetFreeSlotG);
+ actor->combatModeOff();
+ }
+ }
+ }
}
_loadingGame = false;
@@ -171,4 +200,30 @@ void Settings::setLearyMode(bool learyMode) {
_learyMode = learyMode;
}
+void Settings::save(SaveFileWriteStream &f) {
+ f.writeInt(_scene);
+ f.writeInt(_set);
+ f.writeInt(_chapter);
+ f.writeInt(_playerAgenda);
+ f.writeInt(_unk0);
+ f.writeInt(_difficulty);
+ f.writeInt(_ammoType);
+ for (int i = 0; i != 3; ++i) {
+ f.writeInt(_ammoAmounts[i]);
+ }
+}
+
+void Settings::load(SaveFileReadStream &f) {
+ _scene = f.readInt();
+ _set = f.readInt();
+ _chapter = f.readInt();
+ _playerAgenda = f.readInt();
+ _unk0 = f.readInt();
+ _difficulty = f.readInt();
+ _ammoType = f.readInt();
+ for (int i = 0; i != 3; ++i) {
+ _ammoAmounts[i] = f.readInt();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/settings.h b/engines/bladerunner/settings.h
index bf2d2d3162..413786e2e5 100644
--- a/engines/bladerunner/settings.h
+++ b/engines/bladerunner/settings.h
@@ -26,6 +26,8 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
enum PlayerAgenda {
kPlayerAgendaPolite = 0,
@@ -39,6 +41,9 @@ class Settings {
BladeRunnerEngine *_vm;
int _chapter;
+ int _scene;
+ int _set;
+ int _unk0;
float _gamma;
bool _chapterChanged;
@@ -49,6 +54,8 @@ class Settings {
bool _startingGame;
bool _loadingGame;
+ // int _unk1;
+
int _fullHDFrames;
int _mst3k;
@@ -85,6 +92,18 @@ public:
return _newSet;
}
+ int getScene() const {
+ return _scene;
+ }
+
+ int getSet() const {
+ return _set;
+ }
+
+ int getChapter() const {
+ return _chapter;
+ }
+
void setChapter(int newChapter) {
_chapterChanged = true;
_newChapter = newChapter;
@@ -117,6 +136,9 @@ public:
bool getLearyMode() const;
void setLearyMode(bool learyMode);
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/slice_animations.cpp b/engines/bladerunner/slice_animations.cpp
index 181b11d9f1..8678c1726b 100644
--- a/engines/bladerunner/slice_animations.cpp
+++ b/engines/bladerunner/slice_animations.cpp
@@ -93,8 +93,28 @@ bool SliceAnimations::openCoreAnim() {
return _coreAnimPageFile.open("COREANIM.DAT");
}
-bool SliceAnimations::openHDFrames() {
- return _framesPageFile.open("HDFRAMES.DAT");
+bool SliceAnimations::openFrames(int fileNumber) {
+ if (_framesPageFile._fileNumber == -1) { // Running for the first time, need to probe
+ // First, try HDFRAMES.DAT
+ if (_framesPageFile.open("HDFRAMES.DAT")) {
+ _framesPageFile._fileNumber = 0;
+
+ return true;
+ }
+ }
+
+ if (_framesPageFile._fileNumber == 0) // HDFRAMES.DAT
+ return true;
+
+ if (_framesPageFile._fileNumber == fileNumber)
+ return true;
+
+ _framesPageFile.close();
+
+ if (fileNumber == 1 && _framesPageFile.open("CDFRAMES.DAT")) // For Chapter1 we try both CDFRAMES.DAT and CDFRAMES1.DAT
+ return true;
+
+ return _framesPageFile.open(Common::String::format("CDFRAMES%d.DAT", fileNumber));
}
bool SliceAnimations::PageFile::open(const Common::String &name) {
@@ -119,11 +139,17 @@ bool SliceAnimations::PageFile::open(const Common::String &name) {
_pageOffsets[pageNumber] = dataOffset + i * _sliceAnimations->_pageSize;
}
- // debug("PageFile::Open: page file \"%s\" opened with %d pages", name.c_str(), pageCount);
+ debug(5, "PageFile::Open: page file \"%s\" opened with %d pages", name.c_str(), pageCount);
return true;
}
+void SliceAnimations::PageFile::close() {
+ if (_file.isOpen()) {
+ _file.close();
+ }
+}
+
void *SliceAnimations::PageFile::loadPage(uint32 pageNumber) {
if (_pageOffsets[pageNumber] == -1)
return nullptr;
diff --git a/engines/bladerunner/slice_animations.h b/engines/bladerunner/slice_animations.h
index edc0684140..0732e596ea 100644
--- a/engines/bladerunner/slice_animations.h
+++ b/engines/bladerunner/slice_animations.h
@@ -64,13 +64,15 @@ class SliceAnimations {
};
struct PageFile {
+ int _fileNumber;
SliceAnimations *_sliceAnimations;
Common::File _file;
Common::Array<int32> _pageOffsets;
- PageFile(SliceAnimations *sliceAnimations) : _sliceAnimations(sliceAnimations) {}
+ PageFile(SliceAnimations *sliceAnimations) : _sliceAnimations(sliceAnimations), _fileNumber(-1) {}
bool open(const Common::String &name);
+ void close();
void *loadPage(uint32 page);
};
@@ -102,7 +104,7 @@ public:
bool open(const Common::String &name);
bool openCoreAnim();
- bool openHDFrames();
+ bool openFrames(int fileNumber);
Palette &getPalette(int i) { return _palettes[i]; };
void *getFramePtr(uint32 animation, uint32 frame);
diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp
index 15633f6581..31da697c20 100644
--- a/engines/bladerunner/slice_renderer.cpp
+++ b/engines/bladerunner/slice_renderer.cpp
@@ -122,7 +122,7 @@ Matrix3x2 SliceRenderer::calculateFacingRotationMatrix() {
float s = sinf(dir);
float c = cosf(dir);
- Matrix3x2 mRotation( c, -s, 0.0f,
+ Matrix3x2 mRotation(c, -s, 0.0f,
s, c, 0.0f);
Matrix3x2 mView(_view->_sliceViewMatrix(0,0), _view->_sliceViewMatrix(0,1), 0.0f,
@@ -164,29 +164,20 @@ void SliceRenderer::calculateBoundingRect() {
Matrix3x2 mScale(_frameScale.x, 0.0f, 0.0f,
0.0f, _frameScale.y, 0.0f);
- _modelMatrix = mProjection * (facingRotation * (mOffset * mScale));
+ _mvpMatrix = mProjection * (facingRotation * (mOffset * mScale));
Vector4 startScreenVector(
- _view->_viewportPosition.x + top.x / top.z * _view->_viewportPosition.z,
- _view->_viewportPosition.y + top.y / top.z * _view->_viewportPosition.z,
+ _view->_viewportPosition.x + (top.x / top.z) * _view->_viewportPosition.z,
+ _view->_viewportPosition.y + (top.y / top.z) * _view->_viewportPosition.z,
1.0f / top.z,
_frameSliceCount * (1.0f / top.z));
Vector4 endScreenVector(
- _view->_viewportPosition.x + bottom.x / bottom.z * _view->_viewportPosition.z,
- _view->_viewportPosition.y + bottom.y / bottom.z * _view->_viewportPosition.z,
+ _view->_viewportPosition.x + (bottom.x / bottom.z) * _view->_viewportPosition.z,
+ _view->_viewportPosition.y + (bottom.y / bottom.z) * _view->_viewportPosition.z,
1.0f / bottom.z,
0.0f);
- _startScreenVector.x = startScreenVector.x;
- _startScreenVector.y = startScreenVector.y;
- _startScreenVector.z = startScreenVector.z;
- _endScreenVector.x = endScreenVector.x;
- _endScreenVector.y = endScreenVector.y;
- _endScreenVector.z = endScreenVector.z;
- _startSlice = startScreenVector.w;
- _endSlice = endScreenVector.w;
-
Vector4 delta = endScreenVector - startScreenVector;
if (delta.y == 0.0f) {
@@ -197,60 +188,68 @@ void SliceRenderer::calculateBoundingRect() {
* Calculate min and max Y
*/
- float screenMinY = 0.0f;
- float screenMaxY = 479.0f;
+ float screenTop = 0.0f;
+ float screenBottom = 479.0f;
- if (startScreenVector.y < screenMinY) {
- if (endScreenVector.y < screenMinY)
+ if (startScreenVector.y < screenTop) {
+ if (endScreenVector.y < screenTop) {
return;
-
- float f = (screenMinY - startScreenVector.y) / delta.y;
+ }
+ float f = (screenTop - startScreenVector.y) / delta.y;
startScreenVector = startScreenVector + f * delta;
- } else if (startScreenVector.y > screenMaxY) {
- if (endScreenVector.y >= screenMaxY)
+ } else if (startScreenVector.y > screenBottom) {
+ if (endScreenVector.y >= screenBottom) {
return;
-
- float f = (screenMaxY - startScreenVector.y) / delta.y;
+ }
+ float f = (screenBottom - startScreenVector.y) / delta.y;
startScreenVector = startScreenVector + f * delta;
}
- if (endScreenVector.y < screenMinY) {
- float f = (screenMinY - endScreenVector.y) / delta.y;
+ if (endScreenVector.y < screenTop) {
+ float f = (screenTop - endScreenVector.y) / delta.y;
endScreenVector = endScreenVector + f * delta;
- } else if (endScreenVector.y > screenMaxY) {
- float f = (screenMaxY - endScreenVector.y) / delta.y;
+ } else if (endScreenVector.y > screenBottom) {
+ float f = (screenBottom - endScreenVector.y) / delta.y;
endScreenVector = endScreenVector + f * delta;
}
- int bbox_min_y = (int)MIN(startScreenVector.y, endScreenVector.y);
- int bbox_max_y = (int)MAX(startScreenVector.y, endScreenVector.y) + 1;
+ _screenRectangle.top = (int)MIN(startScreenVector.y, endScreenVector.y);
+ _screenRectangle.bottom = (int)MAX(startScreenVector.y, endScreenVector.y) + 1;
/*
* Calculate min and max X
*/
- Matrix3x2 mB6 = _modelMatrix + Vector2(startScreenVector.x, 25.5f / startScreenVector.z);
- Matrix3x2 mC2 = _modelMatrix + Vector2(endScreenVector.x, 25.5f / endScreenVector.z);
+ Matrix3x2 mStart(
+ 1.0f, 0.0f, startScreenVector.x,
+ 0.0f, 1.0f, 25.5f / startScreenVector.z
+ );
- float min_x = 640.0f;
- float max_x = 0.0f;
+ Matrix3x2 mEnd(
+ 1.0f, 0.0f, endScreenVector.x,
+ 0.0f, 1.0f, 25.5f / endScreenVector.z
+ );
- for (float i = 0.0f; i <= 256.0f; i += 255.0f) {
- for (float j = 0.0f; j <= 256.0f; j += 255.0f) {
- Vector2 v1 = mB6 * Vector2(i, j);
+ Matrix3x2 mStartMVP = mStart * _mvpMatrix;
+ Matrix3x2 mEndMVP = mEnd * _mvpMatrix;
- min_x = MIN(min_x, v1.x);
- max_x = MAX(max_x, v1.x);
+ float minX = 640.0f;
+ float maxX = 0.0f;
- Vector2 v2 = mC2 * Vector2(i, j);
+ for (float i = 0.0f; i <= 256.0f; i += 255.0f) {
+ for (float j = 0.0f; j <= 256.0f; j += 255.0f) {
+ Vector2 v1 = mStartMVP * Vector2(i, j);
+ minX = MIN(minX, v1.x);
+ maxX = MAX(maxX, v1.x);
- min_x = MIN(min_x, v2.x);
- max_x = MAX(max_x, v2.x);
+ Vector2 v2 = mEndMVP * Vector2(i, j);
+ minX = MIN(minX, v2.x);
+ maxX = MAX(maxX, v2.x);
}
}
- int bbox_min_x = CLIP((int)min_x, 0, 640);
- int bbox_max_x = CLIP((int)max_x + 1, 0, 640);
+ _screenRectangle.left = CLIP((int)minX, 0, 640);
+ _screenRectangle.right = CLIP((int)maxX + 1, 0, 640);
_startScreenVector.x = startScreenVector.x;
_startScreenVector.y = startScreenVector.y;
@@ -260,11 +259,6 @@ void SliceRenderer::calculateBoundingRect() {
_endScreenVector.z = endScreenVector.z;
_startSlice = startScreenVector.w;
_endSlice = endScreenVector.w;
-
- _screenRectangle.left = bbox_min_x;
- _screenRectangle.right = bbox_max_x;
- _screenRectangle.top = bbox_min_y;
- _screenRectangle.bottom = bbox_max_y;
}
void SliceRenderer::loadFrame(int animation, int frame) {
@@ -285,7 +279,8 @@ void SliceRenderer::loadFrame(int animation, int frame) {
}
struct SliceLineIterator {
- int _sliceMatrix[2][3];
+ // int _sliceMatrix[2][3];
+ Matrix3x2 _sliceMatrix;
int _startY;
int _endY;
@@ -316,8 +311,9 @@ void SliceLineIterator::setup(
float size = endScreenY - startScreenY;
- if (size <= 0.0f || startScreenZ <= 0.0f)
+ if (size <= 0.0f || startScreenZ <= 0.0f) {
_currentY = _endY + 1;
+ }
_currentZ = startScreenZ;
_stepZ = (endScreenZ - startScreenZ) / size;
@@ -328,7 +324,7 @@ void SliceLineIterator::setup(
_currentX = startScreenX;
_stepX = (endScreenX - startScreenX) / size;
- _field_38 = (int)((25.5f / size) * (1.0f / endScreenZ - 1.0f / startScreenZ) * 64.0);
+ _field_38 = (int)((25.5f / size) * (1.0f / endScreenZ - 1.0f / startScreenZ) * 64.0f);
_currentY = _startY;
float offsetX = _currentX;
@@ -342,9 +338,7 @@ void SliceLineIterator::setup(
m = scale_matrix * (translate_matrix * m);
- for (int r = 0; r != 2; ++r)
- for (int c = 0; c != 3; ++c)
- _sliceMatrix[r][c] = m(r, c);
+ _sliceMatrix = m;
}
float SliceLineIterator::line() {
@@ -364,8 +358,8 @@ void SliceLineIterator::advance() {
_currentSlice += _stepSlice;
_currentX += _stepX;
_currentY += 1;
- _sliceMatrix[0][2] += (int)(65536.0f * _stepX);
- _sliceMatrix[1][2] += _field_38;
+ _sliceMatrix._m[0][2] += (int)(65536.0f * _stepX);
+ _sliceMatrix._m[1][2] += _field_38;
}
static void setupLookupTable(int t[256], int inc) {
@@ -393,7 +387,7 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
_endScreenVector.x, _endScreenVector.y, _endScreenVector.z,
_startScreenVector.x, _startScreenVector.y, _startScreenVector.z,
_endSlice, _startSlice,
- _modelMatrix
+ _mvpMatrix
);
SliceRendererLights sliceRendererLights = SliceRendererLights(_lights);
@@ -424,12 +418,12 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
_setEffectColor.g = setEffectColor.g * 31.0f * 65536.0f;
_setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
- setupLookupTable(_m11lookup, sliceLineIterator._sliceMatrix[0][0]);
- setupLookupTable(_m12lookup, sliceLineIterator._sliceMatrix[0][1]);
- _m13 = sliceLineIterator._sliceMatrix[0][2];
- setupLookupTable(_m21lookup, sliceLineIterator._sliceMatrix[1][0]);
- setupLookupTable(_m22lookup, sliceLineIterator._sliceMatrix[1][1]);
- _m23 = sliceLineIterator._sliceMatrix[1][2];
+ setupLookupTable(_m12lookup, sliceLineIterator._sliceMatrix(0, 1));
+ setupLookupTable(_m11lookup, sliceLineIterator._sliceMatrix(0, 0));
+ _m13 = sliceLineIterator._sliceMatrix(0, 2);
+ setupLookupTable(_m21lookup, sliceLineIterator._sliceMatrix(1, 0));
+ setupLookupTable(_m22lookup, sliceLineIterator._sliceMatrix(1, 1));
+ _m23 = sliceLineIterator._sliceMatrix(1, 2);
if (_animationsShadowEnabled[_animation]) {
float coeficientShadow;
@@ -545,8 +539,9 @@ void SliceRenderer::drawOnScreen(int animationId, int animationFrame, int screen
}
void SliceRenderer::drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr, int y) {
- if (slice < 0 || (uint32)slice >= _frameSliceCount)
+ if (slice < 0 || (uint32)slice >= _frameSliceCount) {
return;
+ }
SliceAnimations::Palette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex);
@@ -714,7 +709,12 @@ void SliceRenderer::drawShadowPolygon(int transparency, Graphics::Surface &surfa
yMax = CLIP(yMax, 0, 480);
yMin = CLIP(yMin, 0, 480);
- int ditheringFactor[] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 };
+ int ditheringFactor[] = {
+ 0, 8, 2, 10,
+ 12, 4, 14, 6,
+ 3, 11, 1, 9,
+ 15, 7, 13, 5
+ };
for (int y = yMin; y < yMax; ++y) {
int xMin = CLIP(polygonLeft[y], 0, 640);
diff --git a/engines/bladerunner/slice_renderer.h b/engines/bladerunner/slice_renderer.h
index d2de61e279..2e3617162c 100644
--- a/engines/bladerunner/slice_renderer.h
+++ b/engines/bladerunner/slice_renderer.h
@@ -67,7 +67,7 @@ class SliceRenderer {
uint32 _framePaletteIndex;
uint32 _frameSliceCount;
- Matrix3x2 _modelMatrix;
+ Matrix3x2 _mvpMatrix;
Vector3 _startScreenVector;
Vector3 _endScreenVector;
float _startSlice;
diff --git a/engines/bladerunner/text_resource.cpp b/engines/bladerunner/text_resource.cpp
index 2a4840c833..8f54f8a976 100644
--- a/engines/bladerunner/text_resource.cpp
+++ b/engines/bladerunner/text_resource.cpp
@@ -46,11 +46,11 @@ TextResource::~TextResource() {
bool TextResource::open(const Common::String &name) {
assert(name.size() <= 8);
- char resName[13];
- sprintf(resName, "%s.TR%s", name.c_str(), _vm->_languageCode);
+ Common::String resName = Common::String::format("%s.TR%s", name.c_str(), _vm->_languageCode.c_str());
Common::ScopedPtr<Common::SeekableReadStream> s(_vm->getResourceStream(resName));
- if (!s)
+ if (!s) {
return false;
+ }
_count = s->readUint32LE();
diff --git a/engines/bladerunner/time.cpp b/engines/bladerunner/time.cpp
new file mode 100644
index 0000000000..a395a811d1
--- /dev/null
+++ b/engines/bladerunner/time.cpp
@@ -0,0 +1,68 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/time.h"
+
+#include "bladerunner/bladerunner.h"
+
+#include "common/timer.h"
+
+namespace BladeRunner {
+
+Time::Time(BladeRunnerEngine *vm) {
+ _vm = vm;
+
+ _start = _vm->getTotalPlayTime();
+ _pauseCount = 0;
+ _offset = 0;
+ _pauseStart = 0;
+}
+
+int Time::current() {
+ int time = _vm->getTotalPlayTime() - _offset;
+ return time - _start;
+}
+
+int Time::pause() {
+ if (_pauseCount == 0) {
+ _pauseStart = current();
+ }
+ return ++_pauseCount;
+}
+
+int Time::getPauseStart() {
+ return _pauseStart;
+}
+
+int Time::unpause() {
+ assert(_pauseCount > 0);
+ if (--_pauseCount == 0) {
+ _offset += current() - _pauseStart;
+ }
+ return _pauseCount;
+}
+
+bool Time::isLocked() {
+ return _pauseCount > 0;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/time.h b/engines/bladerunner/time.h
new file mode 100644
index 0000000000..bda8c84d14
--- /dev/null
+++ b/engines/bladerunner/time.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.
+ *
+ */
+
+#ifndef BLADERUNNER_TIME_H
+#define BLADERUNNER_TIME_H
+
+namespace BladeRunner {
+
+class BladeRunnerEngine;
+
+class Time {
+ BladeRunnerEngine *_vm;
+
+ int _start;
+ int _pauseCount;
+ int _offset;
+ int _pauseStart;
+
+public:
+ Time(BladeRunnerEngine *vm);
+
+ int current();
+ int pause();
+ int getPauseStart();
+ int unpause();
+ bool isLocked();
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/ui/elevator.cpp b/engines/bladerunner/ui/elevator.cpp
index 3f668efd75..7a6ab3ca35 100644
--- a/engines/bladerunner/ui/elevator.cpp
+++ b/engines/bladerunner/ui/elevator.cpp
@@ -315,8 +315,7 @@ void Elevator::mouseOutCallback(int, void *self) {
void Elevator::mouseDownCallback(int, void *self) {
Elevator *elevator = ((Elevator *)self);
- const char *name = elevator->_vm->_gameInfo->getSfxTrack(515);
- elevator->_vm->_audioPlayer->playAud(name, 100, 0, 0, 50, 0);
+ elevator->_vm->_audioPlayer->playAud(elevator->_vm->_gameInfo->getSfxTrack(515), 100, 0, 0, 50, 0);
}
void Elevator::mouseUpCallback(int buttonId, void *self) {
diff --git a/engines/bladerunner/ui/end_credits.cpp b/engines/bladerunner/ui/end_credits.cpp
new file mode 100644
index 0000000000..6d964d0290
--- /dev/null
+++ b/engines/bladerunner/ui/end_credits.cpp
@@ -0,0 +1,170 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "common/rect.h"
+
+#include "audio/mixer.h"
+
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/ambient_sounds.h"
+#include "bladerunner/audio_speech.h"
+#include "bladerunner/font.h"
+#include "bladerunner/game_info.h"
+#include "bladerunner/mouse.h"
+#include "bladerunner/music.h"
+#include "bladerunner/text_resource.h"
+#include "bladerunner/ui/end_credits.h"
+
+namespace BladeRunner {
+
+EndCredits::EndCredits(BladeRunnerEngine *vm) {
+ _vm = vm;
+}
+
+EndCredits::~EndCredits() {
+}
+
+void EndCredits::show() {
+ _vm->_mouse->disable();
+ _vm->_mixer->stopAll();
+ _vm->_ambientSounds->removeAllNonLoopingSounds(true);
+ _vm->_ambientSounds->removeAllLoopingSounds(4);
+ _vm->_audioSpeech->stopSpeech();
+
+ _vm->_music->play(_vm->_gameInfo->getMusicTrack(17), 100, 0, 2, -1, 0, 3);
+
+ Font *fontBig = new Font(_vm);
+ fontBig->open("TAHOMA24.FON", 640, 480, -1, 0, 0);
+ fontBig->setSpacing(1, 0);
+
+ Font *fontSmall = new Font(_vm);
+ fontSmall->open("TAHOMA18.FON", 640, 480, -1, 0, 0);
+ fontSmall->setSpacing(1, 0);
+
+ TextResource *textResource = new TextResource(_vm);
+ textResource->open("ENDCRED");
+
+ int textCount = textResource->getCount();
+ int *textPositions = (int *)malloc(textCount * sizeof(int));
+ int y = 452;
+ bool small = false;
+
+ for (int i = 0; i < textCount; i++) {
+ Common::String s = textResource->getText(i);
+ if (s.hasPrefix("^")) {
+ if (!small) {
+ y += 28;
+ }
+ small = false;
+ } else {
+ if (small) {
+ y += 24;
+ } else {
+ y += 28;
+ }
+ small = true;
+ }
+ if (s.hasPrefix("^")) {
+ textPositions[i] = y;
+ } else {
+ textPositions[i] = y + 2;
+ }
+ }
+
+ _vm->_vqaIsPlaying = true;
+ _vm->_vqaStopIsRequested = false;
+
+ double position = 0.0;
+ uint32 timeLast = _vm->getTotalPlayTime();
+
+ while (!_vm->_vqaStopIsRequested && !_vm->shouldQuit()) {
+ if (position >= textPositions[textCount - 1]) {
+ break;
+ }
+
+ //soundSystem::tick(SoundSystem);
+ _vm->handleEvents();
+
+ if (!_vm->_gameIsRunning) {
+ timeLast = _vm->getTotalPlayTime();
+
+ continue;
+ }
+
+ uint32 timeNow = _vm->getTotalPlayTime();
+ position += (double)(timeNow - timeLast) * 0.05f;
+ timeLast = timeNow;
+
+ _vm->_surfaceFront.fillRect(Common::Rect(640, 480), 0);
+
+ for (int i = 0; i < textCount; i++) {
+ Common::String s = textResource->getText(i);
+ Font *font;
+ int height;
+
+ if (s.hasPrefix("^")) {
+ font = fontBig;
+ height = 28;
+ s.deleteChar(0);
+ } else {
+ font = fontSmall;
+ height = 24;
+ }
+
+ y = textPositions[i] - (int)position;
+
+ if (y < 452 && y + height > 28) {
+ int x;
+
+ if (font == fontBig) {
+ x = 280;
+ } else {
+ x = 270 - font->getTextWidth(s);
+ }
+
+ font->draw(s, _vm->_surfaceFront, x, y);
+ }
+ }
+
+ _vm->_surfaceFront.fillRect(Common::Rect(0, 0, 640, 28), 0);
+ _vm->_surfaceFront.fillRect(Common::Rect(0, 452, 640, 480), 0);
+
+ _vm->blitToScreen(_vm->_surfaceFront);
+
+ _vm->_system->delayMillis(10);
+ }
+
+ _vm->_vqaIsPlaying = false;
+ _vm->_vqaStopIsRequested = false;
+
+ free(textPositions);
+ delete textResource;
+
+ delete fontSmall;
+ delete fontBig;
+
+ _vm->_music->stop(0);
+ _vm->_mouse->enable();
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/ui/end_credits.h b/engines/bladerunner/ui/end_credits.h
new file mode 100644
index 0000000000..39086cd796
--- /dev/null
+++ b/engines/bladerunner/ui/end_credits.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_UI_END_CREDITS_H
+#define BLADERUNNER_UI_END_CREDITS_H
+
+namespace BladeRunner {
+
+class BladeRunnerEngine;
+
+class EndCredits {
+ BladeRunnerEngine *_vm;
+
+public:
+ EndCredits(BladeRunnerEngine *vm);
+ ~EndCredits();
+
+ void show();
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/ui/kia.cpp b/engines/bladerunner/ui/kia.cpp
index 86fdc9254a..756f1bd2cd 100644
--- a/engines/bladerunner/ui/kia.cpp
+++ b/engines/bladerunner/ui/kia.cpp
@@ -350,7 +350,7 @@ void KIA::tick() {
_shapes->get(47)->draw(_vm->_surfaceFront, 182, 446);
}
}
- _vm->_mainFont->drawColor("1.00", _vm->_surfaceFront, 438, 471, 0x1CE7);
+ _vm->_mainFont->drawColor("1.00", _vm->_surfaceFront, 438, 471, 0x1CE7); // TODO: 1.01 for DVD version
if (!_transitionId) {
_buttons->drawTooltip(_vm->_surfaceFront, mouse.x, mouse.y);
}
diff --git a/engines/bladerunner/ui/kia_log.cpp b/engines/bladerunner/ui/kia_log.cpp
index 51b922a8f7..7f75f2e944 100644
--- a/engines/bladerunner/ui/kia_log.cpp
+++ b/engines/bladerunner/ui/kia_log.cpp
@@ -55,7 +55,7 @@ void KIALog::add(int type, int dataSize, const void *data) {
_entries[_currentIndex].dataSize = dataSize;
if (dataSize > 0) {
- char *dataCopy = new char[dataSize];
+ unsigned char *dataCopy = new unsigned char[dataSize];
memcpy(dataCopy, data, dataSize);
_entries[_currentIndex].data = dataCopy;
} else {
diff --git a/engines/bladerunner/ui/kia_log.h b/engines/bladerunner/ui/kia_log.h
index 4a89492817..99c834e3f0 100644
--- a/engines/bladerunner/ui/kia_log.h
+++ b/engines/bladerunner/ui/kia_log.h
@@ -33,7 +33,7 @@ class KIALog {
struct Entry {
int type;
int dataSize;
- const char *data;
+ const unsigned char *data;
};
BladeRunnerEngine *_vm;
diff --git a/engines/bladerunner/ui/scores.cpp b/engines/bladerunner/ui/scores.cpp
new file mode 100644
index 0000000000..c4a7df778c
--- /dev/null
+++ b/engines/bladerunner/ui/scores.cpp
@@ -0,0 +1,218 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "bladerunner/ui/scores.h"
+
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/font.h"
+#include "bladerunner/savefile.h"
+#include "bladerunner/scene.h"
+#include "bladerunner/text_resource.h"
+#include "bladerunner/vqa_player.h"
+
+#include "common/keyboard.h"
+
+namespace BladeRunner {
+
+Scores::Scores(BladeRunnerEngine *vm) {
+ _vm = vm;
+
+ _font = nullptr;
+ _txtScorers = nullptr;
+
+ reset();
+}
+
+Scores::~Scores() {
+}
+
+void Scores::open() {
+ if (!_vm->openArchive("MODE.MIX")) {
+ return;
+ }
+
+ _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack);
+
+ if (!_vqaPlayer->open("SCORE.VQA")) {
+ return;
+ }
+
+ _vqaPlayer->setLoop(1, -1, 0, nullptr, nullptr);
+
+ // TODO: Freeze game time
+
+ _txtScorers = new TextResource(_vm);
+ _txtScorers->open("SCORERS");
+
+ _font = new Font(_vm);
+ _font->open("TAHOMA24.FON", 640, 480, -1, 0, 0);
+ _font->setSpacing(1, 0);
+
+ fill();
+
+ _isOpen = true;
+ _isLoaded = false;
+}
+
+bool Scores::isOpen() const {
+ return _isOpen;
+}
+
+void Scores::close() {
+ _isOpen = false;
+
+ delete _font;
+ _font = nullptr;
+
+ delete _txtScorers;
+ _txtScorers = nullptr;
+
+ if (_vqaPlayer) {
+ _vqaPlayer->close();
+ delete _vqaPlayer;
+ _vqaPlayer = nullptr;
+ }
+
+ _vm->closeArchive("MODE.MIX");
+
+ // TODO: Unfreeze game time
+ _vm->_scene->resume();
+}
+
+void Scores::set(int index, int value) {
+ if (value > _scores[index]) {
+ _scores[index] = value;
+ }
+
+ _lastScoreId = index;
+ _lastScoreValue = value;
+}
+
+void Scores::handleKeyDown(const Common::KeyState &kbd) {
+ close();
+}
+
+int Scores::handleMouseUp(int x, int y) {
+ if (_isLoaded) {
+ close();
+ }
+
+ _isLoaded = false;
+
+ return false;
+}
+
+int Scores::handleMouseDown(int x, int y) {
+ _isLoaded = true;
+
+ return false;
+}
+
+void Scores::tick() {
+ if (!_vm->_gameIsRunning) {
+ return;
+ }
+
+ int frame = _vqaPlayer->update();
+ assert(frame >= -1);
+
+ // vqaPlayer renders to _surfaceBack
+ blit(_vm->_surfaceBack, _vm->_surfaceFront);
+
+ _vm->_surfaceFront.hLine(200, 139, 400, 0x3e0);
+ _vm->_surfaceFront.hLine(200, 347, 400, 0x1f);
+
+ _font->draw(_txtScorers->getText(7), _vm->_surfaceFront, 200, 114);
+
+ int y = 140;
+
+ for (int i = 0; i < 7; i++) {
+ _font->draw(_txtScorers->getText(_scorers[i]), _vm->_surfaceFront, 220, y);
+ _font->drawNumber(_scores[_scorers[i]], _vm->_surfaceFront, 360, y);
+
+ y += 26;
+ }
+
+ _font->draw(_txtScorers->getText(8), _vm->_surfaceFront, 200, 322);
+ _font->draw(_txtScorers->getText(_lastScoreId), _vm->_surfaceFront, 220, 348);
+ _font->drawNumber(_lastScoreValue, _vm->_surfaceFront, 360, 348);
+
+ _vm->blitToScreen(_vm->_surfaceFront);
+}
+
+void Scores::fill() {
+ for (int i = 0; i < 7; i++) {
+ _scorers[i] = i;
+ }
+
+ // Network sorting using Bose-Nelson Algorithm
+ const byte network[32] = { // Bose-Nelson
+ 1,2, 3,4, 5,6,
+ 0,2, 3,5, 4,6,
+ 0,1, 4,5, 2,6,
+ 0,4, 1,5,
+ 0,3, 2,5,
+ 1,3, 2,4,
+ 2,3
+ };
+
+ for (int i = 0; i < 32; i += 2) {
+ int i1 = network[i], i2 = network[i + 1];
+ if (_scores[_scorers[i1]] < _scores[_scorers[i2]]) {
+ SWAP(_scorers[i1], _scorers[i2]);
+ }
+ }
+}
+
+void Scores::reset() {
+ _isOpen = false;
+ _isLoaded = false;
+ _vqaPlayer = nullptr;
+
+ for (int i = 0; i < 7; i++) {
+ _scores[i] = -80;
+ _scorers[i] = 0;
+ }
+
+ _lastScoreId = 0;
+ _lastScoreValue = 0;
+}
+
+void Scores::save(SaveFileWriteStream &f) {
+ for (int i = 0; i < 7; i++) {
+ f.writeInt(_scores[i]);
+ }
+
+ f.writeInt(_lastScoreId);
+ f.writeInt(_lastScoreValue);
+}
+
+void Scores::load(SaveFileReadStream &f) {
+ for (int i = 0; i < 7; i++) {
+ _scores[i] = f.readInt();
+ }
+
+ _lastScoreId = f.readInt();
+ _lastScoreValue = f.readInt();
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/ui/scores.h b/engines/bladerunner/ui/scores.h
new file mode 100644
index 0000000000..80fd409675
--- /dev/null
+++ b/engines/bladerunner/ui/scores.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_SCORES_H
+#define BLADERUNNER_SCORES_H
+
+#include "common/array.h"
+
+namespace Common {
+struct KeyState;
+}
+
+namespace BladeRunner {
+
+class BladeRunnerEngine;
+class Font;
+class Shape;
+class SaveFileReadStream;
+class SaveFileWriteStream;
+class TextResource;
+class VQAPlayer;
+class UIImagePicker;
+
+class Scores {
+ BladeRunnerEngine *_vm;
+ bool _isOpen;
+ bool _isLoaded;
+ VQAPlayer *_vqaPlayer;
+ int _scores[7];
+ int _scorers[7];
+
+ int _lastScoreId;
+ int _lastScoreValue;
+
+ Font *_font;
+ TextResource *_txtScorers;
+
+public:
+ Scores(BladeRunnerEngine *vm);
+ ~Scores();
+
+ void open();
+ bool isOpen() const;
+ void close();
+
+ int query(int index) { return _scores[index]; }
+ void set(int index, int value);
+
+ void handleKeyDown(const Common::KeyState &kbd);
+ int handleMouseUp(int x, int y);
+ int handleMouseDown(int x, int y);
+
+ void tick();
+ void fill();
+
+ void reset();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/ui/spinner.cpp b/engines/bladerunner/ui/spinner.cpp
index 0740715fc4..9e491f719c 100644
--- a/engines/bladerunner/ui/spinner.cpp
+++ b/engines/bladerunner/ui/spinner.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_constants.h"
#include "bladerunner/mouse.h"
+#include "bladerunner/savefile.h"
#include "bladerunner/scene.h"
#include "bladerunner/shape.h"
#include "bladerunner/text_resource.h"
@@ -262,6 +263,20 @@ void Spinner::resume() {
_vqaPlayer->setLoop(1, -1, kLoopSetModeJustStart, nullptr, nullptr);
}
+void Spinner::save(SaveFileWriteStream &f) {
+ assert(!_isOpen);
+
+ for (int i = 0; i != kSpinnerDestinations; ++i) {
+ f.writeBool(_isDestinationSelectable[i]);
+ }
+}
+
+void Spinner::load(SaveFileReadStream &f) {
+ for (int i = 0; i != kSpinnerDestinations; ++i) {
+ _isDestinationSelectable[i] = f.readBool();
+ }
+}
+
const Spinner::Destination *Spinner::getDestinationsFar() {
static const Destination destinations[] = {
{ 0, Common::Rect(220, 227, 246, 262) },
diff --git a/engines/bladerunner/ui/spinner.h b/engines/bladerunner/ui/spinner.h
index b1785a57eb..d2d666e8e1 100644
--- a/engines/bladerunner/ui/spinner.h
+++ b/engines/bladerunner/ui/spinner.h
@@ -29,9 +29,11 @@
namespace BladeRunner {
class BladeRunnerEngine;
+class SaveFileReadStream;
+class SaveFileWriteStream;
class Shape;
-class VQAPlayer;
class UIImagePicker;
+class VQAPlayer;
class Spinner {
static const int kSpinnerDestinations = 10;
@@ -70,6 +72,9 @@ public:
void reset();
void resume();
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
+
private:
static void mouseUpCallback(int, void *);
static const Destination *getDestinationsFar();
diff --git a/engines/bladerunner/ui/ui_scroll_box.cpp b/engines/bladerunner/ui/ui_scroll_box.cpp
index 6bd4dabdd4..a030e534c5 100644
--- a/engines/bladerunner/ui/ui_scroll_box.cpp
+++ b/engines/bladerunner/ui/ui_scroll_box.cpp
@@ -481,7 +481,7 @@ void UIScrollBox::draw(Graphics::Surface &surface) {
}
if (_center) {
- x = (_rect.width() - _vm->_mainFont->getTextWidth(_lines[i]->text)) / 2;
+ x = _rect.left + (_rect.width() - _vm->_mainFont->getTextWidth(_lines[i]->text)) / 2;
}
_vm->_mainFont->drawColor(_lines[i]->text, surface, x, y, color);
@@ -490,8 +490,7 @@ void UIScrollBox::draw(Graphics::Surface &surface) {
y2 += kLineHeight;
y += kLineHeight;
++i;
- }
- while (i < lastLineVisible);
+ } while (i < lastLineVisible);
}
// draw scroll up button
diff --git a/engines/bladerunner/vector.h b/engines/bladerunner/vector.h
index f3cc1f1e6d..22ef5cd839 100644
--- a/engines/bladerunner/vector.h
+++ b/engines/bladerunner/vector.h
@@ -37,6 +37,14 @@ public:
Vector2(float ax, float ay) : x(ax), y(ay) {}
};
+inline bool operator==(const Vector2 &a, const Vector2 &b) {
+ return a.x == b.x && a.y == b.y;
+}
+
+inline bool operator!=(const Vector2 &a, const Vector2 &b) {
+ return !(a == b);
+}
+
class Vector3 {
public:
float x;
@@ -132,6 +140,10 @@ inline float distance(float x1, float z1, float x2, float z2) {
return int_part + frac_part;
}
+inline float distance(const Vector2 &v1, const Vector2 &v2) {
+ return distance(v1.x, v1.y, v2.x, v2.y);
+}
+
inline float distance(const Vector3 &v1, const Vector3 &v2) {
return distance(v1.x, v1.z, v2.x, v2.z);
}
diff --git a/engines/bladerunner/view.cpp b/engines/bladerunner/view.cpp
index d304b92bb1..72c070ecc0 100644
--- a/engines/bladerunner/view.cpp
+++ b/engines/bladerunner/view.cpp
@@ -31,8 +31,9 @@ bool View::readVqa(Common::ReadStream *stream) {
_frame = stream->readUint32LE();
float d[12];
- for (int i = 0; i != 12; ++i)
+ for (int i = 0; i != 12; ++i) {
d[i] = stream->readFloatLE();
+ }
_frameViewMatrix = Matrix4x3(d);
@@ -54,17 +55,11 @@ void View::setFovX(float fovX) {
}
void View::calculateSliceViewMatrix() {
- Matrix4x3 m = _frameViewMatrix;
-
- m = m * rotationMatrixX(float(M_PI) / 2.0f);
-
- Matrix4x3 a(-1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, -1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f);
-
- m = a * m;
-
- _sliceViewMatrix = m;
+ Matrix4x3 mRotation = rotationMatrixX(float(M_PI) / 2.0f);
+ Matrix4x3 mInvert(-1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f);
+ _sliceViewMatrix = mInvert * (_frameViewMatrix * mRotation);
}
void View::calculateCameraPosition() {
diff --git a/engines/bladerunner/waypoints.cpp b/engines/bladerunner/waypoints.cpp
index 4d80841e50..bf2f09b8a6 100644
--- a/engines/bladerunner/waypoints.cpp
+++ b/engines/bladerunner/waypoints.cpp
@@ -22,6 +22,8 @@
#include "bladerunner/waypoints.h"
+#include "bladerunner/savefile.h"
+
namespace BladeRunner {
Waypoints::Waypoints(BladeRunnerEngine *vm, int count) {
@@ -89,4 +91,24 @@ float Waypoints::getZ(int waypointId) const {
return _waypoints[waypointId].position.z;
}
+void Waypoints::save(SaveFileWriteStream &f) {
+ f.writeInt(_count);
+ for (int i = 0; i < _count; ++i) {
+ Waypoint &w = _waypoints[i];
+ f.writeInt(w.setId);
+ f.writeVector3(w.position);
+ f.writeInt(w.present);
+ }
+}
+
+void Waypoints::load(SaveFileReadStream &f) {
+ _count = f.readInt();
+ for (int i = 0; i < _count; ++i) {
+ Waypoint &w = _waypoints[i];
+ w.setId = f.readInt();
+ w.position = f.readVector3();
+ w.present = f.readInt();
+ }
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/waypoints.h b/engines/bladerunner/waypoints.h
index 826f8f5a94..6bbe8d3db4 100644
--- a/engines/bladerunner/waypoints.h
+++ b/engines/bladerunner/waypoints.h
@@ -30,6 +30,9 @@
namespace BladeRunner {
+class SaveFileReadStream;
+class SaveFileWriteStream;
+
class Waypoints {
friend class Debugger;
@@ -55,6 +58,9 @@ public:
bool set(int waypointId, int setId, Vector3 position);
bool reset(int waypointId);
+
+ void save(SaveFileWriteStream &f);
+ void load(SaveFileReadStream &f);
};
} // End of namespace BladeRunner
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index d3f8a93c1d..9a8ea0dde9 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -56,7 +56,7 @@ class Walk;
class Text;
class Talk;
-#define kSavegameVersion 2
+#define kSavegameVersion 3
#define kSavegameStrSize 11
#define kPocketX 174
#define kPocketY 176
@@ -99,8 +99,9 @@ struct SavegameHeader {
uint8 version;
Common::String saveName;
Graphics::Surface *thumbnail;
- int saveYear, saveMonth, saveDay;
- int saveHour, saveMinutes;
+ int16 saveYear, saveMonth, saveDay;
+ int16 saveHour, saveMinutes;
+ uint32 playTime;
};
extern const char *savegameStr;
@@ -246,7 +247,7 @@ public:
void mainLoop();
void handleFrame();
void saveGame(int slotNumber, const Common::String &desc);
- static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
void switchMusic();
void selectPocket(int n);
void expandSprite(Sprite *spr);
diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp
index b60f201cb0..05461e30e1 100644
--- a/engines/cge/cge_main.cpp
+++ b/engines/cge/cge_main.cpp
@@ -243,9 +243,7 @@ bool CGEEngine::loadGame(int slotNumber, SavegameHeader *header, bool tiny) {
return true;
}
- // Delete the thumbnail
- saveHeader.thumbnail->free();
- delete saveHeader.thumbnail;
+ g_engine->setTotalPlayTime(saveHeader.playTime * 1000);
}
// Get in the savegame
@@ -371,6 +369,8 @@ void CGEEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &he
out->writeSint16LE(td.tm_mday);
out->writeSint16LE(td.tm_hour);
out->writeSint16LE(td.tm_min);
+
+ out->writeUint32LE(g_engine->getTotalPlayTime() / 1000);
}
void CGEEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream, bool tiny) {
@@ -424,8 +424,16 @@ void CGEEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteSt
}
}
-bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
- header.thumbnail = nullptr;
+WARN_UNUSED_RESULT bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) {
+ header.version = 0;
+ header.saveName.clear();
+ header.thumbnail = nullptr;
+ header.saveYear = 0;
+ header.saveMonth = 0;
+ header.saveDay = 0;
+ header.saveHour = 0;
+ header.saveMinutes = 0;
+ header.playTime = 0;
// Get the savegame version
header.version = in->readByte();
@@ -433,23 +441,26 @@ bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &heade
return false;
// Read in the string
- header.saveName.clear();
char ch;
while ((ch = (char)in->readByte()) != '\0')
header.saveName += ch;
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
- header.saveYear = in->readSint16LE();
- header.saveMonth = in->readSint16LE();
- header.saveDay = in->readSint16LE();
- header.saveHour = in->readSint16LE();
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
header.saveMinutes = in->readSint16LE();
+ if (header.version >= 3) {
+ header.playTime = in->readUint32LE();
+ }
+
return true;
}
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 482591bf50..f6399d484c 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -126,7 +126,7 @@ public:
return "Soltys (C) 1994-1996 L.K. Avalon";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual int getMaximumSaveSlot() const;
@@ -135,13 +135,8 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
};
-static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
- { 0, { 0 } }
-};
-
static ADGameDescription s_fallbackDesc = {
- "Soltys",
+ "soltys",
"Unknown version",
AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
Common::UNK_LANG,
@@ -150,38 +145,40 @@ static ADGameDescription s_fallbackDesc = {
GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
};
-const ADGameDescription *CGEMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &s_fallbackDesc, { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
- const ADGameDescription *game;
- game = detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback, &filesProps);
+ADDetectedGame CGEMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame game = detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback);
- if (!game)
- return nullptr;
+ if (!game.desc)
+ return ADDetectedGame();
SearchMan.addDirectory("CGEMetaEngine::fallbackDetect", fslist.begin()->getParent());
ResourceManager *resman;
resman = new ResourceManager();
- bool result = resman->exist("CGE.SAY");
+ bool sayFileFound = resman->exist("CGE.SAY");
delete resman;
SearchMan.remove("CGEMetaEngine::fallbackDetect");
- if (!result)
- return nullptr;
+ if (!sayFileFound)
+ return ADDetectedGame();
- reportUnknown(fslist.begin()->getParent(), filesProps);
- return &s_fallbackDesc;
+ return game;
}
bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- (f == kSupportsListSaves) ||
- (f == kSupportsLoadingDuringStartup) ||
- (f == kSupportsDeleteSave) ||
- (f == kSavesSupportMetaInfo) ||
- (f == kSavesSupportThumbnail) ||
- (f == kSavesSupportCreationDate) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime) ||
(f == kSimpleSavesNames);
}
@@ -221,10 +218,6 @@ SaveStateList CGEMetaEngine::listSaves(const char *target) const {
// Valid savegame
if (CGE::CGEEngine::readSavegameHeader(file, header)) {
saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
- if (header.thumbnail) {
- header.thumbnail->free();
- delete header.thumbnail;
- }
}
} else {
// Must be an original format savegame
@@ -253,7 +246,7 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl
f->read(buffer, kSavegameStrSize + 1);
bool hasHeader = !strncmp(buffer, CGE::savegameStr, kSavegameStrSize + 1) &&
- CGE::CGEEngine::readSavegameHeader(f, header);
+ CGE::CGEEngine::readSavegameHeader(f, header, false);
delete f;
if (!hasHeader) {
@@ -267,6 +260,10 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl
desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
desc.setSaveTime(header.saveHour, header.saveMinutes);
+ if (header.playTime) {
+ desc.setPlayTime(header.playTime * 1000);
+ }
+
// Slot 0 is used for the 'automatic save on exit' save in Soltys, thus
// we prevent it from being deleted or overwritten by accident.
desc.setDeletableFlag(slot != 0);
diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp
index 4d3a103663..a7e065fe01 100644
--- a/engines/cge/vga13h.cpp
+++ b/engines/cge/vga13h.cpp
@@ -707,7 +707,7 @@ uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 col
uint16 D = ((r > R) ? (r - R) : (R - r)) +
((g > G) ? (g - G) : (G - g)) +
((b > B) ? (b - B) : (B - b)) +
- ((l > L) ? (l - L) : (L - l)) * 10 ;
+ ((l > L) ? (l - L) : (L - l)) * 10;
if (D < dif) {
found = i;
diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h
index 18f919b5eb..1fa23ad6f7 100644
--- a/engines/cge2/cge2.h
+++ b/engines/cge2/cge2.h
@@ -32,12 +32,13 @@
#include "common/savefile.h"
#include "common/serializer.h"
#include "engines/engine.h"
-#include "engines/advancedDetector.h"
#include "common/system.h"
#include "cge2/fileio.h"
#include "cge2/console.h"
#include "audio/mixer.h"
+struct ADGameDescription;
+
namespace CGE2 {
class Vga;
@@ -105,7 +106,7 @@ struct SavegameHeader;
#define kQuitText 201
#define kNoQuitText 202
-#define kSavegameVersion 1
+#define kSavegameVersion 2
#define kSavegameStrSize 12
#define kSavegameStr "SCUMMVM_CGE2"
@@ -115,8 +116,9 @@ struct SavegameHeader {
uint8 version;
Common::String saveName;
Graphics::Surface *thumbnail;
- int saveYear, saveMonth, saveDay;
- int saveHour, saveMinutes;
+ int16 saveYear, saveMonth, saveDay;
+ int16 saveHour, saveMinutes;
+ uint32 playTime;
};
enum ColorBank { kCBRel, kCBStd, kCBSay, kCBInf, kCBMnu, kCBWar };
@@ -161,7 +163,7 @@ public:
virtual Common::Error loadGameState(int slot);
virtual Common::Error run();
- static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
GUI::Debugger *getDebugger() {
return _console;
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
index d05dfffedc..ec6925ac74 100644
--- a/engines/cge2/detection.cpp
+++ b/engines/cge2/detection.cpp
@@ -62,6 +62,16 @@ static const ADGameDescription gameDescriptions[] = {
},
{
+ "sfinx", "Freeware v1.1",
+ {
+ {"vol.cat", 0, "aa402aed24a72c53a4d1211c456b79dd", 129024},
+ {"vol.dat", 0, "5966ac26d91d664714349669f9dd09b5", 34180367},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ {
"sfinx", "Freeware v0.3",
{
{"vol.cat", 0, "f158e469dccbebc5a632eb848df89779", 129024},
@@ -122,7 +132,7 @@ public:
return "Sfinx (C) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual int getMaximumSaveSlot() const;
@@ -131,13 +141,8 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
};
-static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
- { 0, { 0 } }
-};
-
static ADGameDescription s_fallbackDesc = {
- "Sfinx",
+ "sfinx",
"Unknown version",
AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
Common::UNK_LANG,
@@ -146,30 +151,31 @@ static ADGameDescription s_fallbackDesc = {
GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
};
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &s_fallbackDesc, { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
+
// This fallback detection looks identical to the one used for CGE. In fact, the difference resides
// in the ResourceManager which handles a different archive format. The rest of the detection is identical.
-const ADGameDescription *CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
-
- const ADGameDescription *game;
- game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback, &filesProps);
+ADDetectedGame CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback);
- if (!game)
- return 0;
+ if (!game.desc)
+ return ADDetectedGame();
SearchMan.addDirectory("CGE2MetaEngine::fallbackDetect", fslist.begin()->getParent());
ResourceManager *resman;
resman = new ResourceManager();
- bool result = resman->exist("CGE.SAY");
+ bool sayFileFound = resman->exist("CGE.SAY");
delete resman;
SearchMan.remove("CGE2MetaEngine::fallbackDetect");
- if (!result)
- return 0;
+ if (!sayFileFound)
+ return ADDetectedGame();
- reportUnknown(fslist.begin()->getParent(), filesProps);
- return &s_fallbackDesc;
+ return game;
}
bool CGE2MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -185,6 +191,7 @@ bool CGE2MetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime) ||
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSimpleSavesNames);
@@ -221,10 +228,6 @@ SaveStateList CGE2MetaEngine::listSaves(const char *target) const {
// Valid savegame
if (CGE2::CGE2Engine::readSavegameHeader(file, header)) {
saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
- if (header.thumbnail) {
- header.thumbnail->free();
- delete header.thumbnail;
- }
}
} else {
// Must be an original format savegame
@@ -253,7 +256,7 @@ SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int s
f->read(buffer, kSavegameStrSize + 1);
bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) &&
- CGE2::CGE2Engine::readSavegameHeader(f, header);
+ CGE2::CGE2Engine::readSavegameHeader(f, header, false);
delete f;
if (!hasHeader) {
@@ -267,6 +270,10 @@ SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int s
desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
desc.setSaveTime(header.saveHour, header.saveMinutes);
+ if (header.playTime) {
+ desc.setPlayTime(header.playTime * 1000);
+ }
+
// Slot 0 is used for the 'automatic save on exit' save in Soltys, thus
// we prevent it from being deleted or overwritten by accident.
desc.setDeletableFlag(slot != 0);
diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp
index 2dac04a0a5..b5c452745b 100644
--- a/engines/cge2/events.cpp
+++ b/engines/cge2/events.cpp
@@ -29,7 +29,6 @@
#include "common/config-manager.h"
#include "common/events.h"
#include "common/translation.h"
-#include "engines/advancedDetector.h"
#include "cge2/events.h"
#include "cge2/text.h"
#include "cge2/cge2_main.h"
diff --git a/engines/cge2/saveload.cpp b/engines/cge2/saveload.cpp
index cd0be84567..a8120c1017 100644
--- a/engines/cge2/saveload.cpp
+++ b/engines/cge2/saveload.cpp
@@ -118,9 +118,7 @@ bool CGE2Engine::loadGame(int slotNumber) {
return false;
}
- // Delete the thumbnail
- saveHeader.thumbnail->free();
- delete saveHeader.thumbnail;
+ g_engine->setTotalPlayTime(saveHeader.playTime * 1000);
}
resetGame();
@@ -178,10 +176,20 @@ void CGE2Engine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &h
out->writeSint16LE(td.tm_mday);
out->writeSint16LE(td.tm_hour);
out->writeSint16LE(td.tm_min);
+
+ out->writeUint32LE(g_engine->getTotalPlayTime() / 1000);
}
-bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
- header.thumbnail = nullptr;
+WARN_UNUSED_RESULT bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) {
+ header.version = 0;
+ header.saveName.clear();
+ header.thumbnail = nullptr;
+ header.saveYear = 0;
+ header.saveMonth = 0;
+ header.saveDay = 0;
+ header.saveHour = 0;
+ header.saveMinutes = 0;
+ header.playTime = 0;
// Get the savegame version
header.version = in->readByte();
@@ -189,23 +197,27 @@ bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &head
return false;
// Read in the string
- header.saveName.clear();
char ch;
while ((ch = (char)in->readByte()) != '\0')
header.saveName += ch;
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
- header.saveYear = in->readSint16LE();
- header.saveMonth = in->readSint16LE();
- header.saveDay = in->readSint16LE();
- header.saveHour = in->readSint16LE();
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
header.saveMinutes = in->readSint16LE();
+ if (header.version >= 2) {
+ header.playTime = in->readUint32LE();
+ }
+
+
return true;
}
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
index 8b0d8b6c77..8b8acb6ade 100644
--- a/engines/cge2/vga13h.cpp
+++ b/engines/cge2/vga13h.cpp
@@ -938,13 +938,13 @@ uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 col
uint16 D = ((r > R) ? (r - R) : (R - r)) +
((g > G) ? (g - G) : (G - g)) +
((b > B) ? (b - B) : (B - b)) +
- ((l > L) ? (l - L) : (L - l)) * 10 ;
+ ((l > L) ? (l - L) : (L - l)) * 10;
if (D < dif) {
found = i;
dif = D;
if (D == 0)
- break; // exact!
+ break; // exact!
}
}
return found;
diff --git a/engines/chewy/chewy.cpp b/engines/chewy/chewy.cpp
index 75c2a8d51b..81f8c7d03a 100644
--- a/engines/chewy/chewy.cpp
+++ b/engines/chewy/chewy.cpp
@@ -94,7 +94,7 @@ Common::Error ChewyEngine::run() {
}*/
//_graphics->playVideo(0);
-
+
_scene->change(0);
//_sound->playSpeech(1);
//_sound->playSound(1);
diff --git a/engines/chewy/console.cpp b/engines/chewy/console.cpp
index 65c4a681d6..af62bf017b 100644
--- a/engines/chewy/console.cpp
+++ b/engines/chewy/console.cpp
@@ -113,7 +113,7 @@ bool Console::Cmd_DrawImage(int argc, const char **argv) {
Common::String filename = argv[1];
int resNum = atoi(argv[2]);
-
+
_vm->_graphics->drawImage(filename, resNum);
return false;
diff --git a/engines/chewy/detection.cpp b/engines/chewy/detection.cpp
index f6f66efba0..7b7f29f9e8 100644
--- a/engines/chewy/detection.cpp
+++ b/engines/chewy/detection.cpp
@@ -70,7 +70,7 @@ static const ChewyGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
},
-
+
{
// Chewy - ESC von F5 - German
// Master version 1.1 (CHEWY.EXE - offset 0x8AB28)
@@ -87,7 +87,7 @@ static const ChewyGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
},
-
+
{
// Chewy - ESC von F5 - German
// Master version 1.0 (CHEWY.EXE - offset 0x8AB10)
diff --git a/engines/chewy/scene.cpp b/engines/chewy/scene.cpp
index 11bb4b38cd..5398a8da12 100644
--- a/engines/chewy/scene.cpp
+++ b/engines/chewy/scene.cpp
@@ -138,7 +138,7 @@ void Scene::change(uint scene) {
_curScene = scene;
_vm->_cursor->setCursor(0);
_vm->_cursor->showCursor();
-
+
loadSceneInfo();
draw();
}
@@ -320,14 +320,14 @@ void Scene::loadSceneInfo() {
_sceneInfo->roomInfo.picNum = indexFile.readByte();
_sceneInfo->roomInfo.autoMoveCount = indexFile.readByte();
_sceneInfo->roomInfo.loadTaf = indexFile.readByte();
-
+
_sceneInfo->roomInfo.tafName = "";
for (int i = 0; i < 14; i++)
_sceneInfo->roomInfo.tafName += indexFile.readByte();
_sceneInfo->roomInfo.zoomFactor = indexFile.readByte();
indexFile.readByte(); // padding
-
+
for (int i = 0; i < MAX_AUTOMOVE; i++) {
_sceneInfo->autoMove[i].x = indexFile.readSint16LE();
_sceneInfo->autoMove[i].y = indexFile.readSint16LE();
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 6c8b4a676d..f1636c902b 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -84,7 +84,7 @@ public:
_guiOptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD);
}
- virtual GameDescriptor findGame(const char *gameId) const {
+ PlainGameDescriptor findGame(const char *gameId) const override {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index a8b4c085ff..70ce8fec98 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -299,11 +299,7 @@ void AdLibSoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) {
void AdLibSoundDriver::setupChannel(int channel, const byte *data, int instrument, int volume) {
assert(channel < 4);
if (data) {
- if (volume > 80) {
- volume = 80;
- } else if (volume < 0) {
- volume = 0;
- }
+ volume = CLIP(volume, 0, 80);
volume += volume / 4;
_channelsVolumeTable[channel] = volume;
diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp
index dd1ce2751c..c90dfe5131 100644
--- a/engines/composer/detection.cpp
+++ b/engines/composer/detection.cpp
@@ -511,10 +511,9 @@ SaveStateList ComposerMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String saveDesc;
- Common::String pattern = Common::String::format("%s.??", target);
+ Common::String pattern = Common::String::format("%s.##", target);
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -531,6 +530,7 @@ SaveStateList ComposerMetaEngine::listSaves(const char *target) const {
}
}
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp
index 6f5d236173..3dfd414fd2 100644
--- a/engines/cruise/detection.cpp
+++ b/engines/cruise/detection.cpp
@@ -241,9 +241,8 @@ SaveStateList CruiseMetaEngine::listSaves(const char *target) const {
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
if (in) {
Cruise::CruiseSavegameHeader header;
- Cruise::readSavegameHeader(in, header);
- saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
- delete header.thumbnail;
+ if (Cruise::readSavegameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
delete in;
}
}
@@ -264,7 +263,11 @@ SaveStateDescriptor CruiseMetaEngine::querySaveMetaInfos(const char *target, int
if (f) {
Cruise::CruiseSavegameHeader header;
- Cruise::readSavegameHeader(f, header);
+ if (!Cruise::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
+
delete f;
// Create the return descriptor
diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp
index a62648df08..7aaeb06905 100644
--- a/engines/cruise/saveload.cpp
+++ b/engines/cruise/saveload.cpp
@@ -43,9 +43,8 @@ struct overlayRestoreTemporary {
overlayRestoreTemporary ovlRestoreData[90];
-bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header) {
+WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[6];
- header.thumbnail = NULL;
// Validate the header Id
in->read(saveIdentBuffer, 6);
@@ -62,9 +61,9 @@ bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header) {
while ((ch = (char)in->readByte()) != '\0') header.saveName += ch;
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
return true;
}
@@ -827,8 +826,10 @@ Common::Error loadSavegameData(int saveGameIdx) {
// Skip over the savegame header
CruiseSavegameHeader header;
- readSavegameHeader(f, header);
- delete header.thumbnail;
+ if (!readSavegameHeader(f, header)) {
+ delete f;
+ return Common::kReadingFailed;
+ }
// Synchronise the remaining data of the savegame
Common::Serializer s(f, NULL);
diff --git a/engines/cruise/saveload.h b/engines/cruise/saveload.h
index 6fb1f4b545..c92f0e9da5 100644
--- a/engines/cruise/saveload.h
+++ b/engines/cruise/saveload.h
@@ -38,7 +38,7 @@ struct CruiseSavegameHeader {
Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName);
Common::Error loadSavegameData(int saveGameIdx);
-bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header);
+WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header, bool skipThumbnail = true);
void initVars();
} // End of namespace Cruise
diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp
index 57dcfcea8f..8d6ca571d1 100644
--- a/engines/cruise/sound.cpp
+++ b/engines/cruise/sound.cpp
@@ -334,11 +334,7 @@ void AdLibSoundDriver::syncSounds() {
void AdLibSoundDriver::adjustVolume(int channel, int volume) {
_channelsVolumeTable[channel].original = volume;
- if (volume > 80) {
- volume = 80;
- } else if (volume < 0) {
- volume = 0;
- }
+ volume = CLIP(volume, 0, 80);
volume += volume / 4;
// The higher possible value for volume is 100
diff --git a/engines/cryo/cryo.h b/engines/cryo/cryo.h
index 515849ffea..9a8bc913ba 100644
--- a/engines/cryo/cryo.h
+++ b/engines/cryo/cryo.h
@@ -25,7 +25,6 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
-#include "engines/advancedDetector.h"
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/error.h"
@@ -39,6 +38,8 @@
#include "cryo/video.h"
#include "cryo/debugger.h"
+struct ADGameDescription;
+
namespace Cryo {
class Console;
diff --git a/engines/cryo/eden.cpp b/engines/cryo/eden.cpp
index 103d9fde9e..c4a76a47a2 100644
--- a/engines/cryo/eden.cpp
+++ b/engines/cryo/eden.cpp
@@ -26,7 +26,6 @@
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/error.h"
-#include "gui/EventRecorder.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/fs.h"
@@ -2321,7 +2320,7 @@ void EdenGame::my_bulle() {
} else if (c >= 0x80 && c < 0x90)
SysBeep(1);
else if (c >= 0x90 && c < 0xA0) {
- while (*textPtr++ != 0xFF) ;
+ while (*textPtr++ != 0xFF) {}
textPtr--;
} else if (c >= 0xA0 && c < 0xC0)
_globals->_textToken1 = c & 0xF;
@@ -2333,7 +2332,7 @@ void EdenGame::my_bulle() {
#ifdef FAKE_DOS_VERSION
_globals->_textWidthLimit = c1 + 160;
#else
- _globals->_textWidthLimit = c1 + _subtitlesXCenter; //TODO: signed? 160 in pc ver
+ _globals->_textWidthLimit = c1 + _subtitlesXCenter; // TODO: signed? 160 in pc ver
#endif
else {
byte c2 = *textPtr++;
diff --git a/engines/cryo/sound.cpp b/engines/cryo/sound.cpp
index 68f067588f..95bf39eca9 100644
--- a/engines/cryo/sound.cpp
+++ b/engines/cryo/sound.cpp
@@ -1,113 +1,113 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "cryo/sound.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "audio/decoders/raw.h"
-
-namespace Cryo {
-
-CSoundChannel::CSoundChannel(Audio::Mixer *mixer, unsigned int sampleRate, bool stereo, bool is16bits) : _mixer(mixer), _sampleRate(sampleRate), _stereo(stereo) {
- _bufferFlags = is16bits ? (Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_16BITS) : Audio::FLAG_UNSIGNED;
- if (stereo)
- _bufferFlags |= Audio::FLAG_STEREO;
- _audioStream = nullptr;
- _volumeLeft = _volumeRight = Audio::Mixer::kMaxChannelVolume;
-}
-
-CSoundChannel::~CSoundChannel() {
- stop();
- if (_audioStream)
- delete _audioStream;
-}
-
-void CSoundChannel::queueBuffer(byte *buffer, unsigned int size, bool playNow, bool playQueue, bool buffering) {
- if (playNow)
- stop();
-
- if (!buffer || !size)
- return;
-
- if (!_audioStream)
- _audioStream = Audio::makeQueuingAudioStream(_sampleRate, _stereo);
-
- if (buffering) {
- byte *localBuffer = (byte*)malloc(size);
- memcpy(localBuffer, buffer, size);
- _audioStream->queueBuffer(localBuffer, size, DisposeAfterUse::YES, _bufferFlags);
- } else
- _audioStream->queueBuffer(buffer, size, DisposeAfterUse::NO, _bufferFlags);
- if (playNow || playQueue)
- play();
-}
-
-void CSoundChannel::play() {
- if (!_audioStream)
- return;
- if (!_mixer->isSoundHandleActive(_soundHandle)) {
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
- applyVolumeChange();
- }
-}
-
-void CSoundChannel::stop() {
- if (_mixer->isSoundHandleActive(_soundHandle))
- _mixer->stopHandle(_soundHandle);
-
- if (_audioStream) {
- _audioStream->finish();
- delete _audioStream;
- _audioStream = nullptr;
- }
-}
-
-unsigned int CSoundChannel::numQueued() {
- return _audioStream ? _audioStream->numQueuedStreams() : 0;
-}
-
-unsigned int CSoundChannel::getVolume() {
- return (_volumeRight + _volumeLeft) / 2;
-}
-
-void CSoundChannel::setVolume(unsigned int volumeLeft, unsigned int volumeRight) {
- _volumeLeft = volumeLeft;
- _volumeRight = volumeRight;
- applyVolumeChange();
-}
-
-void CSoundChannel::setVolumeLeft(unsigned int volume) {
- setVolume(volume, _volumeRight);
-}
-
-void CSoundChannel::setVolumeRight(unsigned int volume) {
- setVolume(_volumeLeft, volume);
-}
-
-void CSoundChannel::applyVolumeChange() {
- unsigned int volume = (_volumeRight + _volumeLeft) / 2;
- int balance = (signed int)(_volumeRight - _volumeLeft) / 2;
- _mixer->setChannelVolume(_soundHandle, volume);
- _mixer->setChannelBalance(_soundHandle, balance);
-}
-
-}
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "cryo/sound.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+
+namespace Cryo {
+
+CSoundChannel::CSoundChannel(Audio::Mixer *mixer, unsigned int sampleRate, bool stereo, bool is16bits) : _mixer(mixer), _sampleRate(sampleRate), _stereo(stereo) {
+ _bufferFlags = is16bits ? (Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_16BITS) : Audio::FLAG_UNSIGNED;
+ if (stereo)
+ _bufferFlags |= Audio::FLAG_STEREO;
+ _audioStream = nullptr;
+ _volumeLeft = _volumeRight = Audio::Mixer::kMaxChannelVolume;
+}
+
+CSoundChannel::~CSoundChannel() {
+ stop();
+ if (_audioStream)
+ delete _audioStream;
+}
+
+void CSoundChannel::queueBuffer(byte *buffer, unsigned int size, bool playNow, bool playQueue, bool buffering) {
+ if (playNow)
+ stop();
+
+ if (!buffer || !size)
+ return;
+
+ if (!_audioStream)
+ _audioStream = Audio::makeQueuingAudioStream(_sampleRate, _stereo);
+
+ if (buffering) {
+ byte *localBuffer = (byte*)malloc(size);
+ memcpy(localBuffer, buffer, size);
+ _audioStream->queueBuffer(localBuffer, size, DisposeAfterUse::YES, _bufferFlags);
+ } else
+ _audioStream->queueBuffer(buffer, size, DisposeAfterUse::NO, _bufferFlags);
+ if (playNow || playQueue)
+ play();
+}
+
+void CSoundChannel::play() {
+ if (!_audioStream)
+ return;
+ if (!_mixer->isSoundHandleActive(_soundHandle)) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ applyVolumeChange();
+ }
+}
+
+void CSoundChannel::stop() {
+ if (_mixer->isSoundHandleActive(_soundHandle))
+ _mixer->stopHandle(_soundHandle);
+
+ if (_audioStream) {
+ _audioStream->finish();
+ delete _audioStream;
+ _audioStream = nullptr;
+ }
+}
+
+unsigned int CSoundChannel::numQueued() {
+ return _audioStream ? _audioStream->numQueuedStreams() : 0;
+}
+
+unsigned int CSoundChannel::getVolume() {
+ return (_volumeRight + _volumeLeft) / 2;
+}
+
+void CSoundChannel::setVolume(unsigned int volumeLeft, unsigned int volumeRight) {
+ _volumeLeft = volumeLeft;
+ _volumeRight = volumeRight;
+ applyVolumeChange();
+}
+
+void CSoundChannel::setVolumeLeft(unsigned int volume) {
+ setVolume(volume, _volumeRight);
+}
+
+void CSoundChannel::setVolumeRight(unsigned int volume) {
+ setVolume(_volumeLeft, volume);
+}
+
+void CSoundChannel::applyVolumeChange() {
+ unsigned int volume = (_volumeRight + _volumeLeft) / 2;
+ int balance = (signed int)(_volumeRight - _volumeLeft) / 2;
+ _mixer->setChannelVolume(_soundHandle, volume);
+ _mixer->setChannelBalance(_soundHandle, balance);
+}
+
+}
diff --git a/engines/cryo/sound.h b/engines/cryo/sound.h
index 72232cc4f1..ad5312f527 100644
--- a/engines/cryo/sound.h
+++ b/engines/cryo/sound.h
@@ -1,70 +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.
- *
- */
-
-#pragma once
-
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "audio/decoders/raw.h"
-
-#include "cryo/cryolib.h"
-
-namespace Cryo {
-
-class CryoEngine;
-
-class CSoundChannel {
-private:
- Audio::Mixer *_mixer;
- Audio::QueuingAudioStream *_audioStream;
- Audio::SoundHandle _soundHandle;
- unsigned int _sampleRate;
- bool _stereo;
- unsigned int _bufferFlags;
-
- void applyVolumeChange();
-
-public:
- CSoundChannel(Audio::Mixer *mixer, unsigned int sampleRate, bool stereo, bool is16bits = false);
- ~CSoundChannel();
-
- // Queue a new buffer, cancel any previously queued buffers if playNow is set
- void queueBuffer(byte *buffer, unsigned int size, bool playNow = false, bool playQueue = true, bool buffering = true);
-
- // Play any queued buffers
- void play();
-
- // Stop playing and purge play queue
- void stop();
-
- // How many buffers in queue (including currently playing one)
- unsigned int numQueued();
-
- // Volume control
- int _volumeLeft, _volumeRight;
- unsigned int getVolume();
- void setVolume(unsigned int volumeLeft, unsigned int volumeRight);
- void setVolumeLeft(unsigned int volume);
- void setVolumeRight(unsigned int volume);
-};
-
-}
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#pragma once
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+
+#include "cryo/cryolib.h"
+
+namespace Cryo {
+
+class CryoEngine;
+
+class CSoundChannel {
+private:
+ Audio::Mixer *_mixer;
+ Audio::QueuingAudioStream *_audioStream;
+ Audio::SoundHandle _soundHandle;
+ unsigned int _sampleRate;
+ bool _stereo;
+ unsigned int _bufferFlags;
+
+ void applyVolumeChange();
+
+public:
+ CSoundChannel(Audio::Mixer *mixer, unsigned int sampleRate, bool stereo, bool is16bits = false);
+ ~CSoundChannel();
+
+ // Queue a new buffer, cancel any previously queued buffers if playNow is set
+ void queueBuffer(byte *buffer, unsigned int size, bool playNow = false, bool playQueue = true, bool buffering = true);
+
+ // Play any queued buffers
+ void play();
+
+ // Stop playing and purge play queue
+ void stop();
+
+ // How many buffers in queue (including currently playing one)
+ unsigned int numQueued();
+
+ // Volume control
+ int _volumeLeft, _volumeRight;
+ unsigned int getVolume();
+ void setVolume(unsigned int volumeLeft, unsigned int volumeRight);
+ void setVolumeLeft(unsigned int volume);
+ void setVolumeRight(unsigned int volume);
+};
+
+}
diff --git a/engines/cryo/video.cpp b/engines/cryo/video.cpp
index fe242425e5..fe8afb7ce8 100644
--- a/engines/cryo/video.cpp
+++ b/engines/cryo/video.cpp
@@ -102,7 +102,7 @@ void HnmPlayer::waitLoop() {
_nextFrameTime = _expectedFrameTime - _timeDrift;
if (_useSoundSync && _vm->_timerTicks > 1000.0 + _nextFrameTime)
_useSound = false;
- while (_vm->_timerTicks < _nextFrameTime) ; // waste time
+ while (_vm->_timerTicks < _nextFrameTime) {} // waste time
_timeDrift = _vm->_timerTicks - _nextFrameTime;
}
diff --git a/engines/director/detection.cpp b/engines/director/detection.cpp
index 16d838fcca..9d293846bc 100644
--- a/engines/director/detection.cpp
+++ b/engines/director/detection.cpp
@@ -112,7 +112,7 @@ public:
return "Macromedia Director (C) Macromedia";
}
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
};
@@ -141,7 +141,7 @@ static Director::DirectorGameDescription s_fallbackDesc = {
static char s_fallbackFileNameBuffer[51];
-const ADGameDescription *DirectorMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame DirectorMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// TODO: Handle Mac fallback
// reset fallback description
@@ -230,10 +230,10 @@ const ADGameDescription *DirectorMetaEngine::fallbackDetect(const FileMap &allFi
warning("Director fallback detection D%d", desc->version);
- return (ADGameDescription *)desc;
+ return ADDetectedGame(&desc->desc);
}
- return 0;
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(DIRECTOR)
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 1b3b59e1ef..e42444dc00 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -241,7 +241,7 @@ void Frame::readChannels(Common::ReadStreamEndian *stream) {
sprite._width = stream->readUint16();
stream->readUint16();
stream->readUint16();
-
+
}
if (sprite._castId) {
diff --git a/engines/director/lingo/lingo-gr.cpp b/engines/director/lingo/lingo-gr.cpp
index b8d9749052..c908b2e591 100644
--- a/engines/director/lingo/lingo-gr.cpp
+++ b/engines/director/lingo/lingo-gr.cpp
@@ -1596,7 +1596,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
-
+
#if YYERROR_VERBOSE
@@ -1807,7 +1807,7 @@ yysyntax_error (char *yyresult, int yystate, int yychar)
}
}
#endif /* YYERROR_VERBOSE */
-
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -1839,7 +1839,7 @@ yydestruct (yymsg, yytype, yyvaluep)
break;
}
}
-
+
/* Prevent warnings from -Wmissing-prototypes. */
@@ -1896,7 +1896,7 @@ yyparse ()
#endif
#endif
{
-
+
int yystate;
int yyn;
int yyresult;
diff --git a/engines/director/lingo/lingo-lex.cpp b/engines/director/lingo/lingo-lex.cpp
index 7b0398367b..de7005275d 100644
--- a/engines/director/lingo/lingo-lex.cpp
+++ b/engines/director/lingo/lingo-lex.cpp
@@ -168,7 +168,7 @@ extern FILE *yyin, *yyout;
#define EOB_ACT_LAST_MATCH 2
#define YY_LESS_LINENO(n)
-
+
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
@@ -225,7 +225,7 @@ struct yy_buffer_state
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
-
+
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
@@ -963,7 +963,7 @@ YY_DECL
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
-
+
#line 85 "engines/director/lingo/lingo-lex.l"
@@ -1859,7 +1859,7 @@ static int yy_get_next_buffer (void)
{
register yy_state_type yy_current_state;
register char *yy_cp;
-
+
yy_current_state = (yy_start);
yy_current_state += YY_AT_BOL();
@@ -1920,7 +1920,7 @@ static int yy_get_next_buffer (void)
{
int c;
-
+
*(yy_c_buf_p) = (yy_hold_char);
if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
@@ -1994,7 +1994,7 @@ static int yy_get_next_buffer (void)
*/
void yyrestart (FILE * input_file )
{
-
+
if ( ! YY_CURRENT_BUFFER ){
yyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
@@ -2011,7 +2011,7 @@ static int yy_get_next_buffer (void)
*/
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
{
-
+
/* TODO. We should be able to replace this entire function body
* with
* yypop_buffer_state();
@@ -2057,7 +2057,7 @@ static void yy_load_buffer_state (void)
YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
{
YY_BUFFER_STATE b;
-
+
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
@@ -2084,7 +2084,7 @@ static void yy_load_buffer_state (void)
*/
void yy_delete_buffer (YY_BUFFER_STATE b )
{
-
+
if ( ! b )
return;
@@ -2100,7 +2100,7 @@ static void yy_load_buffer_state (void)
#ifndef __cplusplus
extern int isatty (int );
#endif /* __cplusplus */
-
+
/* Initializes or reinitializes a buffer.
* This function is sometimes called more than once on the same buffer,
* such as during a yyrestart() or at EOF.
@@ -2109,7 +2109,7 @@ extern int isatty (int );
{
int oerrno = errno;
-
+
yy_flush_buffer(b );
b->yy_input_file = file;
@@ -2125,7 +2125,7 @@ extern int isatty (int );
}
b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-
+
errno = oerrno;
}
@@ -2214,7 +2214,7 @@ void yypop_buffer_state (void)
static void yyensure_buffer_stack (void)
{
yy_size_t num_to_alloc;
-
+
if (!(yy_buffer_stack)) {
/* First allocation is just for 2 elements, since we don't know if this
@@ -2227,9 +2227,9 @@ static void yyensure_buffer_stack (void)
);
if ( ! (yy_buffer_stack) )
YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
+
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
+
(yy_buffer_stack_max) = num_to_alloc;
(yy_buffer_stack_top) = 0;
return;
@@ -2263,7 +2263,7 @@ static void yyensure_buffer_stack (void)
YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
{
YY_BUFFER_STATE b;
-
+
if ( size < 2 ||
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
@@ -2299,7 +2299,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
*/
YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
{
-
+
return yy_scan_bytes(yystr,strlen(yystr) );
}
@@ -2315,7 +2315,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len
YY_BUFFER_STATE b;
char *buf;
yy_size_t n, i;
-
+
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
buf = (char *) yyalloc(n );
@@ -2373,7 +2373,7 @@ static void yy_fatal_error (yyconst char* msg )
*/
int yyget_lineno (void)
{
-
+
return yylineno;
}
@@ -2416,7 +2416,7 @@ char *yyget_text (void)
*/
void yyset_lineno (int line_number )
{
-
+
yylineno = line_number;
}
@@ -2477,7 +2477,7 @@ static int yy_init_globals (void)
/* yylex_destroy is for both reentrant and non-reentrant scanners. */
int yylex_destroy (void)
{
-
+
/* Pop the buffer stack, destroying each element. */
while(YY_CURRENT_BUFFER){
yy_delete_buffer(YY_CURRENT_BUFFER );
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index e748583146..22b33e7bcc 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -176,7 +176,7 @@ void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
uint32 ver = stream->readUint32LE();
-
+
if (ver != MKTAG('P', 'J', '9', '5'))
error("Invalid projector tag found in v5 EXE [%s]", tag2str(ver));
diff --git a/engines/dm/dm.h b/engines/dm/dm.h
index 16307778ba..e330cb6be7 100644
--- a/engines/dm/dm.h
+++ b/engines/dm/dm.h
@@ -332,7 +332,7 @@ public:
Thing _thingParty; // @ C0xFFFF_THING_PARTY
};
-bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header);
+WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail = true);
} // End of namespace DM
diff --git a/engines/dm/dungeonman.cpp b/engines/dm/dungeonman.cpp
index ab35477183..7d7b80685e 100644
--- a/engines/dm/dungeonman.cpp
+++ b/engines/dm/dungeonman.cpp
@@ -1465,6 +1465,7 @@ Thing DungeonMan::getDiscardThing(uint16 thingType) {
case kDMThingTypeGroup:
if (((Group *)squareThingData)->getDoNotDiscard())
continue;
+ // fall through
case kDMThingTypeProjectile:
setCurrentMap(mapIndex);
if (thingType == kDMThingTypeGroup) {
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index 7f31b29575..f75e7eb170 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -2162,22 +2162,20 @@ void DisplayMan::drawSquareD0L(Direction dir, int16 posX, int16 posY) {
uint16 squareAspect[5];
_vm->_dungeonMan->setSquareAspect(squareAspect, dir, posX, posY);
switch (squareAspect[kDMSquareAspectElement]) {
- case kDMElementTypeWall:
- drawWallSetBitmap(bitmapWallSetWallD0L, _frameWalls163[kDMViewSquareD0L]);
- break;
+ case kDMElementTypeStairsSide:
+ drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexSideD0L, frameStairsSideD0L);
+ return;
+ case kDMElementTypePit:
+ drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD0L : kDMGraphicIdxFloorPitD0L, frameFloorPitD0L);
+ // fall through
case kDMElementTypeCorridor:
- case kDMElementTypeTeleporter:
case kDMElementTypeDoorSide:
+ case kDMElementTypeTeleporter:
drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD0L, kDMCellOrderBackRight);
break;
- case kDMElementTypePit:
- drawFloorPitOrStairsBitmap(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD0L : kDMGraphicIdxFloorPitD0L, frameFloorPitD0L);
- case kDMElementTypeStairsSide:
- if (squareAspect[kDMSquareAspectStairsUp])
- drawFloorPitOrStairsBitmap(_stairsNativeBitmapIndexSideD0L, frameStairsSideD0L);
- break;
- default:
- break;
+ case kDMElementTypeWall:
+ drawWallSetBitmap(bitmapWallSetWallD0L, _frameWalls163[kDMViewSquareD0L]);
+ return;
}
drawCeilingPit(kDMGraphicIdxCeilingPitD0L, &frameCeilingPitD0L, posX, posY, false);
@@ -2200,6 +2198,7 @@ void DisplayMan::drawSquareD0R(Direction dir, int16 posX, int16 posY) {
case kDMElementTypePit:
drawFloorPitOrStairsBitmapFlippedHorizontally(squareAspect[kDMSquareAspectPitInvisible] ? kDMGraphicIdxFloorPitInvisibleD0L
: kDMGraphicIdxFloorPitD0L, frameFloorPitD0R);
+ // fall through
case kDMElementTypeCorridor:
case kDMElementTypeDoorSide:
case kDMElementTypeTeleporter:
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index dfdcdc017f..f36a8ddc31 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -1518,6 +1518,7 @@ bool GroupMan::isCreatureAttacking(Group *group, int16 mapX, int16 mapY, uint16
projectileThing = _vm->_thingExplPoisonCloud;
break;
}
+ // fall through
case kDMCreatureTypeDemon:
case kDMCreatureTypeRedDragon:
projectileThing = _vm->_thingExplFireBall;
diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp
index 3d8f76c33f..864a726367 100644
--- a/engines/dm/loadsave.cpp
+++ b/engines/dm/loadsave.cpp
@@ -70,7 +70,10 @@ LoadgameResult DMEngine::loadgame(int16 slot) {
file = saveFileManager->openForLoading(fileName);
SaveGameHeader header;
- readSaveGameHeader(file, &header);
+ if (!readSaveGameHeader(file, &header)) {
+ delete file;
+ return kDMLoadgameFailure;
+ }
warning("MISSING CODE: missing check for matching format and platform in save in f435_loadgame");
@@ -397,7 +400,7 @@ bool DMEngine::writeCompleteSaveFile(int16 saveSlot, Common::String& saveDescrip
return true;
}
-bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header) {
+WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail) {
uint32 id = in->readUint32BE();
// Check if it's a valid ScummVM savegame
@@ -419,7 +422,11 @@ bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header) {
header->_descr.setDescription(saveName);
// Get the thumbnail
- header->_descr.setThumbnail(Graphics::loadThumbnail(*in));
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) {
+ return false;
+ }
+ header->_descr.setThumbnail(thumbnail);
uint32 saveDate = in->readUint32BE();
uint16 saveTime = in->readUint16BE();
diff --git a/engines/dm/menus.cpp b/engines/dm/menus.cpp
index 1600f589e9..f547bbe934 100644
--- a/engines/dm/menus.cpp
+++ b/engines/dm/menus.cpp
@@ -733,9 +733,9 @@ Spell *MenuMan::getSpellFromSymbols(byte *symbols) {
if (*(symbols + 1)) {
int16 bitShiftCount = 24;
int32 curSymbols = 0;
- do
+ do {
curSymbols |= (long)*symbols++ << bitShiftCount;
- while (*symbols && ((bitShiftCount -= 8) >= 0));
+ } while (*symbols && ((bitShiftCount -= 8) >= 0));
Spell *curSpell = SpellsArray;
int16 spellIndex = 25;
while (spellIndex--) {
@@ -1136,6 +1136,7 @@ bool MenuMan::isActionPerformed(uint16 champIndex, int16 actionIndex) {
_vm->_sound->requestPlay(kDMSoundIndexWoodenThudAttackTrolinAntmanStoneGolem, dungeon._partyMapX, dungeon._partyMapY, kDMSoundModePlayOneTickLater);
break;
}
+ // fall through
case kDMActionDisrupt:
case kDMActionJab:
case kDMActionParry:
diff --git a/engines/dm/projexpl.cpp b/engines/dm/projexpl.cpp
index e8b0f4a143..0738cf64ba 100644
--- a/engines/dm/projexpl.cpp
+++ b/engines/dm/projexpl.cpp
@@ -503,10 +503,10 @@ void ProjExpl::processEvent25(TimelineEvent *event) {
case 0xFF82:
if (!(attack >>= 1))
break;
+ // fall through
case 0xFF80:
if (curSquareType == kDMElementTypeDoor)
_vm->_groupMan->groupIsDoorDestoryedByAttack(mapX, mapY, attack, true, 0);
-
break;
case 0xFF83:
if ((groupThing != _vm->_thingEndOfList) && getFlag(creatureInfo->_attributes, kDMCreatureMaskNonMaterial)) {
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index 65427bd8cd..9a76e3890c 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -132,10 +132,6 @@ SaveStateList DraciMetaEngine::listSaves(const char *target) const {
Draci::DraciSavegameHeader header;
if (Draci::readSavegameHeader(in, header)) {
saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
- if (header.thumbnail) {
- header.thumbnail->free();
- delete header.thumbnail;
- }
}
delete in;
}
@@ -157,7 +153,11 @@ SaveStateDescriptor DraciMetaEngine::querySaveMetaInfos(const char *target, int
if (f) {
Draci::DraciSavegameHeader header;
- Draci::readSavegameHeader(f, header);
+ if (!Draci::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
+
delete f;
// Create the return descriptor
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp
index 4fbf2d31ea..af57b1eb37 100644
--- a/engines/draci/game.cpp
+++ b/engines/draci/game.cpp
@@ -1594,7 +1594,7 @@ Game::~Game() {
delete[] _items;
}
-void Game::DoSync(Common::Serializer &s, uint8 saveVersion) {
+void Game::synchronize(Common::Serializer &s, uint8 saveVersion) {
s.syncAsUint16LE(_currentRoom._roomNum);
for (uint i = 0; i < _info._numObjects; ++i) {
diff --git a/engines/draci/game.h b/engines/draci/game.h
index 53a472a552..1e3cca9b9d 100644
--- a/engines/draci/game.h
+++ b/engines/draci/game.h
@@ -330,7 +330,7 @@ public:
void setEnableSpeedText(bool value) { _enableSpeedText = value; }
bool getEnableSpeedText() const { return _enableSpeedText; }
- void DoSync(Common::Serializer &s, uint8 saveVersion);
+ void synchronize(Common::Serializer &s, uint8 saveVersion);
private:
void updateOrdinaryCursor();
diff --git a/engines/draci/saveload.cpp b/engines/draci/saveload.cpp
index 3e7f8651c1..83c64b5725 100644
--- a/engines/draci/saveload.cpp
+++ b/engines/draci/saveload.cpp
@@ -35,9 +35,8 @@ namespace Draci {
static const char *const draciIdentString = "DRACI";
-bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header) {
+WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[6];
- header.thumbnail = NULL;
// Validate the header Id
in->read(saveIdentBuffer, 6);
@@ -59,9 +58,9 @@ bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header) {
header.playtime = in->readUint32LE();
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
return true;
}
@@ -107,7 +106,7 @@ Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName,
} else {
// Create the remainder of the savegame
Common::Serializer s(NULL, f);
- vm._game->DoSync(s, header.version);
+ vm._game->synchronize(s, header.version);
f->finalize();
delete f;
@@ -130,10 +129,6 @@ Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm) {
if (!readSavegameHeader(f, header)) {
return Common::kNoGameDataFoundError;
}
- if (header.thumbnail) {
- header.thumbnail->free();
- delete header.thumbnail;
- }
// Pre-processing
vm->_game->rememberRoomNumAsPrevious();
@@ -141,7 +136,7 @@ Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm) {
// Synchronise the remaining data of the savegame
Common::Serializer s(f, NULL);
- vm->_game->DoSync(s, header.version);
+ vm->_game->synchronize(s, header.version);
delete f;
// Post-processing
diff --git a/engines/draci/saveload.h b/engines/draci/saveload.h
index 6f951a3409..bceaebb468 100644
--- a/engines/draci/saveload.h
+++ b/engines/draci/saveload.h
@@ -42,7 +42,7 @@ struct DraciSavegameHeader {
class DraciEngine;
-bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header);
+WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header, bool skipThumbnail = true);
void writeSavegameHeader(Common::OutSaveFile *out, const DraciSavegameHeader &header);
Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName, DraciEngine &vm);
Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm);
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 5f453839e7..a1f2f3e117 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -430,7 +430,11 @@ SaveStateDescriptor DrasculaMetaEngine::querySaveMetaInfos(const char *target, i
return SaveStateDescriptor();
}
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ delete in;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
delete in;
diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp
index 11966047b0..36af0c3811 100644
--- a/engines/dreamweb/detection.cpp
+++ b/engines/dreamweb/detection.cpp
@@ -198,7 +198,12 @@ SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, i
uint32 saveDate = in->readUint32LE();
uint32 saveTime = in->readUint32LE();
uint32 playTime = in->readUint32LE();
- Graphics::Surface *thumbnail = Graphics::loadThumbnail(*in);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ warning("Missing or broken thumbnail - skipping");
+ delete in;
+ return desc;
+ }
int day = (saveDate >> 24) & 0xFF;
int month = (saveDate >> 16) & 0xFF;
diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp
index 9dd1d6beb4..3144a0ebff 100644
--- a/engines/fullpipe/detection.cpp
+++ b/engines/fullpipe/detection.cpp
@@ -184,7 +184,9 @@ SaveStateList FullpipeMetaEngine::listSaves(const char *target) const {
Common::ScopedPtr<Common::InSaveFile> in(saveFileMan->openForLoading(*file));
if (in) {
Fullpipe::FullpipeSavegameHeader header;
- Fullpipe::readSavegameHeader(in.get(), header);
+ if (!Fullpipe::readSavegameHeader(in.get(), header)) {
+ continue;
+ }
SaveStateDescriptor desc;
@@ -212,7 +214,9 @@ SaveStateDescriptor FullpipeMetaEngine::querySaveMetaInfos(const char *target, i
if (f) {
Fullpipe::FullpipeSavegameHeader header;
- Fullpipe::readSavegameHeader(f.get(), header);
+ if (!Fullpipe::readSavegameHeader(f.get(), header, false)) {
+ return SaveStateDescriptor();
+ }
// Create the return descriptor
SaveStateDescriptor desc;
diff --git a/engines/fullpipe/gameloader.h b/engines/fullpipe/gameloader.h
index 03c3093086..eb5957c78e 100644
--- a/engines/fullpipe/gameloader.h
+++ b/engines/fullpipe/gameloader.h
@@ -84,7 +84,7 @@ struct FullpipeSavegameHeader {
uint32 date;
uint16 time;
uint32 playtime;
- Common::SharedPtr<Graphics::Surface> thumbnail;
+ Graphics::Surface *thumbnail;
};
struct SaveHeader {
@@ -142,7 +142,7 @@ class GameLoader : public CObject {
};
const char *getSavegameFile(int saveGameIdx);
-bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header);
+WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header, bool skipThumbnail = true);
void parseSavegameHeader(Fullpipe::FullpipeSavegameHeader &header, SaveStateDescriptor &desc);
Inventory2 *getGameLoaderInventory();
diff --git a/engines/fullpipe/interaction.h b/engines/fullpipe/interaction.h
index 9ffcdccc91..7ea58e60b4 100644
--- a/engines/fullpipe/interaction.h
+++ b/engines/fullpipe/interaction.h
@@ -70,11 +70,10 @@ public:
private:
InteractionList _interactions;
- int16 _field_20;
static bool compareInteractions(const Interaction *i1, const Interaction *i2);
public:
- InteractionController() : _field_20(0), _flag24(true) {}
+ InteractionController() : _flag24(true) {}
virtual ~InteractionController();
virtual bool load(MfcArchive &file);
diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp
index be1e73ff70..3fdb6636ec 100644
--- a/engines/fullpipe/modal.cpp
+++ b/engines/fullpipe/modal.cpp
@@ -21,23 +21,21 @@
*/
#include "fullpipe/fullpipe.h"
-#include "fullpipe/messages.h"
+
#include "fullpipe/constants.h"
+#include "fullpipe/gameloader.h"
+#include "fullpipe/messages.h"
+#include "fullpipe/modal.h"
#include "fullpipe/motion.h"
+#include "fullpipe/objectnames.h"
#include "fullpipe/scenes.h"
-#include "fullpipe/gameloader.h"
#include "fullpipe/statics.h"
-#include "fullpipe/modal.h"
-#include "fullpipe/constants.h"
-#include "fullpipe/objectnames.h"
+#include "engines/savestate.h"
#include "graphics/palette.h"
#include "graphics/surface.h"
-#include "engines/savestate.h"
-#include "engines/advancedDetector.h"
-
namespace Fullpipe {
ModalIntro::ModalIntro() {
@@ -2142,7 +2140,8 @@ bool ModalSaveGame::getFileInfo(int slot, FileInfo *fileinfo) {
return false;
Fullpipe::FullpipeSavegameHeader header;
- Fullpipe::readSavegameHeader(f.get(), header);
+ if (!Fullpipe::readSavegameHeader(f.get(), header))
+ return false;
// Create the return descriptor
SaveStateDescriptor desc(slot, header.saveName);
@@ -2396,7 +2395,7 @@ bool ModalDemo::init(int counterDiff) {
if (_clickedQuit == -1)
return true;
- g_system->openUrl("http://www.amazon.de/EuroVideo-Bildprogramm-GmbH-Full-Pipe/dp/B003TO51YE/ref=sr_1_1?ie=UTF8&s=videogames&qid=1279207213&sr=8-1");
+ g_system->openUrl("http://www.amazon.de/EuroVideo-Bildprogramm-GmbH-Full-Pipe/dp/B003TO51YE/ref=sr_1_1");
g_fp->_gameContinue = false;
diff --git a/engines/fullpipe/scenes/scene22.cpp b/engines/fullpipe/scenes/scene22.cpp
index 5b9b091f36..f71460576f 100644
--- a/engines/fullpipe/scenes/scene22.cpp
+++ b/engines/fullpipe/scenes/scene22.cpp
@@ -218,7 +218,7 @@ void sceneHandler22_stoolLogic(ExCommand *cmd) {
ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_TABURETTE, -1);
if (ani && (ani->_flags & 4)) {
int x = g_fp->_aniMan->_ox;
- int y = g_fp->_aniMan->_ox;
+ int y = g_fp->_aniMan->_oy;
if (sqrt((double)((841 - x) * (841 - x) + (449 - y) * (449 - y)))
< sqrt((double)((1075 - x) * (1075 - x) + (449 - y) * (449 - y)))) {
diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp
index 703190be0b..5b89b6b0e2 100644
--- a/engines/fullpipe/stateloader.cpp
+++ b/engines/fullpipe/stateloader.cpp
@@ -22,6 +22,13 @@
#include "fullpipe/fullpipe.h"
+#include "fullpipe/constants.h"
+#include "fullpipe/gameloader.h"
+#include "fullpipe/interaction.h"
+#include "fullpipe/objects.h"
+#include "fullpipe/scene.h"
+#include "fullpipe/statics.h"
+
#include "common/file.h"
#include "common/array.h"
#include "common/list.h"
@@ -29,15 +36,6 @@
#include "graphics/thumbnail.h"
-#include "fullpipe/objects.h"
-#include "fullpipe/gameloader.h"
-#include "fullpipe/scene.h"
-#include "fullpipe/statics.h"
-#include "fullpipe/interaction.h"
-#include "fullpipe/gameloader.h"
-
-#include "fullpipe/constants.h"
-
namespace Fullpipe {
bool GameLoader::readSavegame(const char *fname) {
@@ -69,6 +67,11 @@ bool GameLoader::readSavegame(const char *fname) {
Common::Array<byte> map(800);
saveFile->read(map.data(), 800);
+ FullpipeSavegameHeader header2;
+ if (Fullpipe::readSavegameHeader(saveFile.get(), header2)) {
+ g_fp->setTotalPlayTime(header2.playtime * 1000);
+ }
+
{
Common::MemoryReadStream tempStream(map.data(), 800, DisposeAfterUse::NO);
MfcArchive temp(&tempStream);
@@ -185,10 +188,10 @@ void fillDummyHeader(Fullpipe::FullpipeSavegameHeader &header) {
// This is wrong header, perhaps it is original savegame. Thus fill out dummy values
header.date = (20 << 24) | (9 << 16) | 2016;
header.time = (9 << 8) | 56;
- header.playtime = 1000;
+ header.playtime = 0;
}
-bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header) {
+WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header, bool skipThumbnail) {
uint oldPos = in->pos();
in->seek(-4, SEEK_END);
@@ -232,13 +235,13 @@ bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header)
header.description = header.saveName;
// Get the thumbnail
- header.thumbnail = Common::SharedPtr<Graphics::Surface>(Graphics::loadThumbnail(*in), Graphics::SurfaceDeleter());
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
+ in->seek(oldPos, SEEK_SET); // Rewind the file
+ return false;
+ }
in->seek(oldPos, SEEK_SET); // Rewind the file
- if (!header.thumbnail)
- return false;
-
return true;
}
diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp
index c1cf912de6..3b60e962c6 100644
--- a/engines/fullpipe/utils.cpp
+++ b/engines/fullpipe/utils.cpp
@@ -49,7 +49,7 @@ bool ObArray::load(MfcArchive &file) {
debugC(5, kDebugLoading, "ObArray::load()");
int count = file.readCount();
- resize(count);
+ reserve(count);
for (int i = 0; i < count; i++) {
CObject *t = file.readClass<CObject>();
@@ -66,7 +66,7 @@ bool DWordArray::load(MfcArchive &file) {
debugC(9, kDebugLoading, "DWordArray::count: %d", count);
- resize(count);
+ reserve(count);
for (int i = 0; i < count; i++) {
int32 t = file.readSint32LE();
diff --git a/engines/game.cpp b/engines/game.cpp
index 7ff51a99cc..ee14acf7c8 100644
--- a/engines/game.cpp
+++ b/engines/game.cpp
@@ -22,6 +22,7 @@
#include "engines/game.h"
#include "common/gui_options.h"
+#include "common/translation.h"
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) {
@@ -34,93 +35,182 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const Pla
return 0;
}
-GameDescriptor::GameDescriptor() {
- setVal("gameid", "");
- setVal("description", "");
+PlainGameDescriptor PlainGameDescriptor::empty() {
+ PlainGameDescriptor pgd;
+ pgd.gameId = nullptr;
+ pgd.description = nullptr;
+ return pgd;
}
-GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions) {
- setVal("gameid", pgd.gameId);
- setVal("description", pgd.description);
+PlainGameDescriptor PlainGameDescriptor::of(const char *gameId, const char *description) {
+ PlainGameDescriptor pgd;
+ pgd.gameId = gameId;
+ pgd.description = description;
+ return pgd;
+}
- if (!guioptions.empty())
- setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
+DetectedGame::DetectedGame() :
+ engineName(nullptr),
+ hasUnknownFiles(false),
+ canBeAdded(true),
+ language(Common::UNK_LANG),
+ platform(Common::kPlatformUnknown),
+ gameSupportLevel(kStableGame) {
}
-GameDescriptor::GameDescriptor(const Common::String &g, const Common::String &d, Common::Language l, Common::Platform p, Common::String guioptions, GameSupportLevel gsl) {
- setVal("gameid", g);
- setVal("description", d);
- if (l != Common::UNK_LANG)
- setVal("language", Common::getLanguageCode(l));
- if (p != Common::kPlatformUnknown)
- setVal("platform", Common::getPlatformCode(p));
- if (!guioptions.empty())
- setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
-
- setSupportLevel(gsl);
+DetectedGame::DetectedGame(const PlainGameDescriptor &pgd) :
+ engineName(nullptr),
+ hasUnknownFiles(false),
+ canBeAdded(true),
+ language(Common::UNK_LANG),
+ platform(Common::kPlatformUnknown),
+ gameSupportLevel(kStableGame) {
+
+ gameId = pgd.gameId;
+ preferredTarget = pgd.gameId;
+ description = pgd.description;
}
-void GameDescriptor::setGUIOptions(Common::String guioptions) {
- if (!guioptions.empty())
- setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
- else
- erase("guioptions");
+DetectedGame::DetectedGame(const Common::String &id, const Common::String &d, Common::Language l, Common::Platform p, const Common::String &ex) :
+ engineName(nullptr),
+ hasUnknownFiles(false),
+ canBeAdded(true),
+ gameSupportLevel(kStableGame) {
+
+ gameId = id;
+ preferredTarget = id;
+ description = d;
+ language = l;
+ platform = p;
+ extra = ex;
+
+ // Append additional information, if set, to the description.
+ description += updateDesc();
}
-void GameDescriptor::appendGUIOptions(const Common::String &str) {
- setVal("guioptions", getVal("guioptions", "") + " " + str);
+void DetectedGame::setGUIOptions(const Common::String &guioptions) {
+ _guiOptions = Common::getGameGUIOptionsDescription(guioptions);
}
-void GameDescriptor::updateDesc(const char *extra) {
- const bool hasCustomLanguage = (language() != Common::UNK_LANG);
- const bool hasCustomPlatform = (platform() != Common::kPlatformUnknown);
- const bool hasExtraDesc = (extra && extra[0]);
+void DetectedGame::appendGUIOptions(const Common::String &str) {
+ if (!_guiOptions.empty())
+ _guiOptions += " ";
+
+ _guiOptions += str;
+}
+
+Common::String DetectedGame::updateDesc() const {
+ const bool hasCustomLanguage = (language != Common::UNK_LANG);
+ const bool hasCustomPlatform = (platform != Common::kPlatformUnknown);
+ const bool hasExtraDesc = !extra.empty();
// Adapt the description string if custom platform/language is set.
- if (hasCustomLanguage || hasCustomPlatform || hasExtraDesc) {
- Common::String descr = description();
+ Common::String descr;
+ if (!hasCustomLanguage && !hasCustomPlatform && !hasExtraDesc)
+ return descr;
- descr += " (";
+ descr += " (";
+
+ if (hasExtraDesc)
+ descr += extra;
+ if (hasCustomPlatform) {
if (hasExtraDesc)
- descr += extra;
- if (hasCustomPlatform) {
- if (hasExtraDesc)
- descr += "/";
- descr += Common::getPlatformDescription(platform());
- }
- if (hasCustomLanguage) {
- if (hasExtraDesc || hasCustomPlatform)
- descr += "/";
- descr += Common::getLanguageDescription(language());
+ descr += "/";
+ descr += Common::getPlatformDescription(platform);
+ }
+ if (hasCustomLanguage) {
+ if (hasExtraDesc || hasCustomPlatform)
+ descr += "/";
+ descr += Common::getLanguageDescription(language);
+ }
+
+ descr += ")";
+
+ return descr;
+}
+
+DetectionResults::DetectionResults(const DetectedGames &detectedGames) :
+ _detectedGames(detectedGames) {
+}
+
+bool DetectionResults::foundUnknownGames() const {
+ for (uint i = 0; i < _detectedGames.size(); i++) {
+ if (_detectedGames[i].hasUnknownFiles) {
+ return true;
}
- descr += ")";
- setVal("description", descr);
}
+ return false;
}
-GameSupportLevel GameDescriptor::getSupportLevel() {
- GameSupportLevel gsl = kStableGame;
- if (contains("gsl")) {
- Common::String gslString = getVal("gsl");
- if (gslString.equals("unstable"))
- gsl = kUnstableGame;
- else if (gslString.equals("testing"))
- gsl = kTestingGame;
+DetectedGames DetectionResults::listRecognizedGames() {
+ DetectedGames candidates;
+ for (uint i = 0; i < _detectedGames.size(); i++) {
+ if (_detectedGames[i].canBeAdded) {
+ candidates.push_back(_detectedGames[i]);
+ }
}
- return gsl;
+ return candidates;
}
-void GameDescriptor::setSupportLevel(GameSupportLevel gsl) {
- switch (gsl) {
- case kUnstableGame:
- setVal("gsl", "unstable");
- break;
- case kTestingGame:
- setVal("gsl", "testing");
- break;
- case kStableGame:
- // Fall Through intended
- default:
- erase("gsl");
+Common::String DetectionResults::generateUnknownGameReport(bool translate, uint32 wordwrapAt) const {
+ assert(!_detectedGames.empty());
+
+ const char *reportStart = _s("The game in '%s' seems to be an unknown game variant.\n\n"
+ "Please report the following data to the ScummVM team at %s "
+ "along with the name of the game you tried to add and "
+ "its version, language, etc.:");
+ const char *reportEngineHeader = _s("Matched game IDs for the %s engine:");
+
+ Common::String report = Common::String::format(
+ translate ? _(reportStart) : reportStart, _detectedGames[0].path.c_str(),
+ "https://bugs.scummvm.org/"
+ );
+ report += "\n";
+
+ FilePropertiesMap matchedFiles;
+
+ const char *currentEngineName = nullptr;
+ for (uint i = 0; i < _detectedGames.size(); i++) {
+ const DetectedGame &game = _detectedGames[i];
+
+ if (!game.hasUnknownFiles) continue;
+
+ if (!currentEngineName || strcmp(currentEngineName, game.engineName) != 0) {
+ currentEngineName = game.engineName;
+
+ // If the engine is not the same as for the previous entry, print an engine line header
+ report += "\n";
+ report += Common::String::format(
+ translate ? _(reportEngineHeader) : reportEngineHeader,
+ game.engineName
+ );
+ report += " ";
+
+ } else {
+ report += ", ";
+ }
+
+ // Add the gameId to the list of matched games for the engine
+ // TODO: Use the gameId here instead of the preferred target.
+ // This is currently impossible due to the AD singleId feature losing the information.
+ report += game.preferredTarget;
+
+ // Consolidate matched files across all engines and detection entries
+ for (FilePropertiesMap::const_iterator it = game.matchedFiles.begin(); it != game.matchedFiles.end(); it++) {
+ matchedFiles.setVal(it->_key, it->_value);
+ }
+ }
+
+ if (wordwrapAt) {
+ report.wordWrap(wordwrapAt);
}
+
+ report += "\n\n";
+
+ for (FilePropertiesMap::const_iterator file = matchedFiles.begin(); file != matchedFiles.end(); ++file)
+ report += Common::String::format(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);
+
+ report += "\n";
+
+ return report;
}
diff --git a/engines/game.h b/engines/game.h
index e01e5c6885..14f9962ce6 100644
--- a/engines/game.h
+++ b/engines/game.h
@@ -38,6 +38,9 @@
struct PlainGameDescriptor {
const char *gameId;
const char *description;
+
+ static PlainGameDescriptor empty();
+ static PlainGameDescriptor of(const char *gameId, const char *description);
};
/**
@@ -47,6 +50,18 @@ struct PlainGameDescriptor {
*/
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list);
+class PlainGameList : public Common::Array<PlainGameDescriptor> {
+public:
+ PlainGameList() {}
+ PlainGameList(const PlainGameList &list) : Common::Array<PlainGameDescriptor>(list) {}
+ PlainGameList(const PlainGameDescriptor *g) {
+ while (g->gameId) {
+ push_back(*g);
+ g++;
+ }
+ }
+};
+
/**
* Ths is an enum to describe how done a game is. This also indicates what level of support is expected.
*/
@@ -56,63 +71,138 @@ enum GameSupportLevel {
kUnstableGame // the game is not even ready for public testing yet
};
+
/**
- * A hashmap describing details about a given game. In a sense this is a refined
- * version of PlainGameDescriptor, as it also contains a gameid and a description string.
- * But in addition, platform and language settings, as well as arbitrary other settings,
- * can be contained in a GameDescriptor.
- * This is an essential part of the glue between the game engines and the launcher code.
+ * A record describing the properties of a file. Used on the existing
+ * files while detecting a game.
*/
-class GameDescriptor : public Common::StringMap {
-public:
- GameDescriptor();
- GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions = Common::String());
- GameDescriptor(const Common::String &gameid,
- const Common::String &description,
- Common::Language language = Common::UNK_LANG,
- Common::Platform platform = Common::kPlatformUnknown,
- Common::String guioptions = Common::String(),
- GameSupportLevel gsl = kStableGame);
+struct FileProperties {
+ int32 size;
+ Common::String md5;
+
+ FileProperties() : size(-1) {}
+};
+
+/**
+ * A map of all relevant existing files while detecting.
+ */
+typedef Common::HashMap<Common::String, FileProperties, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FilePropertiesMap;
+
+/**
+ * Details about a given game.
+ *
+ * While PlainGameDescriptor refers to a game supported by an engine, this refers to a game copy
+ * that has been detected by an engine's detector.
+ * It contains all the necessary data to add the game to the configuration manager and / or to launch it.
+ */
+struct DetectedGame {
+ DetectedGame();
+ explicit DetectedGame(const PlainGameDescriptor &pgd);
+ DetectedGame(const Common::String &id,
+ const Common::String &description,
+ Common::Language language = Common::UNK_LANG,
+ Common::Platform platform = Common::kPlatformUnknown,
+ const Common::String &extra = Common::String());
+
+ void setGUIOptions(const Common::String &options);
+ void appendGUIOptions(const Common::String &str);
+ Common::String getGUIOptions() const { return _guiOptions; }
/**
- * Update the description string by appending (EXTRA/PLATFORM/LANG) to it.
- * Values that are missing are omitted, so e.g. (EXTRA/LANG) would be
- * added if no platform has been specified but a language and an extra string.
+ * The name of the engine supporting the detected game
*/
- void updateDesc(const char *extra = 0);
+ const char *engineName;
- void setGUIOptions(Common::String options);
- void appendGUIOptions(const Common::String &str);
+ /**
+ * A game was detected, but some files were not recognized
+ *
+ * This can happen when the md5 or size of the detected files did not match the engine's detection tables.
+ * When this is true, the list of matched files below contains detail about the unknown files.
+ *
+ * @see matchedFiles
+ */
+ bool hasUnknownFiles;
+
+ /**
+ * An optional list of the files that were used to match the game with the engine's detection tables
+ */
+ FilePropertiesMap matchedFiles;
+
+ /**
+ * This detection entry contains enough data to add the game to the configuration manager and launch it
+ *
+ * @see matchedGame
+ */
+ bool canBeAdded;
+
+ Common::String gameId;
+ Common::String preferredTarget;
+ Common::String description;
+ Common::Language language;
+ Common::Platform platform;
+ Common::String path;
+ Common::String extra;
/**
* What level of support is expected of this game
*/
- GameSupportLevel getSupportLevel();
- void setSupportLevel(GameSupportLevel gsl);
-
- Common::String &gameid() { return getVal("gameid"); }
- Common::String &description() { return getVal("description"); }
- const Common::String &gameid() const { return getVal("gameid"); }
- const Common::String &description() const { return getVal("description"); }
- Common::Language language() const { return contains("language") ? Common::parseLanguage(getVal("language")) : Common::UNK_LANG; }
- Common::Platform platform() const { return contains("platform") ? Common::parsePlatform(getVal("platform")) : Common::kPlatformUnknown; }
-
- const Common::String &preferredtarget() const {
- return contains("preferredtarget") ? getVal("preferredtarget") : getVal("gameid");
- }
+ GameSupportLevel gameSupportLevel;
+
+private:
+ /**
+ * Update the description string by appending (EXTRA/PLATFORM/LANG) to it.
+ * Values that are missing are omitted, so e.g. (EXTRA/LANG) would be
+ * added if no platform has been specified but a language and an extra string.
+ */
+ Common::String updateDesc() const;
+
+ Common::String _guiOptions;
};
/** List of games. */
-class GameList : public Common::Array<GameDescriptor> {
+typedef Common::Array<DetectedGame> DetectedGames;
+
+/**
+ * Contains a list of games found by the engines' detectors.
+ *
+ * Each detected game can either:
+ * - be fully recognized (e.g. an exact match was found in the detection tables of an engine)
+ * - be an unknown variant (e.g. a game using files with the same name was found in the detection tables)
+ * - be recognized with unknown files (e.g. the game was exactly not found in the detection tables,
+ * but the detector was able to gather enough data to allow launching the game)
+ *
+ * Practically, this means a detected game can be in both the recognized game list and in the unknown game
+ * report handled by this class.
+ */
+class DetectionResults {
public:
- GameList() {}
- GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {}
- GameList(const PlainGameDescriptor *g) {
- while (g->gameId) {
- push_back(GameDescriptor(*g));
- g++;
- }
- }
+ explicit DetectionResults(const DetectedGames &detectedGames);
+
+ /**
+ * List all the games that were recognized by the engines
+ *
+ * Recognized games can be added to the configuration manager and then launched.
+ */
+ DetectedGames listRecognizedGames();
+
+ /**
+ * Were unknown game variants found by the engines?
+ *
+ * When unknown game variants are found, an unknown game report can be generated.
+ */
+ bool foundUnknownGames() const;
+
+ /**
+ * Generate a report that we found an unknown game variant, together with the file
+ * names, sizes and MD5 sums.
+ *
+ * @param translate translate the report to the currently active GUI language
+ * @param wordwrapAt word wrap the text part of the report after a number of characters
+ */
+ Common::String generateUnknownGameReport(bool translate, uint32 wordwrapAt = 0) const;
+
+private:
+ DetectedGames _detectedGames;
};
#endif
diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp
index d19d420ff8..97c9128002 100644
--- a/engines/gnap/detection.cpp
+++ b/engines/gnap/detection.cpp
@@ -141,13 +141,8 @@ SaveStateList GnapMetaEngine::listSaves(const char *target) const {
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;
- }
+ if (Gnap::GnapEngine::readSavegameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
delete in;
}
}
@@ -179,7 +174,11 @@ SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int s
SaveStateDescriptor desc(slot, saveName);
if (version != 1) {
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*file, thumbnail)) {
+ delete file;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
}
diff --git a/engines/gnap/gnap.cpp b/engines/gnap/gnap.cpp
index cf8710c64d..9b0015e646 100644
--- a/engines/gnap/gnap.cpp
+++ b/engines/gnap/gnap.cpp
@@ -979,7 +979,7 @@ int GnapEngine::playSoundC() {
if (!_timers[_soundTimerIndexC]) {
_timers[_soundTimerIndexC] = getRandom(50) + 150;
- soundId = kSoundIdsC[getRandom(7)] ;
+ soundId = kSoundIdsC[getRandom(7)];
playSound(soundId | 0x10000, false);
}
return soundId;
diff --git a/engines/gnap/gnap.h b/engines/gnap/gnap.h
index dbefa31795..dd653304e7 100644
--- a/engines/gnap/gnap.h
+++ b/engines/gnap/gnap.h
@@ -319,7 +319,7 @@ public:
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);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header, bool skipThumbnail = true);
void delayTicks(int val, int idx, bool updateCursor);
void delayTicksA(int val, int idx);
diff --git a/engines/gnap/menu.cpp b/engines/gnap/menu.cpp
index 9606273b4c..34b5f18473 100644
--- a/engines/gnap/menu.cpp
+++ b/engines/gnap/menu.cpp
@@ -589,9 +589,8 @@ void GnapEngine::writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeade
out->writeSint16LE(td.tm_min);
}
-bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header) {
+WARN_UNUSED_RESULT bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = nullptr;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -612,9 +611,9 @@ bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &
if (header._version == 1)
header._thumbnail = nullptr;
else {
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
}
// Read in save date/time
diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp
index e204ced1e8..864a701aa6 100644
--- a/engines/gob/detection/detection.cpp
+++ b/engines/gob/detection/detection.cpp
@@ -33,9 +33,9 @@ class GobMetaEngine : public AdvancedMetaEngine {
public:
GobMetaEngine();
- virtual GameDescriptor findGame(const char *gameId) const;
+ PlainGameDescriptor findGame(const char *gameId) const override;
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual const char *getName() const;
virtual const char *getOriginalCopyright() const;
@@ -59,29 +59,26 @@ GobMetaEngine::GobMetaEngine() :
_guiOptions = GUIO1(GUIO_NOLAUNCHLOAD);
}
-GameDescriptor GobMetaEngine::findGame(const char *gameId) const {
+PlainGameDescriptor GobMetaEngine::findGame(const char *gameId) const {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
-const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
+ADDetectedGame GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame detectedGame = detectGameFilebased(allFiles, fslist, Gob::fileBased);
+ if (!detectedGame.desc) {
+ return ADDetectedGame();
+ }
- const Gob::GOBGameDescription *game;
- game = (const Gob::GOBGameDescription *)detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
- if (!game)
- return 0;
+ const Gob::GOBGameDescription *game = (const Gob::GOBGameDescription *)detectedGame.desc;
if (game->gameType == Gob::kGameTypeOnceUponATime) {
game = detectOnceUponATime(fslist);
- if (!game)
- return 0;
+ if (game) {
+ detectedGame.desc = &game->desc;
+ }
}
- ADGameIdList gameIds;
- gameIds.push_back(game->desc.gameId);
-
- reportUnknown(fslist.begin()->getParent(), filesProps, gameIds);
- return (const ADGameDescription *)game;
+ return detectedGame;
}
const Gob::GOBGameDescription *GobMetaEngine::detectOnceUponATime(const Common::FSList &fslist) {
diff --git a/engines/hopkins/computer.cpp b/engines/hopkins/computer.cpp
index 16977e0cb8..aff3c914f6 100644
--- a/engines/hopkins/computer.cpp
+++ b/engines/hopkins/computer.cpp
@@ -918,9 +918,9 @@ void ComputerManager::getScoreName() {
char score[16];
sprintf(score, "%d", _breakoutScore);
int scoreLen = 0;
- do
+ do {
++scoreLen;
- while (score[scoreLen]);
+ } while (score[scoreLen]);
for (int i = scoreLen - 1, scorePos = 8; i >= 0; i--) {
_score[scoreLine]._score.setChar(score[i], scorePos--);
diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp
index 041afecaa8..ebefee6278 100644
--- a/engines/hopkins/detection.cpp
+++ b/engines/hopkins/detection.cpp
@@ -168,9 +168,6 @@ SaveStateList HopkinsMetaEngine::listSaves(const char *target) const {
if (in) {
if (Hopkins::SaveLoadManager::readSavegameHeader(in, header)) {
saveList.push_back(SaveStateDescriptor(slot, header._saveName));
-
- header._thumbnail->free();
- delete header._thumbnail;
}
delete in;
@@ -198,7 +195,11 @@ SaveStateDescriptor HopkinsMetaEngine::querySaveMetaInfos(const char *target, in
if (f) {
Hopkins::hopkinsSavegameHeader header;
- Hopkins::SaveLoadManager::readSavegameHeader(f, header);
+ if (!Hopkins::SaveLoadManager::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
+
delete f;
// Create the return descriptor
diff --git a/engines/hopkins/dialogs.cpp b/engines/hopkins/dialogs.cpp
index fc613f892d..cabdc9e9ea 100644
--- a/engines/hopkins/dialogs.cpp
+++ b/engines/hopkins/dialogs.cpp
@@ -448,9 +448,9 @@ void DialogsManager::showInventory() {
_vm->_script->_tempObjectFl = false;
if (_vm->_soundMan->_voiceOffFl) {
- do
+ do {
_vm->_events->refreshScreenAndEvents();
- while (!_vm->_globals->_exitId && _vm->_events->getMouseButton() != 1);
+ } while (!_vm->_globals->_exitId && _vm->_events->getMouseButton() != 1);
_vm->_fontMan->hideText(9);
}
if (_vm->_globals->_exitId) {
@@ -692,7 +692,7 @@ void DialogsManager::showSaveLoad(SaveLoadMode mode) {
for (int slotNumber = 1; slotNumber <= 6; ++slotNumber) {
hopkinsSavegameHeader header;
- if (_vm->_saveLoad->readSavegameHeader(slotNumber, header)) {
+ if (_vm->_saveLoad->readSavegameHeader(slotNumber, header, false)) {
Graphics::Surface thumb8;
_vm->_saveLoad->convertThumb16To8(header._thumbnail, &thumb8);
diff --git a/engines/hopkins/font.cpp b/engines/hopkins/font.cpp
index 7d57f564a9..9d11c5a940 100644
--- a/engines/hopkins/font.cpp
+++ b/engines/hopkins/font.cpp
@@ -281,9 +281,9 @@ void FontManager::box(int idx, int messageId, const Common::String &filename, in
int ptrb = _boxWidth - 4;
for (;;) {
lineSize = curLineSize;
- do
+ do {
curChar = _tempText[tempTextIdx + curLineSize++];
- while (curChar != ' ' && curChar != '%');
+ } while (curChar != ' ' && curChar != '%');
if (curLineSize >= ptrb / _fontFixedWidth) {
if (curChar == '%')
curChar = ' ';
diff --git a/engines/hopkins/hopkins.cpp b/engines/hopkins/hopkins.cpp
index f28de39827..dd64c0cc71 100644
--- a/engines/hopkins/hopkins.cpp
+++ b/engines/hopkins/hopkins.cpp
@@ -314,9 +314,9 @@ bool HopkinsEngine::runWin95Demo() {
_graphicsMan->loadImage("ENDUK");
_graphicsMan->fadeInLong();
_events->mouseOn();
- do
+ do {
_events->refreshScreenAndEvents();
- while (_events->getMouseButton() != 1);
+ } while (_events->getMouseButton() != 1);
_graphicsMan->fadeOutLong();
restoreSystem();
} else
@@ -2047,9 +2047,9 @@ void HopkinsEngine::playUnderwaterBaseCutscene() {
_graphicsMan->fadeInLong();
_objectsMan->enableHidingBehavior();
- do
+ do {
_events->refreshScreenAndEvents();
- while (!shouldQuit() && _objectsMan->getBobAnimDataIdx(8) != 22);
+ } while (!shouldQuit() && _objectsMan->getBobAnimDataIdx(8) != 22);
if (!shouldQuit()) {
_graphicsMan->fadeOutLong();
@@ -2092,9 +2092,9 @@ void HopkinsEngine::playEnding() {
_graphicsMan->fadeInLong();
_globals->_eventMode = EVENTMODE_IGNORE;
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(6) != 54);
+ } while (_objectsMan->getBobAnimDataIdx(6) != 54);
_globals->_introSpeechOffFl = true;
_talkMan->startAnimatedCharacterDialogue("GM4.PE2");
@@ -2104,38 +2104,38 @@ void HopkinsEngine::playEnding() {
_objectsMan->setBobAnimation(9);
_objectsMan->setBobAnimation(7);
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(7) != 54);
+ } while (_objectsMan->getBobAnimDataIdx(7) != 54);
_soundMan->playSample(1);
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(7) != 65);
+ } while (_objectsMan->getBobAnimDataIdx(7) != 65);
_globals->_introSpeechOffFl = true;
_talkMan->startAnimatedCharacterDialogue("DUELB4.PE2");
_events->mouseOff();
_globals->_disableInventFl = true;
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(7) != 72);
+ } while (_objectsMan->getBobAnimDataIdx(7) != 72);
_globals->_introSpeechOffFl = true;
_talkMan->startAnimatedCharacterDialogue("DUELH1.PE2");
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(7) != 81);
+ } while (_objectsMan->getBobAnimDataIdx(7) != 81);
_globals->_introSpeechOffFl = true;
_talkMan->startAnimatedCharacterDialogue("DUELB5.PE2");
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(7) != 120);
+ } while (_objectsMan->getBobAnimDataIdx(7) != 120);
_objectsMan->stopBobAnimation(7);
if (_globals->_saveData->_data[svGameWonFl] == 1) {
@@ -2150,9 +2150,9 @@ void HopkinsEngine::playEnding() {
_events->_rateCounter = 0;
if (!_events->_escKeyFl) {
- do
+ do {
_events->refreshEvents();
- while (_events->_rateCounter < 2000 / _globals->_speed && !_events->_escKeyFl);
+ } while (_events->_rateCounter < 2000 / _globals->_speed && !_events->_escKeyFl);
}
_events->_escKeyFl = false;
_graphicsMan->fadeOutLong();
@@ -2184,15 +2184,15 @@ void HopkinsEngine::playEnding() {
_talkMan->startAnimatedCharacterDialogue("GM5.PE2");
_globals->_disableInventFl = true;
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(8) != 5);
+ } while (_objectsMan->getBobAnimDataIdx(8) != 5);
_soundMan->directPlayWav("SOUND41.WAV");
- do
+ do {
_events->refreshScreenAndEvents();
- while (_objectsMan->getBobAnimDataIdx(8) != 21);
+ } while (_objectsMan->getBobAnimDataIdx(8) != 21);
_graphicsMan->fadeOutLong();
_graphicsMan->endDisplayBob();
diff --git a/engines/hopkins/objects.cpp b/engines/hopkins/objects.cpp
index b54b21bbc9..d67cd7b60c 100644
--- a/engines/hopkins/objects.cpp
+++ b/engines/hopkins/objects.cpp
@@ -2761,9 +2761,9 @@ void ObjectsManager::handleSpecialGames() {
break;
_vm->_globals->_disableInventFl = true;
- do
+ do {
_vm->_events->refreshScreenAndEvents();
- while (getBobAnimDataIdx(8) != 3);
+ } while (getBobAnimDataIdx(8) != 3);
_vm->_globals->_introSpeechOffFl = true;
_vm->_talkMan->startAnimatedCharacterDialogue("GM3.PE2");
stopBobAnimation(8);
diff --git a/engines/hopkins/saveload.cpp b/engines/hopkins/saveload.cpp
index 05c7fb8119..35a80458ff 100644
--- a/engines/hopkins/saveload.cpp
+++ b/engines/hopkins/saveload.cpp
@@ -77,9 +77,8 @@ void SaveLoadManager::load(const Common::String &file, byte *buf) {
delete savefile;
}
-bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header) {
+WARN_UNUSED_RESULT bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = NULL;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -96,9 +95,9 @@ bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegame
while ((ch = (char)in->readByte()) != '\0') header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header._year = in->readSint16LE();
@@ -186,10 +185,10 @@ Common::Error SaveLoadManager::loadGame(int slot) {
// Read in the savegame header
hopkinsSavegameHeader header;
- readSavegameHeader(savefile, header);
- if (header._thumbnail)
- header._thumbnail->free();
- delete header._thumbnail;
+ if (!readSavegameHeader(savefile, header)) {
+ delete savefile;
+ return Common::kReadingFailed;
+ }
// Read in the savegame data
syncSavegameData(serializer, header._version);
@@ -212,14 +211,14 @@ Common::Error SaveLoadManager::loadGame(int slot) {
return Common::kNoError;
}
-bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header) {
+WARN_UNUSED_RESULT bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header, bool skipThumbnail) {
// Try and open the save file for reading
Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(
_vm->generateSaveName(slot));
if (!savefile)
return false;
- bool result = readSavegameHeader(savefile, header);
+ bool result = readSavegameHeader(savefile, header, skipThumbnail);
delete savefile;
return result;
}
diff --git a/engines/hopkins/saveload.h b/engines/hopkins/saveload.h
index 7b4ec307f5..33234f49fa 100644
--- a/engines/hopkins/saveload.h
+++ b/engines/hopkins/saveload.h
@@ -61,9 +61,9 @@ public:
bool saveFile(const Common::String &file, const void *buf, size_t n);
void load(const Common::String &file, byte *buf);
- static bool readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header, bool skipThumbnail = true);
void writeSavegameHeader(Common::OutSaveFile *out, hopkinsSavegameHeader &header);
- bool readSavegameHeader(int slot, hopkinsSavegameHeader &header);
+ WARN_UNUSED_RESULT bool readSavegameHeader(int slot, hopkinsSavegameHeader &header, bool skipThumbnail = true);
Common::Error saveGame(int slot, const Common::String &saveName);
Common::Error loadGame(int slot);
diff --git a/engines/hopkins/talk.cpp b/engines/hopkins/talk.cpp
index 00c4ab0332..f3cd6bd026 100644
--- a/engines/hopkins/talk.cpp
+++ b/engines/hopkins/talk.cpp
@@ -120,9 +120,9 @@ void TalkManager::startAnimatedCharacterDialogue(const Common::String &filename)
if (_vm->_globals->_introSpeechOffFl) {
int idx = 1;
int answer;
- do
+ do {
answer = dialogAnswer(idx++, false);
- while (answer != -1);
+ } while (answer != -1);
}
clearCharacterAnim();
_vm->_globals->_introSpeechOffFl = false;
@@ -208,9 +208,9 @@ void TalkManager::startStaticCharacterDialogue(const Common::String &filename) {
if (_vm->_globals->_introSpeechOffFl) {
int idx = 1;
int answer;
- do
+ do {
answer = dialogAnswer(idx++, true);
- while (answer != -1);
+ } while (answer != -1);
}
_characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
@@ -879,9 +879,9 @@ void TalkManager::handleForestAnswser(int zone, int verb) {
_vm->_objectsMan->setBobAnimation(6);
_vm->_soundMan->playSample(1);
_vm->_objectsMan->showSpecialActionAnimation(_vm->_objectsMan->_forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 4);
- do
+ do {
_vm->_events->refreshScreenAndEvents();
- while (_vm->_objectsMan->getBobAnimDataIdx(6) < 12);
+ } while (_vm->_objectsMan->getBobAnimDataIdx(6) < 12);
_vm->_objectsMan->stopBobAnimation(6);
_vm->_objectsMan->setBobAnimation(8);
@@ -927,9 +927,9 @@ void TalkManager::handleForestAnswser(int zone, int verb) {
_vm->_objectsMan->setBobAnimation(5);
_vm->_soundMan->playSample(1);
_vm->_objectsMan->showSpecialActionAnimation(_vm->_objectsMan->_forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 4);
- do
+ do {
_vm->_events->refreshScreenAndEvents();
- while (_vm->_objectsMan->getBobAnimDataIdx(5) < 12);
+ } while (_vm->_objectsMan->getBobAnimDataIdx(5) < 12);
_vm->_objectsMan->stopBobAnimation(5);
_vm->_objectsMan->setBobAnimation(7);
switch (_vm->_globals->_screenId) {
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index 4e4746c002..6d2fec5421 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -241,7 +241,12 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s
SaveStateDescriptor desc(slot, saveName);
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*file, thumbnail)) {
+ warning("Missing or broken savegame thumbnail");
+ delete file;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
uint32 saveDate = file->readUint32BE();
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index 5f6892bd20..ed82c04d7d 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -638,7 +638,6 @@ void HugoEngine::initialize() {
calcMaxScore(); // Initialize maxscore
_rnd = new Common::RandomSource("hugo");
- _rnd->setSeed(42); // Kick random number generator
switch (_gameVariant) {
case kGameVariantH1Dos:
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 70c7e7c93c..79e1d9f494 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -256,7 +256,7 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
if (in) {
- if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError) {
+ if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError) {
// WORKAROUND: Old savegames are using 'German' as description for kyra3 restart game save (slot 0),
// since that looks odd we replace it by "New Game".
if (slotNum == 0 && header.gameID == Kyra::GI_KYRA3)
@@ -298,7 +298,7 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s
Kyra::KyraEngine_v1::SaveHeader header;
Kyra::KyraEngine_v1::ReadSaveHeaderError error;
- error = Kyra::KyraEngine_v1::readSaveHeader(in, true, header);
+ error = Kyra::KyraEngine_v1::readSaveHeader(in, header, false);
delete in;
if (error == Kyra::KyraEngine_v1::kRSHENoError) {
diff --git a/engines/kyra/eobcommon.h b/engines/kyra/eobcommon.h
index 1401d59dae..d214da0944 100644
--- a/engines/kyra/eobcommon.h
+++ b/engines/kyra/eobcommon.h
@@ -885,7 +885,7 @@ protected:
void inflictMonsterDamage(EoBMonsterInPlay *m, int damage, bool giveExperience);
void calcAndInflictMonsterDamage(EoBMonsterInPlay *m, int times, int pips, int offs, int flags, int savingThrowType, int savingThrowEffect);
void calcAndInflictCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, int savingThrowEffect);
- int calcCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, int damageType) ;
+ int calcCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, int damageType);
void inflictCharacterDamage(int charIndex, int damage);
bool characterAttackHitTest(int charIndex, int monsterIndex, int item, int attackType);
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 4de7494510..bbbd59a4b8 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -416,7 +416,7 @@ protected:
kRSHEIoError = 3
};
- static ReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header);
+ WARN_UNUSED_RESULT static ReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header, bool skipThumbnail = true);
void loadGameStateCheck(int slot);
virtual Common::Error loadGameState(int slot) = 0;
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index b44850f5c9..c306d6cb5d 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -37,12 +37,11 @@
namespace Kyra {
-KyraEngine_v1::ReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
+WARN_UNUSED_RESULT KyraEngine_v1::ReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) {
uint32 type = in->readUint32BE();
header.originalSave = false;
header.oldHeader = false;
header.flags = 0;
- header.thumbnail = 0;
if (type == MKTAG('K', 'Y', 'R', 'A') || type == MKTAG('A', 'R', 'Y', 'K')) { // old Kyra1 header ID
header.gameID = GI_KYRA1;
@@ -125,10 +124,8 @@ KyraEngine_v1::ReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekabl
header.flags = in->readUint32BE();
if (header.version >= 14) {
- if (loadThumbnail) {
- header.thumbnail = Graphics::loadThumbnail(*in);
- } else {
- Graphics::skipThumbnail(*in);
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
+ return kRSHEIoError;
}
}
@@ -140,7 +137,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena
if (!(in = _saveFileMan->openForLoading(filename)))
return 0;
- ReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header);
+ ReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header);
if (errorCode != kRSHENoError) {
if (errorCode == kRSHEInvalidType)
warning("No ScummVM Kyra engine savefile header");
diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp
index 6c1bd572e1..3a9a647fa5 100644
--- a/engines/kyra/screen_eob.cpp
+++ b/engines/kyra/screen_eob.cpp
@@ -499,7 +499,7 @@ void Screen_EoB::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y,
int16 dX = x - (_dsX1 << 3);
int16 dY = y;
int16 dW = _dsX2 - _dsX1;
- uint8 pixelsPerByte = *src++ ;
+ uint8 pixelsPerByte = *src++;
uint16 dH = *src++;
uint16 width = (*src++) << 3;
@@ -1211,7 +1211,7 @@ void Screen_EoB::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, ui
if (t <= v && (ii == rootColor || ii != i)) {
v = t;
- col = ii ;
+ col = ii;
}
}
*dst++ = col;
diff --git a/engines/kyra/sequences_darkmoon.cpp b/engines/kyra/sequences_darkmoon.cpp
index 53a30d0079..68d6f752e0 100644
--- a/engines/kyra/sequences_darkmoon.cpp
+++ b/engines/kyra/sequences_darkmoon.cpp
@@ -876,7 +876,7 @@ void DarkMoonEngine::seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *da
const uint8 *shp = sq->_shapes[(*++posOld) - 1];
items[i + 1].data = shp;
items[i + 1].size = shp[1];
- items[i + 1].x = (dm->w - shp[2]) << 2 ;
+ items[i + 1].x = (dm->w - shp[2]) << 2;
items[i + 1].dataType = 1;
delete[] items[i + 1].str;
items[i + 1].str = 0;
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 942cf16502..7ee1ad7e4b 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -3378,7 +3378,7 @@ void KyraEngine_HoF::seq_showStarcraftLogo() {
int KyraEngine_HoF::seq_playIntro() {
bool startupSaveLoadable = saveFileLoadable(0);
- return SeqPlayer_HOF(this, _screen, _system, startupSaveLoadable).play(kSequenceVirgin, startupSaveLoadable? kSequenceTitle : kSequenceNoLooping);
+ return SeqPlayer_HOF(this, _screen, _system, startupSaveLoadable).play(kSequenceVirgin, startupSaveLoadable ? kSequenceTitle : kSequenceNoLooping);
}
int KyraEngine_HoF::seq_playOutro() {
diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp
index 58484c2fd9..a8091c9d41 100644
--- a/engines/kyra/sequences_lok.cpp
+++ b/engines/kyra/sequences_lok.cpp
@@ -785,6 +785,8 @@ void KyraEngine_LoK::seq_dispelMagicAnimation() {
return;
}
_screen->hideMouse();
+ // TODO
+ // This condition is always false. Is this a typo or a bug in the original?
if (_currentCharacter->sceneId == 210 && _currentCharacter->sceneId < 160)
_currentCharacter->facing = 3;
if (_malcolmFlag == 7 && _beadStateVar == 3) {
diff --git a/engines/kyra/sound_digital.cpp b/engines/kyra/sound_digital.cpp
index a1600f6464..551d79cc55 100644
--- a/engines/kyra/sound_digital.cpp
+++ b/engines/kyra/sound_digital.cpp
@@ -30,6 +30,8 @@
#include "audio/decoders/vorbis.h"
#include "audio/decoders/flac.h"
+#include "common/util.h"
+
namespace Kyra {
class KyraAudioStream : public Audio::SeekableAudioStream {
@@ -203,11 +205,7 @@ int AUDStream::readBuffer(int16 *buffer, const int numSamples) {
}
inline int16 clip8BitSample(int16 sample) {
- if (sample > 255)
- return 255;
- if (sample < 0)
- return 0;
- return sample;
+ return CLIP<int16>(sample, 0, 255);
}
int AUDStream::readChunk(int16 *buffer, const int maxSamples) {
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index 4b77bf1351..3559133cb1 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -169,24 +169,24 @@ public:
SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer);
virtual ~SoundPC98();
- virtual kType getMusicType() const { return kPC98; }
+ virtual kType getMusicType() const override { return kPC98; }
- virtual bool init();
+ virtual bool init() override;
- virtual void initAudioResourceInfo(int set, void *info);
- virtual void selectAudioResourceSet(int set);
- virtual bool hasSoundFile(uint file) const;
- virtual void loadSoundFile(uint file);
- virtual void loadSoundFile(Common::String file);
+ virtual void initAudioResourceInfo(int set, void *info) override;
+ virtual void selectAudioResourceSet(int set) override;
+ virtual bool hasSoundFile(uint file) const override;
+ virtual void loadSoundFile(uint file) override;
+ virtual void loadSoundFile(Common::String file) override;
- virtual void playTrack(uint8 track);
- virtual void haltTrack();
- virtual void beginFadeOut();
+ virtual void playTrack(uint8 track) override;
+ virtual void haltTrack() override;
+ virtual void beginFadeOut() override;
virtual int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool isSfx) override { return -1; }
- virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF);
+ virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF) override;
- virtual void updateVolumeSettings();
+ virtual void updateVolumeSettings() override;
private:
int _lastTrack;
@@ -204,25 +204,25 @@ public:
SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer);
virtual ~SoundTownsPC98_v2();
- virtual kType getMusicType() const { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; }
+ virtual kType getMusicType() const override { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; }
- virtual bool init();
- virtual void process();
+ virtual bool init() override;
+ virtual void process() override;
- virtual void initAudioResourceInfo(int set, void *info);
- virtual void selectAudioResourceSet(int set);
- virtual bool hasSoundFile(uint file) const;
- virtual void loadSoundFile(uint file) {}
- virtual void loadSoundFile(Common::String file);
+ virtual void initAudioResourceInfo(int set, void *info) override;
+ virtual void selectAudioResourceSet(int set) override;
+ virtual bool hasSoundFile(uint file) const override;
+ virtual void loadSoundFile(uint file) override {}
+ virtual void loadSoundFile(Common::String file) override;
- virtual void playTrack(uint8 track);
- virtual void haltTrack();
- virtual void beginFadeOut();
+ virtual void playTrack(uint8 track) override;
+ virtual void haltTrack() override;
+ virtual void beginFadeOut() override;
virtual int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume = 255, uint8 priority = 255, bool isSfx = true) override;
- virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF);
+ virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF) override;
- virtual void updateVolumeSettings();
+ virtual void updateVolumeSettings() override;
private:
Audio::AudioStream *_currentSFX;
@@ -320,22 +320,22 @@ public:
SoundAmiga(KyraEngine_v1 *vm, Audio::Mixer *mixer);
virtual ~SoundAmiga();
- virtual kType getMusicType() const { return kAmiga; } //FIXME
+ virtual kType getMusicType() const override { return kAmiga; } //FIXME
- virtual bool init();
+ virtual bool init() override;
- virtual void initAudioResourceInfo(int set, void *info);
- virtual void selectAudioResourceSet(int set);
- virtual bool hasSoundFile(uint file) const;
- virtual void loadSoundFile(uint file);
- virtual void loadSoundFile(Common::String) {}
+ virtual void initAudioResourceInfo(int set, void *info) override;
+ virtual void selectAudioResourceSet(int set) override;
+ virtual bool hasSoundFile(uint file) const override;
+ virtual void loadSoundFile(uint file) override;
+ virtual void loadSoundFile(Common::String) override {}
- virtual void playTrack(uint8 track);
- virtual void haltTrack();
- virtual void beginFadeOut();
+ virtual void playTrack(uint8 track) override;
+ virtual void haltTrack() override;
+ virtual void beginFadeOut() override;
virtual int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool isSfx) override { return -1; }
- virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF);
+ virtual void playSoundEffect(uint8 track, uint8 volume = 0xFF) override;
protected:
Audio::MaxTrax *_driver;
diff --git a/engines/lab/lab.h b/engines/lab/lab.h
index 2a1e527098..aedf0181ec 100644
--- a/engines/lab/lab.h
+++ b/engines/lab/lab.h
@@ -502,7 +502,7 @@ private:
void handleTrialWarning();
};
-bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header);
+WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail = true);
} // End of namespace Lab
diff --git a/engines/lab/map.cpp b/engines/lab/map.cpp
index 057cac3589..a856b76885 100644
--- a/engines/lab/map.cpp
+++ b/engines/lab/map.cpp
@@ -367,13 +367,11 @@ void LabEngine::drawMap(uint16 curRoom, uint16 curMsg, uint16 floorNum, bool fad
_imgHugeMaze->drawImage(_utils->mapScaleX(524), _utils->mapScaleY(97));
} else if (floorNum == kFloorSurMaze) {
Common::Rect textRect = Common::Rect(_utils->mapScaleX(360), 0, _utils->mapScaleX(660), _utils->mapScaleY(450));
- const char *textPtr = _resource->getStaticText(kTextSurmazeMessage).c_str();
- _graphics->flowText(_msgFont, 0, 7, 0, true, true, true, true, textRect, textPtr);
+ _graphics->flowText(_msgFont, 0, 7, 0, true, true, true, true, textRect, _resource->getStaticText(kTextSurmazeMessage).c_str());
}
if ((floorNum >= kFloorLower) && (floorNum <= kFloorCarnival)) {
- const char *textPrt = _resource->getStaticText(floorNum - 1).c_str();
- _graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 75, 134, 97), textPrt);
+ _graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 75, 134, 97), _resource->getStaticText(floorNum - 1).c_str());
}
if (!_rooms[curMsg]._roomMsg.empty())
diff --git a/engines/lab/savegame.cpp b/engines/lab/savegame.cpp
index 656595e3e5..46ef1486f0 100644
--- a/engines/lab/savegame.cpp
+++ b/engines/lab/savegame.cpp
@@ -76,7 +76,7 @@ void LabEngine::writeSaveGameHeader(Common::OutSaveFile *out, const Common::Stri
out->writeUint32BE(playTime);
}
-bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) {
+WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail) {
uint32 id = in->readUint32BE();
// Check if it's a valid ScummVM savegame
@@ -98,7 +98,11 @@ bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) {
header._descr.setDescription(saveName);
// Get the thumbnail
- header._descr.setThumbnail(Graphics::loadThumbnail(*in));
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) {
+ return false;
+ }
+ header._descr.setThumbnail(thumbnail);
uint32 saveDate = in->readUint32BE();
uint16 saveTime = in->readUint16BE();
@@ -174,7 +178,11 @@ bool LabEngine::loadGame(int slot) {
return false;
SaveGameHeader header;
- readSaveGameHeader(file, header);
+ if (!readSaveGameHeader(file, header)) {
+ delete file;
+ return false;
+ }
+
_roomNum = file->readUint16LE();
_music->checkRoomMusic(1, _roomNum);
_direction = file->readUint16LE();
diff --git a/engines/lastexpress/menu/menu.cpp b/engines/lastexpress/menu/menu.cpp
index cbd2a4a819..3a17cec6df 100644
--- a/engines/lastexpress/menu/menu.cpp
+++ b/engines/lastexpress/menu/menu.cpp
@@ -434,7 +434,7 @@ bool Menu::handleEvent(StartMenuAction action, Common::EventType type) {
case kMenuCase4:
if (clicked)
_index = 0;
- // fall down to kMenuContinue
+ // fall through
//////////////////////////////////////////////////////////////////////////
case kMenuContinue: {
diff --git a/engines/lilliput/configure.engine b/engines/lilliput/configure.engine
new file mode 100644
index 0000000000..0b912f7dc8
--- /dev/null
+++ b/engines/lilliput/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 lilliput "Lilliput" no
diff --git a/engines/sludge/transition.h b/engines/lilliput/console.cpp
index 5ce556870d..e7746a01bb 100644
--- a/engines/sludge/transition.h
+++ b/engines/lilliput/console.cpp
@@ -8,25 +8,27 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+
* You should have received a copy of the GNU General Public 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 SLUDGE_TRANSITION_H
-#define SLUDGE_TRANSITION_H
-namespace Sludge {
+#include "lilliput/console.h"
+#include "lilliput/lilliput.h"
+
+namespace Lilliput {
-void fixBrightness();
-void resetRandW();
+LilliputConsole::LilliputConsole(LilliputEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
-} // End of namespace Sludge
+LilliputConsole::~LilliputConsole() {
+}
-#endif
+} // End of namespace Lilliput
diff --git a/engines/lilliput/console.h b/engines/lilliput/console.h
new file mode 100644
index 0000000000..cd7edb3f42
--- /dev/null
+++ b/engines/lilliput/console.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 LILLIPUT_CONSOLE_H
+#define LILLIPUT_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Lilliput {
+
+class LilliputEngine;
+
+class LilliputConsole : public GUI::Debugger {
+public:
+ LilliputConsole(LilliputEngine *vm);
+ virtual ~LilliputConsole(void);
+
+private:
+ LilliputEngine *_vm;
+ bool Cmd_listScreens(int argc, const char **argv);
+ bool Cmd_listObjects(int argc, const char **argv);
+ bool Cmd_getObject(int argc, const char **argv);
+ bool Cmd_getAllObjects(int argc, const char **argv);
+ bool Cmd_gotoScreen(int argc, const char **argv);
+ bool Cmd_boundaries(int argc, const char **argv);
+};
+
+} // End of namespace Lilliput
+
+#endif
diff --git a/engines/lilliput/detection.cpp b/engines/lilliput/detection.cpp
new file mode 100644
index 0000000000..eb65ad2d64
--- /dev/null
+++ b/engines/lilliput/detection.cpp
@@ -0,0 +1,292 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/textconsole.h"
+#include "graphics/thumbnail.h"
+#include "graphics/surface.h"
+
+#include "lilliput/lilliput.h"
+
+namespace Lilliput {
+
+struct LilliputGameDescription {
+ ADGameDescription desc;
+ GameType gameType;
+};
+
+uint32 LilliputEngine::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
+
+const char *LilliputEngine::getGameId() const {
+ return _gameDescription->desc.gameId;
+}
+
+
+static const PlainGameDescriptor lilliputGames[] = {
+ // Games
+ {"robin", "Adventures of Robin Hood"},
+ {"rome", "Rome: Pathway to Power"},
+ {0, 0}
+};
+
+static const LilliputGameDescription gameDescriptions[] = {
+
+ // Robin Hood English
+ {
+ {
+ "robin", 0,
+ {
+ {"erules.prg", 0, "92aaf84693a8948497ad57864fa31c2a", 71010},
+ {"isomap.dta", 0, "bad97eae03a4db3e99565e39b0b3c06a", 16384},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
+ kGameTypeRobin
+ },
+ // Robin Hood French
+ {
+ {
+ "robin", 0,
+ {
+ {"frules.prg", 0, "cf076c5ebfe8b3571e74a6a46d79426f", 76660},
+ {"isomap.dta", 0, "bad97eae03a4db3e99565e39b0b3c06a", 16384},
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
+ kGameTypeRobin
+ },
+ // Robin Hood German
+ {
+ {
+ "robin", 0,
+ {
+ {"grules.prg", 0, "b53b7353dc1e841b206a64851e7bc58c", 78050},
+ {"isomap.dta", 0, "bad97eae03a4db3e99565e39b0b3c06a", 16384},
+ AD_LISTEND
+ },
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
+ kGameTypeRobin
+ },
+ // Robin Hood Italian
+ {
+ {
+ "robin", 0,
+ {
+ {"irules.prg", 0, "4d69ed3cda1e1d73585905517ea705d1", 75654},
+ {"isomap.dta", 0, "bad97eae03a4db3e99565e39b0b3c06a", 16384},
+ AD_LISTEND
+ },
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
+ kGameTypeRobin
+ },
+ {AD_TABLE_END_MARKER, kGameTypeNone}
+};
+
+class LilliputMetaEngine : public AdvancedMetaEngine {
+public:
+ LilliputMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(LilliputGameDescription), lilliputGames) {
+ }
+
+ const char *getName() const {
+ return "Lilliput";
+ }
+
+ const char *getOriginalCopyright() const {
+ return "Lilliput Engine copyright S.L.Grand, Brainware, 1991-1992";
+ }
+
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
+ bool hasFeature(MetaEngineFeature f) const;
+
+ int getMaximumSaveSlot() const;
+ SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ void removeSaveState(const char *target, int slot) const;
+};
+
+bool LilliputMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
+ if (gd) {
+ *engine = new LilliputEngine(syst, (const LilliputGameDescription *)gd);
+ ((LilliputEngine *)*engine)->initGame((const LilliputGameDescription *)gd);
+ }
+ return gd != 0;
+}
+
+bool LilliputMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+int LilliputMetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+
+SaveStateList LilliputMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += "-##.SAV";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+
+ SaveStateList saveList;
+ char slot[3];
+ int slotNum = 0;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
+ slot[0] = filename->c_str()[filename->size() - 6];
+ slot[1] = filename->c_str()[filename->size() - 5];
+ slot[2] = '\0';
+ // Obtain the last 2 digits of the filename (without extension), since they correspond to the save slot
+ slotNum = atoi(slot);
+ if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ int saveVersion = file->readByte();
+
+ if (saveVersion != kSavegameVersion) {
+ warning("Savegame of incompatible version");
+ delete file;
+ continue;
+ }
+
+ // read name
+ uint16 nameSize = file->readUint16BE();
+ if (nameSize >= 255) {
+ delete file;
+ continue;
+ }
+ char name[256];
+ file->read(name, nameSize);
+ name[nameSize] = 0;
+
+ saveList.push_back(SaveStateDescriptor(slotNum, name));
+ delete file;
+ }
+ }
+ }
+
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+SaveStateDescriptor LilliputMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot);
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (file) {
+ int saveVersion = file->readByte();
+
+ if (saveVersion != kSavegameVersion) {
+ warning("Savegame of incompatible version");
+ delete file;
+ return SaveStateDescriptor();
+ }
+
+ uint32 saveNameLength = file->readUint16BE();
+ Common::String saveName;
+ for (uint32 i = 0; i < saveNameLength; ++i) {
+ char curChr = file->readByte();
+ saveName += curChr;
+ }
+
+ SaveStateDescriptor desc(slot, saveName);
+
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*file, thumbnail)) {
+ delete file;
+ return SaveStateDescriptor();
+ }
+ desc.setThumbnail(thumbnail);
+
+ desc.setDeletableFlag(true);
+ desc.setWriteProtectedFlag(false);
+
+ uint32 saveDate = file->readUint32BE();
+ uint16 saveTime = file->readUint16BE();
+
+ int day = (saveDate >> 24) & 0xFF;
+ int month = (saveDate >> 16) & 0xFF;
+ int year = saveDate & 0xFFFF;
+
+ desc.setSaveDate(year, month, day);
+
+ int hour = (saveTime >> 8) & 0xFF;
+ int minutes = saveTime & 0xFF;
+
+ desc.setSaveTime(hour, minutes);
+
+ // Slot 0 is used for the 'restart game' save in all Robin games, thus
+ // we prevent it from being deleted.
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+
+ delete file;
+ return desc;
+ }
+ return SaveStateDescriptor();
+}
+
+void LilliputMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+} // End of namespace Lilliput
+
+#if PLUGIN_ENABLED_DYNAMIC(LILLIPUT)
+REGISTER_PLUGIN_DYNAMIC(LILLIPUT, PLUGIN_TYPE_ENGINE, Lilliput::LilliputMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(LILLIPUT, PLUGIN_TYPE_ENGINE, Lilliput::LilliputMetaEngine);
+#endif
+
+namespace Lilliput {
+
+void LilliputEngine::initGame(const LilliputGameDescription *gd) {
+ _gameType = gd->gameType;
+ _platform = gd->desc.platform;
+}
+
+} // End of namespace Lilliput
diff --git a/engines/lilliput/lilliput.cpp b/engines/lilliput/lilliput.cpp
new file mode 100644
index 0000000000..e41ec36067
--- /dev/null
+++ b/engines/lilliput/lilliput.cpp
@@ -0,0 +1,2856 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "common/random.h"
+#include "common/error.h"
+#include "common/debug-channels.h"
+#include "common/config-manager.h"
+#include "common/textconsole.h"
+#include "common/memstream.h"
+#include "common/events.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+
+#include "lilliput/lilliput.h"
+#include "engines/util.h"
+#include "lilliput/script.h"
+#include "lilliput/sound.h"
+
+namespace Lilliput {
+
+LilliputEngine *LilliputEngine::s_Engine = 0;
+
+static const byte _basisPalette[768] = {
+ 0, 0, 0, 0, 0, 42, 0, 42, 0, 0, 42, 42,
+ 42, 0, 0, 42, 0, 42, 42, 21, 0, 42, 42, 42,
+ 21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63,
+ 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63,
+ 63, 63, 63, 59, 59, 59, 54, 54, 54, 50, 50, 50,
+ 46, 46, 46, 42, 42, 42, 38, 38, 38, 33, 33, 33,
+ 29, 29, 29, 25, 25, 25, 21, 21, 21, 17, 17, 17,
+ 13, 13, 13, 8, 8, 8, 4, 4, 4, 0, 0, 0,
+ 63, 54, 54, 63, 46, 46, 63, 39, 39, 63, 31, 31,
+ 63, 23, 23, 63, 16, 16, 63, 8, 8, 63, 0, 0,
+ 57, 0, 0, 51, 0, 0, 45, 0, 0, 39, 0, 0,
+ 33, 0, 0, 28, 0, 0, 22, 0, 0, 16, 0, 0,
+ 63, 58, 54, 63, 54, 46, 63, 50, 39, 63, 46, 31,
+ 63, 42, 23, 63, 38, 16, 63, 34, 8, 63, 30, 0,
+ 57, 27, 0, 51, 24, 0, 45, 21, 0, 39, 19, 0,
+ 33, 16, 0, 28, 14, 0, 22, 11, 0, 16, 8, 0,
+ 63, 63, 54, 63, 63, 46, 63, 63, 39, 63, 63, 31,
+ 63, 62, 23, 63, 61, 16, 63, 61, 8, 63, 61, 0,
+ 57, 54, 0, 51, 49, 0, 45, 43, 0, 39, 39, 0,
+ 33, 33, 0, 28, 27, 0, 22, 21, 0, 16, 16, 0,
+ 62, 63, 54, 59, 61, 47, 56, 59, 42, 53, 58, 36,
+ 50, 56, 32, 47, 54, 26, 44, 52, 22, 41, 50, 17,
+ 36, 46, 14, 32, 42, 11, 28, 37, 8, 24, 33, 6,
+ 20, 29, 4, 16, 25, 2, 13, 20, 1, 10, 16, 0,
+ 54, 63, 54, 48, 61, 48, 43, 59, 43, 38, 58, 38,
+ 33, 56, 33, 29, 54, 29, 25, 52, 24, 21, 50, 20,
+ 16, 46, 16, 14, 42, 13, 10, 37, 9, 8, 33, 7,
+ 6, 29, 4, 4, 25, 2, 2, 20, 1, 1, 16, 0,
+ 59, 63, 63, 53, 63, 63, 47, 62, 63, 41, 61, 62,
+ 35, 60, 62, 30, 59, 62, 24, 57, 62, 18, 55, 62,
+ 20, 52, 56, 15, 47, 50, 11, 42, 45, 8, 37, 39,
+ 5, 32, 33, 3, 27, 27, 1, 22, 22, 0, 16, 16,
+ 54, 59, 63, 46, 56, 63, 39, 53, 63, 31, 50, 63,
+ 23, 47, 63, 16, 44, 63, 8, 42, 63, 0, 39, 63,
+ 0, 35, 57, 0, 31, 51, 0, 27, 45, 0, 23, 39,
+ 0, 19, 33, 0, 16, 28, 0, 12, 22, 0, 9, 16,
+ 54, 54, 63, 46, 47, 63, 39, 39, 63, 31, 32, 63,
+ 23, 24, 63, 16, 16, 63, 8, 9, 63, 0, 1, 63,
+ 0, 1, 57, 0, 1, 51, 0, 0, 45, 0, 0, 39,
+ 0, 0, 33, 0, 0, 28, 0, 0, 22, 0, 0, 16,
+ 54, 63, 54, 47, 63, 46, 39, 63, 39, 32, 63, 31,
+ 24, 63, 23, 16, 63, 16, 8, 63, 8, 0, 63, 0,
+ 0, 56, 0, 0, 49, 0, 0, 43, 0, 0, 36, 0,
+ 0, 30, 0, 0, 23, 0, 0, 16, 0, 0, 10, 0,
+ 63, 54, 63, 63, 46, 63, 63, 39, 63, 63, 31, 63,
+ 63, 23, 63, 63, 16, 63, 63, 8, 63, 63, 0, 63,
+ 56, 0, 57, 50, 0, 51, 45, 0, 45, 39, 0, 39,
+ 33, 0, 33, 27, 0, 28, 22, 0, 22, 16, 0, 16,
+ 63, 58, 55, 63, 56, 52, 63, 54, 49, 63, 53, 47,
+ 63, 51, 44, 63, 49, 41, 63, 47, 39, 63, 46, 36,
+ 63, 44, 32, 63, 41, 28, 63, 39, 24, 60, 37, 23,
+ 58, 35, 22, 55, 34, 21, 52, 32, 20, 50, 31, 19,
+ 47, 30, 18, 45, 28, 17, 42, 26, 16, 40, 25, 15,
+ 39, 24, 14, 36, 23, 13, 34, 22, 12, 32, 20, 11,
+ 29, 19, 10, 27, 18, 9, 23, 16, 8, 21, 15, 7,
+ 18, 14, 6, 16, 12, 6, 14, 11, 5, 10, 8, 3,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+LilliputEngine::LilliputEngine(OSystem *syst, const LilliputGameDescription *gd) : Engine(syst), _gameDescription(gd) {
+ _system = syst;
+ DebugMan.addDebugChannel(kDebugEngine, "Engine", "Engine debug level");
+ DebugMan.addDebugChannel(kDebugScript, "Script", "Script debug level");
+ DebugMan.addDebugChannel(kDebugSound, "Sound", "Sound debug level");
+ DebugMan.addDebugChannel(kDebugEngineTBC, "EngineTBC", "Engine debug level");
+ DebugMan.addDebugChannel(kDebugScriptTBC, "ScriptTBC", "Script debug level");
+
+ _console = new LilliputConsole(this);
+ _rnd = 0;
+ _mousePos = Common::Point(0, 0);
+ _oldMousePos = Common::Point(0, 0);
+ _mouseDisplayPos = Common::Point(0, 0);
+ _mouseButton = 0;
+ _mouseClicked = false;
+ _savedMousePosDivided = Common::Point(-1, -1);
+ _mousePreviousEventType = Common::EVENT_INVALID;
+ _skipDisplayFlag1 = 1;
+ _skipDisplayFlag2 = 0;
+ _displayMap = false;
+ _debugFlag = 0;
+ _debugFlag2 = 0;
+
+ _scriptHandler = new LilliputScript(this);
+ _soundHandler = new LilliputSound(this);
+
+ _handleOpcodeReturnCode = 0;
+ _delayedReactivationAction = false;
+ _selectedCharacterId = -1;
+ _numCharactersToDisplay = 0;
+ _nextDisplayCharacterPos = Common::Point(0, 0);
+ _animationTick = 0;
+ _byte12A05 = 10; // Used to trigger sound and animations in int8, 1 time out of 10
+ _refreshScreenFlag = false;
+ _byte16552 = 0;
+ _lastInterfaceHotspotIndex = -1;
+ _lastInterfaceHotspotButton = 0;
+ _lastAnimationTick = 0;
+
+ _currentScriptCharacter = 0;
+ _currentScriptCharacterPos = Common::Point(0, 0);
+ _host = 0;
+ _nextCharacterIndex = 0;
+ _waitingSignal = -1;
+ _waitingSignalCharacterId = -1;
+ _newModesEvaluatedNumber = 0;
+ _savedSurfaceUnderMousePos = Common::Point(0, 0);
+ _displayGreenHand = false;
+ _isCursorGreenHand = false;
+ _displayStringIndex = 0;
+ _signalTimer = 0;
+ _numCharacters = 0;
+
+ _saveFlag = true;
+ _actionType = kActionNone;
+
+ _doorEntranceMask[0] = _doorExitMask[3] = 1;
+ _doorEntranceMask[1] = _doorExitMask[2] = 2;
+ _doorEntranceMask[2] = _doorExitMask[1] = 4;
+ _doorEntranceMask[3] = _doorExitMask[0] = 8;
+
+ for (int i = 0; i < 3; i++)
+ _codeEntered[i] = 0;
+
+ for (int i = 0; i < 4; i++)
+ _homeInDirLikelyhood[i] = 0;
+
+ for (int i = 0; i < 40; i++) {
+ _characterTargetPos[i] = Common::Point(0, 0);
+ _charactersToDisplay[i] = 0;
+ _characterRelativePos[i] = Common::Point(-1, -1);
+ _characterDisplay[i] = Common::Point(0, 0);
+ _characterMagicPuffFrame[i] = -1;
+ _characterSubTargetPos[i] = Common::Point(-1, -1);
+ _specialCubes[i] = 0;
+
+ _characterSignals[i] = -1;
+ _characterPos[i] = Common::Point(-1, -1);
+ _characterPosAltitude[i] = 0;
+ _characterFrameArray[i] = 0;
+ _characterCarried[i] = -1;
+ _characterBehindDist[i] = 4;
+ _characterAboveDist[i] = 0;
+ _spriteSizeArray[i] = 20;
+ _characterDirectionArray[i] = 0;
+ _characterMobility[i] = 0;
+ _characterTypes[i] = 0;
+ _characterBehaviour[i] = 0;
+ _characterHomePos[i] = Common::Point(0, 0);
+ _signalArr[i] = -1;
+ }
+
+ for (int i = 0; i < 30; i++)
+ _signalArray[i] = -1;
+
+ for (int i = 0; i < 256; i++)
+ _savedSurfaceUnderMouse[i] = 0;
+
+ for (int i = 0; i < 160; i++)
+ _displayStringBuf[i] = 0;
+
+ for (int i = 0; i < 1400 + 3120; i++) {
+ _characterVariables[i] = 0;
+ }
+
+ _currentCharacterAttributes = NULL;
+ _bufferIdeogram = NULL;
+ _bufferMen = NULL;
+ _bufferMen2 = NULL;
+ _bufferIsoChars = NULL;
+ _bufferIsoMap = NULL;
+ _bufferCubegfx = NULL;
+
+ _sequencesArr = nullptr;
+ _packedStringIndex = nullptr;
+ _packedStringNumb = 0;
+ _packedStrings = nullptr;
+ _initScript = nullptr;
+ _initScriptSize = 0;
+ _menuScript = nullptr;
+ _menuScriptSize = 0;
+ _arrayGameScriptIndex = nullptr;
+ _gameScriptIndexSize = 0;
+ _arrayGameScripts = nullptr;
+ _listNumb = 0;
+ _listIndex = nullptr;
+ _listArr = nullptr;
+ _rectNumb = 0;
+ for (int i = 0; i < 40; ++i)
+ _enclosureRect[i] = Common::Rect(0, 0, 0, 0);
+
+ _interfaceHotspotNumb = 0;
+ for (int i = 0; i < 20; ++i)
+ _keyboardMapping[i] = Common::KEYCODE_DOLLAR;
+
+ _mainSurface = nullptr;
+ _smallAnimsFrameIndex = 0;
+ _keyDelay = 0;
+ _int8Timer = 0;
+ _keyboard_nextIndex = 0;
+ _keyboard_oldIndex = 0;
+ _normalCursor = nullptr;
+ _greenCursor = nullptr;
+ _word10800_ERULES = 0;
+ _currentDisplayCharacter = 0;
+
+ _shouldQuit = false;
+ _eventMan = nullptr;
+ _lastTime = 0;
+ _gameType = kGameTypeNone;
+ _platform = Common::kPlatformUnknown;
+}
+
+LilliputEngine::~LilliputEngine() {
+ DebugMan.clearAllDebugChannels();
+ delete _console;
+ delete _soundHandler;
+ delete _scriptHandler;
+ delete _rnd;
+}
+
+GUI::Debugger *LilliputEngine::getDebugger() {
+ return _console;
+}
+
+void LilliputEngine::update() {
+ // update every 20 ms.
+ int currentTime = _system->getMillis();
+ if (currentTime - _lastTime > 20) {
+ _lastTime += ((currentTime - _lastTime) / 20) * 20;
+ newInt8();
+ pollEvent();
+ if (_displayGreenHand == true && _isCursorGreenHand == false) {
+ _isCursorGreenHand = true;
+ CursorMan.pushCursor(_greenCursor, 16, 16, 0, 0, 0);
+ } else if (_displayGreenHand == false && _isCursorGreenHand == true) {
+ _isCursorGreenHand = false;
+ CursorMan.popCursor();
+ }
+
+ _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
+ _system->updateScreen();
+ }
+}
+
+void LilliputEngine::newInt8() {
+ _soundHandler->refresh();
+
+ if (_byte12A05 != 0)
+ --_byte12A05;
+ else {
+ _byte12A05 = 10;
+ if (_int8Timer != 0)
+ --_int8Timer;
+
+ _animationTick ^= 1;
+ if (!_refreshScreenFlag)
+ displayRefreshScreen();
+ }
+}
+
+bool LilliputEngine::hasFeature(EngineFeature f) const {
+ return (f == kSupportsRTL) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
+}
+
+const char *LilliputEngine::getCopyrightString() const {
+ return "copyright S.L.Grand, Brainware, 1991 - 1992";
+}
+
+GameType LilliputEngine::getGameType() const {
+ return _gameType;
+}
+
+Common::Platform LilliputEngine::getPlatform() const {
+ return _platform;
+}
+
+void LilliputEngine::displayCharacter(int index, Common::Point pos, int flags) {
+ debugC(2, kDebugEngine, "displayCharacter(%d, %d - %d, %d)", index, pos.x, pos.y, flags);
+
+ byte *buf = _savedSurfaceGameArea1 + (pos.y * 256) + pos.x;
+
+ byte *src = _bufferMen;
+ if (index < 0) {
+ src = _bufferIdeogram;
+ index = -index;
+ } else if (index >= 0xF0) {
+ src = _bufferMen2;
+ index -= 0xF0;
+ }
+
+ src += (index * 256);
+
+ if ((flags & 2) == 0) {
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 16; x++) {
+ if (src[x] != 0)
+ buf[x] = src[x];
+ }
+ src += 16;
+ buf += 256;
+ }
+ } else {
+ // Sprite mirror
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 16; x++) {
+ // May need a hack of 1 pixel
+ if (src[15 - x] != 0)
+ buf[x] = src[15 - x];
+ }
+ src += 16;
+ buf += 256;
+ }
+ }
+}
+
+void LilliputEngine::display16x16IndexedBuf(byte *buf, int index, Common::Point pos, bool transparent, bool updateScreen) {
+ debugC(2, kDebugEngine, "display16x16IndexedBuf(buf, %d, %d - %d)", index, pos.x, pos.y);
+
+ int index1 = index * 16 * 16;
+ byte *newBuf = &buf[index1];
+
+ int vgaIndex = pos.x + (pos.y * 320);
+
+ for (int i = 0; i < 16; i++) {
+ // clip on y
+ if (pos.y + i < 200) {
+ for (int j = 0; j < 16; j++) {
+ // clip on x
+ if ((newBuf[j] != 0 || !transparent) && (pos.x + j < 320))
+ ((byte *)_mainSurface->getPixels())[vgaIndex + j] = newBuf[j];
+ }
+ }
+ vgaIndex += 320;
+ newBuf += 16;
+ }
+
+ if (updateScreen) {
+ _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
+ _system->updateScreen();
+ }
+}
+
+void LilliputEngine::display16x16Buf(byte *buf, Common::Point pos, bool transparent, bool updateScreen) {
+ debugC(2, kDebugEngine, "display16x16Buf(buf, %d, %d)", pos.x, pos.y);
+
+ display16x16IndexedBuf(buf, 0, pos, transparent, updateScreen);
+}
+
+void LilliputEngine::fill16x16Rect(byte col, Common::Point pos) {
+ debugC(2, kDebugEngineTBC, "fill16x16Rect(%d, %d - %d)", col, pos.x, pos.y);
+
+ int index = pos.x + (pos.y * 320);
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 16; j++) {
+ ((byte *)_mainSurface->getPixels())[index + j] = col;
+ }
+ index += 320;
+ }
+}
+
+void LilliputEngine::saveSurfaceGameArea() {
+ debugC(2, kDebugEngine, "saveSurfaceGameArea()");
+
+ int index = (16 * 320) + 64; // 5184
+ for (int i = 0; i < 176; i++) {
+ for (int j = 0; j < 256; j++)
+ _savedSurfaceGameArea3[(i * 256) + j] = ((byte *)_mainSurface->getPixels())[index + j];
+ index += 320;
+ }
+}
+
+void LilliputEngine::saveSurfaceSpeech() {
+ debugC(2, kDebugEngine, "saveSurfaceSpeech()");
+
+ int index = 66;
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 252; j++)
+ _savedSurfaceSpeech[(i * 252) + j] = ((byte *)_mainSurface->getPixels())[index + j];
+ index += 320;
+ }
+}
+
+void LilliputEngine::restoreSurfaceSpeech() {
+ debugC(2, kDebugEngine, "restoreSurfaceSpeech()");
+
+ int index = 66;
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 252; j++)
+ ((byte *)_mainSurface->getPixels())[index + j] = _savedSurfaceSpeech[(i * 252) + j];
+ index += 320;
+ }
+}
+
+
+void LilliputEngine::displayInterfaceHotspots() {
+ debugC(2, kDebugEngine, "displayInterfaceHotspots()");
+
+ if (_displayMap)
+ return;
+
+ for (int index = 0; index < _interfaceHotspotNumb; index++) {
+ int tmpVal = _scriptHandler->_interfaceHotspotStatus[index] * 20;
+ display16x16IndexedBuf(_bufferIdeogram, tmpVal + index, _interfaceHotspots[index]);
+ }
+}
+
+void LilliputEngine::displayLandscape() {
+ debugC(2, kDebugEngine, "displayLandscape()");
+
+ memcpy(_savedSurfaceGameArea2, _savedSurfaceGameArea3, 176 * 256); // 45056
+
+ int index = (_scriptHandler->_viewportPos.y * 64 + _scriptHandler->_viewportPos.x) * 4;
+
+ for (int posY = 0; posY < 8; posY++) {
+ for (int posX = 0; posX < 8 ; posX++) {
+ assert (index < 16384);
+ displayIsometricBlock(_savedSurfaceGameArea2, _bufferIsoMap[index], posX, posY, 0);
+ index += 4;
+ }
+ index += 224;
+ }
+}
+
+// Display dialog bubble
+void LilliputEngine::displaySpeechBubble() {
+ debugC(2, kDebugEngine, "displaySpeechBubble()");
+ static const byte _array15976[16] = {244, 248, 250, 250, 252, 252, 252, 252, 252, 252, 252, 252, 250, 250, 248, 244};
+
+ int index = 192;
+
+ for (int i = 0; i < 16; i++) {
+ int var3 = _array15976[i];
+ int tmpIndex = index - (var3 / 2);
+ var3 &= 0xFE;
+ for (int j = 0; j < var3; j++) {
+ ((byte *)_mainSurface->getPixels())[tmpIndex + j] = 17;
+ }
+ index += 320;
+ }
+}
+
+void LilliputEngine::displaySpeechLine(int vgaIndex, byte *srcBuf, int &bufIndex) {
+ debugC(2, kDebugEngine, "displaySpeechLine()");
+
+ int var3 = 0;
+ int var1;
+ int bckIndex = bufIndex;
+
+ for (;;) {
+ var1 = srcBuf[bufIndex];
+ if ((var1 == 0) || (var1 == '|'))
+ break;
+
+ ++bufIndex;
+ ++var3;
+ }
+
+ var1 = (0x3D - var3) * 2;
+ vgaIndex += var1;
+
+ bufIndex = bckIndex;
+ for (;;) {
+ var1 = srcBuf[bufIndex];
+ ++bufIndex;
+ if ((var1 == 0) || (var1 == '|'))
+ break;
+
+ displayChar(vgaIndex, var1);
+ vgaIndex += 4;
+ }
+}
+
+void LilliputEngine::displaySpeech(byte *buf) {
+ debugC(2, kDebugEngine, "displaySpeech(%s)", buf);
+
+ int vgaIndex = 70;
+ int bufIndex = 0;
+
+ bool multiLineFlag = false;
+ byte var1;
+
+ for (;;) {
+ var1 = buf[bufIndex];
+ ++bufIndex;
+ if (var1 == 0) {
+ vgaIndex += (4 * 320);
+ break;
+ } else if (var1 == '|') {
+ multiLineFlag = true;
+ break;
+ }
+ }
+
+ bufIndex = 0;
+ displaySpeechLine(vgaIndex, buf, bufIndex);
+ if (multiLineFlag) {
+ vgaIndex += (8 * 320);
+ displaySpeechLine(vgaIndex, buf, bufIndex);
+ }
+}
+
+void LilliputEngine::initGameAreaDisplay() {
+ debugC(1, kDebugEngine, "initGameAreaDisplay()");
+
+ // display background
+ byte *tmpBuf = loadVGA("SCREEN.GFX", 320 * 200, true);
+ memcpy(_mainSurface->getPixels(), tmpBuf, 320 * 200);
+ _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
+ _system->updateScreen();
+
+ // display game area on top of background
+ saveSurfaceGameArea();
+ saveSurfaceSpeech();
+ displayInterfaceHotspots();
+ displayLandscape();
+ prepareGameArea();
+ displayGameArea();
+
+ free(tmpBuf);
+}
+
+void LilliputEngine::displayIsometricBlock(byte *buf, int var1, int posX, int posY, int var3) {
+ debugC(1, kDebugEngine, "displayIsometricBlock(buf, %d, %d - %d, %d)", var1, posX, posY, var3);
+
+ byte tmpByte1 = ((7 + posX - posY) << 4) & 0xFF;
+ byte tmpByte2 = ((4 + posX + posY - (var3 >> 7)) << 3) & 0xFF;
+
+ int index = (tmpByte2 << 8) + tmpByte1;
+ int index2 = var1 << 10;
+
+ for (int i = 0; i < 32; i++) {
+ for (int j = 0; j < 32; j++) {
+ if (_bufferCubegfx[index2 + j] != 0)
+ buf[index + j] = _bufferCubegfx[index2 + j];
+ }
+ index2 += 32;
+ index += 256;
+ }
+}
+
+void LilliputEngine::displayGameArea() {
+ debugC(2, kDebugEngine, "displayGameArea()");
+
+ if (_displayMap)
+ return;
+
+ int index = (16 * 320) + 64; // 5184
+ for (int i = 0; i < 176; i++) {
+ for (int j = 0; j < 256; j++)
+ ((byte *)_mainSurface->getPixels())[index + j] = _savedSurfaceGameArea1[(i * 256) + j];
+ index += 320;
+ }
+
+ _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
+ _system->updateScreen();
+}
+
+void LilliputEngine::restoreMapPoints() {
+ debugC(2, kDebugEngine, "restoreMapPoints()");
+
+ byte *buf = (byte *)_mainSurface->getPixels();
+ for (byte index = 0; index < _numCharacters; index++) {
+ buf[_mapSavedPixelIndex[index]] = _mapSavedPixel[index];
+ }
+}
+
+void LilliputEngine::displayCharactersOnMap() {
+ debugC(2, kDebugEngineTBC, "displayCharactersOnMap()");
+
+ moveCharacters();
+
+ byte *buf = (byte *)_mainSurface->getPixels();
+ for (int index = _numCharacters - 1; index >= 0; index--) {
+ if (((_characterTypes[index] & 2) == 0) && (_scriptHandler->_characterTilePos[index].y != -1)) {
+ // FIXME: This is still wrong, but less. The values in both arrays should be verified now!
+ int pixIndex = 320 + ((15 * _scriptHandler->_characterTilePos[index].y) / 4) + (_scriptHandler->_characterTilePos[index].x * 4) + 1;
+
+ _mapSavedPixelIndex[index] = pixIndex;
+ _mapSavedPixel[index] = buf[pixIndex];
+ buf[pixIndex] = _scriptHandler->_characterMapPixelColor[index];
+ }
+ }
+}
+
+void LilliputEngine::moveCharacters() {
+ debugC(2, kDebugEngine, "moveCharacters()");
+
+ _numCharactersToDisplay = 0;
+ byte index = _numCharacters - 1;
+ Common::Point pos16213 = Common::Point(_scriptHandler->_viewportPos.x << 3, _scriptHandler->_viewportPos.y << 3);
+
+ for (int i = index; i >= 0; i--) {
+ if (_characterCarried[i] != -1) {
+ int index2 = _characterCarried[i];
+ _characterPosAltitude[i] = _characterPosAltitude[index2] + _characterAboveDist[i];
+ int8 behindDist = _characterBehindDist[i];
+ _characterDirectionArray[i] = _characterDirectionArray[index2];
+ int nextPosX = _characterPos[index2].x;
+ int nextPosY = _characterPos[index2].y;
+
+ switch (_characterDirectionArray[i]) {
+ case 0:
+ nextPosX -= behindDist;
+ break;
+ case 1:
+ nextPosY += behindDist;
+ break;
+ case 2:
+ nextPosY -= behindDist;
+ break;
+ default:
+ nextPosX += behindDist;
+ break;
+ }
+
+ _characterPos[i] = Common::Point(nextPosX, nextPosY);
+ }
+
+ _scriptHandler->_characterTilePos[i] = Common::Point(_characterPos[i].x >> 3, _characterPos[i].y >> 3);
+ _characterRelativePos[i] = Common::Point(-1, -1);
+ _characterDisplay[i] = Common::Point(-1, -1);
+
+ int tileX = (_characterPos[i].x >> 3) - _scriptHandler->_viewportPos.x;
+ int tileY = (_characterPos[i].y >> 3) - _scriptHandler->_viewportPos.y;
+ if ((tileX >= 0) && (tileX <= 7) && (tileY >= 0) && (tileY <= 7)) {
+ _characterRelativePos[i] = Common::Point(tileX, tileY);
+ int tempX = _characterPos[i].x - pos16213.x;
+ int tempY = _characterPos[i].y - pos16213.y;
+ _characterDisplay[i].x = ((60 + tempX - tempY) * 2) & 0xFF;
+ _characterDisplay[i].y = (20 + tempX + tempY - _characterPosAltitude[i]) & 0xFF;
+ _charactersToDisplay[_numCharactersToDisplay] = i;
+ ++_numCharactersToDisplay;
+ }
+ }
+
+ sortCharacters();
+}
+
+void LilliputEngine::setNextDisplayCharacter(int var1) {
+ debugC(2, kDebugEngine, "setNextDisplayCharacter(%d)", var1);
+
+ byte charNum = var1 & 0xFF;
+ if (charNum < _numCharactersToDisplay) {
+ int index = _charactersToDisplay[charNum];
+ _nextDisplayCharacterPos = _characterRelativePos[index];
+ } else
+ _nextDisplayCharacterPos = Common::Point(-1, -1);
+}
+
+void LilliputEngine::prepareGameArea() {
+ debugC(2, kDebugEngine, "prepareGameArea()");
+
+ moveCharacters();
+ _currentDisplayCharacter = 0;
+ setNextDisplayCharacter(0);
+
+ memcpy(_savedSurfaceGameArea1, _savedSurfaceGameArea2, 176 * 256); // 45056;
+
+ int index1 = (_scriptHandler->_viewportPos.y * 64 + _scriptHandler->_viewportPos.x) * 4;
+ assert(index1 < 16384);
+ byte *map = &_bufferIsoMap[index1];
+
+ for (int posY = 0; posY < 8; posY++) {
+ for (int posX = 0; posX < 8; posX++) {
+ if (map[1] != 0xFF) {
+ int var1 = map[1];
+ if ((_cubeFlags[var1] & 128) != 0)
+ var1 += _animationTick;
+ displayIsometricBlock(_savedSurfaceGameArea1, var1, posX, posY, 1 << 8);
+ }
+ renderCharacters(map, Common::Point(posX, posY));
+
+ if (map[2] != 0xFF) {
+ int var1 = map[2];
+ if ((_cubeFlags[var1] & 128) != 0)
+ var1 += _animationTick;
+ displayIsometricBlock(_savedSurfaceGameArea1, var1, posX, posY, 2 << 8);
+ }
+ map += 4;
+ }
+ map += 224;
+ }
+}
+
+void LilliputEngine::displayRefreshScreen() {
+ debugC(2, kDebugEngine, "displayRefreshScreen()");
+
+ if (_displayMap) {
+ bool forceReturnFl = false;
+ checkMapClosing(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ restoreMapPoints();
+ updateCharPosSequence();
+ handleCharacterTimers();
+ checkInteractions();
+ checkSpecialCubes();
+ handleSignals();
+ displayCharactersOnMap();
+ } else {
+ scrollToViewportCharacterTarget();
+ checkSpeechClosing();
+ prepareGameArea();
+ displayGameArea();
+ updateCharPosSequence();
+ handleCharacterTimers();
+ checkInteractions();
+ checkSpecialCubes();
+ handleSignals();
+ handleGameMouseClick();
+ checkInterfaceActivationDelay();
+ displayHeroismIndicator();
+ }
+}
+
+void LilliputEngine::resetSmallAnims() {
+ debugC(2, kDebugEngine, "resetSmallAnims()");
+
+ _smallAnims[0]._active = false;
+ _smallAnims[1]._active = false;
+ _smallAnims[2]._active = false;
+ _smallAnims[3]._active = false;
+ _smallAnimsFrameIndex = 0;
+}
+
+void LilliputEngine::displaySmallIndexedAnim(byte index, byte subIndex) {
+ debugC(2, kDebugEngine, "displaySmallIndexedAnim(%d, %d)", index, subIndex);
+
+ if (!_smallAnims[index]._active)
+ return;
+
+ display16x16IndexedBuf(_bufferIdeogram, _smallAnims[index]._frameIndex[subIndex], _smallAnims[index]._pos, false);
+}
+
+void LilliputEngine::displaySmallAnims() {
+ debugC(2, kDebugEngine, "displaySmallAnims()");
+
+ if (_animationTick == _lastAnimationTick)
+ return;
+
+ _lastAnimationTick = _animationTick;
+
+ assert(_smallAnimsFrameIndex < 8);
+ int subIndex = _smallAnimsFrameIndex;
+ displaySmallIndexedAnim(0, subIndex);
+ displaySmallIndexedAnim(1, subIndex);
+ displaySmallIndexedAnim(2, subIndex);
+ displaySmallIndexedAnim(3, subIndex);
+
+ ++subIndex;
+ if (subIndex == 8)
+ subIndex = 0;
+
+ _smallAnimsFrameIndex = subIndex;
+}
+
+void LilliputEngine::paletteFadeOut() {
+ debugC(2, kDebugEngine, "paletteFadeOut()");
+
+ resetSmallAnims();
+ byte palette[768];
+ for (int fade = 256; fade >= 0; fade -= 8) {
+ for (int i = 0; i < 768; i++) {
+ palette[i] = (_curPalette[i] * fade) >> 8;
+ }
+ _system->getPaletteManager()->setPalette(palette, 0, 256);
+ _system->updateScreen();
+ _system->delayMillis(20);
+ pollEvent();
+ }
+}
+
+void LilliputEngine::paletteFadeIn() {
+ debugC(2, kDebugEngine, "paletteFadeIn()");
+
+ byte palette[768];
+ for (int fade = 8; fade <= 256; fade += 8) {
+ for (int i = 0; i < 768; i++) {
+ palette[i] = (_curPalette[i] * fade) >> 8;
+ }
+ _system->getPaletteManager()->setPalette(palette, 0, 256);
+ _system->updateScreen();
+ _system->delayMillis(20);
+ pollEvent();
+ }
+}
+
+int16 LilliputEngine::checkObstacle(int x1, int y1, int x2, int y2) {
+ debugC(2, kDebugEngine, "checkObstacle(%d, %d, %d, %d)", x1, y1, x2, y2);
+
+ int index = ((y1 * 64) + x1) * 4;
+ assert((index > 0) && (index <= 16380));
+ byte *isoMap = &_bufferIsoMap[index + 1];
+
+ int16 dx = x2 - x1;
+ int16 dy = y2 - y1;
+
+ int16 tmpMapMoveX = 0;
+ int16 tmpMapMoveY = 0;
+ int16 mapMoveY = 0;
+ int16 mapMoveX = 0;
+
+ int16 nonDiagdelta = 0;
+ int16 diagDelta = 0;
+
+ if (dx < 0) {
+ dx = -dx;
+ tmpMapMoveX = -4;
+ } else {
+ tmpMapMoveX = 4;
+ }
+
+ if (dy < 0) {
+ dy = -dy;
+ tmpMapMoveY = -256;
+ } else {
+ tmpMapMoveY = 256;
+ }
+
+ if (dx >= dy) {
+ mapMoveY = 0;
+ mapMoveX = tmpMapMoveX;
+ } else {
+ int16 tmp = dy;
+ dy = dx;
+ dx = tmp;
+ mapMoveX = 0;
+ mapMoveY = tmpMapMoveY;
+ }
+
+ nonDiagdelta = dy * 2;
+ int16 var1 = nonDiagdelta - dx;
+ diagDelta = nonDiagdelta - (dx * 2);
+
+ mapMoveX += mapMoveY;
+ tmpMapMoveX += tmpMapMoveY;
+
+ int count = 0;
+
+ while (*isoMap == 0xFF) {
+ if (var1 >= 0) {
+ isoMap += tmpMapMoveX;
+ var1 += diagDelta;
+ } else {
+ isoMap += mapMoveX;
+ var1 += nonDiagdelta;
+ }
+
+ count++;
+ if (count > dx) {
+ return 0;
+ }
+ }
+ return tmpMapMoveY;
+}
+
+void LilliputEngine::startNavigateFromMap() {
+ debugC(2, kDebugEngine, "startNavigateFromMap()");
+
+ _selectedCharacterId = -1;
+ _savedMousePosDivided = Common::Point(-1, -1);
+ byte newX = _mousePos.x / 4;
+ byte newY = _mousePos.y / 3;
+
+ if ((newX >= 64) || (newY >= 64))
+ return;
+
+ _savedMousePosDivided = Common::Point(newX, newY);
+ _actionType = kCubeSelected;
+}
+
+void LilliputEngine::unselectInterfaceHotspots() {
+ debugC(2, kDebugEngine, "unselectInterfaceHotspots()");
+
+ for (int index = 0; index < _interfaceHotspotNumb; index++) {
+ if (_scriptHandler->_interfaceHotspotStatus[index] == kHotspotSelected)
+ _scriptHandler->_interfaceHotspotStatus[index] = kHotspotEnabled;
+ }
+}
+
+void LilliputEngine::checkMapClosing(bool &forceReturnFl) {
+ debugC(2, kDebugEngineTBC, "checkMapClosing()");
+
+ forceReturnFl = false;
+ if (!_displayMap)
+ return;
+
+ pollEvent();
+ if (!_keyboard_checkKeyboard()) {
+ _keyboard_getch();
+ } else {
+ if (_mouseButton != 1)
+ return;
+
+ _mouseButton = 0;
+ startNavigateFromMap();
+ }
+
+ _displayMap = false;
+ paletteFadeOut();
+ _displayGreenHand = false;
+ unselectInterfaceHotspots();
+ initGameAreaDisplay();
+ _scriptHandler->_heroismLevel = 0;
+ moveCharacters();
+ paletteFadeIn();
+ forceReturnFl = true;
+}
+
+void LilliputEngine::checkInteractions() {
+ debugC(2, kDebugEngine, "checkInteractions()");
+
+ for (int index = _numCharacters - 1; index >= 0; index--) {
+ if (_characterTypes[index] & 1)
+ continue;
+
+ int c1 = _scriptHandler->_characterTilePos[index].x;
+ int c2 = _scriptHandler->_characterTilePos[index].y;
+
+ // Hack: Skip if disabled (c2 negative)
+ if (c2 == -1)
+ continue;
+
+ for (int index2 = _numCharacters - 1; index2 >= 0; index2--) {
+ byte _newStatus = 0;
+ if ((index != index2) &&
+ (_characterCarried[index] != index2) &&
+ (_characterCarried[index2] != index) &&
+ (_characterTypes[index2] & 2) == 0) {
+ int d1 = _scriptHandler->_characterTilePos[index2].x;
+ int d2 = _scriptHandler->_characterTilePos[index2].y;
+
+ if (d1 != -1) {
+ int x = c1 - d1;
+ if ((x > -6) && (x < 6)) {
+ int y = c2 - d2;
+ if ((y > -6) && (y < 6)) {
+ _newStatus = 1;
+
+ if ((c1 == d1) && (c2 == d2)) {
+ _newStatus = 4;
+ } else if ((_characterTypes[index] & 4) != 0) {
+ _newStatus = 0;
+ } else {
+ switch (_characterDirectionArray[index]) {
+ case 0:
+ if (d1 > c1) {
+ _newStatus = 2;
+
+ if (d2 == c2)
+ _newStatus = 3;
+
+ if (checkObstacle(c1, c2, d1, d2) != 0)
+ _newStatus = 1;
+ }
+ break;
+ case 1:
+ if (d2 < c2) {
+ _newStatus = 2;
+
+ if (d1 == c1)
+ _newStatus = 3;
+
+ if (checkObstacle(c1, c2, d1, d2) != 0)
+ _newStatus = 1;
+ }
+ break;
+ case 2:
+ if (d2 > c2) {
+ _newStatus = 2;
+
+ if (d1 == c1)
+ _newStatus = 3;
+
+ if (checkObstacle(c1, c2, d1, d2) != 0)
+ _newStatus = 1;
+ }
+ break;
+ default:
+ if (d1 < c1) {
+ _newStatus = 2;
+
+ if (d2 == c2)
+ _newStatus = 3;
+
+ if (checkObstacle(c1, c2, d1, d2) != 0)
+ _newStatus = 1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ int8 v2 = _scriptHandler->_interactions[index2 + (index * 40)] & 0xFF;
+ int8 v1 = v2;
+
+ if (v2 != _newStatus) {
+ _scriptHandler->_characterScriptEnabled[index] = 1;
+ v2 = _newStatus;
+ }
+ _scriptHandler->_interactions[index2 + (index * 40)] = (v1 << 8) + v2;
+ }
+ }
+}
+
+void LilliputEngine::displayCharacterStatBar(int8 type, int16 averagePosX, int8 score, int16 posY) {
+ debugC(2, kDebugEngine, "displayCharacterStatBar(%d, %d, %d, %d)", type, averagePosX, score, posY);
+
+ int16 posX = averagePosX;
+
+ // If var equals 45 ('-'), score bar from -x to +x. If not (usually 43 '+'), score bar from 0 to x.
+ if (type == 45) {
+ posX += 35;
+ score -= 35;
+
+ if (score < 0) {
+ posX += score;
+ score = -score;
+ }
+ }
+
+ byte *vgaBuf = (byte *)_mainSurface->getPixels();
+ int vgaIndex = posX + (320 * posY);
+
+ if (score == 0)
+ ++score;
+
+ // Draw bar, color green, high = 4, width = score
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < score; j++) {
+ vgaBuf[vgaIndex + j] = 2;
+ }
+ vgaIndex += 320;
+ }
+}
+
+void LilliputEngine::displayString(byte *buf, Common::Point pos) {
+ debugC(2, kDebugEngine, "displayString(%s, %d - %d)", buf, pos.x, pos.y);
+
+ int index = (pos.y * 320) + pos.x;
+
+ int i = 0;
+ while (buf[i] != 0) {
+ displayChar(index, buf[i]);
+ ++i;
+ index += 4;
+ }
+}
+
+void LilliputEngine::displayChar(int index, int var1) {
+ debugC(2, kDebugEngine, "displayChar(%d, %d)", index, var1);
+
+ int indexVga = index;
+ int indexChar = var1 << 5;
+
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 4; j++)
+ ((byte *)_mainSurface->getPixels())[indexVga + j] = _bufferIsoChars[indexChar + j];
+ indexVga += 320;
+ indexChar += 4;
+ }
+
+}
+
+void LilliputEngine::sortCharacters() {
+ debugC(2, kDebugEngine, "sortCharacters()");
+
+ if (_numCharactersToDisplay <= 1)
+ return;
+
+ for (int var4 = _numCharactersToDisplay - 1; var4 > 0; var4--) {
+ bool found = false;
+
+ for (int var2 = 0; var2 < var4; var2++) {
+ int index1 = _charactersToDisplay[var2];
+ int index2 = _charactersToDisplay[var2 + 1];
+
+ if (_characterRelativePos[index1].y < _characterRelativePos[index2].y)
+ continue;
+
+ if (_characterRelativePos[index1].y == _characterRelativePos[index2].y) {
+ if (_characterRelativePos[index1].x < _characterRelativePos[index2].x)
+ continue;
+
+ if (_characterRelativePos[index1].x == _characterRelativePos[index2].x) {
+ if (_characterPosAltitude[index1] < _characterPosAltitude[index2])
+ continue;
+
+ if (_characterPosAltitude[index1] == _characterPosAltitude[index2]) {
+ if (_characterDisplay[index1].y < _characterDisplay[index2].y)
+ continue;
+ }
+ }
+ }
+
+ byte tmpVal = _charactersToDisplay[var2];
+ _charactersToDisplay[var2] = _charactersToDisplay[var2 + 1];
+ _charactersToDisplay[var2 + 1] = tmpVal;
+ found = true;
+ }
+
+ if (!found)
+ return;
+ }
+}
+
+void LilliputEngine::scrollToViewportCharacterTarget() {
+ debugC(2, kDebugEngine, "scrollToViewportCharacterTarget()");
+
+ if (_scriptHandler->_viewportCharacterTarget == -1)
+ return;
+
+ int tileX = (_characterPos[_scriptHandler->_viewportCharacterTarget].x >> 3) - _scriptHandler->_viewportPos.x;
+ int tileY = (_characterPos[_scriptHandler->_viewportCharacterTarget].y >> 3) - _scriptHandler->_viewportPos.y;
+ Common::Point newPos = _scriptHandler->_viewportPos;
+
+ if (tileX >= 1) {
+ if (tileX > 6){
+ newPos.x += 4;
+ if (newPos.x > 56)
+ newPos.x = 56;
+ }
+ } else {
+ newPos.x -= 4;
+ if (newPos.x < 0)
+ newPos.x = 0;
+ }
+
+ if ((tileY < 1) && (newPos.y < 4))
+ newPos.y = 0;
+ else {
+ if (tileY < 1)
+ newPos.y -= 4;
+
+ if (tileY > 6) {
+ newPos.y += 4;
+ if (newPos.y >= 56)
+ newPos.y = 56;
+ }
+ }
+ viewportScrollTo(newPos);
+}
+
+void LilliputEngine::viewportScrollTo(Common::Point goalPos) {
+ debugC(2, kDebugEngine, "viewportScrollTo(%d, %d)", goalPos.x, goalPos.y);
+
+ if (goalPos == _scriptHandler->_viewportPos)
+ return;
+
+ int16 dx = 0;
+ if (goalPos.x != _scriptHandler->_viewportPos.x) {
+ if (goalPos.x < _scriptHandler->_viewportPos.x)
+ --dx;
+ else
+ ++dx;
+ }
+
+ int16 dy = 0;
+ if (goalPos.y != _scriptHandler->_viewportPos.y) {
+ if (goalPos.y < _scriptHandler->_viewportPos.y)
+ --dy;
+ else
+ ++dy;
+ }
+
+ do {
+ _scriptHandler->_viewportPos.x += dx;
+ _scriptHandler->_viewportPos.y += dy;
+
+ displayLandscape();
+ prepareGameArea();
+ displayGameArea();
+
+ if (goalPos.x == _scriptHandler->_viewportPos.x)
+ dx = 0;
+
+ if (goalPos.y == _scriptHandler->_viewportPos.y)
+ dy = 0;
+ } while ((dx != 0) || (dy != 0));
+
+ _soundHandler->update();
+}
+
+void LilliputEngine::renderCharacters(byte *buf, Common::Point pos) {
+ debugC(2, kDebugEngine, "renderCharacters(buf, %d - %d)", pos.x, pos.y);
+
+ if (_nextDisplayCharacterPos != pos)
+ return;
+
+ _byte16552 = 0;
+
+ if (buf[1] != 0xFF) {
+ int tmpIndex = buf[1];
+ if ((_cubeFlags[tmpIndex] & 16) == 0)
+ ++_byte16552;
+ }
+
+ int index = _charactersToDisplay[_currentDisplayCharacter];
+ Common::Point characterPos = _characterDisplay[index];
+
+ if (index == _scriptHandler->_talkingCharacter)
+ displaySpeechBubbleTail(characterPos);
+
+ if (_byte16552 != 1) {
+ byte flag = _characterDirectionArray[index];
+ int16 frame = _characterFrameArray[index];
+
+ if (frame != -1) {
+ frame += _scriptHandler->_characterPose[index];
+ if ((flag & 1) == 1)
+ frame += _spriteSizeArray[index];
+
+ if (_characterMagicPuffFrame[index] != -1) {
+ frame = _characterMagicPuffFrame[index] + 82;
+ --_characterMagicPuffFrame[index];
+ frame = -frame;
+ }
+
+ displayCharacter(frame, characterPos, flag);
+ }
+ }
+
+ ++_currentDisplayCharacter;
+ setNextDisplayCharacter(_currentDisplayCharacter);
+
+ renderCharacters(buf, pos);
+}
+
+void LilliputEngine::displaySpeechBubbleTail(Common::Point displayPos) {
+ debugC(2, kDebugEngine, "displaySpeechBubbleTail(%d, %d)", displayPos.x, displayPos.y);
+
+ int orgX = displayPos.x + 8;
+ int orgY = displayPos.y;
+ int var2 = 0;
+
+ int x = orgX;
+ int y = orgY;
+ do {
+ displaySpeechBubbleTailLine(Common::Point(x, y), var2);
+ --x;
+ y /= 2;
+ } while (y != 0);
+
+ x = orgX + 1;
+ y = orgY / 2;
+
+ while (y != 0) {
+ displaySpeechBubbleTailLine(Common::Point(x, y), var2);
+ ++x;
+ y /= 2;
+ }
+}
+
+void LilliputEngine::displaySpeechBubbleTailLine(Common::Point pos, int var2) {
+ debugC(2, kDebugEngine, "displaySpeechBubbleTailLine(%d - %d, %d)", pos.x, pos.y, var2);
+
+ int index = pos.x + (var2 * 256);
+ for (int i = 1 + pos.y - var2; i > 0; i--) {
+ _savedSurfaceGameArea1[index] = 17;
+ index += 256;
+ }
+}
+
+void LilliputEngine::checkSpeechClosing() {
+ debugC(2, kDebugEngine, "checkSpeechClosing()");
+
+ if (_scriptHandler->_speechTimer != 0) {
+ --_scriptHandler->_speechTimer;
+ if (_scriptHandler->_speechTimer == 0) {
+ restoreSurfaceSpeech();
+ _scriptHandler->_talkingCharacter = -1;
+ }
+ }
+}
+
+byte LilliputEngine::getDirection(Common::Point param1, Common::Point param2) {
+ debugC(2, kDebugEngine, "getDirection(%d - %d, %d - %d)", param1.x, param1.y, param2.x, param2.y);
+
+ static const byte _directionsArray[8] = {0, 2, 0, 1, 3, 2, 3, 1};
+
+ Common::Point var1 = param2;
+ Common::Point var2 = param1;
+
+ int8 var1h = var1.x - var2.x;
+ int8 var1l = var1.y - var2.y;
+ int8 var2l = 0;
+
+ if (var1h < 0) {
+ var2l |= 4;
+ var1h = -var1h;
+ }
+
+ if (var1l < 0) {
+ var2l |= 2;
+ var1l = -var1l;
+ }
+
+ if (var1h < var1l)
+ var2l |= 1;
+
+ return _directionsArray[var2l];
+}
+
+byte LilliputEngine::sequenceCharacterHomeIn(int index, Common::Point param1) {
+ debugC(2, kDebugEngine, "sequenceCharacterHomeIn(%d, %d - %d)", index, param1.x, param1.y);
+
+ Common::Point target = _characterSubTargetPos[index];
+
+ if (target.x != -1) {
+ if (target != _scriptHandler->_characterTilePos[index]) {
+ homeInChooseDirection(index);
+ _scriptHandler->_characterNextSequence[index] -= (param1.x & 0x0F);
+ return kSeqNoInc | kSeqRepeat;
+ }
+
+ if (target == _characterTargetPos[index])
+ return kSeqRepeat;
+ }
+
+ homeInPathFinding(index);
+
+ Common::Point pos1 = _scriptHandler->_characterTilePos[index];
+ Common::Point pos2 = _characterSubTargetPos[index];
+
+ _characterDirectionArray[index] = getDirection(pos1, pos2);
+
+ homeInChooseDirection(index);
+ _scriptHandler->_characterNextSequence[index] -= (param1.x & 0x0F);
+ return kSeqNoInc | kSeqRepeat;
+}
+
+void LilliputEngine::homeInPathFinding(int index) {
+ debugC(2, kDebugEngine, "homeInPathFinding(%d)", index);
+
+ int16 enclosureSrc = checkEnclosure(_scriptHandler->_characterTilePos[index]);
+ int16 enclosureDst = checkEnclosure(_characterTargetPos[index]);
+
+ if (enclosureSrc == enclosureDst) {
+ _characterSubTargetPos[index] = _characterTargetPos[index];
+ return;
+ }
+
+ if (enclosureSrc == -1) {
+ int tmpVal = checkOuterEnclosure(_characterTargetPos[index]);
+ if (tmpVal == -1)
+ warning("homeInPathFinding: Unexpected negative index");
+ else
+ _characterSubTargetPos[index] = _portalPos[tmpVal];
+ return;
+ }
+
+ if ((enclosureDst != -1) &&
+ (_characterTargetPos[index].x >= _enclosureRect[enclosureSrc].left) &&
+ (_characterTargetPos[index].x <= _enclosureRect[enclosureSrc].right) &&
+ (_characterTargetPos[index].y >= _enclosureRect[enclosureSrc].top) &&
+ (_characterTargetPos[index].y <= _enclosureRect[enclosureSrc].bottom)) {
+ _characterSubTargetPos[index] = _portalPos[enclosureDst];
+ return;
+ }
+
+ _characterSubTargetPos[index] = _portalPos[enclosureSrc];
+
+ if (_enclosureRect[enclosureSrc].left != _enclosureRect[enclosureSrc].right) {
+ if (_portalPos[enclosureSrc].x == _enclosureRect[enclosureSrc].left) {
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x - 1, _portalPos[enclosureSrc].y);
+ return;
+ }
+
+ if (_portalPos[enclosureSrc].x == _enclosureRect[enclosureSrc].right) {
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x + 1, _portalPos[enclosureSrc].y);
+ return;
+ }
+
+ if (_enclosureRect[enclosureSrc].bottom != _enclosureRect[enclosureSrc].top) {
+ if (_portalPos[enclosureSrc].y == _enclosureRect[enclosureSrc].top)
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y - 1);
+ else // CHECKME: Should be a check on y == bottom
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y + 1);
+
+ return;
+ }
+ }
+
+ int mapIndex = (_portalPos[enclosureSrc].y * 64 + _portalPos[enclosureSrc].x) * 4;
+ assert(mapIndex < 16384);
+
+ int tmpVal = _bufferIsoMap[mapIndex + 3];
+ if ((tmpVal & 8) != 0)
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x + 1, _portalPos[enclosureSrc].y);
+ else if ((tmpVal & 4) != 0)
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y - 1);
+ else if ((tmpVal & 2) != 0)
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x, _portalPos[enclosureSrc].y + 1);
+ else
+ _characterSubTargetPos[index] = Common::Point(_portalPos[enclosureSrc].x - 1, _portalPos[enclosureSrc].y);
+
+ return;
+}
+
+void LilliputEngine::homeInChooseDirection(int index) {
+ debugC(2, kDebugEngine, "homeInChooseDirection(%d)", index);
+
+ static const int16 mapArrayMove[4] = {4, -256, 256, -4};
+
+ _curCharacterTilePos = _scriptHandler->_characterTilePos[index];
+
+ evaluateDirections(index);
+ int direction = (_characterDirectionArray[index] ^ 3);
+
+ _homeInDirLikelyhood[direction] -= 8;
+ byte closeWallFl = 0;
+
+ int mapIndex = ((_curCharacterTilePos.y * 64) + _curCharacterTilePos.x) * 4;
+ int retVal = 0;
+ for (int i = 3; i >= 0; i--) {
+ int mapIndexDiff = mapArrayMove[i];
+ assert(mapIndex + mapIndexDiff + 3 < 16384);
+ if (((_bufferIsoMap[mapIndex + mapIndexDiff + 3] & _doorEntranceMask[i]) != 0) && ((_bufferIsoMap[mapIndex + 3] & _doorExitMask[i]) != 0)) {
+ if ((_bufferIsoMap[mapIndex + mapIndexDiff + 3] & 0x80) != 0 && (homeInAvoidDeadEnds(i, index) != 0)) {
+ _homeInDirLikelyhood[i] -= 20;
+ }
+
+ int tmpVal = ((_characterMobility[index] & 7) ^ 7);
+ retVal = _cubeFlags[_bufferIsoMap[mapIndex + mapIndexDiff]];
+ tmpVal &= retVal;
+ if (tmpVal == 0)
+ continue;
+ }
+ _homeInDirLikelyhood[i] = -98;
+ ++closeWallFl;
+ }
+
+ if (closeWallFl != 0)
+ _homeInDirLikelyhood[_characterDirectionArray[index]] += 3;
+
+ int tmpVal = -99;
+ for (int i = 3; i >= 0; i--) {
+ if (tmpVal < _homeInDirLikelyhood[i]) {
+ retVal = i;
+ tmpVal = _homeInDirLikelyhood[i];
+ }
+ }
+
+ _characterDirectionArray[index] = retVal;
+}
+
+byte LilliputEngine::homeInAvoidDeadEnds(int indexb, int indexs) {
+ debugC(2, kDebugEngine, "homeInAvoidDeadEnds(%d, %d)", indexb, indexs);
+
+ static const int8 constDirX[4] = {1, 0, 0, -1};
+ static const int8 constDirY[4] = {0, -1, 1, 0};
+
+ Common::Point tmpPos = Common::Point(_curCharacterTilePos.x + constDirX[indexb], _curCharacterTilePos.y + constDirY[indexb]);
+
+ int16 idx = checkEnclosure(tmpPos);
+ if (idx == -1)
+ return 1;
+
+ if ((tmpPos.x >= _enclosureRect[idx].left) && (tmpPos.x <= _enclosureRect[idx].right) && (tmpPos.y >= _enclosureRect[idx].top) && (tmpPos.y <= _enclosureRect[idx].bottom))
+ return 0;
+
+ if ((tmpPos.x >= _enclosureRect[idx].left) && (tmpPos.x <= _enclosureRect[idx].right) && (tmpPos.y >= _enclosureRect[idx].top) && (tmpPos.y <= _enclosureRect[idx].bottom))
+ return 0;
+
+ return 1;
+}
+
+int16 LilliputEngine::checkEnclosure(Common::Point pos) {
+ debugC(2, kDebugEngine, "checkEnclosure(%d, %d)", pos.x, pos.y);
+
+ for (int i = 0; i < _rectNumb; ++i) {
+ if ((pos.x >= _enclosureRect[i].left) && (pos.x <= _enclosureRect[i].right) && (pos.y >= _enclosureRect[i].top) && (pos.y <= _enclosureRect[i].bottom))
+ return i;
+ }
+ return -1;
+}
+
+int16 LilliputEngine::checkOuterEnclosure(Common::Point pos) {
+ debugC(2, kDebugEngine, "checkOuterEnclosure(%d, %d)", pos.x, pos.y);
+
+ for (int i = _rectNumb - 1; i >= 0 ; --i) {
+ if ((pos.x >= _enclosureRect[i].left) && (pos.x <= _enclosureRect[i].right) && (pos.y >= _enclosureRect[i].top) && (pos.y <= _enclosureRect[i].bottom))
+ return i;
+ }
+ return -1;
+}
+
+void LilliputEngine::evaluateDirections(int index) {
+ debugC(2, kDebugEngine, "evaluateDirections(%d)", index);
+
+ static const int8 arrayMoveX[4] = {1, 0, 0, -1};
+ static const int8 arrayMoveY[4] = {0, -1, 1, 0};
+
+ int16 arrayDistance[4];
+
+ for (int i = 3; i >= 0; i--) {
+ int16 var1h = _curCharacterTilePos.x + arrayMoveX[i] - _characterSubTargetPos[index].x;
+ int16 var1l = _curCharacterTilePos.y + arrayMoveY[i] - _characterSubTargetPos[index].y;
+ arrayDistance[i] = (var1l * var1l) + (var1h * var1h);
+ }
+
+ for (int i = 0; i < 4; i++)
+ _homeInDirLikelyhood[i] = 0;
+
+ int8 tmpIndex = 0;
+ for (int i = 3; i > 0; i--) {
+ int16 smallestDistance = 0x7FFF;
+ for (int j = 0; j < 4; j++) {
+ if (smallestDistance > arrayDistance[j]) {
+ smallestDistance = arrayDistance[j];
+ tmpIndex = j;
+ }
+ }
+ arrayDistance[tmpIndex] = 0x7FFF;
+ _homeInDirLikelyhood[tmpIndex] = i;
+ }
+}
+
+void LilliputEngine::addCharToBuf(byte character) {
+ debugC(2, kDebugEngine, "addCharToBuf(%c)", character);
+
+ _displayStringBuf[_displayStringIndex] = character;
+ if (_displayStringIndex < 158)
+ ++_displayStringIndex;
+}
+
+void LilliputEngine::numberToString(int param1) {
+ debugC(2, kDebugEngine, "numberToString(%d)", param1);
+
+ static const int exp10[6] = {10000, 1000, 100, 10, 1};
+
+ int var1 = param1;
+ bool hideZeros = true;
+ for (int i = 0; i < 5; i++) {
+ int count = 0;
+ while (var1 >= 0) {
+ ++count;
+ var1 -= exp10[i];
+ }
+ var1 += exp10[i];
+ --count;
+
+ byte tmpVal = count + 0x30;
+
+ if (i == 4)
+ addCharToBuf(tmpVal);
+ else if ((count != 0) || (!hideZeros)) {
+ hideZeros = false;
+ addCharToBuf(tmpVal);
+ }
+ }
+}
+
+void LilliputEngine::updateCharPosSequence() {
+ debugC(2, kDebugEngine, "updateCharPosSequence()");
+
+ int index = _numCharacters - 1;
+ byte result;
+ while (index >= 0) {
+ result = kSeqRepeat;
+ while (result & kSeqRepeat) {
+ if (_scriptHandler->_characterNextSequence[index] == 16)
+ break;
+
+ uint16 index2 = _scriptHandler->_characterNextSequence[index] + (index * 16);
+ Common::Point var1 = _scriptHandler->_sequenceArr[index2];
+
+ // /8, then /2 as the function array is a word array
+ int16 posSeqType = var1.x / 16;
+
+ switch (posSeqType) {
+ case 0: // Move
+ // x stands for moveType, y for poseType
+ result = sequenceMoveCharacter(index, var1.x, var1.y);
+ break;
+ case 1: // Face direction
+ // x stands for the next direction, y for the poseType
+ result = sequenceSetCharacterDirection(index, var1.x, var1.y);
+ break;
+ case 10: // Seek move target
+ result = sequenceSeekMovingCharacter(index, var1);
+ break;
+ case 11: // Sound
+ result = sequenceSound(index, var1);
+ break;
+ case 12: // Home in target
+ result = sequenceCharacterHomeIn(index, var1);
+ break;
+ case 13: // Character mobility
+ result = sequenceSetMobility(index, var1);
+ break;
+ case 14: // Repeat sequence
+ result = sequenceRepeat(index, var1, index2);
+ break;
+ case 15: // End
+ result = sequenceEnd(index);
+ break;
+ default:
+ result = kSeqNone;
+ break;
+ }
+
+ if ((result & kSeqNoInc) == 0) {
+ ++_scriptHandler->_characterNextSequence[index];
+ if (_scriptHandler->_characterNextSequence[index] == 16)
+ _scriptHandler->_characterScriptEnabled[index] = 1;
+ }
+ }
+ --index;
+ }
+}
+
+byte LilliputEngine::sequenceEnd(int index) {
+ debugC(2, kDebugEngine, "sequenceEnd(%d)", index);
+
+ _scriptHandler->_characterNextSequence[index] = 16;
+ _scriptHandler->_characterScriptEnabled[index] = 1;
+
+ return kSeqNoInc;
+}
+
+byte LilliputEngine::sequenceRepeat(int index, Common::Point var1, int tmpVal) {
+ debugC(2, kDebugEngine, "sequenceRepeat(%d, %d - %d, %d)", index, var1.x, var1.y, tmpVal);
+
+ byte counter = var1.y;
+ if (counter != 0) {
+ if ((counter & 0xF0) == 0)
+ counter |= (counter << 4);
+
+ counter -= 16;
+ _scriptHandler->_sequenceArr[tmpVal] = Common::Point(var1.x, counter);
+
+ if ((counter & 0xF0) == 0)
+ return kSeqRepeat;
+ }
+
+ _scriptHandler->_characterNextSequence[index] -= (var1.x & 0x0F);
+ return kSeqNoInc | kSeqRepeat;
+}
+
+byte LilliputEngine::sequenceSetCharacterDirection(int index, int direction, int poseType) {
+ debugC(2, kDebugEngine, "sequenceSetCharacterDirection(%d, %d - %d)", index, direction, poseType);
+
+ char newDir = direction & 3;
+ _characterDirectionArray[index] = newDir;
+ setCharacterPose(index, poseType);
+
+ return kSeqNone;
+}
+
+byte LilliputEngine::sequenceSetMobility(int index, Common::Point var1) {
+ debugC(2, kDebugEngine, "sequenceSetMobility(%d, %d - %d)", index, var1.x, var1.y);
+
+ _characterMobility[index] = var1.y;
+ return kSeqRepeat;
+}
+
+byte LilliputEngine::sequenceSound(int index, Common::Point var1) {
+ debugC(2, kDebugEngine, "sequenceSound(%d, %d - %d)", index, var1.x, var1.y);
+
+ int param4x = ((index | 0xFF00) >> 8);
+ _soundHandler->play(var1.y, _scriptHandler->_viewportPos,
+ _scriptHandler->_characterTilePos[index], Common::Point(param4x, 0));
+ return kSeqRepeat;
+}
+
+byte LilliputEngine::sequenceSeekMovingCharacter(int index, Common::Point var1) {
+ debugC(2, kDebugEngine, "sequenceSeekMovingCharacter(%d, %d - %d)", index, var1.x, var1.y);
+
+ int charIndex = _scriptHandler->_characterSeek[index];
+ Common::Point charPos = _scriptHandler->_characterTilePos[charIndex];
+
+ if ((_characterSubTargetPos[index].x != -1) && (_characterSubTargetPos[index] == _characterTargetPos[index]))
+ _characterSubTargetPos[index] = charPos;
+
+ _characterTargetPos[index] = charPos;
+
+ return sequenceCharacterHomeIn(index, var1);
+}
+
+void LilliputEngine::checkSpecialCubes() {
+ debugC(2, kDebugEngine, "checkSpecialCubes()");
+
+ for (int index1 = _numCharacters - 1; index1 >= 0; index1--) {
+ // Hack: The original doesn't check if it's disabled, which looks wrong
+ if ((_scriptHandler->_characterTilePos[index1].x == -1) || (_scriptHandler->_characterTilePos[index1].y == -1))
+ continue;
+ //
+
+ int mapIndex = 3 + (_scriptHandler->_characterTilePos[index1].y * 64 + _scriptHandler->_characterTilePos[index1].x) * 4;
+ assert((mapIndex >= 0) && (mapIndex < 16384));
+ byte var1 = _bufferIsoMap[mapIndex] & 0x40;
+
+ if (var1 == _specialCubes[index1])
+ continue;
+
+ _specialCubes[index1] = var1;
+ if (var1 != 0)
+ _scriptHandler->_characterScriptEnabled[index1] = 1;
+ }
+}
+
+void LilliputEngine::handleCharacterTimers() {
+ debugC(2, kDebugEngine, "handleCharacterTimers()");
+
+ int index1 = _animationTick + 2;
+
+ for (byte i = 0; i < _numCharacters; i++) {
+ byte *varPtr = getCharacterAttributesPtr(index1);
+ if (varPtr[0] != 0) {
+ if (varPtr[0] == 1) {
+ varPtr[0] = 0;
+ } else {
+ --varPtr[0];
+ if (varPtr[0] == 1)
+ _scriptHandler->_characterScriptEnabled[i] = 1;
+ }
+ }
+
+ index1 += 32;
+ }
+}
+
+void LilliputEngine::keyboard_handleInterfaceShortcuts(bool &forceReturnFl) {
+ debugC(2, kDebugEngine, "keyboard_handleInterfaceShortcuts()");
+
+ forceReturnFl = false;
+
+ if (!_keyboard_checkKeyboard())
+ return;
+
+ Common::Event event = _keyboard_getch();
+
+ int8 index = -1;
+ for (int8 i = 0; i < _interfaceHotspotNumb; i++) {
+ if (event.kbd.keycode == _keyboardMapping[i]) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index != -1) {
+ byte button = 1;
+ if (event.type == Common::EVENT_KEYUP)
+ button = 2;
+ handleInterfaceHotspot(index, button);
+ forceReturnFl = true;
+ }
+}
+
+void LilliputEngine::checkNumericCode() {
+ debugC(2, kDebugEngine, "checkNumericCode()");
+
+ static bool altKeyFl = false;
+ static int16 keyCount = 0;
+
+ if (_keyboard_oldIndex == _keyboard_nextIndex)
+ return;
+
+ Common::Event oldEvent = _keyboard_buffer[_keyboard_oldIndex];
+ if ((oldEvent.kbd.keycode == Common::KEYCODE_LALT) || (oldEvent.kbd.keycode == Common::KEYCODE_RALT)) {
+ if (oldEvent.type == Common::EVENT_KEYDOWN) {
+ altKeyFl = true;
+ keyCount = 0;
+ return;
+ } else if (oldEvent.type == Common::EVENT_KEYUP) {
+ altKeyFl = false;
+ if (keyCount == 3)
+ _actionType = kCodeEntered;
+ return;
+ }
+ }
+
+ if (keyCount >= 3)
+ return;
+
+ if ((altKeyFl) && (oldEvent.type == Common::EVENT_KEYDOWN)) {
+ switch (oldEvent.kbd.keycode) {
+ case Common::KEYCODE_KP0:
+ case Common::KEYCODE_KP1:
+ case Common::KEYCODE_KP2:
+ case Common::KEYCODE_KP3:
+ case Common::KEYCODE_KP4:
+ case Common::KEYCODE_KP5:
+ case Common::KEYCODE_KP6:
+ case Common::KEYCODE_KP7:
+ case Common::KEYCODE_KP8:
+ case Common::KEYCODE_KP9:
+ case Common::KEYCODE_0:
+ case Common::KEYCODE_1:
+ case Common::KEYCODE_2:
+ case Common::KEYCODE_3:
+ case Common::KEYCODE_4:
+ case Common::KEYCODE_5:
+ case Common::KEYCODE_6:
+ case Common::KEYCODE_7:
+ case Common::KEYCODE_8:
+ case Common::KEYCODE_9:
+ _codeEntered[keyCount] = oldEvent.kbd.keycode - Common::KEYCODE_0;
+ ++keyCount;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void LilliputEngine::handleGameMouseClick() {
+ debugC(2, kDebugEngine, "handleGameMouseClick()");
+
+ checkNumericCode();
+
+ bool forceReturnFl = false;
+ keyboard_handleInterfaceShortcuts(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ if (_mouseButton == 0) {
+ if (!_mouseClicked)
+ return;
+ _mouseClicked = false;
+ _mouseButton = 2;
+ }
+
+ int button = _mouseButton;
+ _mouseButton = 0;
+
+ if (button == 2) {
+ if (_lastInterfaceHotspotIndex != -1)
+ handleInterfaceHotspot(_lastInterfaceHotspotIndex, button);
+ return;
+ }
+
+ forceReturnFl = false;
+ checkInterfaceHotspots(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ Common::Point pos = Common::Point(_mousePos.x - 64, _mousePos.y - 16);
+
+ if ((pos.x < 0) || (pos.x > 255) || (pos.y < 0) || (pos.y > 176))
+ return;
+
+ forceReturnFl = false;
+ checkClickOnCharacter(pos, forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ checkClickOnGameArea(pos);
+}
+
+void LilliputEngine::checkClickOnGameArea(Common::Point pos) {
+ debugC(2, kDebugEngine, "checkClickOnGameArea(%d, %d)", pos.x, pos.y);
+
+ int x = pos.x - 8;
+ int y = pos.y - 4;
+
+ x = (x / 16) - 7;
+ y = (y / 8) - 4;
+
+ int arrowY = (y - x) >> 1;
+ int arrowX = y - arrowY;
+
+ if ((arrowX >= 0) && (arrowY >= 0) && (arrowX < 8) && (arrowY < 8)) {
+ arrowX += _scriptHandler->_viewportPos.x;
+ arrowY += _scriptHandler->_viewportPos.y;
+ _savedMousePosDivided = Common::Point(arrowX, arrowY);
+ _actionType = kCubeSelected;
+ }
+}
+
+void LilliputEngine::checkClickOnCharacter(Common::Point pos, bool &forceReturnFl) {
+ debugC(2, kDebugEngine, "checkClickOnCharacter(%d, %d)", pos.x, pos.y);
+
+ forceReturnFl = false;
+
+ for (int8 i = 0; i < _numCharacters; i++) {
+ // check if position is over a character
+ if ((pos.x >= _characterDisplay[i].x) && (pos.x <= _characterDisplay[i].x + 17) && (pos.y >= _characterDisplay[i].y) && (pos.y <= _characterDisplay[i].y + 17) && (i != _host)) {
+ _selectedCharacterId = i;
+ _actionType = kActionGoto;
+ if (_delayedReactivationAction)
+ _actionType = kActionTalk;
+
+ forceReturnFl = true;
+ return;
+ }
+ }
+}
+
+void LilliputEngine::checkInterfaceHotspots(bool &forceReturnFl) {
+ debugC(2, kDebugEngine, "checkInterfaceHotspots()");
+
+ forceReturnFl = false;
+ for (int index = _interfaceHotspotNumb - 1; index >= 0; index--) {
+ if (isMouseOverHotspot(_mousePos, _interfaceHotspots[index])) {
+ handleInterfaceHotspot(index, 1);
+ forceReturnFl = true;
+ return;
+ }
+ }
+}
+
+bool LilliputEngine::isMouseOverHotspot(Common::Point mousePos, Common::Point hotspotPos) {
+ debugC(2, kDebugEngine, "isMouseOverHotspot(%d - %d, %d - %d)", mousePos.x, mousePos.y, hotspotPos.x, hotspotPos.y);
+
+ if ((mousePos.x < hotspotPos.x) || (mousePos.y < hotspotPos.y) || (mousePos.x > hotspotPos.x + 16) || (mousePos.y > hotspotPos.y + 16))
+ return false;
+
+ return true;
+}
+
+void LilliputEngine::handleInterfaceHotspot(byte index, byte button) {
+ debugC(2, kDebugEngine, "handleInterfaceHotspot(%d, %d)", index, button);
+
+ if (_scriptHandler->_interfaceHotspotStatus[index] < kHotspotEnabled)
+ return;
+
+ _lastInterfaceHotspotIndex = index;
+ _lastInterfaceHotspotButton = button;
+
+ if (button == 2) {
+ if (!_delayedReactivationAction) {
+ _scriptHandler->_interfaceHotspotStatus[index] = kHotspotEnabled;
+ _actionType = kButtonReleased;
+ displayInterfaceHotspots();
+ }
+ return;
+ }
+
+ if (_delayedReactivationAction) {
+ unselectInterfaceButton();
+ return;
+ }
+
+ unselectInterfaceHotspots();
+ _scriptHandler->_interfaceHotspotStatus[index] = kHotspotSelected;
+ if (_interfaceTwoStepAction[index] == 1) {
+ _delayedReactivationAction = true;
+ _displayGreenHand = true;
+ } else {
+ _actionType = kButtonPressed;
+ }
+
+ displayInterfaceHotspots();
+}
+
+void LilliputEngine::setCharacterPose(int charIdx, int poseIdx) {
+ debugC(2, kDebugEngine, "setCharacterPose(%d, %d)", charIdx, poseIdx);
+
+ // CHECKME: Add an assert on poseIdx to check if it's between 0 and 31?
+ int index = (charIdx * 32) + poseIdx;
+ _scriptHandler->_characterPose[charIdx] = _poseArray[index];
+}
+
+byte LilliputEngine::sequenceMoveCharacter(int idx, int moveType, int poseType) {
+ debugC(2, kDebugEngine, "sequenceMoveCharacter(%d, %d - %d)", idx, moveType, poseType);
+
+ setCharacterPose(idx, poseType);
+
+ int index = idx;
+ switch (moveType) {
+ case 0:
+ // No movement
+ break;
+ case 1:
+ moveCharacterSpeed2(index);
+ break;
+ case 2:
+ moveCharacterSpeed4(index);
+ break;
+ case 3:
+ moveCharacterBack2(index);
+ break;
+ case 4:
+ turnCharacter1(index);
+ break;
+ case 5:
+ turnCharacter2(index);
+ break;
+ case 6:
+ moveCharacterUp1(index);
+ break;
+ case 7:
+ moveCharacterUp2(index);
+ break;
+ case 8:
+ moveCharacterDown1(index);
+ break;
+ case 9:
+ moveCharacterDown2(index);
+ break;
+ case 10:
+ moveCharacterSpeed3(index);
+ break;
+ default:
+ // CHECKME: It's so bad it could be an error()
+ warning("sequenceMoveCharacter - Unexpected value %d", moveType);
+ }
+
+ return kSeqNone;
+}
+
+void LilliputEngine::turnCharacter1(int index) {
+ debugC(2, kDebugEngine, "turnCharacter1(%d)", index);
+
+ static const byte nextDirection[4] = {1, 3, 0, 2};
+ _characterDirectionArray[index] = nextDirection[_characterDirectionArray[index]];
+}
+
+void LilliputEngine::turnCharacter2(int index) {
+ debugC(2, kDebugEngine, "turnCharacter2(%d)", index);
+
+ static const byte nextDirection[4] = {2, 0, 3, 1};
+ _characterDirectionArray[index] = nextDirection[_characterDirectionArray[index]];
+}
+
+void LilliputEngine::moveCharacterUp1(int index) {
+ debugC(2, kDebugEngine, "moveCharacterUp1(%d)", index);
+
+ _characterPosAltitude[index] += 1;
+}
+
+void LilliputEngine::moveCharacterUp2(int index) {
+ debugC(2, kDebugEngine, "moveCharacterUp2(%d)", index);
+
+ _characterPosAltitude[index] += 2;
+}
+
+void LilliputEngine::moveCharacterDown1(int index) {
+ debugC(2, kDebugEngine, "moveCharacterDown1(%d)", index);
+
+ _characterPosAltitude[index] -= 1;
+}
+
+void LilliputEngine::moveCharacterDown2(int index) {
+ debugC(2, kDebugEngine, "moveCharacterDown2(%d)", index);
+
+ _characterPosAltitude[index] -= 2;
+}
+
+void LilliputEngine::moveCharacterSpeed2(int index) {
+ debugC(2, kDebugEngine, "moveCharacterSpeed2(%d)", index);
+
+ moveCharacterForward(index, 2);
+}
+
+void LilliputEngine::moveCharacterSpeed4(int index) {
+ debugC(2, kDebugEngine, "moveCharacterSpeed4(%d)", index);
+
+ moveCharacterForward(index, 4);
+}
+
+void LilliputEngine::moveCharacterBack2(int index) {
+ debugC(2, kDebugEngine, "moveCharacterBack2(%d)", index);
+
+ moveCharacterForward(index, -2);
+}
+
+void LilliputEngine::moveCharacterSpeed3(int index) {
+ debugC(2, kDebugEngine, "moveCharacterSpeed3(%d)", index);
+
+ moveCharacterForward(index, 3);
+}
+
+void LilliputEngine::moveCharacterForward(int index, int16 speed) {
+ debugC(2, kDebugEngine, "moveCharacterForward(%d, %d)", index, speed);
+
+ int16 newX = _characterPos[index].x;
+ int16 newY = _characterPos[index].y;
+ switch (_characterDirectionArray[index]) {
+ case 0:
+ newX += speed;
+ break;
+ case 1:
+ newY -= speed;
+ break;
+ case 2:
+ newY += speed;
+ break;
+ default:
+ newX -= speed;
+ break;
+ }
+ checkCollision(index, Common::Point(newX, newY), _characterDirectionArray[index]);
+}
+
+void LilliputEngine::checkCollision(int index, Common::Point pos, int direction) {
+ debugC(2, kDebugEngine, "checkCollision(%d, %d - %d, %d)", index, pos.x, pos.y, direction);
+
+ int16 diffX = pos.x >> 3;
+ if (((diffX & 0xFF) == _scriptHandler->_characterTilePos[index].x) && ((pos.y >> 3) == _scriptHandler->_characterTilePos[index].y)) {
+ _characterPos[index] = pos;
+ return;
+ }
+
+ if ((pos.x < 0) || (pos.x >= 512) || (pos.y < 0) || (pos.y >= 512))
+ return;
+
+ int mapIndex = (_scriptHandler->_characterTilePos[index].y * 64 + _scriptHandler->_characterTilePos[index].x) * 4;
+ assert(mapIndex < 16384);
+
+ if ((_bufferIsoMap[mapIndex + 3] & _doorExitMask[direction]) == 0)
+ return;
+
+ mapIndex = ((pos.y & 0xFFF8) << 3) + diffX;
+ mapIndex <<= 2;
+
+ if ((_bufferIsoMap[mapIndex + 3] & _doorEntranceMask[direction]) == 0)
+ return;
+
+ byte var1 = _characterMobility[index];
+ var1 &= 7;
+ var1 ^= 7;
+
+ if ((var1 & _cubeFlags[_bufferIsoMap[mapIndex]]) != 0)
+ return;
+
+ _characterPos[index] = pos;
+}
+
+void LilliputEngine::signalDispatcher(byte type, byte index, int var4) {
+ debugC(2, kDebugEngine, "signalDispatcher(%d, %d, %d)", type, index, var4);
+
+ if (type == 0) { // Message sent to one target character
+ sendMessageToCharacter(index, var4);
+ return;
+ }
+
+ if (type == 3) { // Broadcast - Sent to all characters
+ for (int i = _numCharacters - 1; i >= 0; i--)
+ sendMessageToCharacter(i, var4);
+ return;
+ }
+
+ int index2 = var4 & 0xFF;
+ for (byte i = 0; i < _numCharacters; i++) {
+ if ((_scriptHandler->_interactions[index2] & 0xFF) >= type)
+ sendMessageToCharacter(i, var4);
+ index2 += 40;
+ }
+}
+
+void LilliputEngine::sendMessageToCharacter(byte index, int var4) {
+ debugC(2, kDebugEngine, "sendMessageToCharacter(%d, %d)", index, var4);
+
+ if (_characterSignals[index] != -1) {
+ _signalArr[index] = var4;
+ } else {
+ _scriptHandler->_characterScriptEnabled[index] = 1;
+ _characterSignals[index] = var4;
+ }
+}
+
+void LilliputEngine::handleSignals() {
+ debugC(2, kDebugEngine, "handleSignals()");
+
+ for (byte i = 0; i < _numCharacters; i++) {
+ if (_signalArr[i] != -1) {
+ _characterSignals[i] = _signalArr[i];
+ _signalArr[i] = -1;
+ _scriptHandler->_characterScriptEnabled[i] = 1;
+ }
+ }
+
+ ++_signalTimer;
+
+ for (int i = 0; i < 10; i++) {
+ if ((_signalArray[(3 * i) + 1] != -1) && (_signalArray[3 * i] == _signalTimer)) {
+ int16 var1 = _signalArray[(3 * i) + 1];
+ int var4 = _signalArray[(3 * i) + 2];
+ _signalArray[(3 * i) + 1] = -1;
+
+ byte type = var1 >> 8;
+ byte index = var1 & 0xFF;
+
+ signalDispatcher(type, index, var4);
+ }
+ }
+}
+
+void LilliputEngine::checkInterfaceActivationDelay() {
+ debugC(2, kDebugEngine, "checkInterfaceActivationDelay()");
+
+ if (_animationTick != 1)
+ return;
+
+ bool needRedraw = false;
+ for (int i = 0; i < _interfaceHotspotNumb; i++) {
+ if (_scriptHandler->_interfaceButtonActivationDelay[i] != 0) {
+ --_scriptHandler->_interfaceButtonActivationDelay[i];
+ if (_scriptHandler->_interfaceButtonActivationDelay[i] == 0) {
+ _scriptHandler->_interfaceHotspotStatus[i] = kHotspotEnabled;
+ needRedraw = true;
+ }
+ }
+ }
+
+ if (needRedraw)
+ displayInterfaceHotspots();
+}
+
+void LilliputEngine::displayHeroismIndicator() {
+ debugC(2, kDebugEngine, "displayHeroismIndicator()");
+
+ if (_scriptHandler->_barAttrPtr == NULL)
+ return;
+
+ int var1 = (_scriptHandler->_barAttrPtr[0] * 25) >> 8;
+
+ if (var1 == _scriptHandler->_heroismLevel)
+ return;
+
+ int var2 = 1;
+ if (var1 > _scriptHandler->_heroismLevel)
+ var1 = 150;
+ else {
+ var2 = -1;
+ var1 = 40;
+ }
+
+ _scriptHandler->_heroismLevel += var2;
+
+ int index = _scriptHandler->_heroismBarX + (_scriptHandler->_heroismBarBottomY * 320);
+
+ var2 = _scriptHandler->_heroismLevel & 0xFF;
+ if (var2 != 0) {
+ for (int i = 0; i < (var2 << 2); i++) {
+ ((byte *)_mainSurface->getPixels())[index] = var1;
+ ((byte *)_mainSurface->getPixels())[index + 1] = var1;
+ ((byte *)_mainSurface->getPixels())[index + 2] = var1;
+ index -= 320;
+ }
+ }
+
+ if (25 - _scriptHandler->_heroismLevel != 0) {
+ var2 = (25 - _scriptHandler->_heroismLevel) << 2;
+ for (int i = 0; i < var2; i++) {
+ ((byte *)_mainSurface->getPixels())[index] = 23;
+ ((byte *)_mainSurface->getPixels())[index + 1] = 23;
+ ((byte *)_mainSurface->getPixels())[index + 2] = 23;
+ index -= 320;
+ }
+ }
+}
+
+void LilliputEngine::pollEvent() {
+ debugC(2, kDebugEngine, "pollEvent()");
+
+ Common::Event event;
+ while (_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP: {
+ Common::Point newMousePos = Common::Point(CLIP<int>(event.mouse.x, 0, 304), CLIP<int>(event.mouse.y, 0, 184));
+
+ if (_mousePreviousEventType != event.type) {
+ _mousePreviousEventType = event.type;
+ if (_mouseButton != 1) {
+ _mouseButton = 2;
+ if (event.type != Common::EVENT_MOUSEMOVE) {
+ _mouseButton = 1;
+ _mousePos = Common::Point(newMousePos.x + 5, newMousePos.y + 1);
+ }
+ } else {
+ _mouseClicked = true;
+ }
+ }
+
+ if (newMousePos != _oldMousePos) {
+ _oldMousePos = newMousePos;
+ _mouseDisplayPos = newMousePos;
+ }
+ _lastEventType = event.type;
+ }
+ break;
+ case Common::EVENT_QUIT:
+ _shouldQuit = true;
+ break;
+ case Common::EVENT_KEYUP:
+ case Common::EVENT_KEYDOWN: {
+ if ((event.type == _lastKeyPressed.type) && (event.kbd == _lastKeyPressed.kbd))
+ break;
+
+ _lastKeyPressed = event;
+ int nextIndex = (_keyboard_nextIndex + 1) % 8;
+ if (_keyboard_oldIndex != nextIndex) {
+ _keyboard_buffer[_keyboard_nextIndex] = event;
+ _keyboard_nextIndex = nextIndex;
+ }
+
+ _lastEventType = event.type;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+byte *LilliputEngine::loadVGA(Common::String filename, int expectedSize, bool loadPal) {
+ debugC(1, kDebugEngine, "loadVGA(%s, %d, %d)", filename.c_str(), expectedSize, (loadPal) ? 1 : 0);
+
+ Common::File f;
+
+ if (!f.open(filename))
+ error("Missing game file %s", filename.c_str());
+
+ int remainingSize = f.size();
+ if (loadPal) {
+ for (int i = 0; i < 768; ++i)
+ _curPalette[i] = f.readByte();
+ remainingSize -= 768;
+
+ fixPaletteEntries(_curPalette, 256);
+ }
+
+ uint8 curByte;
+ byte *decodeBuffer = (byte *)malloc(expectedSize);
+ int size = 0;
+
+ for (; (remainingSize > 0) && (size < expectedSize);) {
+ curByte = f.readByte();
+ --remainingSize;
+
+ if (curByte == 0xFF)
+ break;
+
+ if (curByte & 0x80) {
+ // Compressed
+ int compSize = (curByte & 0x7F);
+ curByte = f.readByte();
+ --remainingSize;
+
+ for (int i = 0; i < compSize; ++i) {
+ decodeBuffer[size] = curByte;
+ ++size;
+ if (size == expectedSize)
+ break;
+ }
+ } else {
+ // Not compressed
+ int rawSize = (curByte & 0xFF);
+ for (int i = 0; i < rawSize; ++i) {
+ decodeBuffer[size] = f.readByte();
+ --remainingSize;
+ ++size;
+ if (size == expectedSize)
+ break;
+ }
+ }
+ }
+ f.close();
+
+ for (int i = size; i < expectedSize; i++)
+ decodeBuffer[i] = 0;
+
+ return decodeBuffer;
+}
+
+byte *LilliputEngine::loadRaw(Common::String filename, int filesize) {
+ debugC(1, kDebugEngine, "loadRaw(%s)", filename.c_str());
+
+ Common::File f;
+
+ if (!f.open(filename))
+ error("Missing game file %s", filename.c_str());
+
+ byte *res = (byte *)malloc(sizeof(byte) * filesize);
+ for (int i = 0; i < filesize; ++i)
+ res[i] = f.readByte();
+
+ f.close();
+ return res;
+}
+
+void LilliputEngine::loadRules() {
+ debugC(1, kDebugEngine, "loadRules()");
+
+ static const Common::KeyCode keybMappingArray[26] = {
+ Common::KEYCODE_a, Common::KEYCODE_b, Common::KEYCODE_c, Common::KEYCODE_d, Common::KEYCODE_e,
+ Common::KEYCODE_f, Common::KEYCODE_g, Common::KEYCODE_h, Common::KEYCODE_i, Common::KEYCODE_j,
+ Common::KEYCODE_k, Common::KEYCODE_l, Common::KEYCODE_m, Common::KEYCODE_n, Common::KEYCODE_o,
+ Common::KEYCODE_p, Common::KEYCODE_q, Common::KEYCODE_r, Common::KEYCODE_s, Common::KEYCODE_t,
+ Common::KEYCODE_u, Common::KEYCODE_v, Common::KEYCODE_w, Common::KEYCODE_x, Common::KEYCODE_y,
+ Common::KEYCODE_z};
+ Common::File f;
+ uint16 curWord;
+
+ Common::String filename = "ERULES.PRG";
+ Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
+
+ switch (lang) {
+ case Common::EN_ANY:
+ break;
+ case Common::FR_FRA:
+ filename = "FRULES.PRG";
+ break;
+ case Common::IT_ITA:
+ filename = "IRULES.PRG";
+ break;
+ case Common::DE_DEU:
+ filename = "GRULES.PRG";
+ break;
+ default:
+ warning("unsupported language, switching back to English");
+ }
+
+ if (!f.open(filename))
+ error("Missing game file %s", filename.c_str());
+
+ _word10800_ERULES = f.readUint16LE();
+
+ // Chunk 1 : Sequences
+ int size = f.readUint16LE();
+ _sequencesArr = (byte *)malloc(sizeof(byte) * size);
+ for (int i = 0; i < size; ++i)
+ _sequencesArr[i] = f.readByte();
+
+ // Chunk 2 : Characters
+ _numCharacters = (f.readUint16LE() & 0xFF);
+ assert(_numCharacters <= 40);
+
+ for (int i = _numCharacters, j = 0; i != 0; i--, j++) {
+ curWord = f.readUint16LE();
+ if (curWord != 0xFFFF)
+ curWord = (curWord << 3) + 4;
+ _characterPos[j].x = curWord;
+
+ curWord = f.readUint16LE();
+ if (curWord != 0xFFFF)
+ curWord = (curWord << 3) + 4;
+ _characterPos[j].y = curWord;
+
+ _characterPosAltitude[j] = (f.readUint16LE() & 0xFF);
+ _characterFrameArray[j] = f.readUint16LE();
+ _characterCarried[j] = (int8)f.readByte();
+ _characterBehindDist[j] = (int8)f.readByte();
+ _characterAboveDist[j] = f.readByte();
+ _spriteSizeArray[j] = f.readByte();
+ _characterDirectionArray[j] = f.readByte();
+ _characterMobility[j] = f.readByte();
+ _characterTypes[j] = f.readByte();
+ _characterBehaviour[j] = f.readByte();
+ _characterHomePos[j].x = f.readByte();
+ _characterHomePos[j].y = f.readByte();
+
+ for (int k = 0; k < 32; k++)
+ _characterVariables[(j * 32) + k] = f.readByte();
+
+ for (int k = 0; k < 32; k++)
+ _poseArray[(j * 32) + k] = f.readByte();
+ }
+
+ // Chunk 3 & 4 : Packed strings & associated indexes
+ _packedStringNumb = f.readSint16LE();
+ curWord = f.readSint16LE();
+
+ _packedStringIndex = (int *)malloc(sizeof(int) * _packedStringNumb);
+ for (int i = 0; i < _packedStringNumb; ++i)
+ _packedStringIndex[i] = f.readUint16LE();
+
+ _packedStrings = (char *)malloc(curWord);
+ for (int i = 0; i < curWord; ++i)
+ _packedStrings[i] = f.readByte();
+
+ // Chunk 5: Scripts
+ // Use byte instead of int, therefore multiply by two the size.
+ // This is for converting it into a memory read stream
+ _initScriptSize = f.readUint16LE() * 2;
+ _initScript = (byte *)malloc(_initScriptSize);
+ for (int i = 0; i < _initScriptSize; ++i)
+ _initScript[i] = f.readByte();
+
+ // Chunk 6: Menu Script
+ _menuScriptSize = f.readUint16LE() * 2;
+ _menuScript = (byte *)malloc(sizeof(byte) * _menuScriptSize);
+ for (int i = 0; i < _menuScriptSize; ++i)
+ _menuScript[i] = f.readByte();
+
+ // Chunk 7 & 8: Game scripts and indexes
+ _gameScriptIndexSize = f.readUint16LE();
+ // Added one position to keep the total size too, as it's useful later
+ _arrayGameScriptIndex = (int *)malloc(sizeof(int) * (_gameScriptIndexSize + 1));
+ for (int i = 0; i < _gameScriptIndexSize; ++i)
+ _arrayGameScriptIndex[i] = f.readUint16LE();
+
+ curWord = f.readUint16LE();
+ _arrayGameScriptIndex[_gameScriptIndexSize] = curWord;
+
+ _arrayGameScripts = (byte *)malloc(sizeof(byte) * curWord);
+ for (int i = 0; i < curWord; ++i)
+ _arrayGameScripts[i] = f.readByte();
+
+ // Chunk 9 : Cube flags
+ for (int i = 0; i < 60; i++)
+ _cubeFlags[i] = f.readByte();
+
+ // Chunk 10 & 11 : Lists
+ _listNumb = f.readByte();
+ assert(_listNumb <= 20);
+
+ if (_listNumb != 0) {
+ _listIndex = (int16 *)malloc(sizeof(int16) * _listNumb);
+ int totalSize = 0;
+ for (int i = 0; i < _listNumb; ++i) {
+ _listIndex[i] = totalSize;
+ totalSize += f.readByte();
+ }
+ if (totalSize != 0) {
+ _listArr = (byte *)malloc(sizeof(byte) * totalSize);
+ for (int i = 0; i < totalSize; i++)
+ _listArr[i] = f.readByte();
+ }
+ }
+
+ // Chunk 12
+ _rectNumb = f.readUint16LE();
+ assert((_rectNumb >= 0) && (_rectNumb <= 40));
+
+ for (int i = 0; i < _rectNumb; i++) {
+ _enclosureRect[i].right = (int16)f.readByte();
+ _enclosureRect[i].left = (int16)f.readByte();
+ _enclosureRect[i].bottom = (int16)f.readByte();
+ _enclosureRect[i].top = (int16)f.readByte();
+
+ int16 tmpValY = (int16)f.readByte();
+ int16 tmpValX = (int16)f.readByte();
+ _keyPos[i] = Common::Point(tmpValX, tmpValY);
+
+ tmpValY = (int16)f.readByte();
+ tmpValX = (int16)f.readByte();
+ _portalPos[i] = Common::Point(tmpValX, tmpValY);
+ }
+
+ // Chunk 13
+ _interfaceHotspotNumb = f.readUint16LE();
+ for (int i = 0 ; i < 20; i++)
+ _interfaceTwoStepAction[i] = f.readByte();
+
+ for (int i = 0 ; i < 20; i++)
+ _interfaceHotspots[i].x = f.readSint16LE();
+
+ for (int i = 0 ; i < 20; i++)
+ _interfaceHotspots[i].y = f.readSint16LE();
+
+ for (int i = 0; i < 20; i++) {
+ byte curByte = f.readByte();
+
+ if (curByte == 0x20)
+ _keyboardMapping[i] = Common::KEYCODE_SPACE;
+ else if (curByte == 0xD)
+ _keyboardMapping[i] = Common::KEYCODE_RETURN;
+ // Hack to avoid xlat out of bounds
+ else if (curByte == 0xFF)
+ _keyboardMapping[i] = Common::KEYCODE_INVALID; // 0x21; ?
+ // Hack to avoid xlat out of bounds
+ else if (curByte == 0x00)
+ _keyboardMapping[i] = Common::KEYCODE_INVALID; // 0xB4; ?
+ else {
+ assert((curByte > 0x40) && (curByte <= 0x41 + 26));
+ _keyboardMapping[i] = keybMappingArray[curByte - 0x41];
+ }
+ }
+ f.close();
+}
+
+void LilliputEngine::displayVGAFile(Common::String fileName) {
+ debugC(1, kDebugEngine, "displayVGAFile(%s)", fileName.c_str());
+
+ byte *buffer = loadVGA(fileName, 64000, true);
+ memcpy(_mainSurface->getPixels(), buffer, 320*200);
+ _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
+ _system->updateScreen();
+}
+
+void LilliputEngine::fixPaletteEntries(uint8 *palette, int num) {
+ debugC(1, kDebugEngine, "fixPaletteEntries(palette, %d)", num);
+ // Color values are coded on 6bits (for old 6bits DAC)
+ for (int32 i = 0; i < num * 3; i++) {
+ int32 col = palette[i];
+ assert(col < 64);
+
+ col = (col << 2) | (col >> 4);
+ if (col > 255)
+ col = 255;
+ palette[i] = col;
+ }
+}
+
+void LilliputEngine::initPalette() {
+ debugC(1, kDebugEngine, "initPalette()");
+
+ for (int i = 0; i < 768; i++)
+ _curPalette[i] = _basisPalette[i];
+
+ fixPaletteEntries(_curPalette, 256);
+ _system->getPaletteManager()->setPalette(_curPalette, 0, 256);
+}
+
+void LilliputEngine::setCurrentCharacter(int index) {
+ debugC(1, kDebugEngine, "setCurrentCharacter(%d)", index);
+
+ assert(index < 40);
+ _currentScriptCharacter = index;
+ _currentScriptCharacterPos = Common::Point(_characterPos[index].x >> 3, _characterPos[index].y >> 3);
+ _currentCharacterAttributes = getCharacterAttributesPtr(_currentScriptCharacter * 32);
+}
+
+void LilliputEngine::unselectInterfaceButton() {
+ debugC(1, kDebugEngine, "unselectInterfaceButton()");
+
+ _delayedReactivationAction = false;
+ _displayGreenHand = false;
+ _lastInterfaceHotspotButton = 0;
+ unselectInterfaceHotspots();
+ displayInterfaceHotspots();
+}
+
+void LilliputEngine::handleMenu() {
+ debugC(1, kDebugEngine, "handleMenu()");
+
+ if (_actionType == kActionNone)
+ return;
+
+ if (_delayedReactivationAction && (_actionType != kActionTalk))
+ return;
+
+ setCurrentCharacter(_host);
+ debugC(1, kDebugScriptTBC, "========================== Menu Script ==============================");
+ _scriptHandler->runMenuScript(ScriptStream(_menuScript, _menuScriptSize));
+ debugC(1, kDebugScriptTBC, "========================== End of Menu Script==============================");
+ _savedMousePosDivided = Common::Point(-1, -1);
+ _selectedCharacterId = -1;
+
+ if (_actionType == kActionTalk)
+ unselectInterfaceButton();
+
+ _actionType = kActionNone;
+}
+
+void LilliputEngine::handleGameScripts() {
+ debugC(1, kDebugEngine, "handleGameScripts()");
+
+ int index = _nextCharacterIndex;
+ int i;
+ for (i = 0; (_scriptHandler->_characterScriptEnabled[index] == 0) && (i < _numCharacters); i++) {
+ ++index;
+ if (index >= _numCharacters)
+ index = 0;
+ }
+
+ if (i > _numCharacters)
+ return;
+
+ _nextCharacterIndex = (index + 1) % _numCharacters;
+
+ _scriptHandler->_characterScriptEnabled[index] = 0;
+ setCurrentCharacter(index);
+
+ _waitingSignal = _characterSignals[index] >> 8;
+ _waitingSignalCharacterId = _characterSignals[index] & 0xFF;
+ _characterSignals[index] = -1;
+ _newModesEvaluatedNumber = 0;
+
+ int tmpVal = _characterBehaviour[index];
+ if (tmpVal == 0xFF)
+ return;
+
+ /* Decompiler follows
+
+ //_scriptHandler->listAllTexts();
+
+ debugC(1, kDebugEngineTBC, "================= Menu Script ==================");
+ ScriptStream script = ScriptStream(_menuScript, _menuScriptSize);
+ _scriptHandler->disasmScript(script);
+ debugC(1, kDebugEngineTBC, "============= End Menu Script ==================");
+
+
+ for (int i = 0; i < _gameScriptIndexSize; i++) {
+ assert(tmpVal < _gameScriptIndexSize);
+ debugC(1, kDebugEngineTBC, "================= Game Script %d ==================", i);
+ ScriptStream script = ScriptStream(&_arrayGameScripts[_arrayGameScriptIndex[i]], _arrayGameScriptIndex[i + 1] - _arrayGameScriptIndex[i]);
+ _scriptHandler->disasmScript(script);
+ debugC(1, kDebugEngineTBC, "============= End Game Script %d ==================", i);
+ }
+
+ while (1);
+ */
+
+ //i = index;
+ //debugC(1, kDebugEngineTBC, "before char %d, pos %d %d, var0 %d, var1 %d, var2 %d var16 %d, script enabled %d", i, _characterPositionX[i], _characterPositionY[i], *getCharacterVariablesPtr(i * 32 + 0), *getCharacterVariablesPtr(i * 32 + 1), *getCharacterVariablesPtr(i * 32 + 2), *getCharacterVariablesPtr(i * 32 + 22), _scriptHandler->_characterScriptEnabled[i]);
+
+ assert(tmpVal < _gameScriptIndexSize);
+ debugC(1, kDebugEngine, "================= Game Script %d for character %d ==================", tmpVal, index);
+ _scriptHandler->runScript(ScriptStream(&_arrayGameScripts[_arrayGameScriptIndex[tmpVal]], _arrayGameScriptIndex[tmpVal + 1] - _arrayGameScriptIndex[tmpVal]));
+ debugC(1, kDebugEngine, "============= End Game Script %d for character %d ==================", tmpVal, index);
+
+ //warning("dump char stat");
+ //debugC(1, kDebugEngineTBC, "after char %d, pos %d %d, var0 %d, var1 %d, var2 %d var16 %d, script enabled %d", i, _characterPositionX[i], _characterPositionY[i], *getCharacterVariablesPtr(i * 32 + 0), *getCharacterVariablesPtr(i * 32 + 1), *getCharacterVariablesPtr(i * 32 + 2), *getCharacterVariablesPtr(i * 32 + 22), _scriptHandler->_characterScriptEnabled[i]);
+}
+
+Common::Error LilliputEngine::run() {
+ debugC(1, kDebugEngine, "run()");
+
+ s_Engine = this;
+ initialize();
+ initGraphics(320, 200);
+ _mainSurface = new Graphics::Surface();
+ _mainSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+
+ // Setup mixer
+ syncSoundSettings();
+ _soundHandler->init();
+
+ // Init palette
+ initPalette();
+
+ // Load files. In the original, the size was hardcoded
+ _bufferIdeogram = loadVGA("IDEOGRAM.VGA", 25600, false);
+ _bufferMen = loadVGA("MEN.VGA", 61440, false);
+ _bufferMen2 = loadVGA("MEN2.VGA", 61440, false);
+ _bufferIsoChars = loadVGA("ISOCHARS.VGA", 4096, false);
+ _bufferIsoMap = loadRaw("ISOMAP.DTA", 16384);
+ _normalCursor = &_bufferIdeogram[80 * 16 * 16];
+ _greenCursor = &_bufferIdeogram[81 * 16 * 16];
+
+ CursorMan.replaceCursor(_normalCursor, 16, 16, 0, 0, 0);
+ CursorMan.showMouse(true);
+
+ loadRules();
+
+ _lastTime = _system->getMillis();
+ _scriptHandler->runScript(ScriptStream(_initScript, _initScriptSize));
+
+ while (!_shouldQuit) {
+ handleMenu();
+ handleGameScripts();
+ // To be removed when handled in the previous fonctions
+ update();
+ }
+
+ return Common::kNoError;
+}
+
+void LilliputEngine::initialize() {
+ debugC(1, kDebugEngine, "initialize");
+
+ _rnd = new Common::RandomSource("robin");
+ _rnd->setSeed(42); // Kick random number generator
+ _shouldQuit = false;
+
+ for (int i = 0; i < 4; i++) {
+ _smallAnims[i]._active = false;
+ _smallAnims[i]._pos = Common::Point(0, 0);
+ for (int j = 0; j < 8; j ++)
+ _smallAnims[i]._frameIndex[j] = 0;
+ }
+}
+
+byte *LilliputEngine::getCharacterAttributesPtr(int16 index) {
+ debugC(1, kDebugEngine, "getCharacterVariablesPtr(%d)", index);
+
+ assert((index > -3120) && (index < 1400));
+ if (index >= 0)
+ return &_characterVariables[index];
+ else
+ return &_characterVariables[1400 - index];
+}
+
+void LilliputEngine::syncSoundSettings() {
+ Engine::syncSoundSettings();
+
+// _sound->syncVolume();
+}
+
+Common::String LilliputEngine::getSavegameFilename(int slot) {
+ return _targetName + Common::String::format("-%02d.SAV", slot);
+}
+
+Common::Event LilliputEngine::_keyboard_getch() {
+ warning("getch()");
+ while(_keyboard_nextIndex == _keyboard_oldIndex)
+ pollEvent();
+
+ Common::Event tmpEvent = _keyboard_buffer[_keyboard_oldIndex];
+ _keyboard_oldIndex = (_keyboard_oldIndex + 1) % 8;
+
+ return tmpEvent;
+}
+
+bool LilliputEngine::_keyboard_checkKeyboard() {
+ return (_keyboard_nextIndex != _keyboard_oldIndex);
+}
+
+void LilliputEngine::_keyboard_resetKeyboardBuffer() {
+ _keyboard_nextIndex = _keyboard_oldIndex = 0;
+}
+
+} // End of namespace Lilliput
diff --git a/engines/lilliput/lilliput.h b/engines/lilliput/lilliput.h
new file mode 100644
index 0000000000..cb4e43c3da
--- /dev/null
+++ b/engines/lilliput/lilliput.h
@@ -0,0 +1,384 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LILLIPUT_LILLIPUT_H
+#define LILLIPUT_LILLIPUT_H
+
+#include "lilliput/console.h"
+#include "lilliput/script.h"
+#include "lilliput/sound.h"
+#include "lilliput/stream.h"
+
+#include "common/file.h"
+#include "common/rect.h"
+#include "common/events.h"
+
+#include "engines/engine.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+namespace Common {
+class RandomSource;
+}
+
+/**
+ * This is the namespace of the Lilliput engine.
+ *
+ * Status of this engine:
+ * - Adventures of Robin Hood is mostly working without sound
+ *
+ * Games using this engine:
+ * - Adventures of Robin Hood
+ * - Rome: Pathway to Rome
+ */
+namespace Lilliput {
+
+static const int kSavegameVersion = 1;
+
+enum GameType {
+ kGameTypeNone = 0,
+ kGameTypeRobin,
+ kGameTypeRome
+};
+
+enum LilliputDebugChannels {
+ kDebugEngine = 1 << 0,
+ kDebugScript = 1 << 1,
+ kDebugSound = 1 << 2,
+ kDebugEngineTBC = 1 << 3,
+ kDebugScriptTBC = 1 << 4
+};
+
+enum InterfaceHotspotStatus {
+ kHotspotOff = 0,
+ kHotspotDisabled = 1,
+ kHotspotEnabled = 2,
+ kHotspotSelected = 3
+};
+
+#define kSeqNone 0
+#define kSeqNoInc 1 << 0
+#define kSeqRepeat 1 << 1
+
+struct LilliputGameDescription;
+
+struct SmallAnim {
+ bool _active;
+ Common::Point _pos;
+ int16 _frameIndex[8];
+};
+
+class LilliputEngine : public Engine {
+public:
+ LilliputEngine(OSystem *syst, const LilliputGameDescription *gd);
+ ~LilliputEngine();
+
+ OSystem *_system;
+
+ GUI::Debugger *getDebugger();
+
+ Common::RandomSource *_rnd;
+ LilliputScript *_scriptHandler;
+ LilliputSound *_soundHandler;
+ Graphics::Surface *_mainSurface;
+
+ SmallAnim _smallAnims[4];
+ int _smallAnimsFrameIndex;
+
+ byte _handleOpcodeReturnCode;
+ byte _keyDelay;
+ byte _lastAnimationTick;
+ byte _animationTick;
+ Common::Point _nextDisplayCharacterPos;
+ byte _int8Timer;
+ Common::Event _lastKeyPressed;
+ Common::EventType _lastEventType;
+ byte _keyboard_nextIndex;
+ byte _keyboard_oldIndex;
+ Common::Event _keyboard_buffer[8];
+ byte _byte12A05;
+ bool _refreshScreenFlag;
+ byte _byte16552;
+ int8 _lastInterfaceHotspotIndex;
+ byte _lastInterfaceHotspotButton; // Unused: set by 2 functions, but never used elsewhere
+ byte _debugFlag; // Mostly useless, as the associated functions are empty
+ byte _debugFlag2; // Unused byte, set by an opcode
+
+ byte _codeEntered[3];
+ char _homeInDirLikelyhood[4];
+ byte *_bufferIsoMap;
+ byte *_bufferCubegfx;
+ byte *_bufferMen;
+ byte *_bufferMen2;
+ byte *_bufferIsoChars;
+ byte *_bufferIdeogram;
+ byte *_normalCursor;
+ byte *_greenCursor;
+ byte _curPalette[768];
+ byte _displayStringBuf[160];
+
+ bool _saveFlag;
+ bool _displayMap;
+
+ int _word10800_ERULES;
+ byte _numCharacters;
+ Common::Point _currentScriptCharacterPos;
+ int _nextCharacterIndex;
+ int8 _waitingSignal;
+ int8 _waitingSignalCharacterId;
+ uint16 _newModesEvaluatedNumber;
+ Common::Point _savedSurfaceUnderMousePos;
+ bool _displayGreenHand;
+ bool _isCursorGreenHand;
+ int _currentDisplayCharacter;
+ int _displayStringIndex;
+ int _signalTimer;
+ Common::Point _curCharacterTilePos;
+
+ int16 _mapSavedPixelIndex[40];
+ byte _mapSavedPixel[40];
+ int16 _characterSignals[40];
+ int16 _signalArr[40];
+ int16 _signalArray[30];
+
+ byte *_sequencesArr;
+ int16 _currentScriptCharacter;
+ Common::Point _characterPos[40];
+ int8 _characterPosAltitude[40];
+ int16 _characterFrameArray[40];
+ int8 _characterCarried[40];
+ int8 _characterBehindDist[40];
+ byte _characterAboveDist[40];
+ byte _spriteSizeArray[40];
+ byte _characterDirectionArray[40];
+ byte _characterMobility[40];
+ byte _characterTypes[40];
+ byte _characterBehaviour[40];
+ Common::Point _characterHomePos[40];
+ byte _characterVariables[1400 + 3120];
+ byte *_currentCharacterAttributes;
+ byte _poseArray[40 * 32];
+ int *_packedStringIndex;
+ int _packedStringNumb;
+ char *_packedStrings;
+ byte *_initScript;
+ int _initScriptSize;
+ byte *_menuScript;
+ int _menuScriptSize;
+ int *_arrayGameScriptIndex;
+ int _gameScriptIndexSize;
+ byte *_arrayGameScripts;
+ byte _cubeFlags[60];
+ byte _listNumb;
+ int16 *_listIndex;
+ byte *_listArr;
+ int16 _rectNumb;
+ Common::Rect _enclosureRect[40];
+ Common::Point _keyPos[40];
+ Common::Point _portalPos[40];
+ int _interfaceHotspotNumb;
+ byte _interfaceTwoStepAction[20];
+ Common::Point _interfaceHotspots[20];
+ Common::KeyCode _keyboardMapping[20];
+ Common::Point _characterTargetPos[40];
+ byte _savedSurfaceUnderMouse[16 * 16];
+ byte _charactersToDisplay[40];
+ Common::Point _characterRelativePos[40];
+ Common::Point _characterDisplay[40];
+ int8 _characterMagicPuffFrame[40];
+ Common::Point _characterSubTargetPos[40];
+ byte _specialCubes[40];
+ byte _doorEntranceMask[4];
+ byte _doorExitMask[4];
+ byte _savedSurfaceGameArea1[176 * 256]; // 45056
+ byte _savedSurfaceGameArea2[176 * 256]; // 45056
+ byte _savedSurfaceGameArea3[176 * 256]; // 45056
+ byte _savedSurfaceSpeech[16 * 252];
+
+ const LilliputGameDescription *_gameDescription;
+ uint32 getFeatures() const;
+ const char *getGameId() const;
+
+ void newInt8();
+ void update();
+
+ void display16x16IndexedBuf(byte *buf, int index, Common::Point pos, bool transparent = true, bool updateScreen = true);
+ void display16x16Buf(byte *buf, Common::Point pos, bool transparent = true, bool updateScreen = true);
+ void fill16x16Rect(byte col, Common::Point pos);
+ void saveSurfaceGameArea();
+ void saveSurfaceSpeech();
+ void displayInterfaceHotspots();
+ void displayLandscape();
+ void displaySpeechBubble();
+ void displaySpeech(byte *buf);
+ void initGameAreaDisplay();
+ void displayIsometricBlock(byte *buf, int var1, int posX, int posY, int var3);
+ void displayGameArea();
+ void prepareGameArea();
+ void displayRefreshScreen();
+ void restoreSurfaceSpeech();
+ void displayCharacterStatBar(int8 type, int16 averagePosX, int8 score, int16 posY);
+ void displayCharacter(int index, Common::Point pos, int flags);
+ void displayString(byte *buf, Common::Point pos);
+ void displayChar(int index, int var1);
+ void displaySmallAnims();
+ void displaySmallIndexedAnim(byte index, byte subIndex);
+
+ void unselectInterfaceHotspots();
+ void startNavigateFromMap();
+ void resetSmallAnims();
+ void paletteFadeOut();
+ void paletteFadeIn();
+
+ void sortCharacters();
+ void scrollToViewportCharacterTarget();
+ void viewportScrollTo(Common::Point goalPos);
+ void checkSpeechClosing();
+ void updateCharPosSequence();
+ void evaluateDirections(int index);
+ byte homeInAvoidDeadEnds(int indexb, int indexs);
+ void signalDispatcher(byte type, byte index, int var4);
+ void sendMessageToCharacter(byte index, int var4);
+ int16 checkEnclosure(Common::Point pos);
+ int16 checkOuterEnclosure(Common::Point pos);
+ byte sequenceSetMobility(int index, Common::Point var1);
+ byte sequenceEnd(int index);
+ void homeInPathFinding(int index);
+
+ void renderCharacters(byte *buf, Common::Point pos);
+
+ void checkNumericCode();
+ void keyboard_handleInterfaceShortcuts(bool &forceReturnFl);
+ byte sequenceCharacterHomeIn(int index, Common::Point param1);
+ byte getDirection(Common::Point param1, Common::Point param2);
+ void addCharToBuf(byte character);
+ void numberToString(int param1);
+ void handleCharacterTimers();
+ byte sequenceMoveCharacter(int idx, int moveType, int poseType);
+ void setCharacterPose(int idx, int poseIdx);
+ void checkSpecialCubes();
+ void checkInteractions();
+ byte sequenceSetCharacterDirection(int index, int direction, int poseType);
+ void handleSignals();
+ void checkInterfaceActivationDelay();
+ int16 checkObstacle(int x1, int y1, int x2, int y2);
+ void displayCharactersOnMap();
+ void restoreMapPoints();
+ void displayHeroismIndicator();
+ void handleGameMouseClick();
+ void handleInterfaceHotspot(byte index, byte button);
+ void checkInterfaceHotspots(bool &forceReturnFl);
+ bool isMouseOverHotspot(Common::Point mousePos, Common::Point hotspotPos);
+ void checkClickOnCharacter(Common::Point pos, bool &forceReturnFl);
+ void checkClickOnGameArea(Common::Point pos);
+ void displaySpeechBubbleTail(Common::Point displayPos);
+ void displaySpeechBubbleTailLine(Common::Point pos, int var2);
+ void displaySpeechLine(int vgaIndex, byte *srcBuf, int &bufIndex);
+ void checkMapClosing(bool &forceReturnFl);
+ void turnCharacter1(int index);
+ void turnCharacter2(int index);
+ void moveCharacterUp1(int index);
+ void moveCharacterUp2(int index);
+ void moveCharacterDown1(int index);
+ void moveCharacterDown2(int index);
+ void moveCharacterSpeed2(int index);
+ void moveCharacterSpeed4(int index);
+ void moveCharacterBack2(int index);
+ void moveCharacterSpeed3(int index);
+ void moveCharacterForward(int index, int16 speed);
+ void checkCollision(int index, Common::Point pos, int direction);
+ byte sequenceSeekMovingCharacter(int index, Common::Point var1);
+ byte sequenceSound(int index, Common::Point var1);
+ byte sequenceRepeat(int index, Common::Point var1, int tmpVal);
+ void homeInChooseDirection(int index);
+
+ void initGame(const LilliputGameDescription *gd);
+ byte *loadVGA(Common::String filename, int fileSize, bool loadPal);
+ byte *loadRaw(Common::String filename, int filesize);
+ void loadRules();
+
+ void displayVGAFile(Common::String fileName);
+ void initPalette();
+ void fixPaletteEntries(uint8 *palette, int num);
+
+ GameType getGameType() const;
+ Common::Platform getPlatform() const;
+
+ bool hasFeature(EngineFeature f) const;
+ const char *getCopyrightString() const;
+
+ Common::String getSavegameFilename(int slot);
+ void syncSoundSettings();
+
+ Common::Point _mousePos;
+ Common::Point _oldMousePos;
+ Common::Point _mouseDisplayPos;
+ int _mouseButton;
+ bool _mouseClicked;
+ Common::EventType _mousePreviousEventType;
+ Common::Point _savedMousePosDivided;
+ int _skipDisplayFlag1;
+ int _skipDisplayFlag2;
+
+ byte _actionType;
+ bool _delayedReactivationAction;
+ int8 _selectedCharacterId;
+ byte _numCharactersToDisplay;
+ int16 _host;
+ bool _shouldQuit;
+
+ void pollEvent();
+ void setCurrentCharacter(int index);
+ void unselectInterfaceButton();
+ void moveCharacters();
+ void setNextDisplayCharacter(int var1);
+ void handleGameScripts();
+
+ // Added by Strangerke
+ byte *getCharacterAttributesPtr(int16 index);
+
+ // Temporary stubs
+ Common::Event _keyboard_getch();
+ bool _keyboard_checkKeyboard();
+ void _keyboard_resetKeyboardBuffer();
+
+protected:
+ Common::EventManager *_eventMan;
+ int _lastTime;
+
+ // Engine APIs
+ Common::Error run();
+ void handleMenu();
+
+private:
+ static LilliputEngine *s_Engine;
+
+ LilliputConsole *_console;
+ GameType _gameType;
+ Common::Platform _platform;
+
+ void initialize();
+};
+
+} // End of namespace Lilliput
+
+#endif
diff --git a/engines/lilliput/module.mk b/engines/lilliput/module.mk
new file mode 100644
index 0000000000..8a095e8045
--- /dev/null
+++ b/engines/lilliput/module.mk
@@ -0,0 +1,20 @@
+MODULE := engines/lilliput
+
+MODULE_OBJS = \
+ console.o \
+ detection.o \
+ lilliput.o \
+ script.o \
+ sound.o \
+ stream.o
+
+MODULE_DIRS += \
+ engines/lilliput
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_LILLIPUT), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/lilliput/script.cpp b/engines/lilliput/script.cpp
new file mode 100644
index 0000000000..cc78c31d37
--- /dev/null
+++ b/engines/lilliput/script.cpp
@@ -0,0 +1,3355 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "lilliput/lilliput.h"
+#include "lilliput/script.h"
+#include "common/debug.h"
+
+#include "common/system.h"
+#include <climits>
+
+namespace Lilliput {
+
+LilliputScript::LilliputScript(LilliputEngine *vm) : _vm(vm), _currScript(NULL) {
+ _cubeSet = 0;
+ _lastRandomValue = 0;
+ _scriptForVal = 0;
+ _textVarNumber = 0;
+ _speechDisplaySpeed = 3;
+ _speechTimer = 0;
+ _word16F00_characterId = -1;
+ _monitoredCharacter = 0;
+ _viewportCharacterTarget = -1;
+ _heroismBarX = 0;
+ _heroismBarBottomY = 0;
+ _viewportPos.x = 0;
+ _viewportPos.y = 0;
+ _currentSpeechId = 0;
+ _monitoredAttr[0] = 0;
+ _monitoredAttr[1] = 1;
+ _monitoredAttr[2] = 2;
+ _monitoredAttr[3] = 3;
+ _barAttrPtr = NULL;
+ _word1825E = Common::Point(0, 0);
+
+ for (int i = 0; i < 20; i++) {
+ _interfaceHotspotStatus[i] = kHotspotOff;
+ _interfaceButtonActivationDelay[i] = 0;
+ }
+
+ for (int i = 0; i < 32; i++) {
+ _newEvaluatedModes[i]._mode = 0;
+ _newEvaluatedModes[i]._priority = 0;
+ }
+
+ for (int i = 0; i < 40; i++) {
+ _characterScriptEnabled[i] = 1;
+ _characterMapPixelColor[i] = 15;
+ _characterPose[i] = 0;
+ _characterNextSequence[i] = 16;
+ _characterLastSequence[i] = -1;
+ _characterTilePos[i] = Common::Point(0, 0);
+ _array122C1[i] = 0;
+ }
+
+ for (int i = 0; i < 640; i++) {
+ _sequenceArr[i] = Common::Point(-1, -1);
+ }
+
+ for (int i = 0; i < 1600; i++)
+ _interactions[i] = 0;
+
+ _heroismLevel = 0;
+ _talkingCharacter = -1;
+ _byte16F05_ScriptHandler = 0;
+ _word18821 = 0;
+}
+
+LilliputScript::~LilliputScript() {
+}
+
+byte LilliputScript::handleOpcodeType1(int curWord) {
+ debugC(2, kDebugScript, "handleOpcodeType1(0x%x)", curWord);
+ switch (curWord) {
+ case 0x0:
+ return OC_checkCharacterGoalPos();
+ break;
+ case 0x1:
+ return OC_comparePos();
+ break;
+ case 0x2:
+ return OC_checkIsoMap3();
+ break;
+ case 0x3:
+ return OC_compareCharacterVariable();
+ break;
+ case 0x4:
+ return OC_CompareLastRandomValue();
+ break;
+ case 0x5:
+ return OC_getRandom();
+ break;
+ case 0x6:
+ return OC_for();
+ break;
+ case 0x7:
+ return OC_compCurrentSpeechId();
+ break;
+ case 0x8:
+ return OC_checkSaveFlag();
+ break;
+ case 0x9:
+ return OC_compScriptForVal();
+ break;
+ case 0xA:
+ return OC_isCarrying();
+ break;
+ case 0xB:
+ return OC_CompareCharacterVariables();
+ break;
+ case 0xC:
+ return OC_compareCoords_1();
+ break;
+ case 0xD:
+ return OC_compareCoords_2();
+ break;
+ case 0xE:
+ return OC_CompareDistanceFromCharacterToPositionWith();
+ break;
+ case 0xF:
+ return OC_compareRandomCharacterId();
+ break;
+ case 0x10:
+ return OC_IsCurrentCharacterIndex();
+ break;
+ case 0x11:
+ return OC_hasVisibilityLevel();
+ break;
+ case 0x12:
+ return OC_hasGainedVisibilityLevel();
+ break;
+ case 0x13:
+ return OC_hasReducedVisibilityLevel();
+ break;
+ case 0x14:
+ return OC_isHost();
+ break;
+ case 0x15:
+ return OC_isSequenceActive();
+ break;
+ case 0x16:
+ return OC_isSequenceFinished();
+ break;
+ case 0x17:
+ return OC_CompareMapValueWith();
+ break;
+ case 0x18:
+ return OC_IsCharacterValid();
+ break;
+ case 0x19:
+ return OC_CheckWaitingSignal();
+ break;
+ case 0x1A:
+ return OC_CurrentCharacterVar0AndVar1Equals();
+ break;
+ case 0x1B:
+ return OC_CurrentCharacterVar0Equals();
+ break;
+ case 0x1C:
+ return OC_checkLastInterfaceHotspotIndexMenu13();
+ break;
+ case 0x1D:
+ return OC_checkLastInterfaceHotspotIndexMenu2();
+ break;
+ case 0x1E:
+ return OC_CompareNumberOfCharacterWithVar0Equals();
+ break;
+ case 0x1F:
+ return OC_IsPositionInViewport();
+ break;
+ case 0x20:
+ return OC_CompareGameVariables();
+ break;
+ case 0x21:
+ return OC_skipNextOpcode();
+ break;
+ case 0x22:
+ return OC_CheckCurrentCharacterAttr2();
+ break;
+ case 0x23:
+ return OC_CheckCurrentCharacterType();
+ break;
+ case 0x24:
+ return OC_CheckCurrentCharacterAttr0And();
+ break;
+ case 0x25:
+ return OC_IsCurrentCharacterAttr0LessEqualThan();
+ break;
+ case 0x26:
+ return OC_isCarried();
+ break;
+ case 0x27:
+ return OC_CheckCurrentCharacterAttr1();
+ break;
+ case 0x28:
+ return OC_isCurrentCharacterSpecial();
+ break;
+ case 0x29:
+ return OC_CurrentCharacterAttr3Equals1();
+ break;
+ case 0x2A:
+ return OC_checkCharacterDirection();
+ break;
+ case 0x2B:
+ return OC_checkLastInterfaceHotspotIndex();
+ break;
+ case 0x2C:
+ return OC_checkSelectedCharacter();
+ break;
+ case 0x2D:
+ return OC_checkDelayedReactivation();
+ break;
+ case 0x2E:
+ return OC_checkTargetReached();
+ break;
+ case 0x2F:
+ return OC_checkFunctionKeyPressed();
+ break;
+ case 0x30:
+ return OC_checkCodeEntered();
+ break;
+ case 0x31:
+ return OC_checkViewPortCharacterTarget();
+ break;
+ default:
+ error("Unexpected opcode %d", curWord);
+ break;
+ }
+}
+
+void LilliputScript::handleOpcodeType2(int curWord) {
+ debugC(2, kDebugScript, "handleOpcodeType2(0x%x)", curWord);
+ switch (curWord) {
+ case 0x0:
+ OC_setWord18821();
+ break;
+ case 0x1:
+ OC_ChangeIsoMap();
+ break;
+ case 0x2:
+ OC_startSpeech();
+ break;
+ case 0x3:
+ OC_getComputedVariantSpeech();
+ break;
+ case 0x4:
+ OC_getRotatingVariantSpeech();
+ break;
+ case 0x5:
+ OC_startSpeechIfMute();
+ break;
+ case 0x6:
+ OC_getComputedVariantSpeechIfMute();
+ break;
+ case 0x7:
+ OC_startSpeechIfSilent();
+ break;
+ case 0x8:
+ OC_ComputeCharacterVariable();
+ break;
+ case 0x9:
+ OC_setAttributeToRandom();
+ break;
+ case 0xA:
+ OC_setCharacterPosition();
+ break;
+ case 0xB:
+ OC_DisableCharacter();
+ break;
+ case 0xC:
+ OC_saveAndQuit();
+ break;
+ case 0xD:
+ OC_nSkipOpcodes();
+ break;
+ case 0xE:
+ OC_startSpeech5();
+ break;
+ case 0xF:
+ OC_resetHandleOpcodeFlag();
+ break;
+ case 0x10:
+ OC_deleteSavegameAndQuit();
+ break;
+ case 0x11:
+ OC_incScriptForVal();
+ break;
+ case 0x12:
+ OC_computeChararacterAttr();
+ break;
+ case 0x13:
+ OC_setTextVarNumber();
+ break;
+ case 0x14:
+ OC_callScript();
+ break;
+ case 0x15:
+ OC_callScriptAndReturn();
+ break;
+ case 0x16:
+ OC_setCurrentScriptCharacterPos();
+ break;
+ case 0x17:
+ OC_initScriptFor();
+ break;
+ case 0x18:
+ OC_setCurrentCharacterSequence();
+ break;
+ case 0x19:
+ OC_setNextCharacterSequence();
+ break;
+ case 0x1A:
+ OC_setHost();
+ break;
+ case 0x1B:
+ OC_changeMapCube();
+ break;
+ case 0x1C:
+ OC_setCharacterCarry();
+ break;
+ case 0x1D:
+ OC_dropCarried();
+ break;
+ case 0x1E:
+ OC_setCurrentCharacter();
+ break;
+ case 0x1F:
+ OC_sendSeeSignal();
+ break;
+ case 0x20:
+ OC_sendHearSignal();
+ break;
+ case 0x21:
+ OC_sendVarSignal();
+ break;
+ case 0x22:
+ OC_sendBroadcastSignal();
+ break;
+ case 0x23:
+ OC_resetWaitingSignal();
+ break;
+ case 0x24:
+ OC_enableCurrentCharacterScript();
+ break;
+ case 0x25:
+ OC_IncCurrentCharacterVar1();
+ break;
+ case 0x26:
+ OC_setCurrentCharacterPos();
+ break;
+ case 0x27:
+ OC_setCurrentCharacterBehavior();
+ break;
+ case 0x28:
+ OC_changeCurrentCharacterSprite();
+ break;
+ case 0x29:
+ OC_getList();
+ break;
+ case 0x2A:
+ OC_setList();
+ break;
+ case 0x2B:
+ OC_setCharacterDirectionTowardsPos();
+ break;
+ case 0x2C:
+ OC_turnCharacterTowardsAnother();
+ break;
+ case 0x2D:
+ OC_setSeek();
+ break;
+ case 0x2E:
+ OC_scrollAwayFromCharacter();
+ break;
+ case 0x2F:
+ OC_skipNextVal();
+ break;
+ case 0x30:
+ OC_setCurrentCharacterAttr6();
+ break;
+ case 0x31:
+ OC_setCurrentCharacterPose();
+ break;
+ case 0x32:
+ OC_setCharacterScriptEnabled();
+ break;
+ case 0x33:
+ OC_setCurrentCharacterAttr2();
+ break;
+ case 0x34:
+ OC_clearCurrentCharacterAttr2();
+ break;
+ case 0x35:
+ OC_setCharacterProperties();
+ break;
+ case 0x36:
+ OC_setMonitoredCharacter();
+ break;
+ case 0x37:
+ OC_setNewPose();
+ break;
+ case 0x38:
+ OC_setCurrentCharacterDirection();
+ break;
+ case 0x39:
+ OC_setInterfaceHotspot();
+ break;
+ case 0x3A:
+ OC_scrollViewPort();
+ break;
+ case 0x3B:
+ OC_setViewPortPos();
+ break;
+ case 0x3C:
+ OC_setCurrentCharacterAltitude();
+ break;
+ case 0x3D:
+ OC_setModePriority();
+ break;
+ case 0x3E:
+ OC_setComputedModePriority();
+ break;
+ case 0x3F:
+ OC_selectBestMode();
+ break;
+ case 0x40:
+ OC_magicPuffEntrance();
+ break;
+ case 0x41:
+ OC_spawnCharacterAtPos();
+ break;
+ case 0x42:
+ OC_CharacterVariableAddOrRemoveFlag();
+ break;
+ case 0x43:
+ OC_PaletteFadeOut();
+ break;
+ case 0x44:
+ OC_PaletteFadeIn();
+ break;
+ case 0x45:
+ OC_loadAndDisplayCubesGfx();
+ break;
+ case 0x46:
+ OC_setCurrentCharacterAttr3();
+ break;
+ case 0x47:
+ OC_setArray122C1();
+ break;
+ case 0x48:
+ OC_sub18367();
+ break;
+ case 0x49:
+ OC_enableCharacterScript();
+ break;
+ case 0x4A:
+ OC_setRulesBuffer2Element();
+ break;
+ case 0x4B:
+ OC_setDebugFlag();
+ break;
+ case 0x4C:
+ OC_setDebugFlag2();
+ break;
+ case 0x4D:
+ OC_waitForEvent();
+ break;
+ case 0x4E:
+ OC_disableInterfaceHotspot();
+ break;
+ case 0x4F:
+ OC_loadFileAerial();
+ break;
+ case 0x50:
+ OC_startSpeechIfSoundOff();
+ break;
+ case 0x51:
+ OC_sub1844A();
+ break;
+ case 0x52:
+ OC_displayNumericCharacterVariable();
+ break;
+ case 0x53:
+ OC_displayVGAFile();
+ break;
+ case 0x54:
+ OC_startSpeechWithoutSpeeker();
+ break;
+ case 0x55:
+ OC_displayTitleScreen();
+ break;
+ case 0x56:
+ OC_initGameAreaDisplay();
+ break;
+ case 0x57:
+ OC_displayCharacterStatBar();
+ break;
+ case 0x58:
+ OC_initSmallAnim();
+ break;
+ case 0x59:
+ OC_setCharacterHeroismBar();
+ break;
+ case 0x5A:
+ OC_setCharacterHome();
+ break;
+ case 0x5B:
+ OC_setViewPortCharacterTarget();
+ break;
+ case 0x5C:
+ OC_showObject();
+ break;
+ case 0x5D:
+ OC_playObjectSound();
+ break;
+ case 0x5E:
+ OC_startLocationSound();
+ break;
+ case 0x5F:
+ OC_stopObjectSound();
+ break;
+ case 0x60:
+ OC_stopLocationSound();
+ break;
+ case 0x61:
+ OC_toggleSound();
+ break;
+ case 0x62:
+ OC_playMusic();
+ break;
+ case 0x63:
+ OC_stopMusic();
+ break;
+ case 0x64:
+ OC_setCharacterMapColor();
+ break;
+ case 0x65:
+ OC_initGameAreaDisplay();
+ break;
+ default:
+ error("Unknown opcode %d", curWord);
+ break;
+ }
+}
+
+static const OpCode opCodes1[] = {
+ { "OC_checkCharacterGoalPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+ { "OC_comparePos", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone },
+ { "OC_checkIsoMap3", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_compareCharacterVariable", 4, kGetValue1, kImmediateValue, kCompareOperation, kImmediateValue, kNone },
+ { "OC_CompareLastRandomValue", 2, kCompareOperation, kImmediateValue, kNone, kNone, kNone },
+ { "OC_getRandom", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_for", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+ { "OC_compCurrentSpeechId", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_checkSaveFlag", 0, kNone, kNone, kNone, kNone, kNone },
+ { "OC_compScriptForVal", 2, kCompareOperation, kImmediateValue, kNone, kNone, kNone },
+ { "OC_isCarrying", 2, kGetValue1, kGetValue1, kNone, kNone, kNone },
+ { "OC_CompareCharacterVariables", 5, kGetValue1, kImmediateValue, kCompareOperation, kGetValue1, kImmediateValue },
+ { "OC_compareCoords_1", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_compareCoords_2", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+ { "OC_CompareDistanceFromCharacterToPositionWith", 3, kgetPosFromScript, kCompareOperation, kImmediateValue, kNone, kNone },
+ { "OC_compareRandomCharacterId", 3, kGetValue1, kCompareOperation, kImmediateValue, kNone, kNone },
+ { "OC_isCurrentCharacterIndex", 1, kGetValue1, kNone, kNone, kNone, kNone },
+ { "OC_hasVisibilityLevel", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },
+ { "OC_hasGainedVisibilityLevel", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },
+ { "OC_hasReducedVisibilityLevel", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone },
+ { "OC_isHost", 1, kGetValue1, kNone, kNone, kNone, kNone },
+ { "OC_isSequenceActive", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_isSequenceFinished", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_compareMapValueWith", 4, kgetPosFromScript, kImmediateValue, kImmediateValue, kCompareOperation, kNone },
+ { "OC_isCharacterValid", 1, kGetValue1, kNone, kNone, kNone, kNone },
+ { "OC_checkWaitingSignal", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_currentCharacterVar0AndVar1Equals", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+ { "OC_currentCharacterVar0Equals", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_checkLastInterfaceHotspotIndexMenu13", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_checkLastInterfaceHotspotIndexMenu2", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_compareNumberOfCharacterWithVar0Equals", 3, kImmediateValue, kCompareOperation, kImmediateValue, kNone, kNone },
+ { "OC_isPositionInViewport", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+ { "OC_compareGameVariables", 2, kGetValue1, kGetValue1, kNone, kNone, kNone },
+ { "OC_skipNextOpcode", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_CheckCurrentCharacterAttr2", 0, kNone, kNone, kNone, kNone, kNone },
+ { "OC_CheckCurrentCharacterType", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+ { "OC_CheckCurrentCharacterAttr0And", 3, kGetValue1, kImmediateValue, kImmediateValue, kNone, kNone },
+ { "OC_IsCurrentCharacterAttr0LessEqualThan", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_isCarried", 1, kGetValue1, kNone, kNone, kNone, kNone },
+ { "OC_CheckCurrentCharacterAttr1", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_isCurrentCharacterStung", 0, kNone, kNone, kNone, kNone, kNone },
+ { "OC_CurrentCharacterAttr3Equals1", 0, kNone, kNone, kNone, kNone, kNone },
+ { "OC_sub1796E", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+ { "OC_checkLastInterfaceHotspotIndex", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+ { "OC_checkSelectedCharacter", 0, kNone, kNone, kNone, kNone, kNone },
+ { "OC_checkDelayedReactivation", 0, kNone, kNone, kNone, kNone, kNone },
+ { "OC_checkTargetReached", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+ { "OC_checkFunctionKeyPressed", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+ { "OC_checkCodeEntered", 3, kImmediateValue, kImmediateValue, kImmediateValue, kNone, kNone },
+ { "OC_checkViewPortCharacterTarget", 1, kGetValue1, kNone, kNone, kNone, kNone },
+};
+
+
+static const OpCode opCodes2[] = {
+/* 0x00 */ { "OC_setWord18821", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x01 */ { "OC_changeIsoMap", 3, kgetPosFromScript, kImmediateValue, kImmediateValue, kNone, kNone },
+/* 0x02 */ { "OC_startSpeech", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x03 */ { "OC_getComputedVariantSpeech", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
+/* 0x04 */ { "OC_getRotatingVariantSpeech", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone }, // todo
+/* 0x05 */ { "OC_startSpeechIfMute", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x06 */ { "OC_getComputedVariantSpeechIfMute", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone }, // pb
+/* 0x07 */ { "OC_startSpeechIfSilent", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x08 */ { "OC_computeCharacterVariable", 4, kGetValue1, kImmediateValue, kComputeOperation, kImmediateValue, kNone },
+/* 0x09 */ { "OC_setAttributeToRandom", 3, kGetValue1, kImmediateValue, kImmediateValue, kNone, kNone },
+/* 0x0a */ { "OC_setCharacterPosition", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone },
+/* 0x0b */ { "OC_disableCharacter", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x0c */ { "OC_saveAndQuit", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x0d */ { "OC_nSkipOpcodes", 1, kImmediateValue, kNone, kNone, kNone, kNone }, // todo : jump to other opcode
+/* 0x0e */ { "OC_startSpeech5", 0, kNone, kNone, kNone, kNone, kNone }, // todo
+/* 0x0f */ { "OC_resetHandleOpcodeFlag", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x10 */ { "OC_deleteSavegameAndQuit", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x11 */ { "OC_incScriptForVal", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x12 */ { "OC_ComputeChararacterAttr", 5, kGetValue1, kImmediateValue,kComputeOperation, kGetValue1, kImmediateValue },
+/* 0x13 */ { "OC_setTextVarNumber", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+/* 0x14 */ { "OC_callScript", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone }, // run script
+/* 0x15 */ { "OC_callScriptAndReturn", 2, kImmediateValue, kGetValue1, kNone, kNone, kNone }, // run script then stop
+/* 0x16 */ { "OC_setCurrentScriptCharacterPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+/* 0x17 */ { "OC_initScriptFor", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x18 */ { "OC_setCurrentCharacterSequence", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x19 */ { "OC_setNextCharacterSequence", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x1a */ { "OC_setHost", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x1b */ { "OC_changeMapCube", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x1c */ { "OC_setCharacterCarry", 4, kGetValue1, kGetValue1, kImmediateValue, kImmediateValue, kNone },
+/* 0x1d */ { "OC_dropCarried", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x1e */ { "OC_setCurrentCharacter", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x1f */ { "OC_sendSeeSignal", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x20 */ { "OC_sendHearSignal", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x21 */ { "OC_sendVarSignal", 3, kImmediateValue, kGetValue1, kImmediateValue, kNone, kNone },
+/* 0x22 */ { "OC_sendBroadcastSignal", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x23 */ { "OC_resetWaitingSignal", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x24 */ { "OC_enableCurrentCharacterScript", 1, kImmediateValue, kNone, kNone, kNone, kNone }, // stop script
+/* 0x25 */ { "OC_incCurrentCharacterVar1", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x26 */ { "OC_setCurrentCharacterPos", 2, kImmediateValue, kgetPosFromScript, kNone, kNone, kNone },
+/* 0x27 */ { "OC_setCurrentCharacterBehavior", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x28 */ { "OC_changeCurrentCharacterSprite", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x29 */ { "OC_getList", 4, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
+/* 0x2a */ { "OC_setList", 4, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
+/* 0x2b */ { "OC_setCharacterDirectionTowardsPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+/* 0x2c */ { "OC_turnCharacterTowardsAnother", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x2d */ { "OC_setSeek", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x2e */ { "OC_scrollAwayFromCharacter", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x2f */ { "OC_skipNextVal", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x30 */ { "OC_setCurrentCharacterAttr6", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x31 */ { "OC_setCurrentCharacterPose", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x32 */ { "OC_setCharacterScriptEnabled", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x33 */ { "OC_setCurrentCharacterAttr2", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x34 */ { "OC_ClearCurrentCharacterAttr2", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x35 */ { "OC_setCharacterProperties", 5, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
+/* 0x36 */ { "OC_setMonitoredCharacter", 5, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
+/* 0x37 */ { "OC_setNewPose", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x38 */ { "OC_setCurrentCharacterDirection", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x39 */ { "OC_setInterfaceHotspot", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x3a */ { "OC_scrollViewPort", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x3b */ { "OC_setViewPortPos", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+/* 0x3c */ { "OC_setCurrentCharacterAltitude", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x3d */ { "OC_setModePriority", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone },
+/* 0x3e */ { "OC_setComputedModePriority", 4, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
+/* 0x3f */ { "OC_selectBestMode", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x40 */ { "OC_magicPuffEntrance", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x41 */ { "OC_spawnCharacterAtPos", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone }, // TODO
+/* 0x42 */ { "OC_characterVariableAddOrRemoveFlag", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
+/* 0x43 */ { "OC_paletteFadeOut", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x44 */ { "OC_paletteFadeIn", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x45 */ { "OC_loadAndDisplayCubesGfx", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x46 */ { "OC_setCurrentCharacterAttr3", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x47 */ { "OC_setArray122C1", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x48 */ { "OC_sub18367", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x49 */ { "OC_enableCharacterScript", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+/* 0x4a */ { "OC_setRulesBuffer2Element", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+/* 0x4b */ { "OC_setDebugFlag", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x4c */ { "OC_setDebugFlag2", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x4d */ { "OC_waitForEvent", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x4e */ { "OC_disableInterfaceHotspot", 2, kImmediateValue, kImmediateValue, kNone, kNone, kNone }, // TODO
+/* 0x4f */ { "OC_loadFileAerial", 1, kNone, kNone, kNone, kNone, kNone },
+/* 0x50 */ { "OC_startSpeechIfSoundOff", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x51 */ { "OC_sub1844A", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+/* 0x52 */ { "OC_displayNumericCharacterVariable", 5, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
+/* 0x53 */ { "OC_displayVGAFile", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x54 */ { "OC_startSpeechWithoutSpeeker", 1, kImmediateValue, kNone, kNone, kNone, kNone }, // TODO
+/* 0x55 */ { "OC_displayTitleScreen", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x56 */ { "OC_initGameAreaDisplay", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x57 */ { "OC_displayCharacterStatBar", 6, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue},
+/* 0x58 */ { "OC_initSmallAnim", 11, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue, kImmediateValue },
+/* 0x59 */ { "OC_setCharacterHeroismBar", 4, kGetValue1, kImmediateValue, kImmediateValue, kImmediateValue, kNone },
+/* 0x5a */ { "OC_setCharacterHome", 2, kGetValue1, kgetPosFromScript, kNone, kNone, kNone }, //TODO
+/* 0x5b */ { "OC_setViewPortCharacterTarget", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x5c */ { "OC_showObject", 3, kGetValue1, kImmediateValue, kImmediateValue, kNone, kNone }, //TODO
+/* 0x5d */ { "OC_playObjectSound", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+/* 0x5e */ { "OC_startLocationSound", 2, kgetPosFromScript, kImmediateValue, kNone, kNone, kNone },
+/* 0x5f */ { "OC_stopObjectSound", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x60 */ { "OC_stopLocationSound", 1, kGetValue1, kNone, kNone, kNone, kNone },
+/* 0x61 */ { "OC_toggleSound", 1, kgetPosFromScript, kNone, kNone, kNone, kNone },
+/* 0x62 */ { "OC_playMusic", 1, kImmediateValue, kNone, kNone, kNone, kNone },
+/* 0x63 */ { "OC_stopMusic", 0, kNone, kNone, kNone, kNone, kNone },
+/* 0x64 */ { "OC_setCharacterMapColor", 2, kGetValue1, kImmediateValue, kNone, kNone, kNone },
+/* 0x65 */ { "OC_initGameAreaDisplay", 0, kNone, kNone, kNone, kNone, kNone }
+};
+
+Common::String LilliputScript::getArgumentString(kValueType type, ScriptStream& script) {
+
+ Common::String str;
+ if (type == kImmediateValue) {
+ str = Common::String::format("0x%x", script.readUint16LE());
+ } else if (type == kGetValue1) {
+ int val = script.readUint16LE();
+ if (val < 1000) {
+ str = Common::String::format("0x%x", val);
+ } else if (val > 1004) {
+ str = Common::String::format("getValue1(0x%x)", val);
+ } else if (val == 1000) {
+ str = Common::String("_selectedCharacterId");
+ } else if (val == 1001) {
+ str = Common::String("_characterIndex");
+ } else if (val == 1002) {
+ str = Common::String("_word16F00_characterId");
+ } else if (val == 1003) {
+ str = Common::String("_currentCharacterVariables[6]");
+ } else if (val == 1004) {
+ str = Common::String("_host");
+ }
+ } else if (type == kgetPosFromScript) {
+ int curWord = script.readUint16LE();
+ int tmpVal = curWord >> 8;
+ switch(tmpVal) {
+ case 0xFF:
+ str = "(_rulesBuffer2_13[currentCharacter],_rulesBuffer2_14[currentCharacter])";
+ break;
+ case 0xFE: {
+ int index = curWord & 0xFF;
+ assert((index >= 0) && (index < 40));
+ str = Common::String::format("_vm->_rulesBuffer2_13[%d],_vm->_rulesBuffer2_14[%d]", index, index);
+ break;
+ }
+ case 0xFD:
+ str = "_currentScriptCharacterPosition";
+ break;
+ case 0xFC: {
+ int index = curWord & 0xFF;
+ assert(index < 40);
+ str = Common::String::format("(characterPositionTileX[%d], characterPositionTileY[%d])", index, index);
+ break;
+ }
+ case 0xFB: {
+ str = "(characterPositionTileX[_word16F00_characterId], characterPositionTileY[_word16F00_characterId])";
+ break;
+ }
+ case 0xFA:
+ str = Common::String::format("(_characterTargetPosX[currentCharacter], _characterTargetPosY[currentCharacter])");
+ break;
+ case 0xF9:
+ str = Common::String::format("(_currentCharacterVariables[4], _currentCharacterVariables[5])");
+ break;
+ case 0xF8: {
+ int index = curWord & 0xFF;
+ assert((index >= 0) && (index < 40));
+ str = Common::String::format("_vm->_rulesBuffer12Pos3[%d]", index);
+ break;
+ }
+ case 0xF7: {
+ str = Common::String::format("(_characterPositionTileX[_currentCharacterVariables[6]], _characterPositionTileY[_currentCharacterVariables[6]])");
+ break;
+ }
+ case 0xF6:
+ str = "_savedMousePosDivided";
+ break;
+ default:
+ str = Common::String::format("(0x%x,0x%x)", curWord >> 8, curWord & 0xFF);
+ break;
+ }
+ } else if (type == kCompareOperation) {
+ int comp = script.readUint16LE();
+ if (comp != '<' && comp != '>')
+ comp = '=';
+ str = Common::String::format("%c", comp);
+ }
+ else if (type == kComputeOperation) {
+ int comp = script.readUint16LE();
+ str = Common::String::format("%c", comp);
+ }
+ return str;
+}
+
+void LilliputScript::disasmScript(ScriptStream script) {
+ while (!script.eos()) {
+ uint16 val = script.readUint16LE();
+ if (val == 0xFFF6) // end of script
+ return;
+
+ bool firstIf = true;
+
+ // check the conditions.
+ while (val != 0xFFF8) {
+ bool neg = false;
+
+ if (val >= 1000) {
+ val -= 1000;
+ // negative condition
+ neg = true;
+ }
+
+ // op code type 1
+ assert(val < sizeof(opCodes1) / sizeof(OpCode));
+ const OpCode *opCode = &opCodes1[val];
+ const kValueType *opArgType = &opCode->_arg1;
+
+ Common::String str;
+
+ if (firstIf) {
+ str = "if (";
+ firstIf = false;
+ } else {
+ str = " ";
+ }
+ if (neg)
+ str += "not ";
+ str += Common::String(opCode->_opName);
+ str += "(";
+
+ for (int p = 0; p < opCode->_numArgs; p++) {
+ str += getArgumentString(*opArgType, script);
+ if (p != opCode->_numArgs - 1)
+ str += ", ";
+
+ opArgType++;
+ }
+ str += ")";
+
+ val = script.readUint16LE();
+
+ if (val == 0xFFF8) {
+ str += ")";
+ }
+
+ debugC(2, kDebugScript, "%s", str.c_str());
+ }
+
+ debugC(2, kDebugScript, "{ ");
+
+ val = script.readUint16LE();
+
+ while (val != 0xFFF7) {
+ // op code type 2
+ assert(val < sizeof(opCodes2) / sizeof(OpCode));
+ const OpCode *opCode = &opCodes2[val];
+ const kValueType *opArgType = &opCode->_arg1;
+
+ Common::String str;
+ str = " ";
+ str += Common::String(opCode->_opName);
+ str += "(";
+
+ for (int p = 0; p < opCode->_numArgs; p++) {
+ str += getArgumentString(*opArgType, script);
+ if (p != opCode->_numArgs - 1)
+ str += ", ";
+ if (p < 4)
+ opArgType++;
+ }
+ str += ");";
+
+ debugC(2, kDebugScript, "%s", str.c_str());
+
+ val = script.readUint16LE();
+ }
+
+ debugC(2, kDebugScript, "} ");
+ debugC(2, kDebugScript, " ");
+ }
+}
+
+int LilliputScript::handleOpcode(ScriptStream *script) {
+ debugC(2, kDebugScript, "handleOpcode");
+
+ _currScript = script;
+ uint16 curWord = _currScript->readUint16LE();
+ if (curWord == 0xFFF6)
+ return 0xFF;
+
+ for (; curWord != 0xFFF8; curWord = _currScript->readUint16LE()) {
+ byte mask = 0;
+ if (curWord > 1000) {
+ curWord -= 1000;
+ mask = 1;
+ }
+ byte result = handleOpcodeType1(curWord);
+ if ((result ^ mask) == 0) {
+ do {
+ curWord = _currScript->readUint16LE();
+ } while (curWord != 0xFFF7);
+ return 0;
+ }
+ }
+
+ _vm->_handleOpcodeReturnCode = 1;
+
+ for (;;) {
+ curWord = _currScript->readUint16LE();
+ if (curWord == 0xFFF7)
+ return _vm->_handleOpcodeReturnCode;
+
+ handleOpcodeType2(curWord);
+ }
+}
+
+void LilliputScript::runScript(ScriptStream script) {
+ debugC(1, kDebugScript, "runScript");
+
+ _byte16F05_ScriptHandler = 1;
+
+ while (handleOpcode(&script) != 0xFF)
+ _vm->update();
+}
+
+void LilliputScript::runMenuScript(ScriptStream script) {
+ debugC(1, kDebugScript, "runMenuScript");
+
+ _byte16F05_ScriptHandler = 0;
+
+ while (handleOpcode(&script) == 0)
+ _vm->update();
+}
+
+byte LilliputScript::compareValues(int16 var1, uint16 oper, int16 var2) {
+ debugC(2, kDebugScript, "compareValues(%d, %c, %d)", var1, oper & 0xFF, var2);
+
+ switch (oper & 0xFF) {
+ case '<':
+ if (var1 < var2)
+ return 1;
+ break;
+ case '>':
+ if (var1 > var2)
+ return 1;
+ break;
+ default:
+ if (var1 == var2)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+void LilliputScript::computeOperation(byte *bufPtr, uint16 oper, int16 var3) {
+ debugC(1, kDebugScript, "computeOperation(bufPtr, %c, %d)", oper & 0xFF, var3 & 0xFF);
+
+ switch (oper & 0xFF) {
+ case '=':
+ bufPtr[0] = var3 & 0xFF;
+ break;
+ case '+': {
+ int tmpVal = bufPtr[0] + var3;
+ if (tmpVal > 0xFF)
+ bufPtr[0] = 0xFF;
+ else
+ bufPtr[0] = (byte)tmpVal;
+ }
+ break;
+ case '-': {
+ int tmpVal = bufPtr[0] - var3;
+ if (tmpVal < 0)
+ bufPtr[0] = 0;
+ else
+ bufPtr[0] = (byte)tmpVal;
+ }
+ break;
+ case '*': {
+ int tmpVal = bufPtr[0] * var3;
+ bufPtr[0] = tmpVal & 0xFF;
+ }
+ break;
+ case '/': {
+ if (var3 != 0)
+ bufPtr[0] /= var3;
+ }
+ break;
+ default: {
+ warning("computeOperation : oper %d", oper);
+ if (var3 != 0) {
+ int tmpVal = bufPtr[0] / var3;
+ if (tmpVal < 0)
+ bufPtr[0] = 0xFF;
+ else
+ bufPtr[0] = 0;
+ }
+ break;
+ }
+ }
+}
+
+void LilliputScript::enableCharacterScript(byte index, byte var1, byte *curBufPtr) {
+ debugC(1, kDebugScript, "enableCharacterScript(%d, %d, curBufPtr)", index, var1);
+
+ assert (index < 40);
+ _characterScriptEnabled[index] = 1;
+ curBufPtr[0] = var1;
+ curBufPtr[1] = 0;
+ curBufPtr[2] = 0;
+ curBufPtr[3] = 0;
+}
+
+void LilliputScript::skipOpcodes(int var1) {
+ debugC(1, kDebugScript, "skipOpcodes(%d)", var1);
+
+ if (var1 == 0) {
+ int curWord = 0;
+ while (curWord != 0xFFF6)
+ curWord = _currScript->readUint16LE();
+
+ _currScript->seek(_currScript->pos() - 4);
+ return;
+ }
+
+ ++var1;
+ int curVal = 0;
+ while (curVal < var1) {
+ int tmpVal = _currScript->readUint16LE();
+ if (tmpVal == 0xFFF7)
+ ++curVal;
+ }
+
+ _currScript->seek(_currScript->pos() - 2);
+}
+
+void LilliputScript::copySequence(int index, byte *buf) {
+ debugC(1, kDebugScript, "copySequence()");
+
+ _characterNextSequence[index] = 0;
+
+ for (int i = 0; i < 16; i++) {
+ _sequenceArr[(index * 16) + i] = Common::Point(buf[(2 * i) + 1], buf[2 * i]);
+ }
+}
+
+void LilliputScript::setSequence(int charIdx, int8 seqIdx) {
+ debugC(1, kDebugScript, "setSequence(%d, %d)", charIdx, seqIdx);
+
+ assert(charIdx < 40);
+ _characterLastSequence[charIdx] = seqIdx;
+
+ byte *buf = _vm->_sequencesArr;
+ if (seqIdx != 0) {
+ int count = 0;
+ while (count < seqIdx) {
+ if ((buf[0] == 0xFF) && (buf[1] == 0xFF))
+ ++count;
+ buf += 2;
+ }
+ }
+
+ copySequence(charIdx, buf);
+}
+
+void LilliputScript::checkSpeechAllowed(bool &forceReturnFl) {
+ debugC(1, kDebugScript, "checkSpeechAllowed()");
+
+ forceReturnFl = false;
+ if ((!_vm->_displayMap) && (_vm->_characterRelativePos[_vm->_currentScriptCharacter].x != -1))
+ return;
+
+ forceReturnFl = true;
+ return;
+}
+
+void LilliputScript::formatSpeechString() {
+ debugC(2, kDebugScript, "formatSpeechString()");
+
+ int index = 0;
+ int var2 = 0x100;
+
+ for (;;) {
+ int var1 = _vm->_displayStringBuf[index++];
+ if (var1 == 0)
+ break;
+
+ if (var1 == '|') {
+ var2 &= 0xFF;
+ ++var2;
+ continue;
+ }
+
+ var2 += 0x100;
+ if ((var2 >> 8) < 61)
+ continue;
+
+ if ((var2 & 0xFF) == 1) {
+ _vm->_displayStringBuf[index - 1] = 0;
+ break;
+ }
+
+ --index;
+ while (_vm->_displayStringBuf[index] != ' ')
+ --index;
+
+ _vm->_displayStringBuf[index] = '|';
+ ++var2;
+ var2 &= 0xFF;
+ ++index;
+ }
+}
+
+void LilliputScript::showSpeech() {
+ debugC(2, kDebugScript, "showSpeech()");
+
+ formatSpeechString();
+ int index = 0;
+
+ for (;;) {
+ if (_vm->_displayStringBuf[index] == 0)
+ break;
+ ++index;
+ }
+
+ index /= _speechDisplaySpeed;
+ index += 4;
+ _speechTimer = index;
+ _vm->displaySpeechBubble();
+ _vm->displaySpeech(_vm->_displayStringBuf);
+}
+
+void LilliputScript::decodePackedText(char *buf) {
+ debugC(2, kDebugScript, "decodePackedText(buf)");
+
+ // All the languages use the English dictionary
+ static const char *nounsArrayPtr = "I am |You are |you are |hou art |in the |"
+ "is the |is a |in a |To the |to the |by |going |here |The|the|and |"
+ "some |build|not |way|I |a |an |from |of |him|her|by |his |ing |tion|"
+ "have |you|I've |can't |up |to |he |she |down |what|What|with|are |"
+ "and|ent|ian|ome|ed |me|my|ai|it|is|of|oo|ea|er|es|th|we|ou|ow|or|"
+ "gh|go|er|st|ee|th|sh|ch|ct|on|ly|ng|nd|nt|ty|ll|le|de|as|ie|in|ss|"
+ "'s |'t |re|gg|tt|pp|nn|ay|ar|wh|";
+
+ _vm->_displayStringIndex = 0;
+ int index = 0;
+ byte var1 = 0;
+ for (;;) {
+ var1 = buf[index];
+ ++index;
+ if (var1 == ']')
+ var1 = 0;
+
+ if (var1 < 0x80) {
+ if (var1 == '@') {
+ var1 = buf[index];
+ ++index;
+ if (var1 == '#') {
+ _vm->numberToString(_textVarNumber);
+ }
+ } else {
+ _vm->addCharToBuf(var1);
+ if (var1 == 0)
+ break;
+ }
+ } else {
+ int nounIndex = 0;
+ byte var3 = 0xFF - var1;
+ for (int i = 0; i < var3; i++) {
+ for (;;) {
+ var1 = nounsArrayPtr[nounIndex];
+ ++nounIndex;
+
+ if (var1 == '|')
+ break;
+ }
+ }
+
+ for (;;) {
+ var1 = nounsArrayPtr[nounIndex];
+ ++nounIndex;
+
+ if (var1 == '|')
+ break;
+
+ _vm->addCharToBuf(var1);
+ }
+ }
+ }
+
+ showSpeech();
+}
+
+int LilliputScript::getPackedStringStartRelativeIndex(int index) {
+ debugC(2, kDebugScript, "getPackedStringStartRelativeIndex(%d)", index);
+
+ int chunk4Index = _vm->_packedStringIndex[index];
+ int result = 0;
+ while (_vm->_packedStrings[chunk4Index + result] == 0x5B)
+ ++result;
+
+ return result + 1;
+}
+
+// Part of the script decompiler
+void LilliputScript::listAllTexts() {
+ debugC(1, kDebugScript, "listAllTexts");
+
+ for (int i = 0; i < _vm->_packedStringNumb; i++) {
+ int index = _vm->_packedStringIndex[i];
+ int variantCount = 0;
+ while (_vm->_packedStrings[index + variantCount] == 0x5B)
+ ++variantCount;
+ /*
+ int it = 0;
+ if (variantCount != 0) {
+ for (int j = 0; j < variantCount; j++) {
+ decodePackedText(&_vm->_packedStrings[index + variantCount + it]);
+ warning("Text 0x%x variant %d : %s", i, j, _vm->_displayStringBuf);
+ do {
+ ++it;
+ } while (_vm->_packedStrings[index + variantCount + it] != 0x5B);
+ }
+ } else {*/
+ decodePackedText(&_vm->_packedStrings[index + variantCount]);
+ debugC(1, kDebugScript, "Text 0x%x variant 0 : %s", i, _vm->_displayStringBuf);
+ /* }*/
+ }
+}
+
+void LilliputScript::startSpeech(int speechId) {
+ debugC(2, kDebugScript, "startSpeech(%d)", speechId);
+
+ if (speechId == -1)
+ return;
+
+ _currentSpeechId = speechId;
+
+ int index = _vm->_packedStringIndex[speechId];
+ int count = 0;
+ while (_vm->_packedStrings[index + count] == '[')
+ ++count;
+
+ int i = 0;
+ if (count != 0) {
+ int tmpVal = _vm->_rnd->getRandomNumber(count);
+ if (tmpVal != 0) {
+ for (int j = 0; j < tmpVal; j++) {
+ do {
+ ++i;
+ } while (_vm->_packedStrings[index + count + i] != ']');
+ ++i;
+ }
+ }
+ }
+
+ decodePackedText(&_vm->_packedStrings[index + count + i]);
+}
+
+int16 LilliputScript::getValue1() {
+ debugC(2, kDebugScript, "getValue1()");
+
+ int16 curWord = _currScript->readUint16LE();
+ if (curWord < 1000)
+ return curWord;
+
+ switch (curWord) {
+ case 1000:
+ return _vm->_selectedCharacterId;
+ case 1001:
+ return _vm->_currentScriptCharacter;
+ case 1002:
+ return _word16F00_characterId;
+ case 1003:
+ return (int16)_vm->_currentCharacterAttributes[6];
+ case 1004:
+ return _vm->_host;
+ default:
+ warning("getValue1: Unexpected large value %d", curWord);
+ return curWord;
+ }
+}
+
+Common::Point LilliputScript::getPosFromScript() {
+ debugC(2, kDebugScript, "getPosFromScript()");
+
+ int curWord = _currScript->readUint16LE();
+ int tmpVal = curWord >> 8;
+ switch(tmpVal) {
+ case 0xFF:
+ assert((_vm->_currentScriptCharacter >= 0) && (_vm->_currentScriptCharacter < 40));
+ return _vm->_characterHomePos[_vm->_currentScriptCharacter];
+ case 0xFE: {
+ int8 index = curWord & 0xFF;
+ assert((index >= 0) && (index < 40));
+ return _vm->_characterHomePos[index];
+ }
+ case 0xFD:
+ return _vm->_currentScriptCharacterPos;
+ case 0xFC: {
+ int8 index = curWord & 0xFF;
+ assert((index >= 0) && (index < 40));
+ int16 x = _vm->_characterPos[index].x >> 3;
+ int16 y = _vm->_characterPos[index].y >> 3;
+
+ return Common::Point(x, y);
+ }
+ case 0xFB: {
+ int index = _word16F00_characterId;
+ assert((index >= 0) && (index < 40));
+ int16 x = _vm->_characterPos[index].x >> 3;
+ int16 y = _vm->_characterPos[index].y >> 3;
+
+ return Common::Point(x, y);
+ }
+ case 0xFA:
+ return _vm->_characterTargetPos[_vm->_currentScriptCharacter];
+ case 0xF9:
+ return Common::Point(_vm->_currentCharacterAttributes[4], _vm->_currentCharacterAttributes[5]);
+ case 0xF8: {
+ int8 index = curWord & 0xFF;
+ assert((index >= 0) && (index < 40));
+ return _vm->_keyPos[index];
+ }
+ case 0xF7: {
+ int8 index = _vm->_currentCharacterAttributes[6];
+ assert((index >= 0) && (index < 40));
+ return Common::Point(_vm->_characterPos[index].x >> 3, _vm->_characterPos[index].y >> 3);
+ }
+ case 0xF6:
+ return _vm->_savedMousePosDivided;
+ default:
+ Common::Point pos = Common::Point(curWord >> 8, curWord & 0xFF);
+ // warning("getPosFromScript - High value %d -> %d %d", curWord, pos.x, pos.y);
+ return pos;
+ }
+}
+
+byte *LilliputScript::getCharacterAttributesPtr() {
+ debugC(2, kDebugScript, "getCharacterVariablePtr()");
+
+ int8 tmpVal = (int8) (getValue1() & 0xFF);
+ int index = tmpVal * 32;
+ index += _currScript->readUint16LE();
+
+ return _vm->getCharacterAttributesPtr(index);
+}
+
+byte LilliputScript::OC_checkCharacterGoalPos() {
+ debugC(2, kDebugScript, "OC_checkCharacterGoalPos()");
+
+ if (_vm->_currentScriptCharacterPos == getPosFromScript()) {
+ return 1;
+ }
+ return 0;
+}
+
+byte LilliputScript::OC_comparePos() {
+ debugC(2, kDebugScript, "OC_comparePos()");
+
+ int index = getValue1();
+ Common::Point var1 = getPosFromScript();
+
+ if (var1 == _characterTilePos[index])
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkIsoMap3() {
+ debugC(1, kDebugScript, "OC_checkIsoMap3()");
+
+ Common::Point var = _vm->_currentScriptCharacterPos;
+ if (var == Common::Point(-1, -1)) {
+ _currScript->readUint16LE();
+ return 0;
+ }
+
+ byte *isoMapBuf = getMapPtr(var);
+ byte var2 = isoMapBuf[3];
+
+ int16 var3 = _currScript->readUint16LE();
+ byte var4 = 8 >> var3;
+
+ if ((var2 & var4) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+byte LilliputScript::OC_compareCharacterVariable() {
+ debugC(1, kDebugScript, "OC_compareCharacterVariable()");
+
+ byte *tmpArr = getCharacterAttributesPtr();
+ byte var1 = tmpArr[0];
+ uint16 oper = _currScript->readUint16LE();
+ int16 var2 = _currScript->readUint16LE();
+
+ return compareValues(var1, oper, var2);
+}
+
+byte LilliputScript::OC_CompareLastRandomValue() {
+ debugC(1, kDebugScript, "OC_CompareLastRandomValue()");
+
+ uint16 operation = _currScript->readUint16LE();
+ int16 val2 = _currScript->readSint16LE();
+ return compareValues(_lastRandomValue, operation, val2);
+}
+
+byte LilliputScript::OC_getRandom() {
+ debugC(1, kDebugScript, "OC_getRandom()");
+
+ int maxVal = _currScript->readUint16LE();
+ int rand = _vm->_rnd->getRandomNumber(maxVal);
+ _lastRandomValue = (rand & 0xFF);
+
+ if (rand == 0)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_for() {
+ debugC(1, kDebugScript, "OC_for()");
+
+ int var1 = _currScript->readUint16LE();
+ int tmpVal = _currScript->readUint16LE() + 1;
+ // no need to seek later, the move is already done
+ _currScript->writeUint16LE(tmpVal, -2);
+ // overwrite the recently used "variable" in the script
+ if (tmpVal < var1)
+ return 0;
+
+ _currScript->writeUint16LE(0, -2);
+ return 1;
+}
+
+byte LilliputScript::OC_compCurrentSpeechId() {
+ debugC(1, kDebugScript, "OC_compCurrentSpeechId()");
+
+ int var1 = _currScript->readUint16LE();
+
+ if (var1 == _currentSpeechId)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkSaveFlag() {
+ debugC(1, kDebugScript, "OC_checkSaveFlag()");
+
+ if (_vm->_saveFlag)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_compScriptForVal() {
+ debugC(1, kDebugScript, "OC_compScriptForVal()");
+
+ uint16 oper = _currScript->readUint16LE();
+ int16 var2 = _currScript->readUint16LE();
+
+ return compareValues(_scriptForVal, oper, var2);
+}
+
+byte LilliputScript::OC_isCarrying() {
+ debugC(1, kDebugScript, "OC_isCarrying()");
+
+ int8 tmpVal = getValue1() & 0xFF;
+ uint16 curWord = _currScript->readUint16LE();
+
+ if (curWord == 3000) {
+ for (int index = 0; index < _vm->_numCharacters; index++) {
+ if (_vm->_characterCarried[index] == tmpVal) {
+ _word16F00_characterId = index;
+ return 1;
+ }
+ }
+ } else {
+ _currScript->seek(_currScript->pos() - 2);
+ int index = getValue1();
+ assert(index < 40);
+ if (_vm->_characterCarried[index] == tmpVal) {
+ _word16F00_characterId = index;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+byte LilliputScript::OC_CompareCharacterVariables() {
+ debugC(1, kDebugScript, "OC_CompareCharacterVariables()");
+
+ byte* buf1 = getCharacterAttributesPtr();
+ int var1 = *buf1;
+
+ int operation = _currScript->readUint16LE();
+
+ byte* buf2 = getCharacterAttributesPtr();
+ int var2 = *buf2;
+
+ return compareValues(var1, operation, var2);
+}
+
+// TODO Rename function to "Check if current script character pos is in enclosure"
+byte LilliputScript::OC_compareCoords_1() {
+ debugC(1, kDebugScript, "OC_compareCoords_1()");
+
+ int index = _currScript->readUint16LE();
+ assert(index < 40);
+
+ if (_vm->_enclosureRect[index].contains(_vm->_currentScriptCharacterPos))
+ return 1;
+
+ return 0;
+}
+
+// TODO Rename function to "Check if given character pos is in enclosure"
+byte LilliputScript::OC_compareCoords_2() {
+ debugC(1, kDebugScript, "OC_compareCoords_2()");
+
+ int16 idx1 = getValue1();
+ int16 idx2 = _currScript->readUint16LE();
+
+ if (_vm->_enclosureRect[idx2].contains(_characterTilePos[idx1]))
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_CompareDistanceFromCharacterToPositionWith() {
+ debugC(1, kDebugScript, "OC_CompareDistanceFromCharacterToPositionWith()");
+
+ Common::Point var1 = getPosFromScript();
+ Common::Point pos = _vm->_currentScriptCharacterPos;
+
+ int dx = var1.x - pos.x;
+ if (dx < 0)
+ dx = -dx;
+
+ int dy = var1.y - pos.y;
+ if (dy < 0)
+ dy = -dy;
+
+ int16 dist = dx + dy;
+
+ uint16 operation = _currScript->readUint16LE();
+ int16 var2 = _currScript->readSint16LE();
+
+ return compareValues(dist, operation, var2);
+}
+
+byte LilliputScript::OC_compareRandomCharacterId() {
+ debugC(1, kDebugScript, "OC_compareRandomCharacterId()");
+
+ byte *tmpArr = getCharacterAttributesPtr();
+ _lastRandomValue = _vm->_rnd->getRandomNumber(tmpArr[0] + 1);
+ uint16 oper = _currScript->readUint16LE();
+ int16 var2 = _currScript->readSint16LE();
+
+ return compareValues(_lastRandomValue, oper, var2);
+}
+
+byte LilliputScript::OC_IsCurrentCharacterIndex() {
+ debugC(1, kDebugScript, "OC_IsCurrentCharacterIndex()");
+
+ int tmpVal = getValue1();
+ if (tmpVal == _vm->_currentScriptCharacter)
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_hasVisibilityLevel() {
+ debugC(1, kDebugScript, "OC_hasVisibilityLevel()");
+
+ byte var4 = _currScript->readUint16LE() & 0xFF;
+ int tmpVal = _currScript->readUint16LE();
+
+ if (tmpVal < 2000) {
+ _currScript->seek(_currScript->pos() - 2);
+ int index = getValue1();
+ int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + index];
+ if ((var1 & 0xFF) < var4)
+ return 0;
+
+ _word16F00_characterId = index;
+ return 1;
+ }
+
+ if (tmpVal == 3000) {
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
+ if ((var1 & 0xFF) >= var4) {
+ _word16F00_characterId = i;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ tmpVal -= 2000;
+ byte var4b = tmpVal & 0xFF;
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
+ if (((var1 & 0xFF) >= var4) && (_vm->_characterBehaviour[i] == var4b)) {
+ _word16F00_characterId = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+byte LilliputScript::OC_hasGainedVisibilityLevel() {
+ debugC(1, kDebugScript, "OC_hasGainedVisibilityLevel()");
+
+ uint16 var4 = _currScript->readUint16LE();
+ int index = _vm->_currentScriptCharacter * 40;
+ uint16 tmpVal = _currScript->readUint16LE();
+
+ if (tmpVal < 2000) {
+ _currScript->seek(_currScript->pos() - 2);
+ int subIndex = getValue1();
+ tmpVal = _interactions[index + subIndex];
+ byte v1 = tmpVal & 0xFF;
+ byte v2 = tmpVal >> 8;
+ if ((v1 < (var4 & 0xFF)) || (v2 >= (var4 & 0xFF)))
+ return 0;
+ _word16F00_characterId = subIndex;
+ return 1;
+ }
+
+ int var1 = tmpVal;
+ if (var1 == 3000) {
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ tmpVal = _interactions[index + i];
+ byte v1 = tmpVal & 0xFF;
+ byte v2 = tmpVal >> 8;
+ if ((v1 >= (var4 & 0xFF)) && (v2 < (var4 & 0xFF))) {
+ _word16F00_characterId = i;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ var1 -= 2000;
+ var4 = ((var1 & 0xFF) << 8) + (var4 & 0xFF);
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ tmpVal = _interactions[index + i];
+ byte v1 = tmpVal & 0xFF;
+ byte v2 = tmpVal >> 8;
+ if ((v1 >= (var4 & 0xFF)) && (v2 < (var4 & 0xFF)) && (_vm->_characterBehaviour[i] == (var4 >> 8))) {
+ _word16F00_characterId = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+byte LilliputScript::OC_hasReducedVisibilityLevel() {
+ debugC(1, kDebugScript, "OC_hasReducedVisibilityLevel()");
+
+ byte var4 = _currScript->readUint16LE() & 0xFF;
+
+ int tmpVal = _currScript->readUint16LE();
+
+ if (tmpVal < 2000) {
+ _currScript->seek(_currScript->pos() - 2);
+ int index = getValue1();
+ int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + index];
+ if (((var1 & 0xFF) >= var4) || ((var1 >> 8) < var4))
+ return 0;
+
+ _word16F00_characterId = index;
+ return 1;
+ }
+
+ if (tmpVal == 3000) {
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
+ if (((var1 & 0xFF) < var4) && ((var1 >> 8) >= var4)) {
+ _word16F00_characterId = i;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ tmpVal -= 2000;
+ byte var4b = tmpVal & 0xFF;
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ int var1 = _interactions[(_vm->_currentScriptCharacter * 40) + i];
+ if (((var1 & 0xFF) < var4) && ((var1 >> 8) >= var4)) {
+ if (_vm->_characterBehaviour[i] == var4b) {
+ _word16F00_characterId = i;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+byte LilliputScript::OC_isHost() {
+ debugC(1, kDebugScript, "OC_isHost()");
+
+ int tmpVal = getValue1();
+ if (tmpVal == _vm->_host)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_isSequenceActive() {
+ debugC(1, kDebugScript, "OC_isSequenceActive()");
+
+ int8 var1 = (_currScript->readUint16LE() & 0xFF);
+ if ((var1 == _characterLastSequence[_vm->_currentScriptCharacter]) && (_characterNextSequence[_vm->_currentScriptCharacter] != 16))
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_isSequenceFinished() {
+ debugC(1, kDebugScript, "OC_isSequenceFinished()");
+
+ int8 var1 = (_currScript->readUint16LE() & 0xFF);
+ if ((var1 == _characterLastSequence[_vm->_currentScriptCharacter]) && (_characterNextSequence[_vm->_currentScriptCharacter] == 16))
+ return 1;
+
+ return 0;
+}
+
+byte *LilliputScript::getMapPtr(Common::Point val) {
+ debugC(1, kDebugScript, "getMapPtr(%d %d)", val.x, val.y);
+
+ return &_vm->_bufferIsoMap[(val.y * 64 + val.x) << 2];
+}
+
+byte LilliputScript::OC_CompareMapValueWith() {
+ debugC(1, kDebugScript, "OC_CompareMapValueWith()");
+
+ Common::Point tmpVal = getPosFromScript();
+
+ if (tmpVal == Common::Point(-1, -1)) {
+ _currScript->seek(_currScript->pos() + 6);
+ return 0;
+ }
+ int16 var2 = _currScript->readUint16LE();
+ byte *buf = getMapPtr(tmpVal);
+ int16 var1 = buf[var2];
+ uint16 oper = _currScript->readUint16LE();
+ var2 = _currScript->readSint16LE();
+
+ return compareValues(var1, oper, var2);
+}
+
+byte LilliputScript::OC_IsCharacterValid() {
+ debugC(1, kDebugScript, "OC_IsCharacterValid()");
+
+ int index = getValue1();
+ if (_vm->_characterPos[index].x == -1)
+ return 0;
+
+ return 1;
+}
+
+byte LilliputScript::OC_CheckWaitingSignal() {
+ debugC(1, kDebugScript, "OC_CheckWaitingSignal()");
+
+ byte curByte = _currScript->readUint16LE() & 0xFF;
+ byte tmpVal = _vm->_waitingSignal;
+
+ if (curByte != tmpVal)
+ return 0;
+
+ _word16F00_characterId = _vm->_waitingSignalCharacterId;
+ return 1;
+}
+
+byte LilliputScript::OC_CurrentCharacterVar0AndVar1Equals() {
+ debugC(1, kDebugScript, "OC_CurrentCharacterVar0AndVar1Equals()");
+
+ byte var1 = _currScript->readUint16LE() & 0xFF;
+ byte var2 = _currScript->readUint16LE() & 0xFF;
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+
+ if ((var1 == _vm->_currentCharacterAttributes[0]) && (var2 == _vm->_currentCharacterAttributes[1]))
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_CurrentCharacterVar0Equals() {
+ debugC(1, kDebugScript, "OC_CurrentCharacterVar0Equals()");
+
+ byte curByte = (_currScript->readUint16LE() & 0xFF);
+ assert(_vm->_currentCharacterAttributes != NULL);
+ if (_vm->_currentCharacterAttributes[0] == curByte)
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_checkLastInterfaceHotspotIndexMenu13() {
+ debugC(1, kDebugScript, "OC_checkLastInterfaceHotspotIndexMenu13()");
+
+ byte tmpVal = (_currScript->readUint16LE() & 0xFF);
+
+ if ((_vm->_actionType != kButtonPressed) && (_vm->_actionType != kActionTalk))
+ return 0;
+
+ if (tmpVal == _vm->_lastInterfaceHotspotIndex)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkLastInterfaceHotspotIndexMenu2() {
+ debugC(1, kDebugScript, "OC_checkLastInterfaceHotspotIndexMenu2()");
+
+ int8 hotspotIndex = (_currScript->readUint16LE() & 0xFF);
+
+ if ((_vm->_actionType == kButtonReleased) && (hotspotIndex == _vm->_lastInterfaceHotspotIndex))
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_CompareNumberOfCharacterWithVar0Equals() {
+ debugC(1, kDebugScript, "OC_CompareNumberOfCharacterWithVar0Equals()");
+
+ byte curByte = (_currScript->readUint16LE() & 0xFF);
+ int16 count = 0;
+
+ for (int i = 0; i < _vm->_numCharacters; i++) {
+ if (curByte == *_vm->getCharacterAttributesPtr(32 * i))
+ ++count;
+ }
+
+ uint16 oper = _currScript->readUint16LE();
+ int16 var2 = _currScript->readSint16LE();
+
+ return compareValues(count, oper, var2);
+}
+
+byte LilliputScript::OC_IsPositionInViewport() {
+ debugC(1, kDebugScript, "OC_IsPositionInViewport()");
+
+ Common::Point var1 = getPosFromScript();
+
+ int16 dx = var1.x - _viewportPos.x;
+ int16 dy = var1.y - _viewportPos.y;
+
+ if ((dx >= 0) && (dx < 8) && (dy >= 0) && (dy < 8))
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_CompareGameVariables() {
+ debugC(1, kDebugScript, "OC_CompareGameVariables()");
+
+ int16 var1 = getValue1();
+ int16 var2 = getValue1();
+ if (var1 == var2)
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_skipNextOpcode() {
+ debugC(1, kDebugScript, "OC_skipNextOpcode()");
+
+ _currScript->readUint16LE();
+ return 1;
+}
+
+byte LilliputScript::OC_CheckCurrentCharacterAttr2() {
+ debugC(1, kDebugScript, "OC_CheckCurrentCharacterAttr2()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ if (_vm->_currentCharacterAttributes[2] == 1)
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_CheckCurrentCharacterType() {
+ debugC(1, kDebugScript, "OC_CheckCurrentCharacterType()");
+
+ int index = getValue1();
+ assert (index < 40);
+
+ byte curByte = (_currScript->readUint16LE() & 0xFF);
+ if (curByte == _vm->_characterBehaviour[index])
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_CheckCurrentCharacterAttr0And() {
+ debugC(1, kDebugScript, "OC_CheckCurrentCharacterAttr0And()");
+
+ byte *bufPtr = getCharacterAttributesPtr();
+ byte var1 = bufPtr[0];
+ byte curByte = (_currScript->readUint16LE() & 0xFF);
+
+ if (var1 & curByte)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_IsCurrentCharacterAttr0LessEqualThan() {
+ debugC(1, kDebugScript, "OC_IsCurrentCharacterAttr0LessEqualThan()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ byte curByte = (_currScript->readUint16LE() & 0xFF);
+
+ if (curByte <= _vm->_currentCharacterAttributes[0])
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_isCarried() {
+ debugC(1, kDebugScript, "OC_isCarried()");
+
+ int16 index = getValue1();
+ assert((index >= 0) && (index < 40));
+ if (_vm->_characterCarried[index] == -1)
+ return 0;
+
+ _word16F00_characterId = _vm->_characterCarried[index];
+
+ return 1;
+}
+
+byte LilliputScript::OC_CheckCurrentCharacterAttr1() {
+ debugC(1, kDebugScript, "OC_CheckCurrentCharacterAttr1()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ byte curByte = (_currScript->readUint16LE() & 0xFF);
+
+ if (_vm->_currentCharacterAttributes[1] == curByte)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_isCurrentCharacterSpecial() {
+ debugC(1, kDebugScript, "OC_isCurrentCharacterSpecial()");
+
+ if (_vm->_currentScriptCharacterPos == Common::Point(-1, -1))
+ return 0;
+
+ if (_vm->_specialCubes[_vm->_currentScriptCharacter] == 0)
+ return 0;
+
+ return 1;
+}
+
+byte LilliputScript::OC_CurrentCharacterAttr3Equals1() {
+ debugC(1, kDebugScript, "OC_CurrentCharacterAttr3Equals1()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ if (_vm->_currentCharacterAttributes[3] == 1)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkCharacterDirection() {
+ debugC(1, kDebugScript, "OC_checkCharacterDirection()");
+
+ int16 index = getValue1();
+ byte expectedVal = (_currScript->readUint16LE() & 0xFF);
+
+ if (_vm->_characterDirectionArray[index] == expectedVal)
+ return 1;
+ return 0;
+}
+
+byte LilliputScript::OC_checkLastInterfaceHotspotIndex() {
+ debugC(1, kDebugScript, "OC_checkLastInterfaceHotspotIndex()");
+
+ uint16 index = _currScript->readUint16LE();
+ int8 var2 = (_currScript->readUint16LE() & 0xFF);
+
+ assert(index < 20);
+
+ if (_interfaceHotspotStatus[index] == var2)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkSelectedCharacter() {
+ debugC(1, kDebugScript, "OC_checkSelectedCharacter()");
+
+ if ((_vm->_selectedCharacterId != -1) || (_vm->_savedMousePosDivided == Common::Point(-1, -1)))
+ return 0;
+
+ return 1;
+}
+
+byte LilliputScript::OC_checkDelayedReactivation() {
+ debugC(1, kDebugScript, "OC_checkDelayedReactivation()");
+
+ if (_vm->_delayedReactivationAction || (_vm->_selectedCharacterId == -1))
+ return 0;
+
+ return 1;
+}
+
+byte LilliputScript::OC_checkTargetReached() {
+ debugC(1, kDebugScript, "OC_checkTargetReached()");
+ Common::Point pos = getPosFromScript();
+
+ if (_vm->_characterTargetPos[_vm->_currentScriptCharacter] == pos)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkFunctionKeyPressed() {
+ debugC(1, kDebugScript, "OC_checkFunctionKeyPressed()");
+
+ static const Common::KeyCode specialKeys[10] = {
+ Common::KEYCODE_F10, Common::KEYCODE_F1, Common::KEYCODE_F2, Common::KEYCODE_F3, Common::KEYCODE_F4,
+ Common::KEYCODE_F5, Common::KEYCODE_F6, Common::KEYCODE_F7, Common::KEYCODE_F8, Common::KEYCODE_F9};
+
+ int8 index = (_currScript->readUint16LE() & 0xFF) - 0x30;
+
+ if (specialKeys[index] == _vm->_lastKeyPressed.kbd.keycode)
+ return 1;
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkCodeEntered() {
+ debugC(1, kDebugScript, "OC_checkCodeEntered()");
+
+ static const byte solutionArr[10] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ if (_vm->_actionType == kCodeEntered) {
+ uint16 index = _currScript->readUint16LE();
+ if (solutionArr[index] == _vm->_codeEntered[0]) {
+ index = _currScript->readUint16LE();
+ if (solutionArr[index] == _vm->_codeEntered[1]) {
+ index = _currScript->readUint16LE();
+ if (solutionArr[index] == _vm->_codeEntered[2]) {
+ return 1;
+ }
+ } else
+ // skip last index check
+ _currScript->seek(_currScript->pos() + 2);
+ } else
+ // skip two last index checks
+ _currScript->seek(_currScript->pos() + 4);
+ } else
+ // skip the three index checks
+ _currScript->seek(_currScript->pos() + 6);
+
+ return 0;
+}
+
+byte LilliputScript::OC_checkViewPortCharacterTarget() {
+ debugC(1, kDebugScript, "OC_checkViewPortCharacterTarget()");
+
+ int var1 = getValue1();
+ if (var1 == _viewportCharacterTarget)
+ return 1;
+
+ return 0;
+}
+
+void LilliputScript::OC_setWord18821() {
+ debugC(1, kDebugScriptTBC, "OC_setWord18821()");
+
+ _word18821 = getValue1();
+}
+
+void LilliputScript::OC_ChangeIsoMap() {
+ debugC(1, kDebugScript, "OC_ChangeIsoMap()");
+
+ Common::Point var1 = getPosFromScript();
+ int var2 = _currScript->readUint16LE();
+ int var3 = _currScript->readUint16LE();
+ byte* mapPtr = getMapPtr(var1);
+
+ int mask = 8 >> var2;
+ mask = ~mask;
+ mapPtr[3] &= mask;
+
+ if (var3 > 0) {
+ mask = ~mask;
+ mapPtr[3] |= mask;
+ }
+}
+
+void LilliputScript::OC_startSpeech() {
+ debugC(1, kDebugScript, "OC_startSpeech()");
+
+ int curWord = _currScript->readUint16LE();
+
+ bool forceReturnFl = false;
+ checkSpeechAllowed(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ _talkingCharacter = _vm->_currentScriptCharacter;
+ startSpeech(curWord);
+}
+
+void LilliputScript::getSpeechVariant(int speechIndex, int speechVariant) {
+ debugC(2, kDebugScript, "getSpeechVariant(%d, %d)", speechIndex, speechVariant);
+
+ // The packed strings are stored by variants, enclosed by imbricated brackets.
+ // So the different possibilities are:
+ // text
+ // [text1]text2
+ // [[text1]text2]text3
+ // etc etc
+
+ if (speechIndex == -1)
+ return;
+
+ _currentSpeechId = speechIndex;
+ int index = _vm->_packedStringIndex[speechIndex];
+
+ // Skip the speech variant opening characters
+ while (_vm->_packedStrings[index] == '[')
+ ++index;
+
+ for (int i = 0; i < speechVariant; i++) {
+ byte tmpVal = ' ';
+ // Skip a speech variant
+ while (tmpVal != ']') {
+ tmpVal = _vm->_packedStrings[index];
+ ++index;
+ }
+ }
+
+ if (_vm->_packedStrings[index] == 0)
+ return;
+
+ decodePackedText(&_vm->_packedStrings[index]);
+}
+
+void LilliputScript::OC_getComputedVariantSpeech() {
+ debugC(1, kDebugScript, "OC_getComputedVariantSpeech()");
+
+ int tmpVal1 = getCharacterAttributesPtr()[0];
+ int tmpVal2 = (_currScript->readUint16LE() & 0xFF);
+ int speechVariant = tmpVal1 / tmpVal2;
+
+ int speechIndex = _currScript->readUint16LE();
+
+ bool forceReturnFl = false;
+ checkSpeechAllowed(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ _talkingCharacter = _vm->_currentScriptCharacter;
+ getSpeechVariant(speechIndex, speechVariant);
+}
+
+void LilliputScript::OC_getRotatingVariantSpeech() {
+ debugC(1, kDebugScript, "OC_getRotatingVariantSpeech()");
+
+ int index = _currScript->readUint16LE();
+ int maxValue = getPackedStringStartRelativeIndex(index);
+
+ int currVariant = _currScript->readUint16LE();
+ int nextVariant = currVariant + 1;
+ if (nextVariant >= maxValue)
+ nextVariant = 0;
+ _currScript->writeUint16LE(nextVariant, -2);
+
+ bool forceReturnFl = false;
+ checkSpeechAllowed(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ _talkingCharacter = _vm->_currentScriptCharacter;
+
+ getSpeechVariant(index, currVariant);
+
+}
+
+void LilliputScript::OC_startSpeechIfMute() {
+ debugC(1, kDebugScript, "OC_startSpeechIfMute()");
+
+ if (_talkingCharacter == -1) {
+ OC_startSpeech();
+ return;
+ }
+
+ _currScript->readUint16LE();
+}
+
+void LilliputScript::OC_getComputedVariantSpeechIfMute() {
+ debugC(1, kDebugScript, "OC_getComputedVariantSpeechIfMute()");
+
+ if (_talkingCharacter == -1) {
+ OC_getComputedVariantSpeech();
+ return;
+ }
+ _currScript->readUint16LE();
+ _currScript->readUint16LE();
+ _currScript->readUint16LE();
+ _currScript->readUint16LE();
+
+}
+
+void LilliputScript::OC_startSpeechIfSilent() {
+ debugC(1, kDebugScript, "OC_startSpeechIfSilent()");
+
+ if (_talkingCharacter == -1) {
+ OC_getRotatingVariantSpeech();
+ return;
+ }
+ _currScript->readUint16LE();
+ _currScript->readUint16LE();
+}
+
+void LilliputScript::OC_ComputeCharacterVariable() {
+ debugC(1, kDebugScript, "OC_ComputeCharacterVariable()");
+
+ byte *bufPtr = getCharacterAttributesPtr();
+ uint16 oper = _currScript->readUint16LE();
+ int16 var3 = _currScript->readSint16LE();
+
+ computeOperation(bufPtr, oper, var3);
+}
+
+void LilliputScript::OC_setAttributeToRandom() {
+ debugC(1, kDebugScript, "OC_setAttributeToRandom()");
+
+ byte *bufPtr = getCharacterAttributesPtr();
+ int maxVal = _currScript->readUint16LE();
+ int randomVal = _vm->_rnd->getRandomNumber(maxVal);
+ *bufPtr = randomVal;
+}
+
+void LilliputScript::OC_setCharacterPosition() {
+ debugC(1, kDebugScript, "OC_setCharacterPosition()");
+
+ int index = getValue1();
+ assert((index >= 0) && (index < 40));
+ Common::Point tmpVal = getPosFromScript();
+
+ int charPosX = (tmpVal.x << 3) + 4;
+ int charPosY = (tmpVal.y << 3) + 4;
+
+ _vm->_characterPos[index] = Common::Point(charPosX, charPosY);
+}
+
+void LilliputScript::OC_DisableCharacter() {
+ debugC(1, kDebugScript, "OC_DisableCharacter()");
+
+ int characterIndex = getValue1();
+ assert(characterIndex < 40);
+
+ if (characterIndex == _vm->_host)
+ _viewportCharacterTarget = -1;
+
+ _vm->_characterPos[characterIndex] = Common::Point(-1, -1);
+}
+
+void LilliputScript::OC_saveAndQuit() {
+ warning("TODO: OC_saveAndQuit");
+ _vm->_soundHandler->remove(); // Kill music
+ // TODO: Save game
+ _vm->_shouldQuit = true;
+}
+
+void LilliputScript::OC_nSkipOpcodes() {
+ debugC(1, kDebugScript, "OC_nSkipOpcodes()");
+
+ int var1 = _currScript->readUint16LE();
+ skipOpcodes(var1);
+}
+
+void LilliputScript::OC_startSpeech5() {
+ debugC(1, kDebugScript, "OC_startSpeech5()");
+
+ bool forceReturnFl = false;
+ checkSpeechAllowed(forceReturnFl);
+ if (forceReturnFl)
+ return;
+
+ _talkingCharacter = _vm->_currentScriptCharacter;
+ startSpeech(5);
+}
+
+void LilliputScript::OC_resetHandleOpcodeFlag() {
+ debugC(1, kDebugScript, "OC_resetHandleOpcodeFlag()");
+
+ _vm->_handleOpcodeReturnCode = 0;
+}
+
+void LilliputScript::OC_deleteSavegameAndQuit() {
+ warning("TODO: OC_deleteSavegameAndQuit");
+ _vm->_shouldQuit = true;
+}
+
+void LilliputScript::OC_incScriptForVal() {
+ debugC(1, kDebugScript, "OC_incScriptForVal()");
+
+ ++_scriptForVal;
+}
+
+void LilliputScript::OC_computeChararacterAttr() {
+ debugC(1, kDebugScript, "OC_ComputeChararacterAttr()");
+
+ byte *tmpArr = getCharacterAttributesPtr();
+ uint16 oper = _currScript->readUint16LE();
+ int16 var3 = getCharacterAttributesPtr()[0];
+ computeOperation(tmpArr, oper, var3);
+}
+
+void LilliputScript::OC_setTextVarNumber() {
+ debugC(1, kDebugScript, "OC_setTextVarNumber()");
+
+ byte *tmpArr = getCharacterAttributesPtr();
+ _textVarNumber = *tmpArr;
+}
+
+void LilliputScript::OC_callScript() {
+ debugC(1, kDebugScript, "OC_callScript()");
+
+ int index = _currScript->readUint16LE();
+ int charIndex = getValue1();
+ _vm->setCurrentCharacter(charIndex);
+
+ int tmpIndex = _vm->_currentScriptCharacter;
+
+ assert(index < _vm->_gameScriptIndexSize);
+ int scriptIndex = _vm->_arrayGameScriptIndex[index];
+
+ _scriptStack.push(_currScript);
+
+ if (_byte16F05_ScriptHandler == 0) {
+ _vm->_handleOpcodeReturnCode = 0;
+ debugC(1, kDebugScript, "========================== Menu Script %d==============================", scriptIndex);
+ runMenuScript(ScriptStream(&_vm->_arrayGameScripts[scriptIndex], _vm->_arrayGameScriptIndex[index + 1] - _vm->_arrayGameScriptIndex[index]));
+ debugC(1, kDebugScript, "========================== End of Menu Script==============================");
+ } else {
+ runScript(ScriptStream(&_vm->_arrayGameScripts[scriptIndex], _vm->_arrayGameScriptIndex[index + 1] - _vm->_arrayGameScriptIndex[index]));
+ }
+
+ _currScript = _scriptStack.pop();
+
+ _vm->setCurrentCharacter(tmpIndex);
+}
+
+void LilliputScript::OC_callScriptAndReturn() {
+ debugC(1, kDebugScript, "OC_callScriptAndReturn()");
+
+ OC_callScript();
+ skipOpcodes(0);
+}
+
+void LilliputScript::OC_setCurrentScriptCharacterPos() {
+ debugC(1, kDebugScript, "OC_setCurrentScriptCharacterPos()");
+
+ Common::Point pos = getPosFromScript();
+ _vm->_characterTargetPos[_vm->_currentScriptCharacter] = pos;
+ _vm->_characterSubTargetPos[_vm->_currentScriptCharacter].x = -1;
+}
+
+void LilliputScript::OC_initScriptFor() {
+ debugC(1, kDebugScript, "OC_initScriptFor()");
+
+ _scriptForVal = 0;
+}
+
+void LilliputScript::OC_setCurrentCharacterSequence() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterSequence()");
+
+ int8 seqIdx = (_currScript->readUint16LE() & 0xFF);
+ setSequence(_vm->_currentScriptCharacter, seqIdx);
+}
+
+void LilliputScript::OC_setNextCharacterSequence() {
+ debugC(1, kDebugScript, "OC_setNextCharacterSequence()");
+
+ int8 seqIdx = (_currScript->readUint16LE() & 0xFF);
+ setSequence(_vm->_currentScriptCharacter + 1, seqIdx);
+}
+
+void LilliputScript::OC_setHost() {
+ debugC(1, kDebugScript, "OC_setHost()");
+
+ _vm->_host = getValue1();
+}
+
+void LilliputScript::OC_changeMapCube() {
+ debugC(1, kDebugScript, "OC_changeMapCube()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ Common::Point var1 = Common::Point(_vm->_currentCharacterAttributes[4], _vm->_currentCharacterAttributes[5]);
+ byte var2 = _vm->_currentCharacterAttributes[6];
+
+ byte *mapPtr = getMapPtr(var1);
+ mapPtr[var2] = _vm->_currentCharacterAttributes[7];
+ mapPtr[3] = _vm->_currentCharacterAttributes[8];
+
+ if (var2 == 0) {
+ _vm->_refreshScreenFlag = true;
+ _vm->displayLandscape();
+ _vm->_refreshScreenFlag = false;
+ }
+}
+
+void LilliputScript::OC_setCharacterCarry() {
+ debugC(1, kDebugScript, "OC_setCharacterCarry()");
+
+ int8 carriedIdx = (getValue1() & 0xFF);
+ int16 index = getValue1();
+
+ int8 distBehind = (_currScript->readSint16LE() & 0xFF);
+ byte distAbove = (_currScript->readUint16LE() & 0xFF);
+
+ assert((index >= 0) && (index < 40));
+ _vm->_characterCarried[index] = carriedIdx;
+ _vm->_characterBehindDist[index] = distBehind;
+ _vm->_characterAboveDist[index] = distAbove;
+}
+
+void LilliputScript::OC_dropCarried() {
+ debugC(1, kDebugScript, "OC_dropCarried()");
+
+ int index = getValue1();
+ _vm->_characterCarried[index] = -1;
+ _vm->_characterPosAltitude[index] = 0;
+ _characterScriptEnabled[index] = 1;
+}
+
+void LilliputScript::OC_setCurrentCharacter() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacter()");
+ int index = getValue1();
+ _vm->setCurrentCharacter(index);
+}
+
+void LilliputScript::sendSignal(int16 var1, byte var2h, byte characterId, int16 var4) {
+ debugC(2, kDebugScript, "sendSignal(%d, %d, %d, %d)", var1, var2h, characterId, var4);
+
+ int index = 0;
+ for (int i = 0; i < 10; i++) {
+ if (_vm->_signalArray[index + 1] == -1) {
+ _vm->_signalArray[index + 1] = var1;
+ _vm->_signalArray[index + 2] = (var2h << 8) + characterId;
+ _vm->_signalArray[index + 0] = _vm->_signalTimer + var4;
+ return;
+ }
+ index += 3;
+ }
+}
+
+void LilliputScript::OC_sendSeeSignal() {
+ debugC(1, kDebugScript, "OC_sendSeeSignal()");
+
+ int16 type = 2 << 8; // SEE
+ int16 var4 = _currScript->readSint16LE();
+ byte var2h = (_currScript->readUint16LE() & 0xFF);
+
+ sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
+}
+
+void LilliputScript::OC_sendHearSignal() {
+ debugC(1, kDebugScript, "OC_sendHearSignal()");
+
+ int16 type = 1 << 8; // HEAR
+ int16 var4 = _currScript->readSint16LE();
+ byte var2h = (_currScript->readUint16LE() & 0xFF);
+
+ sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
+}
+
+void LilliputScript::OC_sendVarSignal() {
+ debugC(1, kDebugScript, "OC_sendVarSignal()");
+
+ int16 var4 = _currScript->readSint16LE();
+ int16 type = getValue1();
+ byte var2h = (_currScript->readUint16LE() & 0xFF);
+
+ sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
+}
+
+void LilliputScript::OC_sendBroadcastSignal() {
+ debugC(1, kDebugScript, "OC_sendBroadcastSignal()");
+
+ int16 type = 3 << 8;
+ int16 var4 = _currScript->readSint16LE();
+ byte var2h = (_currScript->readUint16LE() & 0xFF);
+
+ sendSignal(type, var2h, _vm->_currentScriptCharacter, var4);
+}
+
+void LilliputScript::OC_resetWaitingSignal() {
+ debugC(1, kDebugScript, "OC_resetWaitingSignal()");
+
+ _vm->_waitingSignal = -1;
+ _vm->_waitingSignalCharacterId = -1;
+}
+
+void LilliputScript::OC_enableCurrentCharacterScript() {
+ debugC(1, kDebugScript, "OC_enableCurrentCharacterScript()");
+
+ uint8 var1 = (_currScript->readUint16LE() & 0xFF);
+ enableCharacterScript(_vm->_currentScriptCharacter , var1, _vm->_currentCharacterAttributes);
+ skipOpcodes(0);
+}
+
+void LilliputScript::OC_IncCurrentCharacterVar1() {
+ debugC(1, kDebugScript, "OC_IncCurrentCharacterVar1()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ ++_vm->_currentCharacterAttributes[1];
+}
+
+void LilliputScript::OC_setCurrentCharacterPos() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterPos()");
+
+ uint16 oper = _currScript->readUint16LE();
+ Common::Point var1 = getPosFromScript();
+ byte* buf = _vm->_currentCharacterAttributes + 4;
+ computeOperation(buf, oper, var1.x);
+ computeOperation(buf + 1, oper, var1.y);
+}
+
+void LilliputScript::OC_setCurrentCharacterBehavior() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterBehavior()");
+
+ uint16 var1 = _currScript->readUint16LE();
+ _vm->_characterBehaviour[_vm->_currentScriptCharacter] = (var1 - 2000) & 0xFF;
+}
+
+void LilliputScript::OC_changeCurrentCharacterSprite() {
+ debugC(2, kDebugScript, "OC_changeCurrentCharacterSprite()");
+
+ int16 var1 = _currScript->readSint16LE();
+ byte var2 = (_currScript->readUint16LE() & 0xFF);
+ _vm->_characterFrameArray[_vm->_currentScriptCharacter] = var1;
+ _vm->_spriteSizeArray[_vm->_currentScriptCharacter] = var2;
+
+}
+
+byte *LilliputScript::getCurrentCharacterVarFromScript() {
+ debugC(2, kDebugScript, "getCurrentCharacterVarFromScript()");
+
+ int index = _currScript->readUint16LE();
+ return &_vm->_currentCharacterAttributes[index];
+}
+
+void LilliputScript::OC_getList() {
+ debugC(1, kDebugScript, "OC_getList()");
+
+ byte *compBuf = getCurrentCharacterVarFromScript();
+ uint16 oper = _currScript->readUint16LE();
+ int index = _currScript->readUint16LE();
+
+ byte *buf = getCurrentCharacterVarFromScript();
+ byte var1 = buf[0];
+ byte var3 = _vm->_listArr[var1 + _vm->_listIndex[index]];
+
+ computeOperation(compBuf, oper, var3);
+}
+
+void LilliputScript::OC_setList() {
+ debugC(1, kDebugScript, "OC_setList()");
+
+ int indexChunk10 = _currScript->readUint16LE();
+
+ byte *compBuf = getCurrentCharacterVarFromScript();
+ int indexChunk11 = _vm->_listIndex[indexChunk10] + compBuf[0];
+
+ uint16 oper = _currScript->readUint16LE();
+
+ byte *tmpBuf = getCurrentCharacterVarFromScript();
+ int16 var3 = tmpBuf[0];
+
+ computeOperation(&_vm->_listArr[indexChunk11], oper, var3);
+}
+
+Common::Point LilliputScript::getCharacterTilePos(int index) {
+ debugC(2, kDebugScript, "getCharacterTilePos(%d)", index);
+
+ return Common::Point(_vm->_characterPos[index].x >> 3, _vm->_characterPos[index].y >> 3);
+}
+
+void LilliputScript::OC_setCharacterDirectionTowardsPos() {
+ debugC(1, kDebugScript, "OC_setCharacterDirectionTowardsPos()");
+
+ Common::Point pos1 = getPosFromScript();
+ Common::Point tilePos = getCharacterTilePos(_vm->_currentScriptCharacter);
+
+ _vm->_characterDirectionArray[_vm->_currentScriptCharacter] = _vm->getDirection(tilePos, pos1);
+}
+
+void LilliputScript::OC_turnCharacterTowardsAnother() {
+ debugC(1, kDebugScript, "OC_turnCharacterTowardsAnother()");
+
+ int index = getValue1();
+
+ static const byte _directionsArray[] = { 0, 2, 0, 1, 3, 2, 3, 1 };
+
+ int dx = _vm->_characterPos[index].x - _vm->_characterPos[_vm->_currentScriptCharacter].x;
+ int dy = _vm->_characterPos[index].y - _vm->_characterPos[_vm->_currentScriptCharacter].y;
+
+ int flag = 0;
+ if (dx < 0) {
+ dx = -dx;
+ flag |= 4;
+ }
+ if (dy < 0) {
+ dy = -dy;
+ flag |= 2;
+ }
+ if (dx < dy) {
+ flag |= 1;
+ }
+
+ _vm->_characterDirectionArray[_vm->_currentScriptCharacter] = _directionsArray[flag];
+}
+
+void LilliputScript::OC_setSeek() {
+ debugC(1, kDebugScript, "OC_setSeek()");
+
+ int16 var = getValue1();
+ _characterSeek[_vm->_currentScriptCharacter] = (byte)(var & 0xFF);
+ _vm->_characterSubTargetPos[_vm->_currentScriptCharacter].x = -1;
+}
+
+void LilliputScript::OC_scrollAwayFromCharacter() {
+ debugC(1, kDebugScript, "OC_scrollAwayFromCharacter()");
+
+ if (_vm->_currentScriptCharacter != _viewportCharacterTarget)
+ return;
+
+ static const int8 speedX[] = {-1, -3, -3, -6};
+ static const int8 speedY[] = {-3, -6, -1, -3};
+
+ int cx = speedX[_vm->_characterDirectionArray[_vm->_currentScriptCharacter]];
+ int cy = speedY[_vm->_characterDirectionArray[_vm->_currentScriptCharacter]];
+
+ Common::Point pos = getCharacterTilePos(_vm->_currentScriptCharacter);
+
+ int newPosX = pos.x + cx;
+ int newPosY = pos.y + cy;
+
+ newPosX = CLIP(newPosX, 0, 56);
+ newPosY = CLIP(newPosY, 0, 56);
+
+ _vm->_refreshScreenFlag = true;
+ _vm->viewportScrollTo(Common::Point(newPosX, newPosY));
+ _vm->_refreshScreenFlag = false;
+
+}
+
+void LilliputScript::OC_skipNextVal() {
+ debugC(1, kDebugScript, "OC_skipNextVal()");
+
+ _currScript->readUint16LE();
+}
+
+void LilliputScript::OC_setCurrentCharacterAttr6() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterAttr6()");
+
+ uint16 var1 = (uint16)getValue1();
+ _vm->_currentCharacterAttributes[6] = var1 & 0xFF;
+}
+
+void LilliputScript::OC_setCurrentCharacterPose() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterPose()");
+
+ int index = _currScript->readUint16LE();
+
+ int tmpVal = (_vm->_currentScriptCharacter * 32) + index;
+ assert (tmpVal < 40 * 32);
+ _characterPose[_vm->_currentScriptCharacter] = _vm->_poseArray[tmpVal];
+ _characterNextSequence[_vm->_currentScriptCharacter] = 16;
+}
+
+void LilliputScript::OC_setCharacterScriptEnabled() {
+ debugC(1, kDebugScript, "OC_setCharacterScriptEnabled()");
+
+ int16 index = getValue1();
+ _characterScriptEnabled[index] = 1;
+}
+
+void LilliputScript::OC_setCurrentCharacterAttr2() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterAttr2()");
+
+ int curWord = _currScript->readUint16LE();
+ assert(_vm->_currentCharacterAttributes != NULL);
+ _vm->_currentCharacterAttributes[2] = curWord & 0xFF;
+}
+
+void LilliputScript::OC_clearCurrentCharacterAttr2() {
+ debugC(1, kDebugScript, "OC_clearCurrentCharacterAttr2()");
+
+ assert(_vm->_currentCharacterAttributes != NULL);
+ _vm->_currentCharacterAttributes[2] = 0;
+}
+
+void LilliputScript::OC_setCharacterProperties() {
+ debugC(1, kDebugScript, "OC_setCharacterProperties()");
+
+ int16 index = getValue1();
+
+ int16 x = _vm->_characterPos[index].x & 0xFFF8;
+ x += _currScript->readSint16LE();
+ _vm->_characterPos[index].x = x;
+
+ int16 y = _vm->_characterPos[index].y & 0xFFF8;
+ y += _currScript->readSint16LE();
+ _vm->_characterPos[index].y = y;
+
+ _vm->_characterPosAltitude[index] = (int8)(_currScript->readUint16LE() & 0xFF);
+ _vm->_characterDirectionArray[index] = _currScript->readUint16LE() & 0xFF;
+}
+
+void LilliputScript::OC_setMonitoredCharacter() {
+ debugC(1, kDebugScript, "OC_setMonitoredCharacter()");
+
+ _monitoredCharacter = getValue1();
+ for (int i = 0; i < 4; i++)
+ _monitoredAttr[i] = _currScript->readUint16LE() & 0xFF;
+}
+
+void LilliputScript::OC_setNewPose() {
+ debugC(1, kDebugScript, "OC_setNewPose()");
+
+ int var2 = _currScript->readUint16LE();
+ byte var1 = (_currScript->readUint16LE() & 0xFF);
+
+ _vm->_poseArray[(_vm->_currentScriptCharacter * 32) + var2] = var1;
+}
+
+void LilliputScript::OC_setCurrentCharacterDirection() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterDirection()");
+
+ _vm->_characterDirectionArray[_vm->_currentScriptCharacter] = (_currScript->readUint16LE() & 0xFF);
+}
+
+void LilliputScript::OC_setInterfaceHotspot() {
+ debugC(1, kDebugScript, "OC_setInterfaceHotspot()");
+
+ int16 index = _currScript->readSint16LE();
+ assert((index >= 0) && (index < 20));
+
+ uint16 curWord = _currScript->readUint16LE();
+ _interfaceHotspotStatus[index] = (curWord & 0xFF);
+ _interfaceButtonActivationDelay[index] = (curWord >> 8);
+
+ _vm->displayInterfaceHotspots();
+}
+
+void LilliputScript::OC_scrollViewPort() {
+ debugC(1, kDebugScript, "OC_scrollViewPort()");
+
+ _viewportCharacterTarget = -1;
+
+ int direction = _currScript->readUint16LE();
+
+ static const int8 scrollValX[] = { 6, 0, 0, -6 };
+ static const int8 scrollValY[] = { 0, -6, 6, 0 };
+
+ int x = _viewportPos.x + scrollValX[direction];
+ int y = _viewportPos.y + scrollValY[direction];
+
+ x = CLIP(x, 0, 56);
+ y = CLIP(y, 0, 56);
+
+ _vm->_refreshScreenFlag = true;
+ _vm->viewportScrollTo(Common::Point(x, y));
+ _vm->_refreshScreenFlag = false;
+}
+
+void LilliputScript::OC_setViewPortPos() {
+ debugC(1, kDebugScript, "OC_setViewPortPos()");
+
+ _viewportCharacterTarget = -1;
+ _viewportPos = getPosFromScript();
+
+ _vm->displayLandscape();
+ _vm->prepareGameArea();
+}
+
+void LilliputScript::OC_setCurrentCharacterAltitude() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterAltitude()");
+
+ _vm->_characterPosAltitude[_vm->_currentScriptCharacter] = (_currScript->readUint16LE() & 0xFF);
+}
+
+void LilliputScript::OC_setModePriority() {
+ debugC(1, kDebugScript, "OC_setModePriority()");
+
+ EvaluatedMode newMode;
+
+ newMode._mode = _currScript->readUint16LE() & 0xFF;
+ newMode._priority = _currScript->readUint16LE() & 0xFF;
+
+ setMode(newMode);
+}
+
+void LilliputScript::setMode(EvaluatedMode newMode) {
+ debugC(2, kDebugScript, "setMode(%d - %d)", newMode._mode, newMode._priority);
+
+ for (int i = 0; i < _vm->_newModesEvaluatedNumber; i++) {
+ if (_newEvaluatedModes[i]._mode == newMode._mode) {
+ int newPriority = newMode._priority + _newEvaluatedModes[i]._priority;
+ newPriority = CLIP(newPriority, 0, 255);
+
+ _newEvaluatedModes[i]._priority = newPriority;
+ return;
+ }
+ }
+
+ _newEvaluatedModes[_vm->_newModesEvaluatedNumber] = newMode;
+ ++_vm->_newModesEvaluatedNumber;
+}
+
+void LilliputScript::OC_setComputedModePriority() {
+ debugC(1, kDebugScript, "OC_setComputedModePriority()");
+
+ int8 mode = (int8)(_currScript->readUint16LE() & 0xFF);
+ byte oper = _currScript->readUint16LE() & 0xFF;
+ uint16 index = _currScript->readUint16LE();
+ int16 c = _vm->_currentCharacterAttributes[index];
+
+ switch (oper) {
+ case '-':
+ c = -1 - c;
+ break;
+ case '>':
+ c -= 128;
+ if (c < 0)
+ c = 0;
+ c *= 2;
+ break;
+ case '<':
+ c = -1 - c - 128;
+ if (c < 0)
+ c = 0;
+ c *= 2;
+ break;
+ case '+':
+ break;
+ default:
+ warning("OC_setComputedModePriority: skipped oper %c", oper);
+ break;
+ }
+ if (c > 0xFF)
+ warning("OC_setComputedModePriority- Abnormal value c = %d, should put back c &= 0xFF;", c);
+
+ int priority = (_currScript->readSint16LE() * c) + c;
+ priority >>= 8;
+
+ EvaluatedMode newMode;
+ newMode._mode = mode;
+ newMode._priority = priority;
+
+ setMode(newMode);
+}
+
+void LilliputScript::OC_selectBestMode() {
+ debugC(1, kDebugScript, "OC_selectBestMode()");
+
+ uint16 var1 = _currScript->readUint16LE();
+
+ int maxValue = 0;
+ int maxItem = var1 & 0xFF;
+
+ for (int i = 0; i < _vm->_newModesEvaluatedNumber; i++) {
+ if (_newEvaluatedModes[i]._priority > maxValue) {
+ maxValue = _newEvaluatedModes[i]._priority;
+ maxItem = _newEvaluatedModes[i]._mode;
+ }
+ }
+ enableCharacterScript(_vm->_currentScriptCharacter, maxItem, _vm->_currentCharacterAttributes);
+}
+
+void LilliputScript::OC_magicPuffEntrance() {
+ debugC(1, kDebugScript, "OC_magicPuffEntrance()");
+
+ int16 index = getValue1();
+ assert((index >0) && (index < 40));
+
+ _vm->_characterMagicPuffFrame[index] = 4;
+}
+
+void LilliputScript::OC_spawnCharacterAtPos() {
+ debugC(1, kDebugScript, "OC_spawnCharacterAtPos()");
+
+ int index = getValue1();
+ Common::Point var4 = getPosFromScript();
+
+ Common::Point pt = var4 + _viewportPos;
+ byte *isoMapBuf = getMapPtr(pt);
+
+ if (isoMapBuf[1] != 0xFF) {
+ int minVal = INT_MAX;
+ for (int var2 = 7; var2 >= 0; var2--) {
+ for (int var3 = 7; var3 >= 0; var3--) {
+ Common::Point(_viewportPos.x + var2, _viewportPos.y + var3);
+ isoMapBuf = getMapPtr(pt);
+
+ if (isoMapBuf[1] == 0xFF) {
+ int x = abs(var2 - var4.x);
+ int y = abs(var3 - var4.y);
+ if (x + y < minVal) {
+ minVal = x + y;
+ _word1825E = Common::Point(var2, var3);
+ }
+ }
+ }
+ }
+ var4 = _word1825E;
+ }
+
+ _vm->_characterPos[index].x = (var4.x + _viewportPos.x) * 8;
+ _vm->_characterPos[index].y = (var4.y + _viewportPos.y) * 8;
+}
+
+void LilliputScript::OC_CharacterVariableAddOrRemoveFlag() {
+ debugC(1, kDebugScript, "OC_CharacterVariableAddOrRemoveFlag()");
+
+ byte *tmpArr = getCharacterAttributesPtr();
+
+ byte var1 = (_currScript->readUint16LE() & 0xFF);
+ byte var2 = (_currScript->readUint16LE() & 0xFF);
+
+ if (var2 == 0)
+ tmpArr[0] &= ~var1;
+ else
+ tmpArr[0] |= var1;
+}
+
+void LilliputScript::OC_PaletteFadeOut() {
+ debugC(1, kDebugScript, "OC_PaletteFadeOut()");
+
+ _vm->_refreshScreenFlag = true;
+ _vm->paletteFadeOut();
+ _vm->_refreshScreenFlag = false;
+}
+
+void LilliputScript::OC_PaletteFadeIn() {
+ debugC(1, kDebugScript, "OC_PaletteFadeIn()");
+
+ _vm->_refreshScreenFlag = true;
+ _vm->paletteFadeIn();
+ _vm->_refreshScreenFlag = false;
+}
+
+void LilliputScript::OC_loadAndDisplayCubesGfx() {
+ debugC(1, kDebugScript, "OC_loadAndDisplayCubesGfx()");
+
+ int setNumb = (_currScript->readUint16LE() & 0xFF);
+ assert((setNumb >= 0) && (setNumb <= 9));
+ Common::String fileName = Common::String::format("CUBES%d.GFX", setNumb);
+ _cubeSet = setNumb; // Useless in this variant, keep for the moment for Rome
+
+ _vm->_bufferCubegfx = _vm->loadVGA(fileName, 61440, false);
+ _vm->displayLandscape();
+ _vm->prepareGameArea();
+}
+
+void LilliputScript::OC_setCurrentCharacterAttr3() {
+ debugC(1, kDebugScript, "OC_setCurrentCharacterAttr3()");
+
+ byte var1 = _currScript->readUint16LE() & 0xFF;
+ assert(_vm->_currentCharacterAttributes != NULL);
+
+ _vm->_currentCharacterAttributes[3] = var1;
+}
+
+void LilliputScript::OC_setArray122C1() {
+ debugC(1, kDebugScript, "OC_setArray122C1()");
+
+ byte var1 = (_currScript->readUint16LE() & 0xFF);
+ _array122C1[_vm->_currentScriptCharacter] = var1;
+}
+
+void LilliputScript::OC_sub18367() {
+ debugC(1, kDebugScriptTBC, "OC_sub18367()");
+
+ _characterScriptEnabled[_vm->_currentScriptCharacter] = 1;
+ _vm->_currentCharacterAttributes[0] = _array122C1[_vm->_currentScriptCharacter];
+ _vm->_currentCharacterAttributes[1] = 0;
+ _vm->_currentCharacterAttributes[2] = 0;
+ _vm->_currentCharacterAttributes[3] = 0;
+}
+
+void LilliputScript::OC_enableCharacterScript() {
+ debugC(1, kDebugScript, "OC_enableCharacterScript()");
+
+ int16 index = getValue1();
+ byte var2 = _currScript->readUint16LE() & 0xFF;
+
+ enableCharacterScript(index, var2, _vm->getCharacterAttributesPtr(index * 32));
+}
+
+void LilliputScript::OC_setRulesBuffer2Element() {
+ debugC(1, kDebugScript, "OC_setRulesBuffer2Element()");
+
+ int index = getValue1();
+ byte var1 = _currScript->readUint16LE() & 0xFF;
+
+ assert((index >= 0) && (index < 40));
+ _vm->_characterMobility[index] = var1;
+}
+
+void LilliputScript::OC_setDebugFlag() {
+ debugC(1, kDebugScript, "OC_setDebugFlag()");
+
+ _vm->_debugFlag = 1;
+}
+
+void LilliputScript::OC_setDebugFlag2() {
+ debugC(1, kDebugScript, "OC_setDebugFlag2()");
+
+ _vm->_debugFlag2 = 1;
+}
+
+void LilliputScript::OC_waitForEvent() {
+ debugC(1, kDebugScript, "OC_waitForEvent()");
+
+ _vm->_refreshScreenFlag = true;
+ while (true) {
+ if (_vm->_keyboard_checkKeyboard()) {
+ _vm->_keyboard_getch();
+ break;;
+ }
+ if (_vm->_mouseButton == 1)
+ break;
+
+ _vm->update();
+ }
+
+ _vm->_mouseButton = 0;
+ _vm->_refreshScreenFlag = false;
+}
+
+void LilliputScript::OC_disableInterfaceHotspot() {
+ debugC(1, kDebugScript, "OC_disableInterfaceHotspot()");
+
+ int index = _currScript->readUint16LE();
+ _interfaceButtonActivationDelay[index] = (_currScript->readUint16LE() & 0xFF);
+ _interfaceHotspotStatus[index] = kHotspotDisabled;
+
+ _vm->displayInterfaceHotspots();
+}
+
+void LilliputScript::OC_loadFileAerial() {
+ debugC(1, kDebugScript, "OC_loadFileAerial()");
+
+ // Unused variable, and the script position is restored afterwards
+ // TODO: Check if this part of the code is present in Rome, else remove it
+ // int var1 = _currScript->readUint16LE() & 0xFF;
+ // byte _byte15EAD = var1;
+
+ _vm->_refreshScreenFlag = true;
+ _talkingCharacter = -1;
+ OC_PaletteFadeOut();
+ _vm->_displayGreenHand = true;
+ _vm->displayVGAFile("AERIAL.GFX");
+ OC_PaletteFadeIn();
+
+ _vm->displayCharactersOnMap();
+ _vm->_displayMap = true;
+
+ _vm->_keyboard_resetKeyboardBuffer();
+
+ _vm->_refreshScreenFlag = false;
+}
+
+void LilliputScript::OC_startSpeechIfSoundOff() {
+ debugC(1, kDebugScript, "OC_startSpeechIfSoundOff()");
+
+ // HACK: In the original, OC_startSpeechIfSoundOff() only calls
+ // OC_startSpeech if sound is off. For the moment, it's always called
+
+ OC_startSpeech();
+}
+
+void LilliputScript::OC_sub1844A() {
+ debugC(1, kDebugScriptTBC, "OC_sub1844A()");
+
+ int characterIndex = getValue1();
+ int var2 = _currScript->readUint16LE();
+
+ _vm->_characterTypes[characterIndex] = (var2 & 0xFF);
+
+ for (int i = 0; i < 40; i++) {
+ _interactions[40 * characterIndex + i] = 0;
+ _interactions[characterIndex + 40 * i] = 0;
+ }
+}
+
+void LilliputScript::OC_displayNumericCharacterVariable() {
+ debugC(1, kDebugScript, "OC_displayNumericCharacterVariable()");
+
+ byte *charAttrArr = getCharacterAttributesPtr();
+ byte attr = charAttrArr[0];
+ int divisor = _currScript->readUint16LE();
+ assert(divisor != 0);
+ int displayVal = attr / (divisor & 0xFF);
+ int posX = _currScript->readSint16LE();
+ int posY = _currScript->readSint16LE();
+
+ if (!_vm->_displayMap)
+ displayNumber(displayVal, Common::Point(posX, posY));
+}
+
+void LilliputScript::displayNumber(byte var1, Common::Point pos) {
+ debugC(1, kDebugScript, "displayNumber(%d, %d - %d)", var1, pos.x, pos.y);
+
+ _vm->_displayStringIndex = 0;
+ _vm->_displayStringBuf[0] = 32;
+ _vm->_displayStringBuf[1] = 32;
+ _vm->_displayStringBuf[2] = 32;
+ _vm->_displayStringBuf[3] = 0;
+
+ _vm->numberToString(var1);
+ _vm->displayString(_vm->_displayStringBuf, pos);
+}
+
+void LilliputScript::OC_displayVGAFile() {
+ debugC(1, kDebugScript, "OC_displayVGAFile()");
+
+ _vm->_refreshScreenFlag = true;
+ _vm->paletteFadeOut();
+ int curWord = _currScript->readUint16LE();
+ int index = _vm->_packedStringIndex[curWord];
+ Common::String fileName = Common::String((const char *)&_vm->_packedStrings[index]);
+ _talkingCharacter = -1;
+ _vm->displayVGAFile(fileName);
+ _vm->paletteFadeIn();
+}
+
+void LilliputScript::OC_startSpeechWithoutSpeeker() {
+ debugC(1, kDebugScript, "OC_startSpeechWithoutSpeeker()");
+
+ int16 speechId = _currScript->readUint16LE();
+ startSpeech(speechId);
+}
+
+void LilliputScript::OC_displayTitleScreen() {
+ debugC(1, kDebugScript, "OC_displayTitleScreen()");
+
+ _vm->_keyDelay = (_currScript->readUint16LE() & 0xFF);
+ _vm->_int8Timer = _vm->_keyDelay;
+
+ _vm->_keyboard_resetKeyboardBuffer();
+
+ _vm->_mouseButton = 0;
+ _vm->_lastKeyPressed = Common::Event();
+
+ while (!_vm->_shouldQuit) {
+ _vm->displaySmallAnims();
+ _vm->update();
+ _vm->pollEvent();
+ if (_vm->_keyboard_checkKeyboard()) {
+ Common::Event event = _vm->_keyboard_getch();
+ _vm->_lastKeyPressed = event;
+ if (event.type == Common::EVENT_KEYDOWN)
+ _vm->_keyboard_getch();
+ break;
+ }
+
+ if (_vm->_mouseButton == 1)
+ break;
+
+ if ((_vm->_keyDelay != 0) && (_vm->_int8Timer == 0))
+ break;
+
+ _vm->_system->delayMillis(1);
+ }
+
+ _vm->_mouseButton = 0;
+}
+
+void LilliputScript::OC_initGameAreaDisplay() {
+ debugC(1, kDebugScript, "OC_initGameAreaDisplay()");
+
+ OC_PaletteFadeOut();
+ _vm->_displayMap = false;
+ _heroismLevel = 0;
+ _vm->unselectInterfaceHotspots();
+
+ _vm->initGameAreaDisplay();
+
+ OC_PaletteFadeIn();
+ _vm->_refreshScreenFlag = false;
+
+ _vm->_soundHandler->update();
+}
+
+void LilliputScript::OC_displayCharacterStatBar() {
+ debugC(1, kDebugScript, "OC_displayCharacterStatBar()");
+
+ byte *tmpArr = getCharacterAttributesPtr();
+ int8 type = (_currScript->readUint16LE() & 0xFF);
+ int8 score = (((70 * tmpArr[0]) / (_currScript->readUint16LE() & 0xFF)) & 0xFF);
+ int16 posX = _currScript->readSint16LE();
+ int16 posY = _currScript->readSint16LE();
+
+ _vm->displayCharacterStatBar(type, posX, score, posY);
+}
+
+void LilliputScript::OC_initSmallAnim() {
+ debugC(1, kDebugScript, "OC_initSmallAnim()");
+
+ int index = _currScript->readUint16LE();
+ assert (index < 4);
+ _vm->_smallAnims[index]._active = true;
+ _vm->_smallAnims[index]._pos.x = _currScript->readSint16LE();
+ _vm->_smallAnims[index]._pos.y = _currScript->readSint16LE();
+
+ for (int i = 0; i < 8; i++)
+ _vm->_smallAnims[index]._frameIndex[i] = _currScript->readUint16LE();
+}
+
+void LilliputScript::OC_setCharacterHeroismBar() {
+ debugC(1, kDebugScript, "OC_setCharacterHeroismBar()");
+
+ _barAttrPtr = getCharacterAttributesPtr();
+ _heroismBarX = _currScript->readUint16LE();
+ _heroismBarBottomY = _currScript->readUint16LE();
+}
+
+void LilliputScript::OC_setCharacterHome() {
+ debugC(1, kDebugScript, "OC_setCharacterHome()");
+
+ int index = getValue1();
+ _vm->_characterHomePos[index] = getPosFromScript();
+}
+
+void LilliputScript::OC_setViewPortCharacterTarget() {
+ debugC(1, kDebugScript, "OC_setViewPortCharacterTarget()");
+
+ _viewportCharacterTarget = getValue1();
+}
+
+void LilliputScript::OC_showObject() {
+ debugC(1, kDebugScript, "OC_showObject()");
+
+ int frameIdx = getValue1();
+ int posX = _currScript->readUint16LE();
+ int posY = _currScript->readUint16LE();
+ Common::Point pos = Common::Point(posX, posY);
+
+ _vm->fill16x16Rect(16, pos);
+
+ int frame = _vm->_characterFrameArray[frameIdx];
+ byte* buf = _vm->_bufferMen;
+
+ if (frame > 240) {
+ buf = _vm->_bufferMen2;
+ frame -= 240;
+ }
+
+ _vm->display16x16IndexedBuf(buf, frame, pos);
+}
+
+void LilliputScript::OC_playObjectSound() {
+ debugC(1, kDebugScript, "OC_playObjectSound()");
+ int index = getValue1();
+ assert(index < 40);
+
+ Common::Point var4 = Common::Point(0xFF, index & 0xFF);
+ int soundId = (_currScript->readUint16LE() & 0xFF);
+
+ _vm->_soundHandler->play(soundId, _viewportPos, _characterTilePos[index], var4);
+}
+
+void LilliputScript::OC_startLocationSound() {
+ debugC(1, kDebugScript, "OC_startLocationSound()");
+
+ Common::Point var3 = getPosFromScript();
+ Common::Point var4 = var3;
+ Common::Point var2 = _viewportPos;
+ int var1 = (_currScript->readUint16LE() & 0xFF);
+
+ _vm->_soundHandler->play(var1, var2, var3, var4);
+}
+
+void LilliputScript::OC_stopObjectSound() {
+ debugC(1, kDebugScript, "OC_stopObjectSound()");
+
+ Common::Point var4 = Common::Point(-1, getValue1() & 0xFF);
+
+ _vm->_soundHandler->stop(var4); // Stop Sound
+}
+
+void LilliputScript::OC_stopLocationSound() {
+ debugC(1, kDebugScript, "OC_stopLocationSound()");
+
+ Common::Point var4 = getPosFromScript();
+
+ _vm->_soundHandler->stop(var4);
+}
+
+void LilliputScript::OC_toggleSound() {
+ debugC(1, kDebugScript, "OC_toggleSound()");
+
+ _vm->_soundHandler->toggleOnOff();
+}
+
+void LilliputScript::OC_playMusic() {
+ debugC(1, kDebugScript, "OC_playMusic()");
+
+ Common::Point var4 = Common::Point(-1, -1);
+ Common::Point var2 = _viewportPos;
+ int var1 = _currScript->readSint16LE() & 0xFF;
+ warning("OC_playMusic: unknown value for var3");
+ Common::Point var3 = Common::Point(-1, -1);
+
+ _vm->_soundHandler->play(var1, var2, var3, var4);
+}
+
+void LilliputScript::OC_stopMusic() {
+ debugC(1, kDebugScript, "OC_stopMusic()");
+
+ _vm->_soundHandler->remove();
+}
+
+void LilliputScript::OC_setCharacterMapColor() {
+ debugC(1, kDebugScript, "OC_setCharacterMapColor()");
+
+ byte index = (getValue1() & 0xFF);
+ int color = _currScript->readUint16LE();
+
+ assert(index < 40);
+ _characterMapPixelColor[index] = (color & 0xFF);
+}
+
+} // End of namespace
diff --git a/engines/lilliput/script.h b/engines/lilliput/script.h
new file mode 100644
index 0000000000..d75d24e3cf
--- /dev/null
+++ b/engines/lilliput/script.h
@@ -0,0 +1,316 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 LILLIPUT_SCRIPT_H
+#define LILLIPUT_SCRIPT_H
+
+#include "common/memstream.h"
+#include "common/stack.h"
+#include "common/random.h"
+#include "common/rect.h"
+
+#include "lilliput/stream.h"
+
+namespace Lilliput {
+
+class LilliputEngine;
+
+enum kActionType {
+ kActionNone = 0,
+ kButtonPressed = 1,
+ kButtonReleased = 2,
+ kActionTalk = 3,
+ kActionGoto = 4,
+ kCubeSelected = 5,
+ kCodeEntered = 6
+};
+
+enum kValueType {
+ kNone,
+ kImmediateValue,
+ kCompareOperation,
+ kComputeOperation,
+ kGetValue1,
+ kgetPosFromScript
+};
+
+struct OpCode {
+ const char* _opName;
+ int _numArgs;
+ kValueType _arg1;
+ kValueType _arg2;
+ kValueType _arg3;
+ kValueType _arg4;
+ kValueType _arg5;
+};
+
+struct EvaluatedMode {
+ int _mode;
+ int _priority;
+};
+
+class LilliputScript {
+public:
+ byte _heroismLevel;
+ byte _speechTimer;
+
+ byte _characterScriptEnabled[40];
+ int8 _interfaceHotspotStatus[20];
+ Common::Point _characterTilePos[40];
+ int8 _characterNextSequence[40];
+ int8 _characterPose[40];
+ byte _interfaceButtonActivationDelay[20];
+ byte _array122C1[40];
+ byte _characterSeek[40];
+ int16 _interactions[40 * 40];
+
+ byte *_barAttrPtr;
+
+ Common::Point _viewportPos;
+ int16 _viewportCharacterTarget;
+ int16 _talkingCharacter;
+ int _heroismBarX;
+ int _heroismBarBottomY;
+
+ Common::Point _sequenceArr[640];
+ byte _characterMapPixelColor[40];
+ int8 _characterLastSequence[40];
+ EvaluatedMode _newEvaluatedModes[32];
+
+ LilliputScript(LilliputEngine *vm);
+ ~LilliputScript();
+
+ void disasmScript(ScriptStream script);
+ void listAllTexts();
+ static Common::String getArgumentString(kValueType type, ScriptStream& script);
+ void runScript(ScriptStream script);
+ void runMenuScript(ScriptStream script);
+private:
+ LilliputEngine *_vm;
+
+ ScriptStream *_currScript;
+ Common::Stack<ScriptStream *> _scriptStack;
+
+ byte _byte16F05_ScriptHandler;
+ byte _cubeSet;
+ byte _lastRandomValue;
+ byte _scriptForVal;
+ byte _textVarNumber;
+ byte _speechDisplaySpeed;
+
+ int16 _word16F00_characterId;
+ int _currentSpeechId;
+ int _word18821;
+ int _monitoredCharacter;
+ Common::Point _word1825E;
+
+ char _monitoredAttr[4];
+
+ int handleOpcode(ScriptStream *script);
+ byte handleOpcodeType1(int curWord);
+ void handleOpcodeType2(int curWord);
+
+ void enableCharacterScript(byte index, byte var1, byte *curBufPtr);
+ void skipOpcodes(int var1);
+ void copySequence(int index, byte *buf);
+ void setSequence(int charIdx, int8 seqIdx);
+ void checkSpeechAllowed(bool &forceReturnFl);
+ void decodePackedText(char *buf);
+ void startSpeech(int var);
+ void displayNumber(byte var1, Common::Point pos);
+ byte *getMapPtr(Common::Point val);
+ byte *getCurrentCharacterVarFromScript();
+ void sendSignal(int16 var1, byte var2h, byte characterId, int16 var4);
+ void getSpeechVariant(int speechIndex, int speechVariant);
+ void showSpeech();
+ void formatSpeechString();
+ Common::Point getCharacterTilePos(int index);
+ int getPackedStringStartRelativeIndex(int index);
+
+ int16 getValue1();
+ Common::Point getPosFromScript();
+
+ byte *getCharacterAttributesPtr();
+ byte compareValues(int16 var1, uint16 oper, int16 var2);
+ void computeOperation(byte *bufPtr, uint16 oper, int16 var2);
+
+ //Opcodes Type 1
+ byte OC_checkCharacterGoalPos();
+ byte OC_comparePos();
+ byte OC_checkIsoMap3();
+ byte OC_compareCharacterVariable();
+ byte OC_CompareLastRandomValue();
+ byte OC_getRandom();
+ byte OC_for();
+ byte OC_compCurrentSpeechId();
+ byte OC_checkSaveFlag();
+ byte OC_compScriptForVal();
+ byte OC_isCarrying();
+ byte OC_CompareCharacterVariables();
+ byte OC_compareCoords_1();
+ byte OC_compareCoords_2();
+ byte OC_CompareDistanceFromCharacterToPositionWith();
+ byte OC_compareRandomCharacterId();
+ byte OC_IsCurrentCharacterIndex();
+ byte OC_hasVisibilityLevel();
+ byte OC_hasGainedVisibilityLevel();
+ byte OC_hasReducedVisibilityLevel();
+ byte OC_isHost();
+ byte OC_isSequenceActive();
+ byte OC_isSequenceFinished();
+ byte OC_CompareMapValueWith();
+ byte OC_IsCharacterValid();
+ byte OC_CheckWaitingSignal();
+ byte OC_CurrentCharacterVar0AndVar1Equals();
+ byte OC_CurrentCharacterVar0Equals();
+ byte OC_checkLastInterfaceHotspotIndexMenu13();
+ byte OC_checkLastInterfaceHotspotIndexMenu2();
+ byte OC_CompareNumberOfCharacterWithVar0Equals();
+ byte OC_IsPositionInViewport();
+ byte OC_CompareGameVariables();
+ byte OC_skipNextOpcode();
+ byte OC_CheckCurrentCharacterAttr2();
+ byte OC_CheckCurrentCharacterType();
+ byte OC_CheckCurrentCharacterAttr0And();
+ byte OC_IsCurrentCharacterAttr0LessEqualThan();
+ byte OC_isCarried();
+ byte OC_CheckCurrentCharacterAttr1();
+ byte OC_isCurrentCharacterSpecial();
+ byte OC_CurrentCharacterAttr3Equals1();
+ byte OC_checkCharacterDirection();
+ byte OC_checkLastInterfaceHotspotIndex();
+ byte OC_checkSelectedCharacter();
+ byte OC_checkDelayedReactivation();
+ byte OC_checkTargetReached();
+ byte OC_checkFunctionKeyPressed();
+ byte OC_checkCodeEntered();
+ byte OC_checkViewPortCharacterTarget();
+
+ // Opcodes Type 2
+ void OC_setWord18821();
+ void OC_ChangeIsoMap();
+ void OC_startSpeech();
+ void OC_getComputedVariantSpeech();
+ void OC_getRotatingVariantSpeech();
+ void OC_startSpeechIfMute();
+ void OC_getComputedVariantSpeechIfMute();
+ void OC_startSpeechIfSilent();
+ void OC_ComputeCharacterVariable();
+ void OC_setAttributeToRandom();
+ void OC_setCharacterPosition();
+ void OC_DisableCharacter();
+ void OC_saveAndQuit();
+ void OC_nSkipOpcodes();
+ void OC_startSpeech5();
+ void OC_resetHandleOpcodeFlag();
+ void OC_deleteSavegameAndQuit();
+ void OC_incScriptForVal();
+ void OC_computeChararacterAttr();
+ void OC_setTextVarNumber();
+ void OC_callScript();
+ void OC_callScriptAndReturn();
+ void OC_setCurrentScriptCharacterPos();
+ void OC_initScriptFor();
+ void OC_setCurrentCharacterSequence();
+ void OC_setNextCharacterSequence();
+ void OC_setHost();
+ void OC_changeMapCube();
+ void OC_setCharacterCarry();
+ void OC_dropCarried();
+ void OC_setCurrentCharacter();
+ void OC_sendSeeSignal();
+ void OC_sendHearSignal();
+ void OC_sendVarSignal();
+ void OC_sendBroadcastSignal();
+ void OC_resetWaitingSignal();
+ void OC_enableCurrentCharacterScript();
+ void OC_IncCurrentCharacterVar1();
+ void OC_setCurrentCharacterPos();
+ void OC_setCurrentCharacterBehavior();
+ void OC_changeCurrentCharacterSprite();
+ void OC_getList();
+ void OC_setList();
+ void OC_setCharacterDirectionTowardsPos();
+ void OC_turnCharacterTowardsAnother();
+ void OC_setSeek();
+ void OC_scrollAwayFromCharacter();
+ void OC_skipNextVal();
+ void OC_setCurrentCharacterAttr6();
+ void OC_setCurrentCharacterPose();
+ void OC_setCharacterScriptEnabled();
+ void OC_setCurrentCharacterAttr2();
+ void OC_clearCurrentCharacterAttr2();
+ void OC_setCharacterProperties();
+ void OC_setMonitoredCharacter();
+ void OC_setNewPose();
+ void OC_setCurrentCharacterDirection();
+ void OC_setInterfaceHotspot();
+ void OC_scrollViewPort();
+ void OC_setViewPortPos();
+ void OC_setCurrentCharacterAltitude();
+ void OC_setModePriority();
+ void setMode(EvaluatedMode newMode);
+ void OC_setComputedModePriority();
+ void OC_selectBestMode();
+ void OC_magicPuffEntrance();
+ void OC_spawnCharacterAtPos();
+ void OC_CharacterVariableAddOrRemoveFlag();
+ void OC_PaletteFadeOut();
+ void OC_PaletteFadeIn();
+ void OC_loadAndDisplayCubesGfx();
+ void OC_setCurrentCharacterAttr3();
+ void OC_setArray122C1();
+ void OC_sub18367();
+ void OC_enableCharacterScript();
+ void OC_setRulesBuffer2Element();
+ void OC_setDebugFlag();
+ void OC_setDebugFlag2();
+ void OC_waitForEvent();
+ void OC_disableInterfaceHotspot();
+ void OC_loadFileAerial();
+ void OC_startSpeechIfSoundOff();
+ void OC_sub1844A();
+ void OC_displayNumericCharacterVariable();
+ void OC_displayVGAFile();
+ void OC_startSpeechWithoutSpeeker();
+ void OC_displayTitleScreen();
+ void OC_initGameAreaDisplay();
+ void OC_displayCharacterStatBar();
+ void OC_initSmallAnim();
+ void OC_setCharacterHeroismBar();
+ void OC_setCharacterHome();
+ void OC_setViewPortCharacterTarget();
+ void OC_showObject();
+ void OC_playObjectSound();
+ void OC_startLocationSound();
+ void OC_stopObjectSound();
+ void OC_stopLocationSound();
+ void OC_toggleSound();
+ void OC_playMusic();
+ void OC_stopMusic();
+ void OC_setCharacterMapColor();
+};
+
+} // End of namespace Lilliput
+
+#endif
+
diff --git a/engines/lilliput/sound.cpp b/engines/lilliput/sound.cpp
new file mode 100644
index 0000000000..9045e47c9a
--- /dev/null
+++ b/engines/lilliput/sound.cpp
@@ -0,0 +1,248 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "lilliput/lilliput.h"
+#include "lilliput/sound.h"
+
+#include "common/debug.h"
+
+namespace Lilliput {
+
+static const byte _aliasArr[40] = {
+ 44, 0, 1, 2, 37, 3, 24, 45, 20, 19,
+ 16, 10, 11, 12, 41, 39, 40, 21, 22, 23,
+ 4, 5, 6, 52, 7, 8, 9, 33, 13, 14,
+ 15, 18, 26, 25, 38, 29, 36, 0xFF, 28, 40
+};
+
+static const bool _loopArr[40] = {
+ 0, 0, 0, 1, 1, 1, 0, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const byte _soundType [40] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
+};
+
+LilliputSound::LilliputSound(LilliputEngine *vm) : _vm(vm) {
+ _unpackedFiles = nullptr;
+ _unpackedSizes = nullptr;
+ _fileNumb = 0;
+
+ _isGM = false;
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+LilliputSound::~LilliputSound() {
+ Audio::MidiPlayer::stop();
+
+ if (_unpackedFiles) {
+ for (int i = 0; i < _fileNumb; i++)
+ free(_unpackedFiles[i]);
+ }
+ free(_unpackedFiles);
+ free(_unpackedSizes);
+}
+
+byte LilliputSound::readByte(const byte *data, uint32 offset) {
+ uint16 al = data[0x201 + (offset >> 1)];
+ return data[1 + (offset & 1) + (al << 1)];
+}
+
+uint32 LilliputSound::decode(const byte *src, byte *dst, uint32 len, uint32 start) {
+ uint32 i = start;
+ for (; i < len; ++i) {
+ *dst++ = readByte(src, i);
+ }
+ return i;
+}
+
+void LilliputSound::loadMusic(Common::String filename) {
+ debugC(1, kDebugSound, "loadMusic(%s)", filename.c_str());
+
+ Common::File f;
+
+ if (!f.open(filename))
+ error("Missing music file %s", filename.c_str());
+
+ _fileNumb = f.readUint16LE();
+
+ int *fileSizes = new int[_fileNumb + 1];
+ for (int i = 0; i < _fileNumb; ++i)
+ fileSizes[i] = f.readUint16LE();
+ f.seek(0, SEEK_END);
+ fileSizes[_fileNumb] = f.pos();
+
+ _unpackedFiles = new byte *[_fileNumb];
+ _unpackedSizes = new uint16[_fileNumb];
+ int pos = (_fileNumb + 1) * 2; // file number + file sizes
+ for (int i = 0; i < _fileNumb; ++i) {
+ int packedSize = fileSizes[i + 1] - fileSizes[i];
+ byte *srcBuf = new byte[packedSize];
+ f.seek(pos, SEEK_SET);
+ f.read(srcBuf, packedSize);
+ if (srcBuf[0] == 'c' || srcBuf[0] == 'C') {
+ int shift = (srcBuf[0] == 'c') ? 1 : 0;
+ _unpackedSizes[i] = (1 + packedSize - 0x201) * 2 - shift;
+ byte *dstBuf = new byte[_unpackedSizes[i]];
+ decode(srcBuf, dstBuf, _unpackedSizes[i], shift);
+ _unpackedFiles[i] = dstBuf;
+ } else {
+ _unpackedSizes[i] = packedSize;
+ byte *dstBuf = new byte[packedSize];
+ for (int j = 0; j < packedSize; ++j)
+ dstBuf[j] = srcBuf[j];
+ _unpackedFiles[i] = dstBuf;
+ }
+ delete[] srcBuf;
+ pos += packedSize;
+ }
+
+ delete[] fileSizes;
+ f.close();
+
+ /* Debug code
+ for (int i = 0; i < _fileNumb; ++i) {
+ Common::DumpFile dmp;
+ Common::String name = Common::String::format("dmp%d.mid", i);
+ dmp.open(name);
+ dmp.write(_unpackedFiles[i], _unpackedSizes[i]);
+ dmp.close();
+ }
+ */
+}
+
+void LilliputSound::send(uint32 b) {
+ if (((b & 0xF0) == 0xC0) && !_isGM && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+
+ Audio::MidiPlayer::send(b);
+}
+
+void LilliputSound::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);
+}
+
+// Used during initialization
+void LilliputSound::init() {
+ debugC(1, kDebugSound, "LilliputSound::init()");
+
+ loadMusic("ROBIN.MUS");
+}
+
+void LilliputSound::refresh() {
+ debugC(1, kDebugSound, "LilliputSound::refresh()");
+}
+
+void LilliputSound::play(int var1, Common::Point var2, Common::Point var3, Common::Point var4) {
+ debugC(1, kDebugSound, "LilliputSound::play(%d, %d - %d, %d - %d, %d - %d)", var1, var2.x, var2.y, var3.x, var3.y, var4.x, var4.y);
+ // warning("LilliputSound::play(%d, %d - %d, %d - %d, %d - %d)", var1, var2.x, var2.y, var3.x, var3.y, var4.x, var4.y);
+
+ // save camera (var2)
+ if (_aliasArr[var1] == 0xFF) {
+ return;
+ }
+
+ if (var3 == Common::Point(-1, -1)) {
+ playMusic(var1);
+ } else if (_soundType[var1] == 0) {
+ warning("Transient");
+ } else {
+ warning("longterm");
+ }
+
+ return;
+}
+void LilliputSound::playMusic(int var1) {
+ int idx = _aliasArr[var1];
+ bool loop = _loopArr[var1];
+
+ _isGM = true;
+
+ if (_parser)
+ _parser->stopPlaying();
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_unpackedFiles[idx], _unpackedSizes[idx])) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpAutoLoop, loop);
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ _isLooping = loop;
+ _isPlaying = true;
+ }
+}
+
+void LilliputSound::stop(Common::Point pos) {
+ debugC(1, kDebugSound, "LilliputSound::stop(%d - %d)", pos.x, pos.y);
+ warning("LilliputSound::stop(%d - %d)", pos.x, pos.y);
+}
+
+void LilliputSound::toggleOnOff() {
+ debugC(1, kDebugSound, "LilliputSound::toggleOnOff()");
+ warning("LilliputSound::toggleOnOff()");
+}
+
+void LilliputSound::update() {
+ debugC(1, kDebugSound, "LilliputSound::update()");
+ warning("LilliputSound::update()");
+}
+
+void LilliputSound::remove() {
+ debugC(1, kDebugSound, "Lilliput::remove()");
+
+ _parser->stopPlaying();
+}
+
+} // End of namespace
diff --git a/engines/lilliput/sound.h b/engines/lilliput/sound.h
new file mode 100644
index 0000000000..f56fd58a6f
--- /dev/null
+++ b/engines/lilliput/sound.h
@@ -0,0 +1,71 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 LILLIPUT_SOUND_H
+#define LILLIPUT_SOUND_H
+
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "audio/midiplayer.h"
+#include "audio/mixer.h"
+
+namespace Lilliput {
+
+class LilliputEngine;
+
+class LilliputSound: public Audio::MidiPlayer {
+public:
+ LilliputSound(LilliputEngine *vm);
+ ~LilliputSound();
+
+ void init();
+ void refresh();
+ void play(int var1, Common::Point var2, Common::Point var3, Common::Point var4);
+ void stop(Common::Point pos);
+ void toggleOnOff();
+ void update();
+ void remove();
+
+private:
+ LilliputEngine *_vm;
+
+ int _fileNumb;
+ byte **_unpackedFiles;
+ uint16 *_unpackedSizes;
+ bool _isGM;
+
+ uint32 decode(const byte *src, byte *dst, uint32 len, uint32 start);
+ byte readByte(const byte *data, uint32 offset);
+
+ void loadMusic(Common::String filename);
+ void playMusic(int var1);
+
+ virtual void send(uint32 b);
+ virtual void sendToChannel(byte channel, uint32 b);
+};
+
+} // End of namespace Lilliput
+
+#endif
+
diff --git a/engines/lilliput/stream.cpp b/engines/lilliput/stream.cpp
new file mode 100644
index 0000000000..6b33c9d357
--- /dev/null
+++ b/engines/lilliput/stream.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 "lilliput/stream.h"
+
+namespace Lilliput {
+
+ScriptStream::ScriptStream(byte *buf, int bufSize) : Common::MemoryReadStream(buf, bufSize) {
+ _orgPtr = buf;
+}
+
+ScriptStream::~ScriptStream() {
+}
+
+void ScriptStream::writeUint16LE(int value, int relativePos) {
+ int writePos = pos() + relativePos;
+ assert((writePos >= 0) && (writePos + 2 < size()));
+
+ Common::MemoryWriteStream tmpStream = Common::MemoryWriteStream(_orgPtr + writePos, size() - writePos);
+ tmpStream.writeUint16LE(value);
+}
+
+} // End of namespace Lilliput
diff --git a/engines/lilliput/stream.h b/engines/lilliput/stream.h
new file mode 100644
index 0000000000..52b80e3524
--- /dev/null
+++ b/engines/lilliput/stream.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LILLIPUT_STREAM_H
+#define LILLIPUT_STREAM_H
+
+#include "common/memstream.h"
+
+namespace Lilliput {
+
+class ScriptStream : public Common::MemoryReadStream {
+private:
+ byte *_orgPtr;
+public:
+ ScriptStream(byte *buf, int bufSize);
+ virtual ~ScriptStream();
+
+ void writeUint16LE(int value, int relativePos = 0);
+};
+
+} // End of namespace Lilliput
+
+#endif
diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp
index 25d68c762d..5acd6d81a0 100644
--- a/engines/lure/sound.cpp
+++ b/engines/lure/sound.cpp
@@ -649,10 +649,7 @@ MidiMusic::~MidiMusic() {
}
void MidiMusic::setVolume(int volume) {
- if (volume < 0)
- volume = 0;
- else if (volume > 255)
- volume = 255;
+ volume = CLIP(volume, 0, 255);
if (_volume == volume)
return;
diff --git a/engines/macventure/detection.cpp b/engines/macventure/detection.cpp
index ba583ef743..5eda420cb2 100644
--- a/engines/macventure/detection.cpp
+++ b/engines/macventure/detection.cpp
@@ -54,7 +54,7 @@ static const PlainGameDescriptor macventureGames[] = {
namespace MacVenture {
-SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot);
+SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot, bool skipThumbnail = true);
class MacVentureMetaEngine : public AdvancedMetaEngine {
public:
@@ -63,18 +63,19 @@ public:
_md5Bytes = 5000000; // TODO: Upper limit, adjust it once all games are added
}
- virtual const char *getName() const override {
+ const char *getName() const {
return "MacVenture";
}
- virtual const char *getOriginalCopyright() const override {
+ const char *getOriginalCopyright() const {
return "(C) ICOM Simulations";
}
- virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- virtual bool hasFeature(MetaEngineFeature f) const;
- virtual SaveStateList listSaves(const char *target) const;
- virtual int getMaximumSaveSlot() const;
- virtual void removeSaveState(const char *target, int slot) const;
+protected:
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ bool hasFeature(MetaEngineFeature f) const;
+ SaveStateList listSaves(const char *target) const;
+ int getMaximumSaveSlot() const;
+ void removeSaveState(const char *target, int slot) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
@@ -163,7 +164,7 @@ SaveStateDescriptor MacVentureMetaEngine::querySaveMetaInfos(const char *target,
Common::InSaveFile *in = saveFileMan->openForLoading(saveFileName);
if (in) {
- desc = loadMetaData(in, slot);
+ desc = loadMetaData(in, slot, false);
delete in;
return desc;
}
diff --git a/engines/macventure/saveload.cpp b/engines/macventure/saveload.cpp
index 89a6301318..c63b6a6951 100644
--- a/engines/macventure/saveload.cpp
+++ b/engines/macventure/saveload.cpp
@@ -42,7 +42,7 @@ namespace MacVenture {
#define MACVENTURE_SAVE_VERSION 1 //1 BYTE
#define MACVENTURE_DESC_LENGTH 4 //4 BYTE for the metadata length
-SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot) {
+SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot, bool skipThumbnail) {
// Metadata is stored at the end of the file
// |THUMBNAIL |
// | |
@@ -65,8 +65,11 @@ SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot) {
s->seek(-(5 + MACVENTURE_DESC_LENGTH + metaSize), SEEK_END);
// Load the thumbnail
- Graphics::Surface *thumb = Graphics::loadThumbnail(*s);
- desc.setThumbnail(thumb);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*s, thumbnail, skipThumbnail)) {
+ return desc;
+ }
+ desc.setThumbnail(thumbnail);
// Load the description
Common::String name;
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index 636c2d147c..bf05385c88 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -535,7 +535,7 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
@@ -557,7 +557,7 @@ bool MadeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame
return gd != 0;
}
-const ADGameDescription *MadeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame MadeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// Set the default values for the fallback descriptor's ADGameDescription part.
Made::g_fallbackDesc.desc.language = Common::UNK_LANG;
Made::g_fallbackDesc.desc.platform = Common::kPlatformDOS;
@@ -569,7 +569,7 @@ const ADGameDescription *MadeMetaEngine::fallbackDetect(const FileMap &allFiles,
Made::g_fallbackDesc.version = 3;
//return (const ADGameDescription *)&Made::g_fallbackDesc;
- return NULL;
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(MADE)
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index a9734ed47d..d8ceb87bb6 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -400,7 +400,8 @@ ResourceReader::~ResourceReader() {
// V2
void ResourceReader::open(const char *filename) {
_fd = new Common::File();
- _fd->open(filename);
+ if (!_fd->open(filename))
+ error("ResourceReader::open() Could not open '%s'", filename);
_fd->skip(0x18); // skip header for now
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
index 4fb8b82eb3..8eb3b4eee9 100644
--- a/engines/mads/detection.cpp
+++ b/engines/mads/detection.cpp
@@ -203,11 +203,8 @@ SaveStateList MADSMetaEngine::listSaves(const char *target) const {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- MADS::Game::readSavegameHeader(in, header);
- saveList.push_back(SaveStateDescriptor(slot, header._saveName));
-
- header._thumbnail->free();
- delete header._thumbnail;
+ if (MADS::Game::readSavegameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
delete in;
}
}
@@ -233,7 +230,10 @@ SaveStateDescriptor MADSMetaEngine::querySaveMetaInfos(const char *target, int s
if (f) {
MADS::MADSSavegameHeader header;
- MADS::Game::readSavegameHeader(f, header);
+ if (!MADS::Game::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
delete f;
// Create the return descriptor
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
index 0a6741ba7a..bea0ea3bb4 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -485,11 +485,6 @@ void Game::loadGame(int slotNumber) {
if (!readSavegameHeader(_saveFile, header))
error("Invalid savegame");
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
// Load most of the savegame data with the exception of scene specific info
synchronize(s, true);
@@ -527,9 +522,8 @@ void Game::saveGame(int slotNumber, const Common::String &saveName) {
const char *const SAVEGAME_STR = "MADS";
#define SAVEGAME_STR_SIZE 4
-bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header) {
+WARN_UNUSED_RESULT bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = nullptr;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -546,9 +540,9 @@ bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header
while ((ch = (char)in->readByte()) != '\0') header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header._year = in->readSint16LE();
diff --git a/engines/mads/game.h b/engines/mads/game.h
index 9defb58b1a..b979160f3d 100644
--- a/engines/mads/game.h
+++ b/engines/mads/game.h
@@ -237,7 +237,7 @@ public:
/**
* Read in a savegame header
*/
- static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header, bool skipThumbnail = true);
/**
* Creates a temporary thumbnail for use in saving games
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index 1db5eaea00..99402748b8 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -45,8 +45,9 @@ GameNebular::GameNebular(MADSEngine *vm)
}
ProtectionResult GameNebular::checkCopyProtection() {
- //if (!ConfMan.getBool("copy_protection"))
- // return PROTECTION_SUCCEED;
+ // Only show copy protection dialog if explicitly wanted
+ if (!ConfMan.getBool("copy_protection"))
+ return PROTECTION_SUCCEED;
CopyProtectionDialog *dlg;
bool correctAnswer;
diff --git a/engines/mads/nebular/nebular_scenes4.cpp b/engines/mads/nebular/nebular_scenes4.cpp
index a4c6a3ebe1..8b7eb1a9ec 100644
--- a/engines/mads/nebular/nebular_scenes4.cpp
+++ b/engines/mads/nebular/nebular_scenes4.cpp
@@ -2443,7 +2443,7 @@ void Scene405::step() {
}
if (_game._trigger == 70) {
- _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount ;
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
_game._player._visible = true;
_globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
_scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
@@ -2458,7 +2458,7 @@ void Scene405::step() {
}
if (_game._trigger == 75) {
- _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount ;
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
_game._player._visible = true;
_scene->_sequences.remove(_globals._sequenceIndexes[1]);
_globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
diff --git a/engines/metaengine.h b/engines/metaengine.h
index b3aaa96a8f..a95ff1593e 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -69,17 +69,17 @@ public:
virtual const char *getOriginalCopyright() const = 0;
/** Returns a list of games supported by this engine. */
- virtual GameList getSupportedGames() const = 0;
+ virtual PlainGameList getSupportedGames() const = 0;
- /** Query the engine for a GameDescriptor for the specified gameid, if any. */
- virtual GameDescriptor findGame(const char *gameid) const = 0;
+ /** Query the engine for a PlainGameDescriptor for the specified gameid, if any. */
+ virtual PlainGameDescriptor findGame(const char *gameId) const = 0;
/**
* Runs the engine's game detector on the given list of files, and returns a
* (possibly empty) list of games supported by the engine which it was able
* to detect amongst the given files.
*/
- virtual GameList detectGames(const Common::FSList &fslist) const = 0;
+ virtual DetectedGames detectGames(const Common::FSList &fslist) const = 0;
/**
* Tries to instantiate an engine instance based on the settings of
@@ -267,10 +267,17 @@ public:
*/
class EngineManager : public Common::Singleton<EngineManager> {
public:
- GameDescriptor findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin = NULL) const;
- GameDescriptor findGame(const Common::String &gameName, const Plugin **plugin = NULL) const;
- GameList detectGames(const Common::FSList &fslist) const;
+ PlainGameDescriptor findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin = NULL) const;
+ PlainGameDescriptor findGame(const Common::String &gameName, const Plugin **plugin = NULL) const;
+ DetectionResults detectGames(const Common::FSList &fslist) const;
const PluginList &getPlugins() const;
+
+ /**
+ * Create a target from the supplied game descriptor
+ *
+ * Returns the created target name.
+ */
+ Common::String createTargetForGame(const DetectedGame &game);
};
/** Convenience shortcut for accessing the engine manager. */
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp
index d8c6d6aacd..205feb824f 100644
--- a/engines/mohawk/bitmap.cpp
+++ b/engines/mohawk/bitmap.cpp
@@ -70,7 +70,7 @@ MohawkBitmap::~MohawkBitmap() {
void MohawkBitmap::decodeImageData(Common::SeekableReadStream *stream) {
_data = stream;
- _header.colorTable.palette = NULL;
+ _header.colorTable.palette = nullptr;
// NOTE: Only the bottom 12 bits of width/height/bytesPerRow are
// considered valid and bytesPerRow has to be an even number.
@@ -650,7 +650,7 @@ MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream *stream) {
error("Could not decode Myst bitmap");
const Graphics::Surface *bmpSurface = bitmapDecoder.getSurface();
- Graphics::Surface *newSurface = 0;
+ Graphics::Surface *newSurface = nullptr;
if (bmpSurface->format.bytesPerPixel == 1) {
_bitsPerPixel = 8;
@@ -662,7 +662,7 @@ MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream *stream) {
}
// Copy the palette to one of our own
- byte *newPal = 0;
+ byte *newPal = nullptr;
if (bitmapDecoder.hasPalette()) {
const byte *palette = bitmapDecoder.getPalette();
@@ -729,7 +729,7 @@ MohawkSurface *LivingBooksBitmap_v1::decodeImage(Common::SeekableReadStream *str
leRLE8 = true;
_data = stream;
- stream = NULL;
+ stream = nullptr;
}
Graphics::Surface *surface = createSurface(_header.width, _header.height);
diff --git a/engines/mohawk/bitmap.h b/engines/mohawk/bitmap.h
index ea8664f39d..18ea72b3ee 100644
--- a/engines/mohawk/bitmap.h
+++ b/engines/mohawk/bitmap.h
@@ -148,16 +148,16 @@ private:
// Mohawk Bitmap format.
class MystBitmap : public MohawkBitmap {
public:
- MystBitmap() : MohawkBitmap() {}
- ~MystBitmap() {}
+ MystBitmap() : MohawkBitmap(), _bitsPerPixel(8) {}
+ ~MystBitmap() override {}
- MohawkSurface *decodeImage(Common::SeekableReadStream *stream);
+ MohawkSurface *decodeImage(Common::SeekableReadStream *stream) override;
protected:
- byte getBitsPerPixel() { return _bitsPerPixel; }
+ byte getBitsPerPixel() override { return _bitsPerPixel; }
private:
- uint16 _bitsPerPixel;
+ byte _bitsPerPixel;
};
#endif
@@ -165,23 +165,23 @@ private:
class LivingBooksBitmap_v1 : public MohawkBitmap {
public:
LivingBooksBitmap_v1() : MohawkBitmap() {}
- ~LivingBooksBitmap_v1() {}
+ ~LivingBooksBitmap_v1() override {}
- MohawkSurface *decodeImage(Common::SeekableReadStream *stream);
+ MohawkSurface *decodeImage(Common::SeekableReadStream *stream) override;
protected:
- byte getBitsPerPixel() { return 8; }
+ byte getBitsPerPixel() override { return 8; }
};
class DOSBitmap : public MohawkBitmap {
public:
DOSBitmap() : MohawkBitmap() {}
- ~DOSBitmap() {}
+ ~DOSBitmap() override {}
- MohawkSurface *decodeImage(Common::SeekableReadStream *stream);
+ MohawkSurface *decodeImage(Common::SeekableReadStream *stream) override;
protected:
- byte getBitsPerPixel() { return ((_header.format & 0x30) >> 4) + 1; }
+ byte getBitsPerPixel() override { return ((_header.format & 0x30) >> 4) + 1; }
private:
void expandMonochromePlane(Graphics::Surface *surface, Common::SeekableReadStream *rawStream);
diff --git a/engines/mohawk/console.h b/engines/mohawk/console.h
index 0cae87da51..7d94bf576f 100644
--- a/engines/mohawk/console.h
+++ b/engines/mohawk/console.h
@@ -35,8 +35,8 @@ class MohawkEngine_Myst;
class MystConsole : public GUI::Debugger {
public:
- MystConsole(MohawkEngine_Myst *vm);
- virtual ~MystConsole(void);
+ explicit MystConsole(MohawkEngine_Myst *vm);
+ ~MystConsole() override;
private:
MohawkEngine_Myst *_vm;
@@ -66,8 +66,8 @@ class MohawkEngine_Riven;
class RivenConsole : public GUI::Debugger {
public:
- RivenConsole(MohawkEngine_Riven *vm);
- virtual ~RivenConsole(void);
+ explicit RivenConsole(MohawkEngine_Riven *vm);
+ ~RivenConsole() override;
private:
MohawkEngine_Riven *_vm;
@@ -95,8 +95,8 @@ private:
class LivingBooksConsole : public GUI::Debugger {
public:
- LivingBooksConsole(MohawkEngine_LivingBooks *vm);
- virtual ~LivingBooksConsole(void);
+ explicit LivingBooksConsole(MohawkEngine_LivingBooks *vm);
+ ~LivingBooksConsole() override;
private:
MohawkEngine_LivingBooks *_vm;
diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h
index 1c39a86ca0..9edd185085 100644
--- a/engines/mohawk/cstime.h
+++ b/engines/mohawk/cstime.h
@@ -129,7 +129,7 @@ enum CSTimeState {
class MohawkEngine_CSTime : public MohawkEngine {
protected:
- Common::Error run();
+ Common::Error run() override;
public:
MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescription *gamedesc);
@@ -142,7 +142,7 @@ public:
CSTimeGraphics *_gfx;
bool _needsUpdate;
- GUI::Debugger *getDebugger() { return _console; }
+ GUI::Debugger *getDebugger() override { return _console; }
CSTimeView *getView() { return _view; }
CSTimeCase *getCase() { return _case; }
CSTimeInterface *getInterface() { return _interface; }
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index cef24e14e5..84b1c73e04 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -151,7 +151,7 @@ NECursorManager::NECursorManager(const Common::String &appName) {
if (!_exe->loadFromEXE(appName)) {
// Not all have cursors anyway, so this is not a problem
delete _exe;
- _exe = 0;
+ _exe = nullptr;
}
}
@@ -183,10 +183,10 @@ MacCursorManager::MacCursorManager(const Common::String &appName) {
if (!_resFork->open(appName)) {
// Not all have cursors anyway, so this is not a problem
delete _resFork;
- _resFork = 0;
+ _resFork = nullptr;
}
} else {
- _resFork = 0;
+ _resFork = nullptr;
}
}
@@ -219,7 +219,7 @@ LivingBooksCursorManager_v2::LivingBooksCursorManager_v2() {
if (!_sysArchive->openFile("system.mhk")) {
delete _sysArchive;
- _sysArchive = 0;
+ _sysArchive = nullptr;
}
}
diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h
index d0d38c9b46..ff5db5b59c 100644
--- a/engines/mohawk/cursors.h
+++ b/engines/mohawk/cursors.h
@@ -72,11 +72,11 @@ protected:
// Uses standard tCUR resources
class DefaultCursorManager : public CursorManager {
public:
- DefaultCursorManager(MohawkEngine *vm, uint32 tag = ID_TCUR) : _vm(vm), _tag(tag) {}
- ~DefaultCursorManager() {}
+ explicit DefaultCursorManager(MohawkEngine *vm, uint32 tag = ID_TCUR) : _vm(vm), _tag(tag) {}
+ ~DefaultCursorManager() override {}
- void setCursor(uint16 id);
- bool hasSource() const { return true; }
+ void setCursor(uint16 id) override;
+ bool hasSource() const override { return true; }
private:
MohawkEngine *_vm;
@@ -110,14 +110,14 @@ class MohawkEngine_Myst;
// Uses WDIB + CLRC resources
class MystCursorManager : public CursorManager {
public:
- MystCursorManager(MohawkEngine_Myst *vm);
- ~MystCursorManager();
+ explicit MystCursorManager(MohawkEngine_Myst *vm);
+ ~MystCursorManager() override;
- void showCursor();
- void hideCursor();
- void setCursor(uint16 id);
- void setDefaultCursor();
- bool hasSource() const { return true; }
+ void showCursor() override;
+ void hideCursor() override;
+ void setCursor(uint16 id) override;
+ void setDefaultCursor() override;
+ bool hasSource() const override { return true; }
private:
MohawkEngine_Myst *_vm;
@@ -128,11 +128,11 @@ private:
// The cursor manager for NE EXE's
class NECursorManager : public CursorManager {
public:
- NECursorManager(const Common::String &appName);
- ~NECursorManager();
+ explicit NECursorManager(const Common::String &appName);
+ ~NECursorManager() override;
- void setCursor(uint16 id);
- bool hasSource() const { return _exe != 0; }
+ void setCursor(uint16 id) override;
+ bool hasSource() const override { return _exe != nullptr; }
private:
Common::NEResources *_exe;
@@ -141,11 +141,11 @@ private:
// The cursor manager for Mac applications
class MacCursorManager : public CursorManager {
public:
- MacCursorManager(const Common::String &appName);
- ~MacCursorManager();
+ explicit MacCursorManager(const Common::String &appName);
+ ~MacCursorManager() override;
- void setCursor(uint16 id);
- bool hasSource() const { return _resFork != 0; }
+ void setCursor(uint16 id) override;
+ bool hasSource() const override { return _resFork != nullptr; }
private:
Common::MacResManager *_resFork;
@@ -156,11 +156,11 @@ private:
class LivingBooksCursorManager_v2 : public CursorManager {
public:
LivingBooksCursorManager_v2();
- ~LivingBooksCursorManager_v2();
+ ~LivingBooksCursorManager_v2() override;
- void setCursor(uint16 id);
- void setCursor(const Common::String &name);
- bool hasSource() const { return _sysArchive != 0; }
+ void setCursor(uint16 id) override;
+ void setCursor(const Common::String &name) override;
+ bool hasSource() const override { return _sysArchive != nullptr; }
private:
MohawkArchive *_sysArchive;
@@ -169,11 +169,11 @@ private:
// The cursor manager for PE EXE's
class PECursorManager : public CursorManager {
public:
- PECursorManager(const Common::String &appName);
- ~PECursorManager();
+ explicit PECursorManager(const Common::String &appName);
+ ~PECursorManager() override;
- void setCursor(uint16 id);
- bool hasSource() const { return !_cursors.empty(); }
+ void setCursor(uint16 id) override;
+ bool hasSource() const override { return !_cursors.empty(); }
private:
struct CursorItem {
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 439ea152c4..58d1483bee 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -116,19 +116,12 @@ static const PlainGameDescriptor mohawkGames[] = {
{"myst", "Myst"},
{"makingofmyst", "The Making of Myst"},
{"riven", "Riven: The Sequel to Myst"},
- {"zoombini", "Logical Journey of the Zoombinis"},
{"cstime", "Where in Time is Carmen Sandiego?"},
- {"csworld", "Where in the World is Carmen Sandiego?"},
- {"csamtrak", "Where in America is Carmen Sandiego? (The Great Amtrak Train Adventure)"},
{"carmentq", "Carmen Sandiego's ThinkQuick Challenge"},
{"carmentqc", "Carmen Sandiego's ThinkQuick Challenge Custom Question Creator"},
{"maggiesfa", "Maggie's Farmyard Adventure"},
- {"jamesmath", "James Discovers/Explores Math"},
- {"treehouse", "The Treehouse"},
{"greeneggs", "Green Eggs and Ham"},
{"seussabc", "Dr Seuss's ABC"},
- {"1stdegree", "In the 1st Degree"},
- {"csusa", "Where in the USA is Carmen Sandiego?"},
{"tortoise", "Aesop's Fables: The Tortoise and the Hare"},
{"arthur", "Arthur's Teacher Trouble"},
{"grandma", "Just Grandma and Me"},
@@ -147,7 +140,7 @@ static const PlainGameDescriptor mohawkGames[] = {
{"stellaluna", "Stellaluna"},
{"sheila", "Sheila Rae, the Brave"},
{"rugratsps", "Rugrats Print Shop" },
- {0, 0}
+ {nullptr, nullptr}
};
#include "mohawk/detection_tables.h"
@@ -159,7 +152,7 @@ static const char *directoryGlobs[] = {
"program",
"95instal",
"Rugrats Adventure Game",
- 0
+ nullptr
};
static const ADExtraGuiOptionsMap optionsList[] = {
@@ -184,25 +177,25 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
return detectGameFilebased(allFiles, fslist, Mohawk::fileBased);
}
- virtual const char *getName() const {
+ const char *getName() const override {
return "Mohawk";
}
- virtual const char *getOriginalCopyright() const {
+ const char *getOriginalCopyright() const override {
return "Myst and Riven (C) Cyan Worlds\nMohawk OS (C) Ubisoft";
}
- virtual bool hasFeature(MetaEngineFeature f) const;
- virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- virtual SaveStateList listSaves(const char *target) const;
+ bool hasFeature(MetaEngineFeature f) const override;
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+ SaveStateList listSaves(const char *target) const override;
SaveStateList listSavesForPrefix(const char *prefix, const char *extension) const;
- virtual int getMaximumSaveSlot() const { return 999; }
- virtual void removeSaveState(const char *target, int slot) const;
- virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ int getMaximumSaveSlot() const override { return 999; }
+ void removeSaveState(const char *target, int slot) const override;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
};
bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -340,21 +333,12 @@ bool MohawkMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGa
warning("CSTime support not compiled in");
return false;
#endif
- case Mohawk::GType_ZOOMBINI:
- case Mohawk::GType_CSWORLD:
- case Mohawk::GType_CSAMTRAK:
- case Mohawk::GType_JAMESMATH:
- case Mohawk::GType_TREEHOUSE:
- case Mohawk::GType_1STDEGREE:
- case Mohawk::GType_CSUSA:
- warning("Unsupported Mohawk Engine");
- return false;
default:
error("Unknown Mohawk Engine");
}
}
- return (gd != 0);
+ return (gd != nullptr);
}
#if PLUGIN_ENABLED_DYNAMIC(MOHAWK)
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index a06b814fbd..e887c11051 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -500,6 +500,24 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.1 (DVD, Pressing code rvd 2811 ab, RVD8AB-BI RVD2811AB)
+ // From wouwehand in #10519
+ {
+ {
+ "riven",
+ "DVD",
+ AD_ENTRY1("a_Data.MHK", "3370cd9a9696814365a2b7fd7a7b726e"),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUI_OPTIONS_RIVEN
+ },
+ GType_RIVEN,
+ GF_DVD,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.0 (DVD, From "Myst: Die Trilogie")
// From DrMcCoy
{
@@ -600,127 +618,6 @@ static const MohawkGameDescription gameDescriptions[] = {
0
},
-
- {
- {
- "zoombini",
- "",
- AD_ENTRY1("ZOOMBINI.MHK", "98b758fec55104c096cfd129048be9a6"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_ZOOMBINI,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "zoombini",
- "",
- AD_ENTRY1("ZOOMBINI.MHK", "0672f65c40dd065840c896e41c13f980"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_ZOOMBINI,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "zoombini",
- "v2.0",
- AD_ENTRY1("ZOOMBINI.MHK", "506b1122ffa740e2566cf0b583d24478"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NOASPECT)
- },
- GType_ZOOMBINI,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "zoombini",
- "",
- AD_ENTRY1("ZOOMBINI.MHK", "6ae0bdf791266b1fe3d4fabbf44c3faa"),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_ZOOMBINI,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "zoombini",
- "",
- AD_ENTRY1("ZOOMBINI.MHK", "8231e58525143ccf6e8b747df34b139f"),
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_ZOOMBINI,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "csworld",
- "v3.0",
- AD_ENTRY1("C2K.MHK", "605fe88380848031bbd0ff84ade6fe40"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_CSWORLD,
- 0,
- 0
- },
-
- {
- {
- "csworld",
- "v3.5",
- AD_ENTRY1("C2K.MHK", "d4857aeb0f5e2e0c4ac556aa74f38c23"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_CSWORLD,
- 0,
- 0
- },
-
- {
- {
- "csamtrak",
- "",
- AD_ENTRY1("AMTRAK.MHK", "2f95301f0bb950d555bb7b0e3b1b7eb1"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_CSAMTRAK,
- 0,
- 0
- },
-
// Harry and the Haunted House v1.0E
// English Windows 3.11
// From strangerke
@@ -935,52 +832,6 @@ static const MohawkGameDescription gameDescriptions[] = {
{
{
- "jamesmath",
- "",
- AD_ENTRY1("BRODER.MHK", "007299da8b2c6e8ec1cde9598c243024"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_JAMESMATH,
- GF_HASMIDI,
- 0
- },
-
- // This is in the NEWDATA folder, so I assume it's a newer version ;)
- {
- {
- "jamesmath",
- "",
- AD_ENTRY1("BRODER.MHK", "53c000938a50dca92860fd9b546dd276"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_JAMESMATH,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "treehouse",
- "",
- AD_ENTRY1("MAINROOM.MHK", "12f51894d7f838af639ea9bf1bc8f45b"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_TREEHOUSE,
- GF_HASMIDI,
- 0
- },
-
- {
- {
"greeneggs",
"",
AD_ENTRY1("GREEN.LB", "5df8438138186f89e71299d7b4f88d06"),
@@ -1088,54 +939,6 @@ static const MohawkGameDescription gameDescriptions[] = {
{
{
- "1stdegree",
- "",
- AD_ENTRY1("AL236_1.MHK", "3ba145492a7b8b4dee0ef4222c5639c3"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_1STDEGREE,
- GF_HASMIDI,
- 0
- },
-
- // In The 1st Degree
- // French Windows
- // From Strangerke
- {
- {
- "1stdegree",
- "",
- AD_ENTRY1("AL236_1.MHK", "0e0c70b1b702b6ddca61a1192ada1282"),
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_1STDEGREE,
- GF_HASMIDI,
- 0
- },
-
- {
- {
- "csusa",
- "",
- AD_ENTRY1("USAC2K.MHK", "b8c9d3a2586f62bce3a48b50d7a700e9"),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_CSUSA,
- 0,
- 0
- },
-
- {
- {
"tortoise",
"",
AD_ENTRY1("TORTOISE.512", "dfcf7bff3d0f187832c9897497efde0e"),
diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp
index 029867f6a6..5700a4641b 100644
--- a/engines/mohawk/dialogs.cpp
+++ b/engines/mohawk/dialogs.cpp
@@ -180,22 +180,22 @@ void MohawkOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd,
MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : MohawkOptionsDialog(vm), _vm(vm) {
// I18N: Option for fast scene switching
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd);
+ _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), nullptr, kZipCmd);
+ _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), nullptr, kTransCmd);
// I18N: Drop book page
- _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd);
+ _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), nullptr, kDropCmd);
// Myst ME only has maps
if (_vm->getFeatures() & GF_ME)
- _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd);
+ _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), nullptr, kMapCmd);
else
- _showMapButton = 0;
+ _showMapButton = nullptr;
// Myst demo only has a menu
if (_vm->getFeatures() & GF_DEMO)
- _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd);
+ _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), nullptr, kMenuCmd);
else
- _returnToMenuButton = 0;
+ _returnToMenuButton = nullptr;
}
MystOptionsDialog::~MystOptionsDialog() {
@@ -204,16 +204,19 @@ MystOptionsDialog::~MystOptionsDialog() {
void MystOptionsDialog::open() {
MohawkOptionsDialog::open();
- _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0);
+ bool canDropPage = _vm->isInteractive() && _vm->_gameState->_globals.heldPage != kNoPage;
+ _dropPageButton->setEnabled(canDropPage);
- if (_showMapButton)
- _showMapButton->setEnabled(_vm->_scriptParser &&
- _vm->_scriptParser->getMap());
+ if (_showMapButton) {
+ bool canShowMap = _vm->isInteractive() && _vm->_scriptParser->getMap();
+ _showMapButton->setEnabled(canShowMap);
+ }
- // Return to menu button is not enabled on the menu
- if (_returnToMenuButton)
- _returnToMenuButton->setEnabled(_vm->_scriptParser &&
- _vm->getCurStack() != kDemoStack);
+ if (_returnToMenuButton) {
+ // Return to menu button is not enabled on the menu
+ bool canReturnToMenu = _vm->isInteractive() && _vm->getCurStack() != kDemoStack;
+ _returnToMenuButton->setEnabled(canReturnToMenu);
+ }
// Zip mode is disabled in the demo
if (_vm->getFeatures() & GF_DEMO)
@@ -266,8 +269,8 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) :
MohawkOptionsDialog(vm),
_vm(vm) {
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd);
+ _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), nullptr, kZipCmd);
+ _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~W~ater Effect Enabled"), nullptr, kWaterCmd);
_transitionModeCaption = new GUI::StaticTextWidget(this, 15, 50, 90, 20, _("Transitions:"), Graphics::kTextAlignRight);
_transitionModePopUp = new GUI::PopUpWidget(this, 115, 50, 120, 20);
diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h
index efc1005737..9e892d768d 100644
--- a/engines/mohawk/dialogs.h
+++ b/engines/mohawk/dialogs.h
@@ -53,35 +53,35 @@ public:
void setInfoText(const Common::String &message);
- virtual void handleMouseDown(int x, int y, int button, int clickCount) {
+ void handleMouseDown(int x, int y, int button, int clickCount) override {
setResult(0);
close();
}
- virtual void handleKeyDown(Common::KeyState state) {
+ void handleKeyDown(Common::KeyState state) override {
setResult(state.ascii);
close();
}
- virtual void reflowLayout();
+ void reflowLayout() override;
};
class PauseDialog : public InfoDialog {
public:
PauseDialog(MohawkEngine* vm, const Common::String &message);
- virtual void handleKeyDown(Common::KeyState state);
+ void handleKeyDown(Common::KeyState state) override;
};
#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN)
class MohawkOptionsDialog : public GUI::Dialog {
public:
- MohawkOptionsDialog(MohawkEngine *_vm);
- virtual ~MohawkOptionsDialog();
+ explicit MohawkOptionsDialog(MohawkEngine *_vm);
+ ~MohawkOptionsDialog() override;
- virtual void open() override;
- virtual void reflowLayout() override;
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+ void open() override;
+ void reflowLayout() override;
+ void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
int getLoadSlot() const { return _loadSlot; }
int getSaveSlot() const { return _saveSlot; }
@@ -112,11 +112,11 @@ class MohawkEngine_Myst;
class MystOptionsDialog : public MohawkOptionsDialog {
public:
- MystOptionsDialog(MohawkEngine_Myst *vm);
- virtual ~MystOptionsDialog();
+ explicit MystOptionsDialog(MohawkEngine_Myst *vm);
+ ~MystOptionsDialog() override;
- virtual void open() override;
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ void open() override;
+ void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
private:
MohawkEngine_Myst *_vm;
@@ -137,11 +137,11 @@ class MohawkEngine_Riven;
class RivenOptionsDialog : public MohawkOptionsDialog {
public:
- RivenOptionsDialog(MohawkEngine_Riven *vm);
- virtual ~RivenOptionsDialog();
+ explicit RivenOptionsDialog(MohawkEngine_Riven *vm);
+ ~RivenOptionsDialog() override;
- virtual void open() override;
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+ void open() override;
+ void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
private:
MohawkEngine_Riven *_vm;
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index ea9b57ae17..fe675235c1 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -30,7 +30,7 @@
namespace Mohawk {
-MohawkSurface::MohawkSurface() : _surface(0), _palette(0) {
+MohawkSurface::MohawkSurface() : _surface(nullptr), _palette(nullptr) {
_offsetX = 0;
_offsetY = 0;
}
@@ -64,7 +64,7 @@ void MohawkSurface::convertToTrueColor() {
_surface->free();
delete _surface;
free(_palette);
- _palette = 0;
+ _palette = nullptr;
_surface = surface;
}
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index f9fdeea15f..797fc1c080 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -41,7 +41,7 @@ class MohawkBitmap;
class MohawkSurface {
public:
MohawkSurface();
- MohawkSurface(Graphics::Surface *surface, byte *palette = NULL, int offsetX = 0, int offsetY = 0);
+ explicit MohawkSurface(Graphics::Surface *surface, byte *palette = nullptr, int offsetX = 0, int offsetY = 0);
~MohawkSurface();
// getSurface() returns the surface in the current format
diff --git a/engines/mohawk/installer_archive.cpp b/engines/mohawk/installer_archive.cpp
index 0abc930683..62fc953f53 100644
--- a/engines/mohawk/installer_archive.cpp
+++ b/engines/mohawk/installer_archive.cpp
@@ -28,7 +28,7 @@
namespace Mohawk {
InstallerArchive::InstallerArchive() : Common::Archive() {
- _stream = 0;
+ _stream = nullptr;
}
InstallerArchive::~InstallerArchive() {
@@ -103,7 +103,7 @@ bool InstallerArchive::open(const Common::String &filename) {
}
void InstallerArchive::close() {
- delete _stream; _stream = 0;
+ delete _stream; _stream = nullptr;
_map.clear();
}
@@ -124,7 +124,7 @@ const Common::ArchiveMemberPtr InstallerArchive::getMember(const Common::String
Common::SeekableReadStream *InstallerArchive::createReadStreamForMember(const Common::String &name) const {
if (!_stream || !_map.contains(name))
- return 0;
+ return nullptr;
const FileEntry &entry = _map[name];
diff --git a/engines/mohawk/installer_archive.h b/engines/mohawk/installer_archive.h
index c3212d7f7c..19f6343b80 100644
--- a/engines/mohawk/installer_archive.h
+++ b/engines/mohawk/installer_archive.h
@@ -36,17 +36,17 @@ namespace Mohawk {
class InstallerArchive : public Common::Archive {
public:
InstallerArchive();
- ~InstallerArchive();
+ ~InstallerArchive() override;
bool open(const Common::String &filename);
void close();
- bool isOpen() const { return _stream != 0; }
+ bool isOpen() const { return _stream != nullptr; }
// Common::Archive API implementation
- bool hasFile(const Common::String &name) const;
- int listMembers(Common::ArchiveMemberList &list) const;
- const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
- Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+ bool hasFile(const Common::String &name) const override;
+ int listMembers(Common::ArchiveMemberList &list) const override;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const override;
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const override;
private:
struct FileEntry {
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 95b4722d81..b9e54e4e20 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -837,6 +837,7 @@ void LBPage::loadBITL(uint16 resourceId) {
break;
default:
warning("Unknown item type %04x", type);
+ // fall through
case 3: // often used for buttons
res = new LBItem(_vm, this, rect);
break;
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 4b87b6464f..4649b9f5c9 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -707,7 +707,7 @@ protected:
class MohawkEngine_LivingBooks : public MohawkEngine {
protected:
- Common::Error run();
+ Common::Error run() override;
public:
MohawkEngine_LivingBooks(OSystem *syst, const MohawkGameDescription *gamedesc);
@@ -725,7 +725,7 @@ public:
Common::SeekableSubReadStreamEndian *wrapStreamEndian(uint32 tag, uint16 id);
Common::String readString(Common::ReadStream *stream);
Common::Rect readRect(Common::ReadStreamEndian *stream);
- GUI::Debugger *getDebugger() { return _console; }
+ GUI::Debugger *getDebugger() override { return _console; }
void addArchive(Archive *archive);
void removeArchive(Archive *archive);
diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp
index b5ea547414..7eb5a0cc3a 100644
--- a/engines/mohawk/livingbooks_code.cpp
+++ b/engines/mohawk/livingbooks_code.cpp
@@ -1349,14 +1349,17 @@ void LBCode::cmdSetPlayParams(const Common::Array<LBValue> &params) {
switch (params.size()) {
case 8:
target->_soundMode = params[7].integer;
+ // fall through
case 7:
target->_controlMode = params[6].integer;
+ // fall through
case 6:
// TODO: _relocPoint?
case 5:
// TODO: _periodMin/Max
case 4:
target->_timingMode = params[3].integer;
+ // fall through
case 3:
// TODO: _delayMin/Max
case 2:
diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp
index 53481af8a7..52f73dbbb1 100644
--- a/engines/mohawk/mohawk.cpp
+++ b/engines/mohawk/mohawk.cpp
@@ -41,8 +41,8 @@ MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc)
// Setup mixer
syncSoundSettings();
- _pauseDialog = 0;
- _cursor = 0;
+ _pauseDialog = nullptr;
+ _cursor = nullptr;
}
MohawkEngine::~MohawkEngine() {
@@ -70,7 +70,6 @@ Common::SeekableReadStream *MohawkEngine::getResource(uint32 tag, uint16 id) {
return _mhk[i]->getResource(tag, id);
error("Could not find a '%s' resource with ID %04x", tag2str(tag), id);
- return NULL;
}
bool MohawkEngine::hasResource(uint32 tag, uint16 id) {
@@ -95,7 +94,6 @@ uint32 MohawkEngine::getResourceOffset(uint32 tag, uint16 id) {
return _mhk[i]->getOffset(tag, id);
error("Could not find a '%s' resource with ID %04x", tag2str(tag), id);
- return 0;
}
uint16 MohawkEngine::findResourceID(uint32 tag, const Common::String &resName) {
@@ -104,7 +102,6 @@ uint16 MohawkEngine::findResourceID(uint32 tag, const Common::String &resName) {
return _mhk[i]->findResourceID(tag, resName);
error("Could not find a '%s' resource matching name '%s'", tag2str(tag), resName.c_str());
- return 0xFFFF;
}
Common::String MohawkEngine::getResourceName(uint32 tag, uint16 id) {
@@ -114,7 +111,6 @@ Common::String MohawkEngine::getResourceName(uint32 tag, uint16 id) {
}
error("Could not find a \'%s\' resource with ID %04x", tag2str(tag), id);
- return 0;
}
} // End of namespace Mohawk
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index c6781ae448..8184f46bad 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -49,14 +49,7 @@ enum MohawkGameType {
GType_MYST,
GType_MAKINGOF,
GType_RIVEN,
- GType_ZOOMBINI,
GType_CSTIME,
- GType_CSWORLD,
- GType_CSAMTRAK,
- GType_JAMESMATH,
- GType_TREEHOUSE,
- GType_1STDEGREE,
- GType_CSUSA,
GType_LIVINGBOOKSV1,
GType_LIVINGBOOKSV2,
GType_LIVINGBOOKSV3,
@@ -68,8 +61,7 @@ enum MohawkGameFeatures {
GF_ME = (1 << 0), // Myst Masterpiece Edition
GF_DVD = (1 << 1),
GF_DEMO = (1 << 2),
- GF_HASMIDI = (1 << 3),
- GF_LB_10 = (1 << 4) // very early Living Books 1.0 games
+ GF_LB_10 = (1 << 3) // very early Living Books 1.0 games
};
struct MohawkGameDescription;
@@ -80,23 +72,22 @@ class CursorManager;
class MohawkEngine : public ::Engine {
protected:
- virtual Common::Error run();
+ Common::Error run() override;
public:
MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc);
- virtual ~MohawkEngine();
+ ~MohawkEngine() override;
// Detection related functions
const MohawkGameDescription *_gameDescription;
const char *getGameId() const;
uint32 getFeatures() const;
const char *getAppName() const;
- uint16 getVersion() const;
Common::Platform getPlatform() const;
uint8 getGameType() const;
Common::Language getLanguage() const;
- bool hasFeature(EngineFeature f) const;
+ bool hasFeature(EngineFeature f) const override;
CursorManager *_cursor;
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 5baa89cea8..a01cfdd343 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -54,7 +54,8 @@
namespace Mohawk {
-MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc) : MohawkEngine(syst, gamedesc) {
+MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc) :
+ MohawkEngine(syst, gamedesc) {
DebugMan.addDebugChannel(kDebugVariable, "Variable", "Track Variable Accesses");
DebugMan.addDebugChannel(kDebugSaveLoad, "SaveLoad", "Track Save/Load Function");
DebugMan.addDebugChannel(kDebugView, "View", "Track Card File (VIEW) Parsing");
@@ -69,7 +70,9 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
_currentCursor = 0;
_mainCursor = kDefaultMystCursor;
_showResourceRects = false;
+ _curStack = 0;
_curCard = 0;
+ _lastSaveTime = 0;
_hoverResource = nullptr;
_activeResource = nullptr;
@@ -82,13 +85,20 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
_scriptParser = nullptr;
_gameState = nullptr;
_optionsDialog = nullptr;
+ _rnd = nullptr;
_prevStack = nullptr;
_mouseClicked = false;
_mouseMoved = false;
_escapePressed = false;
- _interactive = true;
+ _waitingOnBlockingOperation = false;
+ _runExitScript = true;
+
+ _needsPageDrop = false;
+ _needsShowCredits = false;
+ _needsShowDemoMenu = false;
+ _needsShowMap = false;
}
MohawkEngine_Myst::~MohawkEngine_Myst() {
@@ -253,8 +263,40 @@ void MohawkEngine_Myst::playMovieBlocking(const Common::String &name, MystStack
waitUntilMovieEnds(video);
}
-void MohawkEngine_Myst::playFlybyMovie(const Common::String &name) {
- Common::String filename = wrapMovieFilename(name, kMasterpieceOnly);
+void MohawkEngine_Myst::playFlybyMovie(uint16 stack, uint16 card) {
+ static const uint16 kMasterpieceOnly = 0xFFFF;
+
+ // Play Flyby Entry Movie on Masterpiece Edition.
+ const char *flyby = nullptr;
+
+ switch (stack) {
+ case kSeleniticStack:
+ flyby = "selenitic flyby";
+ break;
+ case kStoneshipStack:
+ flyby = "stoneship flyby";
+ break;
+ // Myst Flyby Movie not used in Original Masterpiece Edition Engine
+ // We play it when first arriving on Myst, and if the user has chosen so.
+ case kMystStack:
+ if (ConfMan.getBool("playmystflyby"))
+ flyby = "myst flyby";
+ break;
+ case kMechanicalStack:
+ flyby = "mech age flyby";
+ break;
+ case kChannelwoodStack:
+ flyby = "channelwood flyby";
+ break;
+ default:
+ break;
+ }
+
+ if (!flyby) {
+ return;
+ }
+
+ Common::String filename = wrapMovieFilename(flyby, kMasterpieceOnly);
VideoEntryPtr video = _video->playMovie(filename, Audio::Mixer::kSFXSoundType);
if (!video) {
error("Failed to open the '%s' movie", filename.c_str());
@@ -271,7 +313,7 @@ void MohawkEngine_Myst::waitUntilMovieEnds(const VideoEntryPtr &video) {
if (!video)
return;
- _interactive = false;
+ _waitingOnBlockingOperation = true;
// Sanity check
if (video->isLooping())
@@ -289,17 +331,17 @@ void MohawkEngine_Myst::waitUntilMovieEnds(const VideoEntryPtr &video) {
// Ensure it's removed
_video->removeEntry(video);
- _interactive = true;
+ _waitingOnBlockingOperation = false;
}
void MohawkEngine_Myst::playSoundBlocking(uint16 id) {
- _interactive = false;
+ _waitingOnBlockingOperation = true;
_sound->playEffect(id);
while (_sound->isEffectPlaying() && !shouldQuit()) {
doFrame();
}
- _interactive = true;
+ _waitingOnBlockingOperation = false;
}
Common::Error MohawkEngine_Myst::run() {
@@ -340,9 +382,6 @@ Common::Error MohawkEngine_Myst::run() {
_mhk.push_back(mhk);
}
- // Test Load Function...
- loadHelp(10000);
-
while (!shouldQuit()) {
doFrame();
}
@@ -353,10 +392,14 @@ Common::Error MohawkEngine_Myst::run() {
void MohawkEngine_Myst::doFrame() {
// Update any background videos
_video->updateMovies();
- if (!_scriptParser->isScriptRunning() && _interactive) {
- _interactive = false;
+ if (isInteractive()) {
+ _waitingOnBlockingOperation = true;
_scriptParser->runPersistentScripts();
- _interactive = true;
+ _waitingOnBlockingOperation = false;
+ }
+
+ if (shouldPerformAutoSave(_lastSaveTime)) {
+ tryAutoSaving();
}
Common::Event event;
@@ -410,9 +453,19 @@ void MohawkEngine_Myst::doFrame() {
}
if (_needsShowCredits) {
- _cursor->hideCursor();
- changeToStack(kCreditsStack, 10000, 0, 0);
- _needsShowCredits = false;
+ if (isInteractive()) {
+ // Attempt to autosave before exiting
+ tryAutoSaving();
+
+ _cursor->hideCursor();
+ changeToStack(kCreditsStack, 10000, 0, 0);
+ _needsShowCredits = false;
+ } else {
+ // Showing the credits in the middle of a script is not possible
+ // because it unloads the previous age, removing data needed by the
+ // rest of the script. Instead we just quit without showing the credits.
+ quitGame();
+ }
}
break;
case Common::KEYCODE_ESCAPE:
@@ -431,12 +484,17 @@ void MohawkEngine_Myst::doFrame() {
break;
}
break;
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ // Attempt to autosave before exiting
+ tryAutoSaving();
+ break;
default:
break;
}
}
- if (!_scriptParser->isScriptRunning() && _interactive) {
+ if (isInteractive()) {
updateActiveResource();
checkCurrentResource();
}
@@ -448,7 +506,7 @@ void MohawkEngine_Myst::doFrame() {
}
bool MohawkEngine_Myst::wait(uint32 duration, bool skippable) {
- _interactive = false;
+ _waitingOnBlockingOperation = true;
uint32 end = getTotalPlayTime() + duration;
do {
@@ -460,7 +518,7 @@ bool MohawkEngine_Myst::wait(uint32 duration, bool skippable) {
}
} while (getTotalPlayTime() < end && !shouldQuit());
- _interactive = true;
+ _waitingOnBlockingOperation = false;
return false;
}
@@ -480,20 +538,27 @@ void MohawkEngine_Myst::pauseEngineIntern(bool pause) {
void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound) {
debug(2, "changeToStack(%d)", stack);
- _curStack = stack;
-
// Fill screen with black and empty cursor
_cursor->setCursor(0);
_currentCursor = 0;
+ _sound->stopEffect();
+ _video->stopVideos();
+
+ // In Myst ME, play a fullscreen flyby movie, except when loading saves.
+ // Also play a flyby when first linking to Myst.
+ if (getFeatures() & GF_ME
+ && (_curStack != kIntroStack || (stack == kMystStack && card == 4134))) {
+ playFlybyMovie(stack, card);
+ }
+
+ _sound->stopBackground();
+
if (getFeatures() & GF_ME)
_system->fillScreen(_system->getScreenFormat().RGBToColor(0, 0, 0));
else
_gfx->clearScreenPalette();
- _sound->stopEffect();
- _sound->stopBackground();
- _video->stopVideos();
if (linkSrcSound)
playSoundBlocking(linkSrcSound);
@@ -503,20 +568,22 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
delete _prevStack;
_prevStack = _scriptParser;
+ _curStack = stack;
+
switch (_curStack) {
case kChannelwoodStack:
- _gameState->_globals.currentAge = 4;
+ _gameState->_globals.currentAge = kChannelwood;
_scriptParser = new MystStacks::Channelwood(this);
break;
case kCreditsStack:
_scriptParser = new MystStacks::Credits(this);
break;
case kDemoStack:
- _gameState->_globals.currentAge = 0;
+ _gameState->_globals.currentAge = kSelenitic;
_scriptParser = new MystStacks::Demo(this);
break;
case kDniStack:
- _gameState->_globals.currentAge = 6;
+ _gameState->_globals.currentAge = kDni;
_scriptParser = new MystStacks::Dni(this);
break;
case kIntroStack:
@@ -526,26 +593,26 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_scriptParser = new MystStacks::MakingOf(this);
break;
case kMechanicalStack:
- _gameState->_globals.currentAge = 3;
+ _gameState->_globals.currentAge = kMechanical;
_scriptParser = new MystStacks::Mechanical(this);
break;
case kMystStack:
- _gameState->_globals.currentAge = 2;
+ _gameState->_globals.currentAge = kMystLibrary;
_scriptParser = new MystStacks::Myst(this);
break;
case kDemoPreviewStack:
_scriptParser = new MystStacks::Preview(this);
break;
case kSeleniticStack:
- _gameState->_globals.currentAge = 0;
+ _gameState->_globals.currentAge = kSelenitic;
_scriptParser = new MystStacks::Selenitic(this);
break;
case kDemoSlidesStack:
- _gameState->_globals.currentAge = 1;
+ _gameState->_globals.currentAge = kStoneship;
_scriptParser = new MystStacks::Slides(this);
break;
case kStoneshipStack:
- _gameState->_globals.currentAge = 1;
+ _gameState->_globals.currentAge = kStoneship;
_scriptParser = new MystStacks::Stoneship(this);
break;
default:
@@ -570,38 +637,6 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_cache.clear();
_gfx->clearCache();
- if (getFeatures() & GF_ME) {
- // Play Flyby Entry Movie on Masterpiece Edition.
- const char *flyby = nullptr;
-
- switch (_curStack) {
- case kSeleniticStack:
- flyby = "selenitic flyby";
- break;
- case kStoneshipStack:
- flyby = "stoneship flyby";
- break;
- // Myst Flyby Movie not used in Original Masterpiece Edition Engine
- // We play it when first arriving on Myst, and if the user has chosen so.
- case kMystStack:
- if (ConfMan.getBool("playmystflyby") && card == 4134)
- flyby = "myst flyby";
- break;
- case kMechanicalStack:
- flyby = "mech age flyby";
- break;
- case kChannelwoodStack:
- flyby = "channelwood flyby";
- break;
- default:
- break;
- }
-
- if (flyby) {
- playFlybyMovie(flyby);
- }
- }
-
changeToCard(card, kTransitionCopy);
if (linkDstSound)
@@ -677,7 +712,7 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
// The demo resets the cursor at each card change except when in the library
if (getFeatures() & GF_DEMO
- && _gameState->_globals.currentAge != 2) {
+ && _gameState->_globals.currentAge != kMystLibrary) {
_cursor->setDefaultCursor();
}
@@ -724,7 +759,7 @@ void MohawkEngine_Myst::checkCurrentResource() {
}
for (uint16 i = 0; i < _resources.size(); i++) {
- if (_resources[i]->contains(mouse) && _resources[i]->type == kMystAreaHover
+ if (_resources[i]->contains(mouse) && _resources[i]->hasType(kMystAreaHover)
&& _hoverResource != _resources[i]) {
_hoverResource = static_cast<MystAreaHover *>(_resources[i]);
_hoverResource->handleMouseEnter();
@@ -955,50 +990,6 @@ void MohawkEngine_Myst::runExitScript() {
_scriptParser->runScript(script);
}
-void MohawkEngine_Myst::loadHelp(uint16 id) {
- // The original version did not have the help system
- if (!(getFeatures() & GF_ME))
- return;
-
- // TODO: Help File contains 5 cards i.e. VIEW, RLST, etc.
- // in addition to HELP resources.
- // These are Ids 9930 to 9934
- // Need to deal with loading and displaying these..
- // Current engine structure only supports display of
- // card from primary stack MHK
-
- debugC(kDebugHelp, "Loading Help System Data");
-
- Common::SeekableReadStream *helpStream = getResource(ID_HELP, id);
-
- uint16 count = helpStream->readUint16LE();
- uint16 *u0 = new uint16[count];
- Common::String helpText;
-
- debugC(kDebugHelp, "\tcount: %d", count);
-
- for (uint16 i = 0; i < count; i++) {
- u0[i] = helpStream->readUint16LE();
- debugC(kDebugHelp, "\tu0[%d]: %d", i, u0[i]);
- }
-
- // TODO: Previous values i.e. u0[0] to u0[count - 2]
- // appear to be resource ids in the help.dat file..
- if (u0[count - 1] != count)
- warning("loadHelp(): last u0 value is not equal to count");
-
- do {
- helpText += helpStream->readByte();
- } while (helpText.lastChar() != 0);
- helpText.deleteLastChar();
-
- debugC(kDebugHelp, "\thelpText: \"%s\"", helpText.c_str());
-
- delete[] u0;
-
- delete helpStream;
-}
-
void MohawkEngine_Myst::loadCursorHints() {
_cursorHints.clear();
@@ -1059,7 +1050,7 @@ void MohawkEngine_Myst::checkCursorHints() {
// Check all the cursor hints to see if we're in a hotspot that contains a hint.
for (uint16 i = 0; i < _cursorHints.size(); i++)
- if (_resources[_cursorHints[i].id] == _activeResource && _activeResource->isEnabled()) {
+ if (_activeResource && _resources[_cursorHints[i].id] == _activeResource && _activeResource->isEnabled()) {
if (_cursorHints[i].cursor == -1) {
uint16 var_value = _scriptParser->getVar(_cursorHints[i].variableHint.var);
@@ -1107,7 +1098,7 @@ void MohawkEngine_Myst::redrawResource(MystAreaImageSwitch *resource, bool updat
void MohawkEngine_Myst::redrawArea(uint16 var, bool update) {
for (uint16 i = 0; i < _resources.size(); i++)
- if (_resources[i]->type == kMystAreaImageSwitch && _resources[i]->getImageSwitchVar() == var)
+ if (_resources[i]->hasType(kMystAreaImageSwitch) && _resources[i]->getImageSwitchVar() == var)
redrawResource(static_cast<MystAreaImageSwitch *>(_resources[i]), update);
}
@@ -1120,36 +1111,34 @@ MystArea *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream
switch (type) {
case kMystAreaAction:
- resource = new MystAreaAction(this, rlstStream, parent);
+ resource = new MystAreaAction(this, type, rlstStream, parent);
break;
case kMystAreaVideo:
- resource = new MystAreaVideo(this, rlstStream, parent);
+ resource = new MystAreaVideo(this, type, rlstStream, parent);
break;
case kMystAreaActionSwitch:
- resource = new MystAreaActionSwitch(this, rlstStream, parent);
+ resource = new MystAreaActionSwitch(this, type, rlstStream, parent);
break;
case kMystAreaImageSwitch:
- resource = new MystAreaImageSwitch(this, rlstStream, parent);
+ resource = new MystAreaImageSwitch(this, type, rlstStream, parent);
break;
case kMystAreaSlider:
- resource = new MystAreaSlider(this, rlstStream, parent);
+ resource = new MystAreaSlider(this, type, rlstStream, parent);
break;
case kMystAreaDrag:
- resource = new MystAreaDrag(this, rlstStream, parent);
+ resource = new MystAreaDrag(this, type, rlstStream, parent);
break;
case kMystVideoInfo:
- resource = new MystVideoInfo(this, rlstStream, parent);
+ resource = new MystVideoInfo(this, type, rlstStream, parent);
break;
case kMystAreaHover:
- resource = new MystAreaHover(this, rlstStream, parent);
+ resource = new MystAreaHover(this, type, rlstStream, parent);
break;
default:
- resource = new MystArea(this, rlstStream, parent);
+ resource = new MystArea(this, type, rlstStream, parent);
break;
}
- resource->type = type;
-
return resource;
}
@@ -1184,15 +1173,34 @@ Common::Error MohawkEngine_Myst::loadGameState(int slot) {
}
Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) {
- return _gameState->save(slot, desc) ? Common::kNoError : Common::kUnknownError;
+ return _gameState->save(slot, desc, false) ? Common::kNoError : Common::kUnknownError;
+}
+
+void MohawkEngine_Myst::tryAutoSaving() {
+ if (!canSaveGameStateCurrently()) {
+ return; // Can't save right now, try again on the next frame
+ }
+
+ _lastSaveTime = _system->getMillis();
+
+ if (!_gameState->isAutoSaveAllowed()) {
+ return; // Can't autosave ever, try again after the next autosave delay
+ }
+
+ if (!_gameState->save(MystGameState::kAutoSaveSlot, "Autosave", true))
+ warning("Attempt to autosave has failed.");
}
bool MohawkEngine_Myst::hasGameSaveSupport() const {
return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF;
}
+bool MohawkEngine_Myst::isInteractive() {
+ return !_scriptParser->isScriptRunning() && !_waitingOnBlockingOperation;
+}
+
bool MohawkEngine_Myst::canLoadGameStateCurrently() {
- if (_scriptParser->isScriptRunning() || !_interactive) {
+ if (!isInteractive()) {
return false;
}
@@ -1229,8 +1237,8 @@ bool MohawkEngine_Myst::canSaveGameStateCurrently() {
}
void MohawkEngine_Myst::dropPage() {
- uint16 page = _gameState->_globals.heldPage;
- bool whitePage = page == 13;
+ HeldPage page = _gameState->_globals.heldPage;
+ bool whitePage = page == kWhitePage;
bool bluePage = page - 1 < 6;
bool redPage = page - 7 < 6;
@@ -1238,25 +1246,25 @@ void MohawkEngine_Myst::dropPage() {
_sound->playEffect(800);
// Drop page
- _gameState->_globals.heldPage = 0;
+ _gameState->_globals.heldPage = kNoPage;
// Redraw page area
- if (whitePage && _gameState->_globals.currentAge == 2) {
+ if (whitePage && _gameState->_globals.currentAge == kMystLibrary) {
_scriptParser->toggleVar(41);
redrawArea(41);
} else if (bluePage) {
- if (page == 6) {
- if (_gameState->_globals.currentAge == 2)
+ if (page == kBlueFirePlacePage) {
+ if (_gameState->_globals.currentAge == kMystLibrary)
redrawArea(24);
} else {
redrawArea(103);
}
} else if (redPage) {
- if (page == 12) {
- if (_gameState->_globals.currentAge == 2)
+ if (page == kRedFirePlacePage) {
+ if (_gameState->_globals.currentAge == kMystLibrary)
redrawArea(25);
- } else if (page == 10) {
- if (_gameState->_globals.currentAge == 1)
+ } else if (page == kRedStoneshipPage) {
+ if (_gameState->_globals.currentAge == kStoneship)
redrawArea(35);
} else {
redrawArea(102);
@@ -1277,9 +1285,9 @@ MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) con
debugC(kDebugView, "\tSound: %d", soundBlock.sound);
soundBlock.soundVolume = stream->readUint16LE();
debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume);
- } else if (soundBlock.sound == kMystSoundActionContinue)
+ } else if (soundBlock.sound == kMystSoundActionContinue) {
debugC(kDebugView, "Continue current sound");
- else if (soundBlock.sound == kMystSoundActionChangeVolume) {
+ } else if (soundBlock.sound == kMystSoundActionChangeVolume) {
debugC(kDebugView, "Continue current sound, change volume");
soundBlock.soundVolume = stream->readUint16LE();
debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume);
@@ -1305,8 +1313,7 @@ MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) con
soundBlock.soundList.push_back(sound);
}
} else {
- debugC(kDebugView, "Unknown");
- warning("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard);
+ error("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard);
}
return soundBlock;
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index 3f756faee0..64fee10fde 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -95,8 +95,6 @@ enum TransitionType {
kNoTransition = 999
};
-const uint16 kMasterpieceOnly = 0xFFFF;
-
struct MystCondition {
uint16 var;
Common::Array<uint16> values;
@@ -176,7 +174,7 @@ protected:
public:
MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc);
- virtual ~MohawkEngine_Myst();
+ ~MohawkEngine_Myst() override;
Common::SeekableReadStream *getResource(uint32 tag, uint16 id) override;
Common::Array<uint16> getResourceIDList(uint32 type) const;
@@ -229,17 +227,25 @@ public:
VideoEntryPtr playMovie(const Common::String &name, MystStack stack);
VideoEntryPtr findVideo(const Common::String &name, MystStack stack);
void playMovieBlocking(const Common::String &name, MystStack stack, uint16 x, uint16 y);
- void playFlybyMovie(const Common::String &name);
+ void playFlybyMovie(uint16 stack, uint16 card);
void waitUntilMovieEnds(const VideoEntryPtr &video);
void playSoundBlocking(uint16 id);
GUI::Debugger *getDebugger() override { return _console; }
+ /**
+ * Is the game currently interactive
+ *
+ * When the game is interactive, the user can interact with the game world
+ * and perform other operations such as loading saved games, ...
+ */
+ bool isInteractive();
bool canLoadGameStateCurrently() override;
bool canSaveGameStateCurrently() override;
Common::Error loadGameState(int slot) override;
Common::Error saveGameState(int slot, const Common::String &desc) override;
+ void tryAutoSaving();
bool hasFeature(EngineFeature f) const override;
private:
@@ -251,6 +257,7 @@ private:
uint16 _curStack;
uint16 _curCard;
+ uint32 _lastSaveTime;
MystView _view;
bool _runExitScript;
@@ -264,8 +271,6 @@ private:
void runInitScript();
void runExitScript();
- void loadHelp(uint16 id);
-
void loadResources();
void drawResourceRects();
void checkCurrentResource();
@@ -286,7 +291,7 @@ private:
bool _mouseClicked;
bool _mouseMoved;
bool _escapePressed;
- bool _interactive; // Is the game currently interactive
+ bool _waitingOnBlockingOperation;
Common::Array<MystCursorHint> _cursorHints;
void loadCursorHints();
diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp
index 7cc39e97b2..eff51bf1c9 100644
--- a/engines/mohawk/myst_areas.cpp
+++ b/engines/mohawk/myst_areas.cpp
@@ -32,9 +32,10 @@
namespace Mohawk {
-MystArea::MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) {
- _vm = vm;
- _parent = parent;
+MystArea::MystArea(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ _vm(vm),
+ _parent(parent),
+ _type(type) {
if (parent == nullptr) {
_flags = rlstStream->readUint16LE();
@@ -77,7 +78,7 @@ void MystArea::handleMouseUp() {
uint16 opcode;
- switch (type) {
+ switch (_type) {
case kMystAreaForward:
opcode = 6;
break;
@@ -118,7 +119,7 @@ void MystArea::setEnabled(bool enabled) {
const Common::String MystArea::describe() {
Common::String desc = Common::String::format("type: %2d rect: (%3d %3d %3d %3d)",
- type, _rect.left, _rect.top, _rect.width(), _rect.height());
+ _type, _rect.left, _rect.top, _rect.width(), _rect.height());
if (_dest != 0)
desc += Common::String::format(" dest: %4d", _dest);
@@ -137,8 +138,8 @@ void MystArea::drawBoundingRect() {
}
}
-MystAreaAction::MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystArea(vm, rlstStream, parent) {
+MystAreaAction::MystAreaAction(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystArea(vm, type, rlstStream, parent) {
debugC(kDebugResource, "\tResource Type 5 Script:");
_script = vm->_scriptParser->readScript(rlstStream, kMystScriptNormal);
@@ -175,8 +176,8 @@ Common::String MystAreaVideo::convertMystVideoName(const Common::String &name) {
return temp + ".mov";
}
-MystAreaVideo::MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystAreaAction(vm, rlstStream, parent) {
+MystAreaVideo::MystAreaVideo(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaAction(vm, type, rlstStream, parent) {
char c = 0;
do {
@@ -195,12 +196,21 @@ MystAreaVideo::MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *
// Position values require modulus 10000 to keep in sane range.
_left = rlstStream->readSint16LE() % 10000;
_top = rlstStream->readSint16LE() % 10000;
- _playOnCardChange = rlstStream->readUint16LE();
+ _playOnCardChange = rlstStream->readUint16LE() != 0;
_direction = rlstStream->readSint16LE();
_playBlocking = rlstStream->readUint16LE();
_loop = rlstStream->readUint16LE();
_playRate = rlstStream->readUint16LE();
+ // WORKAROUND: Myst v1.0 has playOnCardChange set to true
+ // for the Myst flyby video shown during the intro.
+ // This causes the flyby to play over the closed Myst book picture.
+ // Later releases of the game have that flag set to false.
+ // Here we apply a resource patch to match the newer releases.
+ if (_videoFile == "qtw/intro/intro2.mov") {
+ _playOnCardChange = false;
+ }
+
debugC(kDebugResource, "\tvideoFile: \"%s\"", _videoFile.c_str());
debugC(kDebugResource, "\tleft: %d", _left);
debugC(kDebugResource, "\ttop: %d", _top);
@@ -281,8 +291,8 @@ void MystAreaVideo::pauseMovie(bool pause) {
handle->pause(pause);
}
-MystAreaActionSwitch::MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystArea(vm, rlstStream, parent) {
+MystAreaActionSwitch::MystAreaActionSwitch(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystArea(vm, type, rlstStream, parent) {
_actionSwitchVar = rlstStream->readUint16LE();
uint16 numSubResources = rlstStream->readUint16LE();
debugC(kDebugResource, "\tactionSwitchVar: %d", _actionSwitchVar);
@@ -335,8 +345,8 @@ void MystAreaActionSwitch::handleMouseDown() {
doSwitch(&MystArea::handleMouseDown);
}
-MystAreaImageSwitch::MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystAreaActionSwitch(vm, rlstStream, parent) {
+MystAreaImageSwitch::MystAreaImageSwitch(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaActionSwitch(vm, type, rlstStream, parent) {
_imageSwitchVar = rlstStream->readUint16LE();
uint16 numSubImages = rlstStream->readUint16LE();
debugC(kDebugResource, "\tvar8: %d", _imageSwitchVar);
@@ -477,8 +487,8 @@ const Common::String MystAreaImageSwitch::describe() {
// No MystResourceType9!
-MystAreaSlider::MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystAreaDrag(vm, rlstStream, parent) {
+MystAreaSlider::MystAreaSlider(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaDrag(vm, type, rlstStream, parent) {
_dragSound = rlstStream->readUint16LE();
debugC(kDebugResource, "\tdrag sound : %d", _dragSound);
@@ -643,8 +653,8 @@ void MystAreaSlider::updatePosition(const Common::Point &mouse) {
_vm->_sound->playEffect(_dragSound);
}
-MystAreaDrag::MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystAreaImageSwitch(vm, rlstStream, parent) {
+MystAreaDrag::MystAreaDrag(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaImageSwitch(vm, type, rlstStream, parent) {
_flagHV = rlstStream->readUint16LE();
_minH = rlstStream->readUint16LE();
_maxH = rlstStream->readUint16LE();
@@ -748,8 +758,8 @@ uint16 MystAreaDrag::getList3(uint16 index) {
return (index < _lists[2].size()) ? _lists[2][index] : 0;
}
-MystVideoInfo::MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystAreaDrag(vm, rlstStream, parent) {
+MystVideoInfo::MystVideoInfo(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystAreaDrag(vm, type, rlstStream, parent) {
_numFrames = rlstStream->readUint16LE();
_firstFrame = rlstStream->readUint16LE();
uint16 frameWidth = rlstStream->readUint16LE();
@@ -774,8 +784,8 @@ MystVideoInfo::~MystVideoInfo() {
}
void MystVideoInfo::drawFrame(uint16 frame) {
- _currentFrame = _firstFrame + frame;
- _vm->_gfx->copyImageToScreen(_currentFrame, _frameRect);
+ uint16 currentFrame = _firstFrame + frame;
+ _vm->_gfx->copyImageToScreen(currentFrame, _frameRect);
}
bool MystVideoInfo::pullLeverV() {
@@ -810,8 +820,8 @@ void MystVideoInfo::releaseLeverV() {
}
}
-MystAreaHover::MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) :
- MystArea(vm, rlstStream, parent) {
+MystAreaHover::MystAreaHover(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent) :
+ MystArea(vm, type, rlstStream, parent) {
_enterOpcode = rlstStream->readUint16LE();
_leaveOpcode = rlstStream->readUint16LE();
diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h
index 32b6ca4f2f..b389f32ea1 100644
--- a/engines/mohawk/myst_areas.h
+++ b/engines/mohawk/myst_areas.h
@@ -58,12 +58,13 @@ enum {
class MystArea {
public:
- MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ MystArea(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
virtual ~MystArea();
virtual const Common::String describe();
void drawBoundingRect();
+ bool hasType(ResourceType type) const { return _type == type; }
bool contains(Common::Point point) { return _rect.contains(point); }
virtual void drawDataToScreen() {}
virtual void handleCardChange() {}
@@ -83,10 +84,10 @@ public:
virtual void handleMouseDrag() {}
MystArea *_parent;
- ResourceType type;
protected:
MohawkEngine_Myst *_vm;
+ ResourceType _type;
uint16 _flags;
Common::Rect _rect;
uint16 _dest;
@@ -94,7 +95,7 @@ protected:
class MystAreaAction : public MystArea {
public:
- MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ MystAreaAction(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
void handleMouseUp() override;
const Common::String describe() override;
@@ -105,7 +106,7 @@ protected:
class MystAreaVideo : public MystAreaAction {
public:
- MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ MystAreaVideo(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
VideoEntryPtr playMovie();
VideoEntryPtr getVideo();
@@ -125,20 +126,20 @@ protected:
uint16 _loop;
int16 _direction; // 1 => forward, -1 => backwards
uint16 _playBlocking;
- uint16 _playOnCardChange;
+ bool _playOnCardChange;
uint16 _playRate; // percents
};
class MystAreaActionSwitch : public MystArea {
public:
- MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
- virtual ~MystAreaActionSwitch();
+ MystAreaActionSwitch(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ ~MystAreaActionSwitch() override;
- virtual void drawDataToScreen() override;
- virtual void handleCardChange() override;
+ void drawDataToScreen() override;
+ void handleCardChange() override;
- virtual void handleMouseUp() override;
- virtual void handleMouseDown() override;
+ void handleMouseUp() override;
+ void handleMouseDown() override;
MystArea *getSubResource(uint16 index) { return _subResources[index]; }
protected:
@@ -152,16 +153,16 @@ protected:
class MystAreaImageSwitch : public MystAreaActionSwitch {
public:
- MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
- virtual ~MystAreaImageSwitch();
+ MystAreaImageSwitch(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ ~MystAreaImageSwitch() override;
struct SubImage {
uint16 wdib;
Common::Rect rect;
};
- virtual const Common::String describe() override;
- virtual void drawDataToScreen() override;
+ const Common::String describe() override;
+ void drawDataToScreen() override;
void drawConditionalDataToScreen(uint16 state, bool update = true);
uint16 getImageSwitchVar() override;
@@ -175,14 +176,14 @@ protected:
class MystAreaDrag : public MystAreaImageSwitch {
public:
- MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
- virtual ~MystAreaDrag();
+ MystAreaDrag(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ ~MystAreaDrag() override;
const Common::String describe() override;
- virtual void handleMouseDown() override;
- virtual void handleMouseUp() override;
- virtual void handleMouseDrag() override;
+ void handleMouseDown() override;
+ void handleMouseUp() override;
+ void handleMouseDrag() override;
uint16 getList1(uint16 index);
uint16 getList2(uint16 index);
@@ -214,8 +215,8 @@ protected:
class MystAreaSlider : public MystAreaDrag {
public:
- MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
- virtual ~MystAreaSlider();
+ MystAreaSlider(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ ~MystAreaSlider() override;
void handleMouseDown() override;
void handleMouseUp() override;
@@ -235,8 +236,8 @@ protected:
class MystVideoInfo : public MystAreaDrag {
public:
- MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
- virtual ~MystVideoInfo();
+ MystVideoInfo(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ ~MystVideoInfo() override;
void drawFrame(uint16 frame);
bool pullLeverV();
@@ -247,14 +248,11 @@ protected:
uint16 _numFrames;
uint16 _firstFrame;
Common::Rect _frameRect;
-
-private:
- uint16 _currentFrame;
};
class MystAreaHover : public MystArea {
public:
- MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
+ MystAreaHover(MohawkEngine_Myst *vm, ResourceType type, Common::SeekableReadStream *rlstStream, MystArea *parent);
const Common::String describe() override;
diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp
index 3f8d15cea5..6b43ea02bc 100644
--- a/engines/mohawk/myst_graphics.cpp
+++ b/engines/mohawk/myst_graphics.cpp
@@ -231,6 +231,15 @@ void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src,
MohawkSurface *mhkSurface = findImage(image);
Graphics::Surface *surface = mhkSurface->getSurface();
+ if (image == 2258 && _vm->getFeatures() & GF_ME) {
+ // In Myst ME, the image for the open red page brother door
+ // when the special lights are on does not have the correct width.
+ // We work around this issue by tweaking the destination rectangle
+ // so it renders at the correct position.
+ // The original executable does the same hack.
+ dest.left += 49;
+ }
+
// Make sure the image is bottom aligned in the dest rect
dest.top = dest.bottom - MIN<int>(surface->h, dest.height());
diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h
index 44669bd6dc..b8217f6cfc 100644
--- a/engines/mohawk/myst_graphics.h
+++ b/engines/mohawk/myst_graphics.h
@@ -40,8 +40,8 @@ enum RectState {
class MystGraphics : public GraphicsManager {
public:
- MystGraphics(MohawkEngine_Myst *vm);
- ~MystGraphics();
+ explicit MystGraphics(MohawkEngine_Myst *vm);
+ ~MystGraphics() override;
void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest);
void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest);
@@ -51,7 +51,6 @@ public:
void runTransition(TransitionType type, Common::Rect rect, uint16 steps, uint16 delay);
void drawRect(Common::Rect rect, RectState state);
void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color);
- void enableDrawingTimeSimulation(bool enable);
void fadeToBlack();
void fadeFromBlack();
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index ba426505e1..c1a593b430 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -40,6 +40,7 @@ MystScriptEntry::MystScriptEntry() {
var = 0;
resourceId = 0;
u1 = 0;
+ opcode = 0;
}
const uint8 MystScriptParser::_stackMap[11] = {
@@ -79,8 +80,10 @@ MystScriptParser::MystScriptParser(MohawkEngine_Myst *vm) :
_invokingResource = nullptr;
_savedCardId = 0;
_savedCursorId = 0;
+ _savedMapCardId = 0;
_tempVar = 0;
_scriptNestingLevel = 0;
+ _startTime = 0;
}
MystScriptParser::~MystScriptParser() {
@@ -375,7 +378,7 @@ void MystScriptParser::o_takePage(uint16 var, const ArgumentsArray &args) {
cursorId = kDefaultMystCursor;
}
- uint16 oldPage = _globals.heldPage;
+ HeldPage oldPage = _globals.heldPage;
// Take / drop page
toggleVar(var);
@@ -385,7 +388,7 @@ void MystScriptParser::o_takePage(uint16 var, const ArgumentsArray &args) {
_vm->redrawArea(var);
// Set new cursor
- if (_globals.heldPage)
+ if (_globals.heldPage != kNoPage)
_vm->setMainCursor(cursorId);
else
_vm->setMainCursor(kDefaultMystCursor);
@@ -600,9 +603,11 @@ void MystScriptParser::o_copyImageToBackBuffer(uint16 var, const ArgumentsArray
Common::Rect dstRect = Common::Rect(args[5], args[6], 544, 333);
- if (dstRect.left == -1 || dstRect.top == -1) {
- // Interpreted as full screen
+ if (dstRect.left == -1) {
dstRect.left = 0;
+ }
+
+ if (dstRect.top == -1) {
dstRect.top = 0;
}
@@ -622,6 +627,8 @@ void MystScriptParser::o_copyImageToBackBuffer(uint16 var, const ArgumentsArray
}
void MystScriptParser::o_changeBackgroundSound(uint16 var, const ArgumentsArray &args) {
+ soundWaitStop();
+
// Used on Stoneship Card 2080
// Used on Channelwood Card 3225 with argc = 8 i.e. Conditional Sound List
Common::MemoryWriteStreamDynamic writeStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
@@ -749,11 +756,11 @@ void MystScriptParser::o_changeCardPlaySoundDirectional(uint16 var, const Argume
debugC(kDebugScript, "\tdelay between steps: %d", delayBetweenSteps);
debugC(kDebugScript, "\tanimated update data size: %d", dataSize);
+ _vm->changeToCard(cardId, kNoTransition);
+
if (soundId)
_vm->_sound->playEffect(soundId);
- _vm->changeToCard(cardId, kNoTransition);
-
animatedUpdate(ArgumentsArray(args.begin() + 4, dataSize), delayBetweenSteps);
}
@@ -784,12 +791,16 @@ void MystScriptParser::o_soundWaitStop(uint16 var, const ArgumentsArray &args) {
// Used on Selenitic Card 1191 (Maze Runner)
// Used on Mechanical Card 6267 (Code Lock)
// Used when Button is pushed...
- while (_vm->_sound->isEffectPlaying())
+ soundWaitStop();
+}
+
+void MystScriptParser::soundWaitStop() const {
+ while (_vm->_sound->isEffectPlaying() && !Engine::shouldQuit())
_vm->doFrame();
}
void MystScriptParser::o_quit(uint16 var, const ArgumentsArray &args) {
- _vm->quitGame();
+ Engine::quitGame();
}
void MystScriptParser::showMap() {
@@ -800,6 +811,8 @@ void MystScriptParser::showMap() {
}
void MystScriptParser::o_exitMap(uint16 var, const ArgumentsArray &args) {
+ assert(_savedMapCardId);
+
_vm->changeToCard(_savedMapCardId, kTransitionCopy);
}
diff --git a/engines/mohawk/myst_scripts.h b/engines/mohawk/myst_scripts.h
index a336f0239a..a7a840b9d3 100644
--- a/engines/mohawk/myst_scripts.h
+++ b/engines/mohawk/myst_scripts.h
@@ -60,7 +60,7 @@ typedef Common::SharedPtr<Common::Array<MystScriptEntry> > MystScript;
class MystScriptParser {
public:
- MystScriptParser(MohawkEngine_Myst *vm);
+ explicit MystScriptParser(MohawkEngine_Myst *vm);
virtual ~MystScriptParser();
void runScript(MystScript script, MystArea *invokingResource = nullptr);
@@ -87,6 +87,7 @@ public:
void showMap();
void animatedUpdate(const ArgumentsArray &args, uint16 delay);
+ void soundWaitStop() const;
// Common opcodes
DECLARE_OPCODE(o_toggleVar);
diff --git a/engines/mohawk/myst_sound.h b/engines/mohawk/myst_sound.h
index 71df23df39..953017097d 100644
--- a/engines/mohawk/myst_sound.h
+++ b/engines/mohawk/myst_sound.h
@@ -39,7 +39,7 @@ class MohawkEngine_Myst;
class MystSound {
public:
- MystSound(MohawkEngine_Myst *vm);
+ explicit MystSound(MohawkEngine_Myst *vm);
~MystSound();
// Effect channel
diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp
index 17df749c74..726b3d6526 100644
--- a/engines/mohawk/myst_stacks/channelwood.cpp
+++ b/engines/mohawk/myst_stacks/channelwood.cpp
@@ -37,7 +37,13 @@ namespace Mohawk {
namespace MystStacks {
Channelwood::Channelwood(MohawkEngine_Myst *vm) :
- MystScriptParser(vm), _state(vm->_gameState->_channelwood) {
+ MystScriptParser(vm),
+ _state(vm->_gameState->_channelwood),
+ _valveVar(0),
+ _siriusDrawerState(0),
+ _doorOpened(0),
+ _leverPulled(false),
+ _leverAction(nullptr) {
setupOpcodes();
}
@@ -181,7 +187,7 @@ uint16 Channelwood::getVar(uint16 var) {
}
case 102: // Sirrus's Desk Drawer / Red Page State
if (_siriusDrawerState) {
- if(!(_globals.redPagesInBook & 16) && (_globals.heldPage != 11))
+ if(!(_globals.redPagesInBook & 16) && (_globals.heldPage != kRedChannelwoodPage))
return 2; // Drawer Open, Red Page Present
else
return 1; // Drawer Open, Red Page Taken
@@ -189,7 +195,7 @@ uint16 Channelwood::getVar(uint16 var) {
return 0; // Drawer Closed
}
case 103: // Blue Page Present
- return !(_globals.bluePagesInBook & 16) && (_globals.heldPage != 5);
+ return !(_globals.bluePagesInBook & 16) && (_globals.heldPage != kBlueChannelwoodPage);
default:
return MystScriptParser::getVar(var);
}
@@ -208,18 +214,18 @@ void Channelwood::toggleVar(uint16 var) {
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 16)) {
- if (_globals.heldPage == 11)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kRedChannelwoodPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 11;
+ _globals.heldPage = kRedChannelwoodPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 16)) {
- if (_globals.heldPage == 5)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kBlueChannelwoodPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 5;
+ _globals.heldPage = kBlueChannelwoodPage;
}
break;
default:
@@ -329,6 +335,7 @@ void Channelwood::o_pipeExtend(uint16 var, const ArgumentsArray &args) {
void Channelwood::o_drawImageChangeCardAndVolume(uint16 var, const ArgumentsArray &args) {
uint16 imageId = args[0];
uint16 cardId = args[1];
+ uint16 volume = args.size() == 3 ? args[2] : 0;
debugC(kDebugScript, "\timageId: %d", imageId);
debugC(kDebugScript, "\tcardId: %d", cardId);
@@ -338,8 +345,7 @@ void Channelwood::o_drawImageChangeCardAndVolume(uint16 var, const ArgumentsArra
_vm->changeToCard(cardId, kTransitionPartToLeft);
- if (args.size() == 3) {
- uint16 volume = args[2];
+ if (volume) {
_vm->_sound->changeBackgroundVolume(volume);
}
}
diff --git a/engines/mohawk/myst_stacks/channelwood.h b/engines/mohawk/myst_stacks/channelwood.h
index 6b8ba9dff7..3302a8e17b 100644
--- a/engines/mohawk/myst_stacks/channelwood.h
+++ b/engines/mohawk/myst_stacks/channelwood.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Channelwood : public MystScriptParser {
public:
- Channelwood(MohawkEngine_Myst *vm);
- ~Channelwood();
+ explicit Channelwood(MohawkEngine_Myst *vm);
+ ~Channelwood() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
@@ -49,7 +49,7 @@ private:
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() override { return 9932; }
+ uint16 getMap() override { return 9932; }
DECLARE_OPCODE(o_bridgeToggle);
DECLARE_OPCODE(o_pipeExtend);
diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp
index ba49ac2201..80ccf7fe9a 100644
--- a/engines/mohawk/myst_stacks/credits.cpp
+++ b/engines/mohawk/myst_stacks/credits.cpp
@@ -23,6 +23,7 @@
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_graphics.h"
+#include "mohawk/cursors.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/credits.h"
@@ -34,9 +35,11 @@ namespace MystStacks {
// NOTE: Credits Start Card is 10000
-Credits::Credits(MohawkEngine_Myst *vm) : MystScriptParser(vm) {
+Credits::Credits(MohawkEngine_Myst *vm) :
+ MystScriptParser(vm),
+ _creditsRunning(false),
+ _curImage(0) {
setupOpcodes();
- _curImage = 0;
}
Credits::~Credits() {
@@ -80,13 +83,17 @@ uint16 Credits::getVar(uint16 var) {
case 0: // Credits Image Control
return _curImage;
case 1: // Credits Music Control (Good / bad ending)
- return _globals.ending != 4;
+ return _globals.ending != kBooksDestroyed;
default:
return MystScriptParser::getVar(var);
}
}
void Credits::o_runCredits(uint16 var, const ArgumentsArray &args) {
+ // The credits stack does not have all the cursors, reset to the default cursor.
+ _globals.heldPage = kNoPage;
+ _vm->setMainCursor(kDefaultMystCursor);
+
// Activate the credits
_creditsRunning = true;
_curImage = 0;
diff --git a/engines/mohawk/myst_stacks/credits.h b/engines/mohawk/myst_stacks/credits.h
index bea5381534..966d93068a 100644
--- a/engines/mohawk/myst_stacks/credits.h
+++ b/engines/mohawk/myst_stacks/credits.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Credits : public MystScriptParser {
public:
- Credits(MohawkEngine_Myst *vm);
- ~Credits();
+ explicit Credits(MohawkEngine_Myst *vm);
+ ~Credits() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
diff --git a/engines/mohawk/myst_stacks/demo.cpp b/engines/mohawk/myst_stacks/demo.cpp
index 7ae55686c5..d2ba70c198 100644
--- a/engines/mohawk/myst_stacks/demo.cpp
+++ b/engines/mohawk/myst_stacks/demo.cpp
@@ -30,10 +30,12 @@
namespace Mohawk {
namespace MystStacks {
-Demo::Demo(MohawkEngine_Myst *vm) : Intro(vm) {
+Demo::Demo(MohawkEngine_Myst *vm) :
+ Intro(vm),
+ _returnToMenuRunning(false),
+ _returnToMenuStep(0),
+ _returnToMenuNextTime(0) {
setupOpcodes();
-
- _returnToMenuStep = 0;
}
Demo::~Demo() {
diff --git a/engines/mohawk/myst_stacks/demo.h b/engines/mohawk/myst_stacks/demo.h
index 337ddaae98..acb224b6cf 100644
--- a/engines/mohawk/myst_stacks/demo.h
+++ b/engines/mohawk/myst_stacks/demo.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Demo : public Intro {
public:
- Demo(MohawkEngine_Myst *vm);
- ~Demo();
+ explicit Demo(MohawkEngine_Myst *vm);
+ ~Demo() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
@@ -52,8 +52,6 @@ private:
DECLARE_OPCODE(o_returnToMenu_init);
- DECLARE_OPCODE(opcode_300);
-
bool _returnToMenuRunning;
uint16 _returnToMenuStep; // 42
uint32 _returnToMenuNextTime; // 6
diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp
index ba53c70037..a38b5d3857 100644
--- a/engines/mohawk/myst_stacks/dni.cpp
+++ b/engines/mohawk/myst_stacks/dni.cpp
@@ -34,9 +34,15 @@ namespace Mohawk {
namespace MystStacks {
Dni::Dni(MohawkEngine_Myst *vm) :
- MystScriptParser(vm) {
+ MystScriptParser(vm),
+ _notSeenAtrus(true),
+ _atrusRunning(false),
+ _waitForLoop(false),
+ _atrusLeft(false),
+ _atrusLeftTime(0),
+ _loopStart(0),
+ _loopEnd(0) {
setupOpcodes();
- _notSeenAtrus = true;
}
Dni::~Dni() {
@@ -74,16 +80,16 @@ void Dni::runPersistentScripts() {
uint16 Dni::getVar(uint16 var) {
switch(var) {
case 0: // Atrus Gone (from across room)
- return _globals.ending == 2;
+ return _globals.ending == kAtrusLeaves;
case 1: // Myst Book Status
- if (_globals.ending != 4)
- return _globals.ending == 3;
+ if (_globals.ending != kBooksDestroyed)
+ return _globals.ending == kForgotPage;
else
return 2; // Linkable
case 2: // Music Type
if (_notSeenAtrus) {
_notSeenAtrus = false;
- return _globals.ending != 4 && _globals.heldPage != 13;
+ return _globals.ending != kBooksDestroyed && _globals.heldPage != kWhitePage;
} else
return 2;
default:
@@ -98,9 +104,9 @@ void Dni::o_handPage(uint16 var, const ArgumentsArray &args) {
VideoEntryPtr atrus = _vm->findVideo(_video, kDniStack);
// Good ending and Atrus asked to give page
- if (_globals.ending == 1 && atrus && atrus->getTime() > (uint)Audio::Timestamp(0, 6801, 600).msecs()) {
- _globals.ending = 2;
- _globals.heldPage = 0;
+ if (_globals.ending == kAtrusWantsPage && atrus && atrus->getTime() > (uint)Audio::Timestamp(0, 6801, 600).msecs()) {
+ _globals.ending = kAtrusLeaves;
+ _globals.heldPage = kNoPage;
_vm->setMainCursor(kDefaultMystCursor);
// Play movie end (atrus leaving)
@@ -121,12 +127,13 @@ void Dni::atrusLeft_run() {
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 98000, 600));
+ _atrusRunning = false;
_waitForLoop = true;
_loopStart = 73095;
_loopEnd = 98000;
// Good ending
- _globals.ending = 4;
+ _globals.ending = kBooksDestroyed;
_globals.bluePagesInBook = 63;
_globals.redPagesInBook = 63;
@@ -146,10 +153,10 @@ void Dni::loopVideo_run() {
}
void Dni::atrus_run() {
- if (_globals.ending == 2) {
+ if (_globals.ending == kAtrusLeaves) {
// Wait for atrus to come back
_atrusLeft = true;
- } else if (_globals.ending == 1) {
+ } else if (_globals.ending == kAtrusWantsPage) {
// Atrus asking for page
if (!_vm->_video->isVideoPlaying()) {
_video = "atr1page";
@@ -159,8 +166,8 @@ void Dni::atrus_run() {
atrus->setLooping(true);
atrus->setBounds(Audio::Timestamp(0, 7388, 600), Audio::Timestamp(0, 14700, 600));
}
- } else if (_globals.ending != 3 && _globals.ending != 4) {
- if (_globals.heldPage == 13) {
+ } else if (_globals.ending != kForgotPage && _globals.ending != kBooksDestroyed) {
+ if (_globals.heldPage == kWhitePage) {
_video = "atr1page";
_videoPos = Common::Point(215, 76);
VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack);
@@ -172,7 +179,7 @@ void Dni::atrus_run() {
_loopEnd = 14700;
// Wait for page
- _globals.ending = 1;
+ _globals.ending = kAtrusWantsPage;
} else {
_video = "atr1nopg";
@@ -181,12 +188,13 @@ void Dni::atrus_run() {
atrus->moveTo(_videoPos.x, _videoPos.y);
atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 46175, 600));
+ _atrusRunning = false;
_waitForLoop = true;
_loopStart = 30656;
_loopEnd = 46175;
// Bad ending
- _globals.ending = 3;
+ _globals.ending = kForgotPage;
}
} else if (!_vm->_video->isVideoPlaying()) {
VideoEntryPtr atrus = _vm->playMovie("atrwrite", kDniStack);
diff --git a/engines/mohawk/myst_stacks/dni.h b/engines/mohawk/myst_stacks/dni.h
index 7ba49b1936..30c9329fe6 100644
--- a/engines/mohawk/myst_stacks/dni.h
+++ b/engines/mohawk/myst_stacks/dni.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Dni : public MystScriptParser {
public:
- Dni(MohawkEngine_Myst *vm);
- ~Dni();
+ explicit Dni(MohawkEngine_Myst *vm);
+ ~Dni() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index 2b431e834a..9e03713b0f 100644
--- a/engines/mohawk/myst_stacks/intro.cpp
+++ b/engines/mohawk/myst_stacks/intro.cpp
@@ -31,7 +31,12 @@
namespace Mohawk {
namespace MystStacks {
-Intro::Intro(MohawkEngine_Myst *vm) : MystScriptParser(vm) {
+Intro::Intro(MohawkEngine_Myst *vm) :
+ MystScriptParser(vm),
+ _introMoviesRunning(false),
+ _introStep(0),
+ _linkBookRunning(false),
+ _linkBookMovie(nullptr) {
setupOpcodes();
}
@@ -66,7 +71,7 @@ void Intro::runPersistentScripts() {
uint16 Intro::getVar(uint16 var) {
switch(var) {
case 0:
- if (_globals.currentAge == 9 || _globals.currentAge == 10)
+ if (_globals.currentAge == kSirrusEnding || _globals.currentAge == kAchenarEnding)
return 2;
else
return _globals.currentAge;
diff --git a/engines/mohawk/myst_stacks/intro.h b/engines/mohawk/myst_stacks/intro.h
index 938a30e691..ec78199802 100644
--- a/engines/mohawk/myst_stacks/intro.h
+++ b/engines/mohawk/myst_stacks/intro.h
@@ -38,8 +38,8 @@ namespace MystStacks {
class Intro : public MystScriptParser {
public:
- Intro(MohawkEngine_Myst *vm);
- ~Intro();
+ explicit Intro(MohawkEngine_Myst *vm);
+ ~Intro() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
diff --git a/engines/mohawk/myst_stacks/makingof.cpp b/engines/mohawk/myst_stacks/makingof.cpp
index 2907c53231..4e0ce516b8 100644
--- a/engines/mohawk/myst_stacks/makingof.cpp
+++ b/engines/mohawk/myst_stacks/makingof.cpp
@@ -30,7 +30,8 @@
namespace Mohawk {
namespace MystStacks {
-MakingOf::MakingOf(MohawkEngine_Myst *vm) : MystScriptParser(vm) {
+MakingOf::MakingOf(MohawkEngine_Myst *vm) :
+ MystScriptParser(vm) {
setupOpcodes();
}
diff --git a/engines/mohawk/myst_stacks/makingof.h b/engines/mohawk/myst_stacks/makingof.h
index cdc64d2991..f65c9696c3 100644
--- a/engines/mohawk/myst_stacks/makingof.h
+++ b/engines/mohawk/myst_stacks/makingof.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class MakingOf : public MystScriptParser {
public:
- MakingOf(MohawkEngine_Myst *vm);
- ~MakingOf();
+ explicit MakingOf(MohawkEngine_Myst *vm);
+ ~MakingOf() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index bd5406a4f1..a58e278590 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -36,23 +36,53 @@ namespace Mohawk {
namespace MystStacks {
Mechanical::Mechanical(MohawkEngine_Myst *vm) :
- MystScriptParser(vm), _state(vm->_gameState->_mechanical) {
+ MystScriptParser(vm),
+ _state(vm->_gameState->_mechanical) {
setupOpcodes();
_elevatorGoingMiddle = false;
_elevatorPosition = 0;
+ _elevatorGoingDown = 0;
+ _elevatorRotationSpeed = 0;
+ _elevatorRotationGearPosition = 0;
+ _elevatorRotationSoundId = 0;
+ _elevatorRotationLeverMoving = false;
+ _elevatorTooLate = false;
+ _elevatorInCabin = false;
+ _elevatorTopCounter = 0;
+ _elevatorNextTime = 0;
_crystalLit = 0;
_mystStaircaseState = false;
_fortressPosition = 0;
- _fortressRotationSpeed = 0;
- _fortressSimulationSpeed = 0;
_gearsWereRunning = false;
_fortressRotationShortMovieWorkaround = false;
_fortressRotationShortMovieCount = 0;
_fortressRotationShortMovieLast = 0;
+
+ _fortressRotationRunning = false;
+ _fortressRotationSpeed = 0;
+ _fortressRotationBrake = 0;
+ _fortressRotationGears = nullptr;
+
+ _fortressSimulationRunning = false;
+ _fortressSimulationInit = false;
+ _fortressSimulationSpeed = 0;
+ _fortressSimulationBrake = 0;
+ _fortressSimulationStartSound1 = 0;
+ _fortressSimulationStartSound2 = 0;
+ _fortressSimulationHolo = nullptr;
+ _fortressSimulationStartup = nullptr;
+ _fortressSimulationHoloRate = 0;
+
+ _birdSinging = false;
+ _birdCrankStartTime = 0;
+ _birdSingEndTime = 0;
+ _bird = nullptr;
+
+ _snakeBox = nullptr;
}
Mechanical::~Mechanical() {
@@ -140,12 +170,12 @@ uint16 Mechanical::getVar(uint16 var) {
return _state.sirrusPanelState;
case 2: // Achenar's Secret Room Crate Lid Open and Blue Page Present
if (_state.achenarCrateOpened) {
- if (_globals.bluePagesInBook & 4 || _globals.heldPage == 3)
+ if (_globals.bluePagesInBook & 4 || _globals.heldPage == kBlueMechanicalPage)
return 2;
else
return 3;
} else {
- return _globals.bluePagesInBook & 4 || _globals.heldPage == 3;
+ return _globals.bluePagesInBook & 4 || _globals.heldPage == kBlueMechanicalPage;
}
case 3: // Achenar's Secret Room Crate State
return _state.achenarCrateOpened;
@@ -193,9 +223,9 @@ uint16 Mechanical::getVar(uint16 var) {
case 22: // Crystal Lit Flag - Red
return _crystalLit == 2;
case 102: // Red page
- return !(_globals.redPagesInBook & 4) && (_globals.heldPage != 9);
+ return !(_globals.redPagesInBook & 4) && (_globals.heldPage != kRedMechanicalPage);
case 103: // Blue page
- return !(_globals.bluePagesInBook & 4) && (_globals.heldPage != 3);
+ return !(_globals.bluePagesInBook & 4) && (_globals.heldPage != kBlueMechanicalPage);
default:
return MystScriptParser::getVar(var);
}
@@ -229,18 +259,18 @@ void Mechanical::toggleVar(uint16 var) {
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 4)) {
- if (_globals.heldPage == 9)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kRedMechanicalPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 9;
+ _globals.heldPage = kRedMechanicalPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 4)) {
- if (_globals.heldPage == 3)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kBlueMechanicalPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 3;
+ _globals.heldPage = kBlueMechanicalPage;
}
break;
default:
diff --git a/engines/mohawk/myst_stacks/mechanical.h b/engines/mohawk/myst_stacks/mechanical.h
index 46cfe687a0..52cd7e7732 100644
--- a/engines/mohawk/myst_stacks/mechanical.h
+++ b/engines/mohawk/myst_stacks/mechanical.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Mechanical : public MystScriptParser {
public:
- Mechanical(MohawkEngine_Myst *vm);
- ~Mechanical();
+ explicit Mechanical(MohawkEngine_Myst *vm);
+ ~Mechanical() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
@@ -49,7 +49,7 @@ private:
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() override { return 9931; }
+ uint16 getMap() override { return 9931; }
void birdSing_run();
void elevatorRotation_run();
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index dbc4ff55b8..4adee5fc20 100644
--- a/engines/mohawk/myst_stacks/myst.cpp
+++ b/engines/mohawk/myst_stacks/myst.cpp
@@ -37,7 +37,9 @@ namespace Mohawk {
namespace MystStacks {
Myst::Myst(MohawkEngine_Myst *vm) :
- MystScriptParser(vm), _state(_vm->_gameState->_myst) {
+ MystScriptParser(vm),
+ _state(_vm->_gameState->_myst),
+ _towerRotationCenter(Common::Point(383, 124)) {
setupOpcodes();
// Card ID preinitialized by the engine for use by opcode 18
@@ -45,22 +47,112 @@ Myst::Myst(MohawkEngine_Myst *vm) :
_savedCardId = 4329;
_towerRotationBlinkLabel = false;
+ _towerRotationBlinkLabelCount = 0;
+ _towerRotationSpeed = 0;
+ _towerRotationMapInitialized = 0;
+ _towerRotationMapRunning = false;
+ _towerRotationMapClicked = false;
+ _towerRotationMapTower = nullptr;
+ _towerRotationMapLabel = nullptr;
+ _towerRotationOverSpot = false;
+
_libraryBookcaseChanged = false;
+ _libraryBookcaseMoving = false;
+ _libraryBookcaseMovie = nullptr;
+ _libraryBookcaseSoundId = 0;
+
+ _libraryBookPagesTurning = false;
+ _libraryBookNumPages = 0;
+ _libraryBookBaseImage = 0;
+ _libraryBookSound1 = 0;
+ _libraryBookSound2 = 0;
+
+ _libraryCombinationBookPagesTurning = false;
+
+ for (uint i = 0; i < ARRAYSIZE(_fireplaceLines); i++) {
+ _fireplaceLines[i] = 0;
+ }
+
_dockVaultState = 0;
+
_cabinDoorOpened = 0;
_cabinHandleDown = 0;
_cabinMatchState = 2;
_cabinGaugeMovieEnabled = false;
+
+ _boilerPressureIncreasing = false;
+ _boilerPressureDecreasing = false;
+ _basementPressureIncreasing = false;
+ _basementPressureDecreasing = false;
+
_matchBurning = false;
+ _matchGoOutCnt = 0;
+ _matchGoOutTime = 0;
+
_tree = nullptr;
_treeAlcove = nullptr;
_treeStopped = false;
_treeMinPosition = 0;
+ _treeMinAccessiblePosition = 0;
+ _treeMaxAccessiblePosition = 0;
+
+ _imagerRunning = false;
+ _imagerRedButton = nullptr;
+ _imagerMovie = nullptr;
+ _imagerValidationRunning = false;
+ _imagerValidationCard = 0;
_imagerValidationStep = 0;
- _observatoryCurrentSlider = nullptr;
+ for (uint i = 0; i < ARRAYSIZE(_imagerSound); i++) {
+ _imagerSound[i] = 0;
+ }
+
_butterfliesMoviePlayed = false;
_state.treeLastMoveTime = _vm->_system->getMillis();
+
_rocketPianoSound = 0;
+ _rocketSlider1 = nullptr;
+ _rocketSlider2 = nullptr;
+ _rocketSlider3 = nullptr;
+ _rocketSlider4 = nullptr;
+ _rocketSlider5 = nullptr;
+ _rocketSliderSound = 0;
+ _rocketLeverPosition = 0;
+
+ _generatorControlRoomRunning = false;
+ _generatorVoltage = _state.generatorVoltage;
+
+ _observatoryRunning = false;
+ _observatoryMonthChanging = false;
+ _observatoryDayChanging = false;
+ _observatoryYearChanging = false;
+ _observatoryTimeChanging = false;
+ _observatoryVisualizer = nullptr;
+ _observatoryGoButton = nullptr;
+ _observatoryCurrentSlider = nullptr;
+ _observatoryDaySlider = nullptr;
+ _observatoryMonthSlider = nullptr;
+ _observatoryYearSlider = nullptr;
+ _observatoryTimeSlider = nullptr;
+ _observatoryLastTime = 0;
+ _observatoryNotInitialized = true;
+ _observatoryIncrement = 0;
+
+ _greenBookRunning = false;
+
+ _gullsFlying1 = false;
+ _gullsFlying2 = false;
+ _gullsFlying3 = false;
+ _gullsNextTime = 0;
+
+ _courtyardBoxSound = 0;
+
+ _clockTurningWheel = 0;
+ _clockWeightPosition = 0;
+ _clockMiddleGearMovedAlone = false;
+ _clockLeverPulled = false;
+ for (uint i = 0; i < ARRAYSIZE(_clockGearsPositions); i++) {
+ _clockGearsPositions[i] = 0;
+ }
}
Myst::~Myst() {
@@ -149,6 +241,8 @@ void Myst::setupOpcodes() {
REGISTER_OPCODE(175, Myst, o_observatoryYearSliderEndMove);
REGISTER_OPCODE(176, Myst, o_observatoryTimeSliderStartMove);
REGISTER_OPCODE(177, Myst, o_observatoryTimeSliderEndMove);
+ REGISTER_OPCODE(178, Myst, o_libraryBookPageTurnStartLeft);
+ REGISTER_OPCODE(179, Myst, o_libraryBookPageTurnStartRight);
REGISTER_OPCODE(180, Myst, o_libraryCombinationBookStop);
REGISTER_OPCODE(181, Myst, NOP);
REGISTER_OPCODE(182, Myst, o_cabinMatchLight);
@@ -211,6 +305,7 @@ void Myst::setupOpcodes() {
void Myst::disablePersistentScripts() {
_libraryBookcaseMoving = false;
_generatorControlRoomRunning = false;
+ _libraryBookPagesTurning = false;
_libraryCombinationBookPagesTurning = false;
_clockTurningWheel = 0;
_towerRotationMapRunning = false;
@@ -242,6 +337,9 @@ void Myst::runPersistentScripts() {
if (_libraryCombinationBookPagesTurning)
libraryCombinationBook_run();
+ if (_libraryBookPagesTurning)
+ libraryBook_run();
+
if (_libraryBookcaseMoving)
libraryBookcaseTransform_run();
@@ -308,7 +406,7 @@ uint16 Myst::getVar(uint16 var) {
case 0: // Myst Library Bookcase Closed
return _state.libraryBookcaseDoor;
case 1:
- if (_globals.ending != 4)
+ if (_globals.ending != kBooksDestroyed)
return _state.libraryBookcaseDoor != 1;
else if (_state.libraryBookcaseDoor == 1)
return 2;
@@ -389,13 +487,13 @@ uint16 Myst::getVar(uint16 var) {
&& _fireplaceLines[4] == 204
&& _fireplaceLines[5] == 250;
case 24: // Fireplace Blue Page Present
- if (_globals.ending != 4)
- return !(_globals.bluePagesInBook & 32) && (_globals.heldPage != 6);
+ if (_globals.ending != kBooksDestroyed)
+ return !(_globals.bluePagesInBook & 32) && (_globals.heldPage != kBlueFirePlacePage);
else
return 0;
case 25: // Fireplace Red Page Present
- if (_globals.ending != 4)
- return !(_globals.redPagesInBook & 32) && (_globals.heldPage != 12);
+ if (_globals.ending != kBooksDestroyed)
+ return !(_globals.redPagesInBook & 32) && (_globals.heldPage != kRedFirePlacePage);
else
return 0;
case 26: // Courtyard Image Box - Cross
@@ -536,25 +634,41 @@ uint16 Myst::getVar(uint16 var) {
return 10;
case 79: // Stellar Observatory Date - Year #4 (Right)
return (_state.observatoryYearSetting / 1) % 10;
- case 80: // Stellar Observatory Hour #1 - Left ( Number 1 (0) or Blank (10))
+ case 80: // Stellar Observatory Hour #1 - Left ( Hour digits can be 10 (Blank), or 0-2)
+ uint32 observatoryLeftMinutes;
if (!observatoryIsDDMMYYYY2400()) {
- if (_state.observatoryTimeSetting % (12 * 60) < (10 * 60))
+ // 12 Hour Format
+ observatoryLeftMinutes = _state.observatoryTimeSetting % (12 * 60);
+ if (observatoryLeftMinutes > 59 && observatoryLeftMinutes < (10 * 60))
return 10;
else
return 1;
} else {
- if (_state.observatoryTimeSetting < (10 * 60))
- return 10;
- else if (_state.observatoryTimeSetting < (20 * 60))
+ // 24 Hour Format
+ observatoryLeftMinutes = _state.observatoryTimeSetting;
+ if (observatoryLeftMinutes < (10 * 60))
+ return 0;
+ else if (observatoryLeftMinutes < (20 * 60))
return 1;
else
return 2;
}
case 81: // Stellar Observatory Hour #2 - Right
- if (!observatoryIsDDMMYYYY2400())
- return ((_state.observatoryTimeSetting % (12 * 60)) / 60) % 10;
- else
- return (_state.observatoryTimeSetting / 60) % 10;
+ uint32 observatoryRightMinutes,observatoryRightHour;
+ if (!observatoryIsDDMMYYYY2400()) {
+ // 12 Hour Format
+ observatoryRightMinutes = _state.observatoryTimeSetting % (12 * 60);
+ observatoryRightHour = observatoryRightMinutes / 60;
+ if (observatoryRightHour % 12 == 0)
+ return 2;
+ else
+ return observatoryRightHour % 10;
+ } else {
+ // 24 Hour Format
+ observatoryRightMinutes = _state.observatoryTimeSetting;
+ observatoryRightHour = observatoryRightMinutes / 60;
+ return observatoryRightHour % 10;
+ }
case 82: // Stellar Observatory Minutes #1 - Left
return (_state.observatoryTimeSetting % 60) / 10;
case 83: // Stellar Observatory Minutes #2 - Right
@@ -592,13 +706,13 @@ uint16 Myst::getVar(uint16 var) {
case 99: // Cabin Boiler Gas Valve Position
return _state.cabinValvePosition % 6;
case 102: // Red page
- if (_globals.ending != 4)
- return !(_globals.redPagesInBook & 1) && (_globals.heldPage != 7);
+ if (_globals.ending != kBooksDestroyed)
+ return !(_globals.redPagesInBook & 1) && (_globals.heldPage != kRedLibraryPage);
else
return 0;
case 103: // Blue page
- if (_globals.ending != 4)
- return !(_globals.bluePagesInBook & 1) && (_globals.heldPage != 1);
+ if (_globals.ending != kBooksDestroyed)
+ return !(_globals.bluePagesInBook & 1) && (_globals.heldPage != kBlueLibraryPage);
else
return 0;
case 300: // Rocket Ship Music Puzzle Slider State
@@ -656,19 +770,19 @@ void Myst::toggleVar(uint16 var) {
_state.rocketshipMarkerSwitch = (_state.rocketshipMarkerSwitch + 1) % 2;
break;
case 24: // Fireplace Blue Page
- if (_globals.ending != 4 && !(_globals.bluePagesInBook & 32)) {
- if (_globals.heldPage == 6)
- _globals.heldPage = 0;
+ if (_globals.ending != kBooksDestroyed && !(_globals.bluePagesInBook & 32)) {
+ if (_globals.heldPage == kBlueFirePlacePage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 6;
+ _globals.heldPage = kBlueFirePlacePage;
}
break;
case 25: // Fireplace Red page
- if (_globals.ending != 4 && !(_globals.redPagesInBook & 32)) {
- if (_globals.heldPage == 12)
- _globals.heldPage = 0;
+ if (_globals.ending != kBooksDestroyed && !(_globals.redPagesInBook & 32)) {
+ if (_globals.heldPage == kRedFirePlacePage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 12;
+ _globals.heldPage = kRedFirePlacePage;
}
break;
case 26: // Courtyard Image Box - Cross
@@ -688,30 +802,30 @@ void Myst::toggleVar(uint16 var) {
}
break;
case 41: // Vault white page
- if (_globals.ending != 4) {
+ if (_globals.ending != kBooksDestroyed) {
if (_dockVaultState == 1) {
_dockVaultState = 2;
- _globals.heldPage = 0;
+ _globals.heldPage = kNoPage;
} else if (_dockVaultState == 2) {
_dockVaultState = 1;
- _globals.heldPage = 13;
+ _globals.heldPage = kWhitePage;
}
}
break;
case 102: // Red page
- if (_globals.ending != 4 && !(_globals.redPagesInBook & 1)) {
- if (_globals.heldPage == 7)
- _globals.heldPage = 0;
+ if (_globals.ending != kBooksDestroyed && !(_globals.redPagesInBook & 1)) {
+ if (_globals.heldPage == kRedLibraryPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 7;
+ _globals.heldPage = kRedLibraryPage;
}
break;
case 103: // Blue page
- if (_globals.ending != 4 && !(_globals.bluePagesInBook & 1)) {
- if (_globals.heldPage == 1)
- _globals.heldPage = 0;
+ if (_globals.ending != kBooksDestroyed && !(_globals.bluePagesInBook & 1)) {
+ if (_globals.heldPage == kBlueLibraryPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 1;
+ _globals.heldPage = kBlueLibraryPage;
}
break;
default:
@@ -812,6 +926,10 @@ uint16 Myst::bookCountPages(uint16 var) {
}
void Myst::o_libraryBookPageTurnLeft(uint16 var, const ArgumentsArray &args) {
+ libraryBookPageTurnLeft();
+}
+
+void Myst::libraryBookPageTurnLeft() {
if (_libraryBookPage - 1 >= 0) {
_libraryBookPage--;
@@ -826,6 +944,10 @@ void Myst::o_libraryBookPageTurnLeft(uint16 var, const ArgumentsArray &args) {
}
void Myst::o_libraryBookPageTurnRight(uint16 var, const ArgumentsArray &args) {
+ libraryBookPageTurnRight();
+}
+
+void Myst::libraryBookPageTurnRight() {
if (_libraryBookPage + 1 < _libraryBookNumPages) {
_libraryBookPage++;
@@ -900,10 +1022,9 @@ void Myst::o_towerRotationStart(uint16 var, const ArgumentsArray &args) {
_vm->_cursor->setCursor(700);
- const Common::Point center = Common::Point(383, 124);
- Common::Point end = towerRotationMapComputeCoords(center, _state.towerRotationAngle);
+ Common::Point end = towerRotationMapComputeCoords(_state.towerRotationAngle);
towerRotationMapComputeAngle();
- towerRotationMapDrawLine(center, end);
+ towerRotationMapDrawLine(end, true);
_vm->_sound->playEffect(5378, true);
}
@@ -974,7 +1095,7 @@ void Myst::o_dockVaultOpen(uint16 var, const ArgumentsArray &args) {
(_state.observatoryMarkerSwitch == 1) &&
(_state.poolMarkerSwitch == 1) &&
(_state.rocketshipMarkerSwitch == 1)) {
- if (_globals.heldPage != 13 && _globals.ending != 4)
+ if (_globals.heldPage != kWhitePage && _globals.ending != kBooksDestroyed)
_dockVaultState = 2;
else
_dockVaultState = 1;
@@ -1017,50 +1138,48 @@ void Myst::o_bookGivePage(uint16 var, const ArgumentsArray &args) {
debugC(kDebugScript, "Card Id (Book Cover): %d", cardIdBookCover);
debugC(kDebugScript, "SoundId (Add Page): %d", soundIdAddPage);
- // No page or white page
- if (!_globals.heldPage || _globals.heldPage == 13) {
- _vm->changeToCard(cardIdBookCover, kTransitionDissolve);
- return;
- }
-
uint16 bookVar = 101;
uint16 mask = 0;
switch (_globals.heldPage) {
- case 7:
+ case kNoPage:
+ case kWhitePage:
+ _vm->changeToCard(cardIdBookCover, kTransitionDissolve);
+ return;
+ case kRedLibraryPage:
bookVar = 100;
// fallthrough
- case 1:
+ case kBlueLibraryPage:
mask = 1;
break;
- case 8:
+ case kRedSeleniticPage:
bookVar = 100;
// fallthrough
- case 2:
+ case kBlueSeleniticPage:
mask = 2;
break;
- case 9:
+ case kRedMechanicalPage:
bookVar = 100;
// fallthrough
- case 3:
+ case kBlueMechanicalPage:
mask = 4;
break;
- case 10:
+ case kRedStoneshipPage:
bookVar = 100;
// fallthrough
- case 4:
+ case kBlueStoneshipPage:
mask = 8;
break;
- case 11:
+ case kRedChannelwoodPage:
bookVar = 100;
// fallthrough
- case 5:
+ case kBlueChannelwoodPage:
mask = 16;
break;
- case 12:
+ case kRedFirePlacePage:
bookVar = 100;
// fallthrough
- case 6:
+ case kBlueFirePlacePage:
mask = 32;
break;
}
@@ -1082,16 +1201,16 @@ void Myst::o_bookGivePage(uint16 var, const ArgumentsArray &args) {
_globals.bluePagesInBook |= mask;
// Remove page from hand
- _globals.heldPage = 0;
+ _globals.heldPage = kNoPage;
_vm->_cursor->showCursor();
if (mask == 32) {
// You lose!
if (var == 100)
- _globals.currentAge = 9;
+ _globals.currentAge = kSirrusEnding;
else
- _globals.currentAge = 10;
+ _globals.currentAge = kAchenarEnding;
_vm->changeToCard(cardIdLose, kTransitionDissolve);
} else {
@@ -1521,6 +1640,7 @@ void Myst::observatoryIncrementMonth(int16 increment) {
}
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
}
void Myst::observatoryMonthChange_run() {
@@ -1587,6 +1707,7 @@ void Myst::observatoryIncrementDay(int16 increment) {
}
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
}
void Myst::observatoryDayChange_run() {
@@ -1647,6 +1768,7 @@ void Myst::observatoryIncrementYear(int16 increment) {
}
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
}
void Myst::observatoryYearChange_run() {
@@ -1712,6 +1834,7 @@ void Myst::observatoryIncrementTime(int16 increment) {
}
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
}
void Myst::observatoryTimeChange_run() {
@@ -2260,7 +2383,7 @@ void Myst::o_rocketPianoMove(uint16 var, const ArgumentsArray &args) {
if (piano.contains(mouse)) {
MystArea *resource = _vm->forceUpdateClickedResource();
- if (resource && resource->type == kMystAreaDrag) {
+ if (resource && resource->hasType(kMystAreaDrag)) {
// Press new key
key = static_cast<MystAreaDrag *>(resource);
src = key->getSubImage(1).rect;
@@ -2336,7 +2459,7 @@ void Myst::o_rocketLeverMove(uint16 var, const ArgumentsArray &args) {
uint16 soundId = lever->getList2(0);
if (soundId)
- _vm->_sound->playEffect(soundId);
+ _vm->playSoundBlocking(soundId);
// If rocket correctly powered
if (_state.generatorVoltage == 59 && !_state.generatorBreakers)
@@ -2407,6 +2530,7 @@ void Myst::observatoryUpdateMonth() {
_state.observatoryMonthSetting = month;
_state.observatoryMonthSlider = _observatoryMonthSlider->_pos.y;
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
// Redraw digits
_vm->redrawArea(73);
@@ -2434,6 +2558,7 @@ void Myst::observatoryUpdateDay() {
_state.observatoryDaySetting = day;
_state.observatoryDaySlider = _observatoryDaySlider->_pos.y;
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
// Redraw digits
_vm->redrawArea(75);
@@ -2462,6 +2587,7 @@ void Myst::observatoryUpdateYear() {
_state.observatoryYearSetting = year;
_state.observatoryYearSlider = _observatoryYearSlider->_pos.y;
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
// Redraw digits
_vm->redrawArea(79);
@@ -2492,6 +2618,7 @@ void Myst::observatoryUpdateTime() {
_state.observatoryTimeSetting = time;
_state.observatoryTimeSlider = _observatoryTimeSlider->_pos.y;
_vm->_sound->playEffect(8500);
+ _vm->wait(20);
// Redraw digits
_vm->redrawArea(80);
@@ -2505,7 +2632,35 @@ void Myst::observatoryUpdateTime() {
}
}
+void Myst::o_libraryBookPageTurnStartLeft(uint16 var, const ArgumentsArray &args) {
+ _tempVar = -1;
+ libraryBookPageTurnLeft();
+ _startTime = _vm->_system->getMillis();
+ _libraryBookPagesTurning = true;
+}
+
+void Myst::o_libraryBookPageTurnStartRight(uint16 var, const ArgumentsArray &args) {
+ _tempVar = 1;
+ libraryBookPageTurnRight();
+ _startTime = _vm->_system->getMillis();
+ _libraryBookPagesTurning = true;
+}
+
+void Myst::libraryBook_run() {
+ uint32 time = _vm->_system->getMillis();
+ if (time >= _startTime + 500) {
+ if (_tempVar > 0) {
+ libraryBookPageTurnRight();
+ _startTime = time;
+ } else if (_tempVar < 0) {
+ libraryBookPageTurnLeft();
+ _startTime = time;
+ }
+ }
+}
+
void Myst::o_libraryCombinationBookStop(uint16 var, const ArgumentsArray &args) {
+ _libraryBookPagesTurning = false;
_libraryCombinationBookPagesTurning = false;
}
@@ -3021,7 +3176,7 @@ void Myst::towerRotationMap_run() {
} else {
// Stop blinking label
_towerRotationBlinkLabel = false;
- _towerRotationMapLabel->drawConditionalDataToScreen(0);
+ towerRotationMapRedraw();
// Blink tower
_startTime = time + 500;
@@ -3087,18 +3242,18 @@ uint16 Myst::towerRotationMapComputeAngle() {
return angle;
}
-Common::Point Myst::towerRotationMapComputeCoords(const Common::Point &center, uint16 angle) {
+Common::Point Myst::towerRotationMapComputeCoords(uint16 angle) {
Common::Point end;
// Polar to rect coords
double radians = angle * M_PI / 180.0;
- end.x = (int16)(center.x + cos(radians) * 310.0);
- end.y = (int16)(center.y + sin(radians) * 310.0);
+ end.x = (int16)(_towerRotationCenter.x + cos(radians) * 310.0);
+ end.y = (int16)(_towerRotationCenter.y + sin(radians) * 310.0);
return end;
}
-void Myst::towerRotationMapDrawLine(const Common::Point &center, const Common::Point &end) {
+void Myst::towerRotationMapDrawLine(const Common::Point &end, bool rotationLabelVisible) {
uint32 color;
if (_vm->getFeatures() & GF_ME) {
@@ -3133,18 +3288,22 @@ void Myst::towerRotationMapDrawLine(const Common::Point &center, const Common::P
_towerRotationMapTower->drawConditionalDataToScreen(0, false);
// Draw label
- _towerRotationMapLabel->drawConditionalDataToScreen(1, false);
+ _towerRotationMapLabel->drawConditionalDataToScreen(rotationLabelVisible ? 1 : 0, false);
// Draw line
- _vm->_gfx->drawLine(center, end, color);
+ _vm->_gfx->drawLine(_towerRotationCenter, end, color);
_vm->_gfx->copyBackBufferToScreen(rect);
}
void Myst::towerRotationMapRotate() {
- const Common::Point center = Common::Point(383, 124);
uint16 angle = towerRotationMapComputeAngle();
- Common::Point end = towerRotationMapComputeCoords(center, angle);
- towerRotationMapDrawLine(center, end);
+ Common::Point end = towerRotationMapComputeCoords(angle);
+ towerRotationMapDrawLine(end, true);
+}
+
+void Myst::towerRotationMapRedraw() {
+ Common::Point end = towerRotationMapComputeCoords(_state.towerRotationAngle);
+ towerRotationMapDrawLine(end, false);
}
void Myst::o_forechamberDoor_init(uint16 var, const ArgumentsArray &args) {
@@ -3559,7 +3718,7 @@ void Myst::greenBook_run() {
VideoEntryPtr book = _vm->playMovie(videoName, kMystStack);
book->moveTo(314, 76);
- if (_globals.ending != 4) {
+ if (_globals.ending != kBooksDestroyed) {
_tempVar = 2;
} else {
book->setBounds(Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h
index 210012616f..ee89af115d 100644
--- a/engines/mohawk/myst_stacks/myst.h
+++ b/engines/mohawk/myst_stacks/myst.h
@@ -37,11 +37,11 @@ namespace MystStacks {
class Myst : public MystScriptParser {
public:
- Myst(MohawkEngine_Myst *vm);
- ~Myst();
+ explicit Myst(MohawkEngine_Myst *vm);
+ ~Myst() override;
- virtual void disablePersistentScripts() override;
- virtual void runPersistentScripts() override;
+ void disablePersistentScripts() override;
+ void runPersistentScripts() override;
protected:
void setupOpcodes();
@@ -49,12 +49,13 @@ protected:
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() override { return 9934; }
+ uint16 getMap() override { return 9934; }
void towerRotationMap_run();
virtual void libraryBookcaseTransform_run();
void generatorControlRoom_run();
void libraryCombinationBook_run();
+ void libraryBook_run();
void clockWheel_run();
void matchBurn_run();
void boilerPressureIncrease_run();
@@ -137,6 +138,8 @@ protected:
DECLARE_OPCODE(o_observatoryYearSliderEndMove);
DECLARE_OPCODE(o_observatoryTimeSliderStartMove);
DECLARE_OPCODE(o_observatoryTimeSliderEndMove);
+ DECLARE_OPCODE(o_libraryBookPageTurnStartLeft);
+ DECLARE_OPCODE(o_libraryBookPageTurnStartRight);
DECLARE_OPCODE(o_libraryCombinationBookStop);
DECLARE_OPCODE(o_cabinMatchLight);
DECLARE_OPCODE(o_courtyardBoxEnter);
@@ -207,6 +210,7 @@ protected:
uint16 _rocketLeverPosition; // 296
VideoEntryPtr _rocketLinkBook; // 268
+ bool _libraryBookPagesTurning;
bool _libraryCombinationBookPagesTurning;
int16 _libraryBookPage; // 86
uint16 _libraryBookNumPages; // 88
@@ -259,6 +263,7 @@ protected:
uint16 _towerRotationSpeed; // 124
bool _towerRotationMapClicked; // 132
bool _towerRotationOverSpot; // 136
+ const Common::Point _towerRotationCenter;
bool _matchBurning;
uint16 _matchGoOutCnt;
@@ -309,6 +314,8 @@ protected:
uint16 rocketSliderGetSound(uint16 pos);
void rocketCheckSolution();
+ void libraryBookPageTurnLeft();
+ void libraryBookPageTurnRight();
void libraryCombinationBookTurnRight();
void libraryCombinationBookTurnLeft();
@@ -326,10 +333,11 @@ protected:
void clockResetGear(uint16 gear);
void towerRotationMapRotate();
+ void towerRotationMapRedraw();
void towerRotationDrawBuildings();
uint16 towerRotationMapComputeAngle();
- Common::Point towerRotationMapComputeCoords(const Common::Point &center, uint16 angle);
- void towerRotationMapDrawLine(const Common::Point &center, const Common::Point &end);
+ Common::Point towerRotationMapComputeCoords(uint16 angle);
+ void towerRotationMapDrawLine(const Common::Point &end, bool rotationLabelVisible);
void boilerFireInit();
void boilerFireUpdate(bool init);
diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp
index bc0dd04360..348a195dea 100644
--- a/engines/mohawk/myst_stacks/preview.cpp
+++ b/engines/mohawk/myst_stacks/preview.cpp
@@ -34,9 +34,18 @@
namespace Mohawk {
namespace MystStacks {
-Preview::Preview(MohawkEngine_Myst *vm) : Myst(vm) {
+Preview::Preview(MohawkEngine_Myst *vm) :
+ Myst(vm) {
setupOpcodes();
_vm->_cursor->hideCursor();
+
+ _libraryState = 0;
+ _library = nullptr;
+
+ _speechRunning = false;
+ _speechStep = 0;
+ _currentCue = 0;
+ _speechNextTime = 0;
}
Preview::~Preview() {
@@ -84,7 +93,7 @@ void Preview::o_stayHere(uint16 var, const ArgumentsArray &args) {
void Preview::o_speechStop(uint16 var, const ArgumentsArray &args) {
_vm->_sound->stopSpeech();
_speechRunning = false;
- _globals.currentAge = 2;
+ _globals.currentAge = kMystLibrary;
}
void Preview::speechUpdateCue() {
@@ -196,7 +205,7 @@ void Preview::speech_run() {
_vm->changeToCard(4329, kTransitionDissolve);
_speechRunning = false;
- _globals.currentAge = 2;
+ _globals.currentAge = kMystLibrary;
_vm->_cursor->showCursor();
break;
diff --git a/engines/mohawk/myst_stacks/preview.h b/engines/mohawk/myst_stacks/preview.h
index 6c0fe83b42..a27fec7cd1 100644
--- a/engines/mohawk/myst_stacks/preview.h
+++ b/engines/mohawk/myst_stacks/preview.h
@@ -39,8 +39,8 @@ namespace MystStacks {
class Preview : public Myst {
public:
- Preview(MohawkEngine_Myst *vm);
- ~Preview();
+ explicit Preview(MohawkEngine_Myst *vm);
+ ~Preview() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp
index 0f1949f128..239030645c 100644
--- a/engines/mohawk/myst_stacks/selenitic.cpp
+++ b/engines/mohawk/myst_stacks/selenitic.cpp
@@ -36,15 +36,48 @@ namespace Mohawk {
namespace MystStacks {
Selenitic::Selenitic(MohawkEngine_Myst *vm) :
- MystScriptParser(vm), _state(vm->_gameState->_selenitic) {
+ MystScriptParser(vm),
+ _state(vm->_gameState->_selenitic) {
setupOpcodes();
+
_mazeRunnerPosition = 288;
_mazeRunnerDirection = 8;
_mazeRunnerDoorOpened = false;
+ _mazeRunnerWindow = nullptr;
+ _mazeRunnerCompass = nullptr;
+ _mazeRunnerLight = nullptr;
+ _mazeRunnerRightButton = nullptr;
+ _mazeRunnerLeftButton = nullptr;
+ _soundReceiverRunning = false;
_soundReceiverDirection = 0;
_soundReceiverStartTime = 0;
_soundReceiverNearBlinkCounter = 0;
+ _soundReceiverSigmaPressed = false;
+
+ for (uint i = 0; i < ARRAYSIZE(_soundReceiverSources); i++) {
+ _soundReceiverSources[i] = nullptr;
+ }
+
+ _soundReceiverCurrentSource = nullptr;
+ _soundReceiverPosition = nullptr;
+ _soundReceiverSpeed = kSoundReceiverSpeedStill;
+ _soundReceiverViewer = nullptr;
+ _soundReceiverRightButton = nullptr;
+ _soundReceiverLeftButton = nullptr;
+ _soundReceiverAngle1 = nullptr;
+ _soundReceiverAngle2 = nullptr;
+ _soundReceiverAngle3 = nullptr;
+ _soundReceiverAngle4 = nullptr;
+ _soundReceiverSigmaButton = nullptr;
+
+ _soundLockSoundId = 0;
+ _soundLockSlider1 = nullptr;
+ _soundLockSlider2 = nullptr;
+ _soundLockSlider3 = nullptr;
+ _soundLockSlider4 = nullptr;
+ _soundLockSlider5 = nullptr;
+ _soundLockButton = nullptr;
}
Selenitic::~Selenitic() {
@@ -157,9 +190,9 @@ uint16 Selenitic::getVar(uint16 var) {
case 33: // Maze runner at entry
return _mazeRunnerPosition != 288;
case 102: // Red page
- return !(_globals.redPagesInBook & 2) && (_globals.heldPage != 8);
+ return !(_globals.redPagesInBook & 2) && (_globals.heldPage != kRedSeleniticPage);
case 103: // Blue page
- return !(_globals.bluePagesInBook & 2) && (_globals.heldPage != 2);
+ return !(_globals.bluePagesInBook & 2) && (_globals.heldPage != kBlueSeleniticPage);
default:
return MystScriptParser::getVar(var);
}
@@ -190,18 +223,18 @@ void Selenitic::toggleVar(uint16 var) {
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 2)) {
- if (_globals.heldPage == 8)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kRedSeleniticPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 8;
+ _globals.heldPage = kRedSeleniticPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 2)) {
- if (_globals.heldPage == 2)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kBlueSeleniticPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 2;
+ _globals.heldPage = kBlueSeleniticPage;
}
break;
default:
@@ -636,7 +669,7 @@ void Selenitic::soundReceiverLeftRight(uint direction) {
_vm->_sound->stopEffect();
_soundReceiverDirection = direction;
- _soundReceiverSpeed = 1;
+ _soundReceiverSpeed = kSoundReceiverSpeedSlow;
_soundReceiverStartTime = _vm->_system->getMillis();
soundReceiverUpdate();
@@ -918,7 +951,7 @@ void Selenitic::soundReceiver_run() {
if (_soundReceiverDirection) {
uint32 currentTime = _vm->_system->getMillis();
- if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) {
+ if (_soundReceiverSpeed == kSoundReceiverSpeedFast && currentTime > _soundReceiverStartTime + 500) {
soundReceiverIncreaseSpeed();
_soundReceiverStartTime = currentTime;
} else if (currentTime > _soundReceiverStartTime + 1000) {
@@ -926,8 +959,9 @@ void Selenitic::soundReceiver_run() {
_soundReceiverStartTime = currentTime;
}
- if (currentTime > _soundReceiverStartTime + 100)
+ if (_soundReceiverSpeed > kSoundReceiverSpeedSlow || currentTime > _soundReceiverStartTime + 100) {
soundReceiverUpdate();
+ }
} else if (!_soundReceiverSigmaPressed) {
soundReceiverUpdateSound();
}
@@ -936,14 +970,20 @@ void Selenitic::soundReceiver_run() {
void Selenitic::soundReceiverIncreaseSpeed() {
switch (_soundReceiverSpeed) {
- case 1:
- _soundReceiverSpeed = 10;
+ case kSoundReceiverSpeedStill:
+ // Should not happen
break;
- case 10:
- _soundReceiverSpeed = 50;
+ case kSoundReceiverSpeedSlow:
+ _soundReceiverSpeed = kSoundReceiverSpeedNormal;
+ break;
+ case kSoundReceiverSpeedNormal:
+ _soundReceiverSpeed = kSoundReceiverSpeedFast;
+ break;
+ case kSoundReceiverSpeedFast:
+ _soundReceiverSpeed = kSoundReceiverSpeedFaster;
break;
- case 50:
- _soundReceiverSpeed = 100;
+ case kSoundReceiverSpeedFaster:
+ // Can't go faster
break;
}
}
@@ -990,7 +1030,7 @@ uint16 Selenitic::soundReceiverCurrentSound(uint16 source, uint16 position) {
if (sourceEnabled) {
if (position == solution) {
soundId = soundIdGood;
- } else if (position > solution && position <= solution + 50) {
+ } else if (position > solution && position < solution + 50) {
_soundReceiverNearBlinkCounter++;
if (_soundReceiverNearBlinkCounter % 2) {
_soundReceiverLeftButton->drawConditionalDataToScreen(2);
@@ -998,7 +1038,7 @@ uint16 Selenitic::soundReceiverCurrentSound(uint16 source, uint16 position) {
_soundReceiverLeftButton->drawConditionalDataToScreen(0);
}
soundId = soundIdNear;
- } else if (position < solution && position >= solution - 50) {
+ } else if (position < solution && position > solution - 50) {
_soundReceiverNearBlinkCounter++;
if (_soundReceiverNearBlinkCounter % 2) {
_soundReceiverRightButton->drawConditionalDataToScreen(2);
@@ -1072,7 +1112,7 @@ void Selenitic::o_soundReceiver_init(uint16 var, const ArgumentsArray &args) {
void Selenitic::o_soundLock_init(uint16 var, const ArgumentsArray &args) {
for (uint i = 0; i < _vm->_resources.size(); i++) {
- if (_vm->_resources[i]->type == kMystAreaSlider) {
+ if (_vm->_resources[i]->hasType(kMystAreaSlider)) {
switch (_vm->_resources[i]->getImageSwitchVar()) {
case 20:
_soundLockSlider1 = _vm->getViewResource<MystAreaSlider>(i);
@@ -1095,7 +1135,7 @@ void Selenitic::o_soundLock_init(uint16 var, const ArgumentsArray &args) {
_soundLockSlider5->setStep(_state.soundLockSliderPositions[4]);
break;
}
- } else if (_vm->_resources[i]->type == kMystAreaImageSwitch && _vm->_resources[i]->getImageSwitchVar() == 28) {
+ } else if (_vm->_resources[i]->hasType(kMystAreaImageSwitch) && _vm->_resources[i]->getImageSwitchVar() == 28) {
_soundLockButton = _vm->getViewResource<MystAreaImageSwitch>(i);
}
}
diff --git a/engines/mohawk/myst_stacks/selenitic.h b/engines/mohawk/myst_stacks/selenitic.h
index 341886d20b..fc20006165 100644
--- a/engines/mohawk/myst_stacks/selenitic.h
+++ b/engines/mohawk/myst_stacks/selenitic.h
@@ -38,8 +38,8 @@ namespace MystStacks {
class Selenitic : public MystScriptParser {
public:
- Selenitic(MohawkEngine_Myst *vm);
- ~Selenitic();
+ explicit Selenitic(MohawkEngine_Myst *vm);
+ ~Selenitic() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
@@ -50,7 +50,7 @@ private:
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() override { return 9930; }
+ uint16 getMap() override { return 9930; }
DECLARE_OPCODE(o_mazeRunnerMove);
DECLARE_OPCODE(o_mazeRunnerSoundRepeat);
@@ -74,6 +74,14 @@ private:
DECLARE_OPCODE(o_mazeRunnerRight_init);
DECLARE_OPCODE(o_mazeRunnerLeft_init);
+ enum SoundReceiverSpeed {
+ kSoundReceiverSpeedStill = 0,
+ kSoundReceiverSpeedSlow = 1,
+ kSoundReceiverSpeedNormal = 5, // The original has this at 10
+ kSoundReceiverSpeedFast = 10, // The original has this at 50 too fast!
+ kSoundReceiverSpeedFaster = 13 // The original has this at 100, way too fast!
+ };
+
void soundReceiver_run();
MystGameState::Selenitic &_state;
@@ -84,7 +92,7 @@ private:
MystAreaImageSwitch *_soundReceiverCurrentSource; // 112
uint16 *_soundReceiverPosition; // 116
uint16 _soundReceiverDirection; // 120
- uint16 _soundReceiverSpeed; // 122
+ SoundReceiverSpeed _soundReceiverSpeed; // 122
uint32 _soundReceiverStartTime; //124
uint _soundReceiverNearBlinkCounter;
MystAreaImageSwitch *_soundReceiverViewer; // 128
diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp
index f8c388d7bc..25d5cf480d 100644
--- a/engines/mohawk/myst_stacks/slides.cpp
+++ b/engines/mohawk/myst_stacks/slides.cpp
@@ -33,9 +33,15 @@
namespace Mohawk {
namespace MystStacks {
-Slides::Slides(MohawkEngine_Myst *vm) : MystScriptParser(vm) {
+Slides::Slides(MohawkEngine_Myst *vm) :
+ MystScriptParser(vm) {
setupOpcodes();
+
_vm->_cursor->hideCursor();
+
+ _cardSwapEnabled = false;
+ _nextCardID = 0;
+ _nextCardTime = 0;
}
Slides::~Slides() {
diff --git a/engines/mohawk/myst_stacks/slides.h b/engines/mohawk/myst_stacks/slides.h
index 63fd9c823e..6970c3b3f0 100644
--- a/engines/mohawk/myst_stacks/slides.h
+++ b/engines/mohawk/myst_stacks/slides.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Slides : public MystScriptParser {
public:
- Slides(MohawkEngine_Myst *vm);
- ~Slides();
+ explicit Slides(MohawkEngine_Myst *vm);
+ ~Slides() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp
index 534efe7197..cd1db68d44 100644
--- a/engines/mohawk/myst_stacks/stoneship.cpp
+++ b/engines/mohawk/myst_stacks/stoneship.cpp
@@ -37,10 +37,14 @@ namespace Mohawk {
namespace MystStacks {
Stoneship::Stoneship(MohawkEngine_Myst *vm) :
- MystScriptParser(vm), _state(vm->_gameState->_stoneship) {
+ MystScriptParser(vm),
+ _state(vm->_gameState->_stoneship) {
setupOpcodes();
_tunnelRunning = false;
+ _tunnelNextTime = 0;
+ _tunnelAlarmSound = 0;
+ _tunnelImagesCount = 0;
_state.lightState = 0;
_state.generatorDepletionTime = 0;
@@ -61,6 +65,31 @@ Stoneship::Stoneship(MohawkEngine_Myst *vm) :
_state.generatorPowerAvailable = 2;
else
_state.generatorPowerAvailable = 0;
+
+ _batteryCharging = false;
+ _batteryDepleting = false;
+ _batteryNextTime = 0;
+ _batteryLastCharge = 0;
+ _batteryGaugeRunning = false;
+ _batteryGauge = nullptr;
+
+ _hologramTurnedOn = 0;
+ _hologramDisplay = nullptr;
+ _hologramSelection = nullptr;
+ _hologramDisplayPos = 0;
+
+ _telescopeRunning = false;
+ _telescopePosition = 0;
+ _telescopePanorama = 0;
+ _telescopeOldMouse = 0;
+ _telescopeLighthouseOff = 0;
+ _telescopeLighthouseOn = 0;
+ _telescopeLighthouseState = false;
+ _telescopeNexTime = 0;
+
+ _cloudOrbMovie = nullptr;
+ _cloudOrbSound = 0;
+ _cloudOrbStopSound = 0;
}
Stoneship::~Stoneship() {
@@ -251,9 +280,9 @@ uint16 Stoneship::getVar(uint16 var) {
return 0; // Closed
}
case 102: // Red page
- return !(_globals.redPagesInBook & 8) && (_globals.heldPage != 10);
+ return !(_globals.redPagesInBook & 8) && (_globals.heldPage != kRedStoneshipPage);
case 103: // Blue page
- return !(_globals.bluePagesInBook & 8) && (_globals.heldPage != 4);
+ return !(_globals.bluePagesInBook & 8) && (_globals.heldPage != kBlueStoneshipPage);
default:
return MystScriptParser::getVar(var);
}
@@ -305,18 +334,18 @@ void Stoneship::toggleVar(uint16 var) {
break;
case 102: // Red page
if (!(_globals.redPagesInBook & 8)) {
- if (_globals.heldPage == 10)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kRedStoneshipPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 10;
+ _globals.heldPage = kRedStoneshipPage;
}
break;
case 103: // Blue page
if (!(_globals.bluePagesInBook & 8)) {
- if (_globals.heldPage == 4)
- _globals.heldPage = 0;
+ if (_globals.heldPage == kBlueStoneshipPage)
+ _globals.heldPage = kNoPage;
else
- _globals.heldPage = 4;
+ _globals.heldPage = kBlueStoneshipPage;
}
break;
default:
@@ -399,7 +428,7 @@ void Stoneship::o_pumpTurnOff(uint16 var, const ArgumentsArray &args) {
for (uint i = 0; i < _vm->_resources.size(); i++) {
MystArea *resource = _vm->_resources[i];
- if (resource->type == kMystAreaImageSwitch && resource->getImageSwitchVar() == buttonVar) {
+ if (resource->hasType(kMystAreaImageSwitch) && resource->getImageSwitchVar() == buttonVar) {
static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true);
break;
}
diff --git a/engines/mohawk/myst_stacks/stoneship.h b/engines/mohawk/myst_stacks/stoneship.h
index dca7ce8fd3..64f58ec427 100644
--- a/engines/mohawk/myst_stacks/stoneship.h
+++ b/engines/mohawk/myst_stacks/stoneship.h
@@ -37,8 +37,8 @@ namespace MystStacks {
class Stoneship : public MystScriptParser {
public:
- Stoneship(MohawkEngine_Myst *vm);
- ~Stoneship();
+ explicit Stoneship(MohawkEngine_Myst *vm);
+ ~Stoneship() override;
void disablePersistentScripts() override;
void runPersistentScripts() override;
@@ -49,7 +49,7 @@ private:
void toggleVar(uint16 var) override;
bool setVarValue(uint16 var, uint16 value) override;
- virtual uint16 getMap() override { return 9933; }
+ uint16 getMap() override { return 9933; }
DECLARE_OPCODE(o_pumpTurnOff);
DECLARE_OPCODE(o_brotherDoorOpen);
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index 213a976413..c65ece55d5 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -41,10 +41,11 @@ MystSaveMetadata::MystSaveMetadata() {
saveHour = 0;
saveMinute = 0;
totalPlayTime = 0;
+ autoSave = false;
}
bool MystSaveMetadata::sync(Common::Serializer &s) {
- static const Common::Serializer::Version kCurrentVersion = 1;
+ static const Common::Serializer::Version kCurrentVersion = 2;
if (!s.syncVersion(kCurrentVersion)) {
return false;
@@ -57,10 +58,13 @@ bool MystSaveMetadata::sync(Common::Serializer &s) {
s.syncAsByte(saveMinute);
s.syncString(saveDescription);
s.syncAsUint32LE(totalPlayTime);
+ s.syncAsByte(autoSave, 2);
return true;
}
+const int MystGameState::kAutoSaveSlot = 0;
+
MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
// Most of the variables are zero at game start.
memset(&_globals, 0, sizeof(_globals));
@@ -78,8 +82,10 @@ MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *sav
// Unknown
_globals.u0 = 2;
// Current Age / Stack - Start in Myst
- _globals.currentAge = 7;
+ _globals.currentAge = kMystStart;
+ _globals.heldPage = kNoPage;
_globals.u1 = 1;
+ _globals.ending = kDniNotVisited;
// Library Bookcase Door - Default to Up
_myst.libraryBookcaseDoor = 1;
@@ -121,13 +127,13 @@ bool MystGameState::load(int slot) {
// Set our default cursor
_vm->_cursor->showCursor();
- if (_globals.heldPage == 0 || _globals.heldPage > 13)
+ if (_globals.heldPage == kNoPage)
_vm->setMainCursor(kDefaultMystCursor);
- else if (_globals.heldPage < 7)
+ else if (_globals.heldPage < kRedLibraryPage) //A blue page is held
_vm->setMainCursor(kBluePageCursor);
- else if (_globals.heldPage < 13)
+ else if (_globals.heldPage < kWhitePage) //A red page is held
_vm->setMainCursor(kRedPageCursor);
- else // if (globals.heldPage == 13)
+ else
_vm->setMainCursor(kWhitePageCursor);
return true;
@@ -178,12 +184,12 @@ void MystGameState::loadMetadata(int slot) {
delete metadataFile;
}
-bool MystGameState::save(int slot, const Common::String &desc) {
+bool MystGameState::save(int slot, const Common::String &desc, bool autoSave) {
if (!saveState(slot)) {
return false;
}
- updateMetadateForSaving(desc);
+ updateMetadateForSaving(desc, autoSave);
return saveMetadata(slot);
}
@@ -214,7 +220,7 @@ Common::String MystGameState::buildMetadataFilename(int slot) {
return Common::String::format("myst-%03d.mym", slot);
}
-void MystGameState::updateMetadateForSaving(const Common::String &desc) {
+void MystGameState::updateMetadateForSaving(const Common::String &desc, bool autoSave) {
// Update save creation info
TimeDate t;
g_system->getTimeAndDate(t);
@@ -225,6 +231,7 @@ void MystGameState::updateMetadateForSaving(const Common::String &desc) {
_metadata.saveMinute = t.tm_min;
_metadata.saveDescription = desc;
_metadata.totalPlayTime = _vm->getTotalPlayTime();
+ _metadata.autoSave = autoSave;
}
bool MystGameState::saveMetadata(int slot) {
@@ -249,12 +256,43 @@ bool MystGameState::saveMetadata(int slot) {
return true;
}
+bool MystGameState::isAutoSaveAllowed() {
+ // Open autosave slot and see if it an autosave
+ // Autosaving will be enabled if it is an autosave or if there is no save in that slot
+
+ Common::String dataFilename = buildSaveFilename(kAutoSaveSlot);
+ Common::ScopedPtr<Common::InSaveFile> dataFile(g_system->getSavefileManager()->openForLoading(dataFilename));
+ if (!dataFile) { // Cannot load non-meta file, enable autosave
+ return true;
+ }
+
+ Common::String metaFilename = buildMetadataFilename(kAutoSaveSlot);
+ Common::ScopedPtr<Common::InSaveFile> metadataFile(g_system->getSavefileManager()->openForLoading(metaFilename));
+ if (!metadataFile) { // Can load non-meta file, but not metafile, could be a save from the original, disable autosave
+ return false;
+ }
+
+ Common::Serializer m(metadataFile.get(), nullptr);
+
+ // Read the metadata file
+ Mohawk::MystSaveMetadata metadata;
+ if (!metadata.sync(m)) { // the save in the autosave slot is corrupted, enable autosave
+ return true;
+ }
+
+ return metadata.autoSave;
+}
+
SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
// Open the metadata file
Common::String filename = buildMetadataFilename(slot);
Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
+
+ SaveStateDescriptor desc;
+ desc.setWriteProtectedFlag(slot == kAutoSaveSlot);
+
if (!metadataFile) {
- return SaveStateDescriptor();
+ return desc;
}
Common::Serializer m(metadataFile, nullptr);
@@ -263,16 +301,23 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
Mohawk::MystSaveMetadata metadata;
if (!metadata.sync(m)) {
delete metadataFile;
- return SaveStateDescriptor();
+ return desc;
}
// Set the save description
- SaveStateDescriptor desc;
desc.setDescription(metadata.saveDescription);
desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
desc.setSaveTime(metadata.saveHour, metadata.saveMinute);
desc.setPlayTime(metadata.totalPlayTime);
- desc.setThumbnail(Graphics::loadThumbnail(*metadataFile));
+ if (metadata.autoSave) // Allow non-saves to be deleted, but not autosaves
+ desc.setDeletableFlag(slot != kAutoSaveSlot);
+
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*metadataFile, thumbnail)) {
+ delete metadataFile;
+ return desc;
+ }
+ desc.setThumbnail(thumbnail);
delete metadataFile;
diff --git a/engines/mohawk/myst_state.h b/engines/mohawk/myst_state.h
index 7d5f3f7102..28bbf60d63 100644
--- a/engines/mohawk/myst_state.h
+++ b/engines/mohawk/myst_state.h
@@ -47,14 +47,61 @@ struct MystSaveMetadata {
uint32 totalPlayTime;
+ bool autoSave;
+
Common::String saveDescription;
MystSaveMetadata();
bool sync(Common::Serializer &s);
};
+// Page being held
+enum HeldPage {
+ kNoPage = 0,
+ kBlueLibraryPage = 1,
+ kBlueSeleniticPage = 2,
+ kBlueMechanicalPage = 3,
+ kBlueStoneshipPage = 4,
+ kBlueChannelwoodPage = 5,
+ kBlueFirePlacePage = 6,
+ kRedLibraryPage = 7,
+ kRedSeleniticPage = 8,
+ kRedMechanicalPage = 9,
+ kRedStoneshipPage = 10,
+ kRedChannelwoodPage = 11,
+ kRedFirePlacePage = 12,
+ kWhitePage = 13
+};
+
+// Age the player is in
+enum ActiveAge {
+ kSelenitic = 0,
+ kStoneship = 1,
+ kMystLibrary = 2,
+ kMechanical = 3,
+ kChannelwood = 4,
+ kIntro = 5,
+ kDni = 6,
+ kMystStart = 7,
+ kCredits = 8,
+ kSirrusEnding = 9,
+ kAchenarEnding = 10
+};
+
+// Various states that Atrus can be in when in Dni
+enum DniEnding {
+ kDniNotVisited = 0, // Player hasn't been to Dni/K'veer yet
+ kAtrusWantsPage = 1, // Player is in Dni with the white page
+ kAtrusLeaves = 2, // Atrus leaves Dni after receiving the white page
+ kForgotPage = 3, // Player has entered Dni without bringing the white page
+ kBooksDestroyed = 4 // Atrus returns to Dni after previously leaving
+ // and destroying the books of his sons
+};
+
class MystGameState {
public:
+ static const int kAutoSaveSlot;
+
MystGameState(MohawkEngine_Myst*, Common::SaveFileManager*);
~MystGameState();
@@ -62,7 +109,8 @@ public:
static Common::String querySaveDescription(int slot);
bool load(int slot);
- bool save(int slot, const Common::String &desc);
+ bool save(int slot, const Common::String &desc, bool autoSave);
+ bool isAutoSaveAllowed();
static void deleteSave(int slot);
void addZipDest(uint16 stack, uint16 view);
@@ -80,14 +128,14 @@ public:
*/
struct Globals {
uint16 u0;
- uint16 currentAge;
- uint16 heldPage;
+ ActiveAge currentAge;
+ HeldPage heldPage;
uint16 u1;
uint16 transitions;
uint16 zipMode;
uint16 redPagesInBook;
uint16 bluePagesInBook;
- uint16 ending;
+ DniEnding ending;
} _globals;
/* 50 Myst Specific Variables :
@@ -297,7 +345,7 @@ private:
bool loadState(int slot);
void loadMetadata(int slot);
bool saveState(int slot);
- void updateMetadateForSaving(const Common::String &desc);
+ void updateMetadateForSaving(const Common::String &desc, bool autoSave);
bool saveMetadata(int slot);
// The values in these regions are lists of VIEW resources
diff --git a/engines/mohawk/resource.cpp b/engines/mohawk/resource.cpp
index b0ae8dd6ea..ea44ca7879 100644
--- a/engines/mohawk/resource.cpp
+++ b/engines/mohawk/resource.cpp
@@ -32,7 +32,7 @@ namespace Mohawk {
// Base Archive code
Archive::Archive() {
- _stream = 0;
+ _stream = nullptr;
}
Archive::~Archive() {
@@ -57,7 +57,7 @@ bool Archive::openFile(const Common::String &fileName) {
void Archive::close() {
_types.clear();
- delete _stream; _stream = 0;
+ delete _stream; _stream = nullptr;
}
bool Archive::hasResource(uint32 tag, uint16 id) const {
diff --git a/engines/mohawk/resource.h b/engines/mohawk/resource.h
index 12c5a139e4..809c55da1d 100644
--- a/engines/mohawk/resource.h
+++ b/engines/mohawk/resource.h
@@ -93,10 +93,6 @@ namespace Mohawk {
#define ID_BMAP MKTAG('B','M','A','P') // Old Mohawk Bitmap
#define ID_BCOD MKTAG('B','C','O','D') // Book Code
-// JamesMath Resource FourCC's
-#define ID_TANM MKTAG('t','A','N','M') // Animation?
-#define ID_TMFO MKTAG('t','M','F','O') // ???
-
// CSTime Resource FourCC's
#define ID_CINF MKTAG('C','I','N','F') // Case Info
#define ID_CONV MKTAG('C','O','N','V') // Conversation
@@ -112,10 +108,6 @@ namespace Mohawk {
#define ID_DATA MKTAG('D','a','t','a') // Game Sound Chunk
#define ID_CUE MKTAG('C','u','e','#') // Game Sound Chunk
-// Mohawk MIDI Tags
-#define ID_MIDI MKTAG('M','I','D','I') // Game Sound (Third Tag), instead of WAVE
-#define ID_PRG MKTAG('P','r','g','#') // MIDI Patch
-
// Common Resource FourCC's
#define ID_TBMP MKTAG('t','B','M','P') // Standard Mohawk Bitmap
#define ID_TWAV MKTAG('t','W','A','V') // Standard Mohawk Sound
@@ -170,25 +162,25 @@ protected:
class MohawkArchive : public Archive {
public:
MohawkArchive() : Archive() {}
- ~MohawkArchive() {}
+ ~MohawkArchive() override {}
- bool openStream(Common::SeekableReadStream *stream);
+ bool openStream(Common::SeekableReadStream *stream) override;
};
class LivingBooksArchive_v1 : public Archive {
public:
LivingBooksArchive_v1() : Archive() {}
- ~LivingBooksArchive_v1() {}
+ ~LivingBooksArchive_v1() override {}
- bool openStream(Common::SeekableReadStream *stream);
+ bool openStream(Common::SeekableReadStream *stream) override;
};
class DOSArchive_v2 : public Archive {
public:
DOSArchive_v2() : Archive() {}
- ~DOSArchive_v2() {}
+ ~DOSArchive_v2() override {}
- bool openStream(Common::SeekableReadStream *stream);
+ bool openStream(Common::SeekableReadStream *stream) override;
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/resource_cache.cpp b/engines/mohawk/resource_cache.cpp
index 0c19934278..ab1758b673 100644
--- a/engines/mohawk/resource_cache.cpp
+++ b/engines/mohawk/resource_cache.cpp
@@ -64,7 +64,7 @@ void ResourceCache::add(uint32 tag, uint16 id, Common::SeekableReadStream *data)
// Returns NULL if not found
Common::SeekableReadStream *ResourceCache::search(uint32 tag, uint16 id) {
if (!enabled)
- return NULL;
+ return nullptr;
debugC(kDebugCache, "Searching for tag 0x%04X id %d", tag, id);
@@ -79,7 +79,7 @@ Common::SeekableReadStream *ResourceCache::search(uint32 tag, uint16 id) {
}
debugC(kDebugCache, "tag 0x%04X id %d not found", tag, id);
- return NULL;
+ return nullptr;
}
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 0bf4024057..8139c1a92f 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -71,6 +71,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
_optionsDialog = nullptr;
_card = nullptr;
_inventory = nullptr;
+ _lastSaveTime = 0;
DebugMan.addDebugChannel(kRivenDebugScript, "Script", "Track Script Execution");
DebugMan.addDebugChannel(kRivenDebugPatches, "Patches", "Track Script Patching");
@@ -240,6 +241,12 @@ void MohawkEngine_Riven::doFrame() {
loadGameStateAndDisplayError(_optionsDialog->getLoadSlot());
if (_optionsDialog->getSaveSlot() >= 0)
saveGameStateAndDisplayError(_optionsDialog->getSaveSlot(), _optionsDialog->getSaveDescription());
+
+ if (hasGameEnded()) {
+ // Attempt to autosave before exiting
+ tryAutoSaving();
+ }
+
_gfx->setTransitionMode((RivenTransitionMode) _vars["transitionmode"]);
_card->initializeZipMode();
break;
@@ -281,6 +288,11 @@ void MohawkEngine_Riven::doFrame() {
break;
}
break;
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ // Attempt to autosave before exiting
+ tryAutoSaving();
+ break;
default:
break;
}
@@ -294,6 +306,10 @@ void MohawkEngine_Riven::doFrame() {
_scriptMan->runQueuedScripts();
}
+ if (shouldPerformAutoSave(_lastSaveTime)) {
+ tryAutoSaving();
+ }
+
_inventory->onFrame();
// Update the screen once per frame
@@ -575,7 +591,7 @@ void MohawkEngine_Riven::loadGameStateAndDisplayError(int slot) {
}
Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) {
- return _saveLoad->saveGame(slot, desc);
+ return _saveLoad->saveGame(slot, desc, false);
}
void MohawkEngine_Riven::saveGameStateAndDisplayError(int slot, const Common::String &desc) {
@@ -589,6 +605,23 @@ void MohawkEngine_Riven::saveGameStateAndDisplayError(int slot, const Common::St
}
}
+void MohawkEngine_Riven::tryAutoSaving() {
+ if (!canSaveGameStateCurrently()) {
+ return; // Can't save right now, try again on the next frame
+ }
+
+ _lastSaveTime = _system->getMillis();
+
+ if (!_saveLoad->isAutoSaveAllowed()) {
+ return; // Can't autosave ever, try again after the next autosave delay
+ }
+
+ Common::Error saveError = _saveLoad->saveGame(RivenSaveLoad::kAutoSaveSlot, "Autosave", true);
+ if (saveError.getCode() != Common::kNoError)
+ warning("Attempt to autosave has failed.");
+}
+
+
void MohawkEngine_Riven::addZipVisitedCard(uint16 cardId, uint16 cardNameId) {
Common::String cardName = getStack()->getName(kCardNames, cardNameId);
if (cardName.empty())
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index 86a431170f..3dc19c7ee4 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -79,11 +79,11 @@ typedef Common::HashMap<Common::String, uint32, Common::IgnoreCase_Hash, Common:
class MohawkEngine_Riven : public MohawkEngine {
protected:
- Common::Error run();
+ Common::Error run() override;
public:
MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc);
- virtual ~MohawkEngine_Riven();
+ ~MohawkEngine_Riven() override;
RivenVideoManager *_video;
RivenSoundManager *_sound;
@@ -95,13 +95,13 @@ public:
// Display debug rectangles around the hotspots
bool _showHotspots;
- GUI::Debugger *getDebugger();
+ GUI::Debugger *getDebugger() override;
- bool canLoadGameStateCurrently();
- bool canSaveGameStateCurrently();
- Common::Error loadGameState(int slot);
- Common::Error saveGameState(int slot, const Common::String &desc);
- bool hasFeature(EngineFeature f) const;
+ bool canLoadGameStateCurrently() override;
+ bool canSaveGameStateCurrently() override;
+ Common::Error loadGameState(int slot) override;
+ Common::Error saveGameState(int slot, const Common::String &desc) override;
+ bool hasFeature(EngineFeature f) const override;
void doFrame();
@@ -121,6 +121,7 @@ private:
RivenStack *_stack;
bool _gameEnded;
+ uint32 _lastSaveTime;
// Variables
void initVars();
@@ -152,6 +153,7 @@ public:
// Save / Load
void runLoadDialog();
void runSaveDialog();
+ void tryAutoSaving();
void loadGameStateAndDisplayError(int slot);
void saveGameStateAndDisplayError(int slot, const Common::String &desc);
diff --git a/engines/mohawk/riven_card.cpp b/engines/mohawk/riven_card.cpp
index 7a5cd617a6..031a88163b 100644
--- a/engines/mohawk/riven_card.cpp
+++ b/engines/mohawk/riven_card.cpp
@@ -72,8 +72,18 @@ void RivenCard::loadCardResource(uint16 id) {
void RivenCard::applyPatches(uint16 id) {
uint32 globalId = _vm->getStack()->getCardGlobalId(id);
- // Apply properties patches
+ applyPropertiesPatch8EB7(globalId);
+ applyPropertiesPatch2E76(globalId);
+ // Apply script patches
+ for (uint i = 0; i < _scripts.size(); i++) {
+ _scripts[i].script->applyCardPatches(_vm, globalId, _scripts[i].type, 0xFFFF);
+ }
+
+ applyPropertiesPatch22118(globalId);
+}
+
+void RivenCard::applyPropertiesPatch8EB7(uint32 globalId) {
// On Jungle Island on the back side of the "beetle" gate, the forward hotspot
// is always enabled, preventing keyboard navigation from automatically opening
// the gate.
@@ -138,7 +148,9 @@ void RivenCard::applyPatches(uint16 id) {
debugC(kRivenDebugPatches, "Applied fix always enabled forward hotspot in card %x", globalId);
}
+}
+void RivenCard::applyPropertiesPatch2E76(uint32 globalId) {
// In Gehn's office, after having encountered him once before and coming back
// with the trap book, the draw update script of card 1 tries to switch to
// card 2 while still loading card 1. Switching cards is not allowed during
@@ -179,7 +191,7 @@ void RivenCard::applyPatches(uint16 id) {
// activatePLST(6);
// break;
// }
- // break;
+ // break;
// case 2:
// activatePLST(5);
// break;
@@ -243,10 +255,138 @@ void RivenCard::applyPatches(uint16 id) {
debugC(kRivenDebugPatches, "Applied invalid card change during screen update (1/2) to card %x", globalId);
// The second part of this patch is in the script patches
}
+}
- // Apply script patches
- for (uint i = 0; i < _scripts.size(); i++) {
- _scripts[i].script->applyCardPatches(_vm, globalId, _scripts[i].type, 0xFFFF);
+void RivenCard::applyPropertiesPatch22118(uint32 globalId) {
+ // On Temple Island, near the steam valve closest to the bridge to Boiler island,
+ // the background sound on the view offering a view to the bridge does
+ // not properly reflect the valve's position.
+ //
+ // The sound is always that of steam going through the pipe when the bridge is
+ // down. When the valve points up, the sound should be that of steam escaping
+ // through the top of the pipe.
+ //
+ // Script before patch:
+ // == Script 0 ==
+ // type: CardLoad
+ // switch (bbigbridge) {
+ // case 0:
+ // switch (tbookvalve) {
+ // case 0:
+ // activatePLST(2);
+ // activateSLST(1);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (bbigbridge) {
+ // case 0:
+ // switch (tbookvalve) {
+ // case 1:
+ // activatePLST(2);
+ // activateSLST(2);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (bbigbridge) {
+ // case 1:
+ // switch (tbookvalve) {
+ // case 0:
+ // activatePLST(1);
+ // activateSLST(2);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (bbigbridge) {
+ // case 1:
+ // switch (tbookvalve) {
+ // case 1:
+ // activatePLST(1);
+ // activateSLST(2);
+ // break;
+ // }
+ // break;
+ // }
+ //
+ //
+ // Script after patch:
+ // == Script 0 ==
+ // type: CardLoad
+ // switch (bbigbridge) {
+ // case 0:
+ // switch (tbookvalve) {
+ // case 0:
+ // activatePLST(2);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (bbigbridge) {
+ // case 0:
+ // switch (tbookvalve) {
+ // case 1:
+ // activatePLST(2);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (bbigbridge) {
+ // case 1:
+ // switch (tbookvalve) {
+ // case 0:
+ // activatePLST(1);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (bbigbridge) {
+ // case 1:
+ // switch (tbookvalve) {
+ // case 1:
+ // activatePLST(1);
+ // break;
+ // }
+ // break;
+ // }
+ // switch (tbookvalve) {
+ // case 0:
+ // activateSLST(1);
+ // break;
+ // case 1:
+ // activateSLST(2);
+ // break;
+ // }
+ if (globalId == 0x22118) {
+ uint16 tBookValveVariable = _vm->getStack()->getIdFromName(kVariableNames, "tbookvalve");
+ uint16 patchData[] = {
+ 1, // Command count in script
+ kRivenCommandSwitch,
+ 2, // Unused
+ tBookValveVariable,
+ 2, // Branches count
+
+ 0, // tbookvalve == 0 branch (steam escaping at the top of the pipe)
+ 1, // Command count in sub-script
+ kRivenCommandActivateSLST,
+ 1, // Argument count
+ 1, // Steam leaking sound id
+
+ 1, // tbookvalve == 1 branch (steam going to the left pipe)
+ 1, // Command count in sub-script
+ kRivenCommandActivateSLST,
+ 1, // Argument count
+ 2, // Steam in pipe sound id
+ };
+
+ RivenScriptPtr patchScript = _vm->_scriptMan->readScriptFromData(patchData, ARRAYSIZE(patchData));
+
+ // Append the patch to the existing script
+ RivenScriptPtr loadScript = getScript(kCardLoadScript);
+ loadScript += patchScript;
+
+ debugC(kRivenDebugPatches, "Applied incorrect steam sounds (2/2) to card %x", globalId);
}
}
diff --git a/engines/mohawk/riven_card.h b/engines/mohawk/riven_card.h
index b11363c916..2b6a8d41bf 100644
--- a/engines/mohawk/riven_card.h
+++ b/engines/mohawk/riven_card.h
@@ -152,6 +152,9 @@ private:
void loadCardHotspotEnableList(uint16 id);
void loadCardWaterEffectList(uint16 id);
void applyPatches(uint16 id);
+ void applyPropertiesPatch8EB7(uint32 globalId);
+ void applyPropertiesPatch2E76(uint32 globalId);
+ void applyPropertiesPatch22118(uint32 globalId);
void setCurrentCardVariable();
RivenScriptPtr getScript(uint16 scriptType) const;
diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp
index d0a5c05636..d4ea8fc703 100644
--- a/engines/mohawk/riven_graphics.cpp
+++ b/engines/mohawk/riven_graphics.cpp
@@ -101,7 +101,7 @@ public:
_lastCopyArea = makeDirectionalInitalArea();
}
- virtual bool drawFrame(uint32 elapsed) override {
+ bool drawFrame(uint32 elapsed) override {
Common::Rect copyArea;
switch (_type) {
case kRivenTransitionWipeLeft:
@@ -162,7 +162,7 @@ public:
complete = false;
}
- virtual bool drawFrame(uint32 elapsed) override {
+ bool drawFrame(uint32 elapsed) override {
Common::Rect newArea;
switch (_type) {
case kRivenTransitionPanLeft:
@@ -264,7 +264,7 @@ public:
_timeBased = false;
}
- virtual bool drawFrame(uint32 elapsed) override {
+ bool drawFrame(uint32 elapsed) override {
assert(_effectScreen->format == _mainScreen->format);
assert(_effectScreen->format == _system->getScreenFormat());
@@ -303,7 +303,22 @@ public:
}
};
-RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) {
+RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) :
+ GraphicsManager(),
+ _vm(vm),
+ _screenUpdateNesting(0),
+ _screenUpdateRunning(false),
+ _enableCardUpdateScript(true),
+ _scheduledTransition(kRivenTransitionNone),
+ _dirtyScreen(false),
+ _creditsImage(302),
+ _creditsPos(0),
+ _transitionMode(kRivenTransitionModeFastest),
+ _transitionOffset(-1),
+ _waterEffect(nullptr),
+ _fliesEffect(nullptr),
+ _transitionFrames(0),
+ _transitionDuration(0) {
_bitmapDecoder = new MohawkBitmap();
// Restrict ourselves to a single pixel format to simplify the effects implementation
@@ -317,20 +332,6 @@ RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm
_effectScreen = new Graphics::Surface();
_effectScreen->create(608, 392, _pixelFormat);
-
- _screenUpdateNesting = 0;
- _screenUpdateRunning = false;
- _enableCardUpdateScript = true;
- _scheduledTransition = kRivenTransitionNone;
- _dirtyScreen = false;
-
- _creditsImage = 302;
- _creditsPos = 0;
-
- _transitionMode = kRivenTransitionModeFastest;
- _transitionOffset = -1;
- _waterEffect = nullptr;
- _fliesEffect = nullptr;
}
RivenGraphics::~RivenGraphics() {
@@ -339,7 +340,8 @@ RivenGraphics::~RivenGraphics() {
_mainScreen->free();
delete _mainScreen;
delete _bitmapDecoder;
- delete _fliesEffect;
+ clearFliesEffect();
+ clearWaterEffect();
}
MohawkSurface *RivenGraphics::decodeImage(uint16 id) {
diff --git a/engines/mohawk/riven_graphics.h b/engines/mohawk/riven_graphics.h
index 31ab84038c..7b831c5609 100644
--- a/engines/mohawk/riven_graphics.h
+++ b/engines/mohawk/riven_graphics.h
@@ -54,8 +54,8 @@ enum RivenTransitionMode {
class RivenGraphics : public GraphicsManager {
public:
- RivenGraphics(MohawkEngine_Riven *vm);
- ~RivenGraphics();
+ explicit RivenGraphics(MohawkEngine_Riven *vm);
+ ~RivenGraphics() override;
// Screen updates
void beginScreenUpdate();
@@ -94,11 +94,11 @@ public:
// Credits
void beginCredits();
void updateCredits();
- uint getCurCreditsImage() { return _creditsImage; }
+ uint getCurCreditsImage() const { return _creditsImage; }
protected:
- MohawkSurface *decodeImage(uint16 id);
- MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
+ MohawkSurface *decodeImage(uint16 id) override;
+ MohawkEngine *getVM() override { return (MohawkEngine *)_vm; }
private:
MohawkEngine_Riven *_vm;
diff --git a/engines/mohawk/riven_inventory.h b/engines/mohawk/riven_inventory.h
index 7c75b48374..8ce5f7ebd2 100644
--- a/engines/mohawk/riven_inventory.h
+++ b/engines/mohawk/riven_inventory.h
@@ -36,7 +36,7 @@ class MohawkEngine_Riven;
*/
class RivenInventory {
public:
- RivenInventory(MohawkEngine_Riven *vm);
+ explicit RivenInventory(MohawkEngine_Riven *vm);
virtual ~RivenInventory();
/** Handle a click event in the inventory area */
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 7165166d8f..e8d29a0c24 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -38,10 +38,11 @@ RivenSaveMetadata::RivenSaveMetadata() {
saveHour = 0;
saveMinute = 0;
totalPlayTime = 0;
+ autoSave = false;
}
bool RivenSaveMetadata::sync(Common::Serializer &s) {
- static const Common::Serializer::Version kCurrentVersion = 1;
+ static const Common::Serializer::Version kCurrentVersion = 2;
if (!s.syncVersion(kCurrentVersion)) {
return false;
@@ -54,10 +55,13 @@ bool RivenSaveMetadata::sync(Common::Serializer &s) {
s.syncAsByte(saveMinute);
s.syncString(saveDescription);
s.syncAsUint32BE(totalPlayTime);
+ s.syncAsByte(autoSave, 2);
return true;
}
+const int RivenSaveLoad::kAutoSaveSlot = 0;
+
RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
}
@@ -105,22 +109,25 @@ Common::String RivenSaveLoad::querySaveDescription(const int slot) {
SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ SaveStateDescriptor descriptor;
+ descriptor.setWriteProtectedFlag(slot == kAutoSaveSlot);
+
if (!loadFile) {
- return SaveStateDescriptor();
+ return descriptor;
}
MohawkArchive mhk;
if (!mhk.openStream(loadFile)) {
- return SaveStateDescriptor();
+ return descriptor;
}
if (!mhk.hasResource(ID_META, 1)) {
- return SaveStateDescriptor();
+ return descriptor;
}
Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
if (!metaStream) {
- return SaveStateDescriptor();
+ return descriptor;
}
Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
@@ -128,14 +135,15 @@ SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
RivenSaveMetadata metadata;
if (!metadata.sync(serializer)) {
delete metaStream;
- return SaveStateDescriptor();
+ return descriptor;
}
- SaveStateDescriptor descriptor;
descriptor.setDescription(metadata.saveDescription);
descriptor.setPlayTime(metadata.totalPlayTime);
descriptor.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
descriptor.setSaveTime(metadata.saveHour, metadata.saveMinute);
+ if (metadata.autoSave) // Allow non-saves to be deleted, but not autosaves
+ descriptor.setDeletableFlag(slot != kAutoSaveSlot);
delete metaStream;
@@ -148,13 +156,51 @@ SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
return descriptor;
}
- descriptor.setThumbnail(Graphics::loadThumbnail(*thmbStream));
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*thmbStream, thumbnail)) {
+ return descriptor;
+ }
+ descriptor.setThumbnail(thumbnail);
delete thmbStream;
return descriptor;
}
+bool RivenSaveLoad::isAutoSaveAllowed() {
+ // Open autosave slot and see if it an autosave
+ // Autosaving will be enabled if it is an autosave or if there is no save in that slot
+
+ Common::String filename = buildSaveFilename(kAutoSaveSlot);
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return true; // There is no save in the autosave slot, enable autosave
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return true; // Corrupt save, enable autosave
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return false; // don't autosave over saves that don't have a meta section (like saves from the original)
+ }
+
+ Common::ScopedPtr<Common::SeekableReadStream> metaStream(mhk.getResource(ID_META, 1));
+ if (!metaStream) {
+ return true; // corrupt save, enable autosave
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream.get(), nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ return true; // corrupt save, enable autosave
+ }
+
+ return metadata.autoSave;
+}
+
Common::Error RivenSaveLoad::loadGame(const int slot) {
if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo
return Common::kNoError;
@@ -375,7 +421,7 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genTHMBSection() const {
return stream;
}
-Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc) const {
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc, bool autoSave) const {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
Common::Serializer serializer = Common::Serializer(nullptr, stream);
@@ -390,12 +436,13 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::St
metadata.saveMinute = t.tm_min;
metadata.saveDescription = desc;
metadata.totalPlayTime = _vm->getTotalPlayTime();
+ metadata.autoSave = autoSave;
metadata.sync(serializer);
return stream;
}
-Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description) {
+Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description, bool autoSave) {
// NOTE: This code is designed to only output a Mohawk archive
// for a Riven saved game. It's hardcoded to do this because
// (as of right now) this is the only place in the engine
@@ -411,7 +458,7 @@ Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &desc
debug (0, "Saving game to \'%s\'", filename.c_str());
- Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description);
+ Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description, autoSave);
Common::MemoryWriteStreamDynamic *nameSection = genNAMESection();
Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection();
Common::MemoryWriteStreamDynamic *varsSection = genVARSSection();
diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h
index 34bfbdc434..1432505b02 100644
--- a/engines/mohawk/riven_saveload.h
+++ b/engines/mohawk/riven_saveload.h
@@ -49,6 +49,8 @@ struct RivenSaveMetadata {
uint32 totalPlayTime;
+ bool autoSave;
+
Common::String saveDescription;
RivenSaveMetadata();
@@ -57,11 +59,14 @@ struct RivenSaveMetadata {
class RivenSaveLoad {
public:
+ static const int kAutoSaveSlot;
+
RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*);
~RivenSaveLoad();
Common::Error loadGame(const int slot);
- Common::Error saveGame(const int slot, const Common::String &description);
+ Common::Error saveGame(const int slot, const Common::String &description, bool autoSave);
+ bool isAutoSaveAllowed();
static void deleteSave(const int slot);
static SaveStateDescriptor querySaveMetaInfos(const int slot);
@@ -74,7 +79,7 @@ private:
static Common::String buildSaveFilename(const int slot);
Common::MemoryWriteStreamDynamic *genNAMESection();
- Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const;
+ Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc, bool autoSave) const;
Common::MemoryWriteStreamDynamic *genTHMBSection() const;
Common::MemoryWriteStreamDynamic *genVARSSection();
Common::MemoryWriteStreamDynamic *genVERSSection();
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index 18a3597086..c12989bca6 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -345,6 +345,24 @@ void RivenScript::applyCardPatches(MohawkEngine_Riven *vm, uint32 cardGlobalId,
debugC(kRivenDebugPatches, "Applied invalid card change during screen update (2/2) to card %x", cardGlobalId);
}
+ // First part of the patch to fix the invalid steam sounds
+ // when looking at the Boiler island bridge from Temple island.
+ // The second part is in the card patches.
+ if (cardGlobalId == 0x22118 && scriptType == kCardLoadScript) {
+ shouldApplyPatches = true;
+
+ // Remove all the activateSLST calls.
+ // Fixed calls will be added back in the second part of the patch.
+ for (uint i = 0; i < _commands.size(); i++) {
+ if (_commands[i]->getType() == kRivenCommandActivateSLST) {
+ _commands.remove_at(i);
+ break;
+ }
+ }
+
+ debugC(kRivenDebugPatches, "Applied incorrect steam sounds (1/2) to card %x", cardGlobalId);
+ }
+
if (shouldApplyPatches) {
for (uint i = 0; i < _commands.size(); i++) {
_commands[i]->applyCardPatches(cardGlobalId, scriptType, hotspotId);
diff --git a/engines/mohawk/riven_sound.h b/engines/mohawk/riven_sound.h
index ce2ddbcbe8..fd14dee151 100644
--- a/engines/mohawk/riven_sound.h
+++ b/engines/mohawk/riven_sound.h
@@ -65,7 +65,7 @@ struct SLSTRecord {
*/
class RivenSoundManager {
public:
- RivenSoundManager(MohawkEngine_Riven *vm);
+ explicit RivenSoundManager(MohawkEngine_Riven *vm);
~RivenSoundManager();
/**
diff --git a/engines/mohawk/riven_stacks/jspit.cpp b/engines/mohawk/riven_stacks/jspit.cpp
index eeff81005b..b1f15a10c0 100644
--- a/engines/mohawk/riven_stacks/jspit.cpp
+++ b/engines/mohawk/riven_stacks/jspit.cpp
@@ -369,7 +369,7 @@ int JSpit::jspitElevatorLoop() {
return 1;
}
}
-
+
return 0;
}
diff --git a/engines/mohawk/riven_stacks/pspit.cpp b/engines/mohawk/riven_stacks/pspit.cpp
index a3134754b4..3c8b4306e4 100644
--- a/engines/mohawk/riven_stacks/pspit.cpp
+++ b/engines/mohawk/riven_stacks/pspit.cpp
@@ -83,7 +83,22 @@ void PSpit::catherineIdleTimer() {
void PSpit::xpisland990_elevcombo(const ArgumentArray &args) {
// Play button sound based on args[0]
_vm->_sound->playSound(args[0] + 5);
+ _vm->_cursor->hideCursor();
_vm->delay(500);
+ _vm->_cursor->showCursor();
+
+ // If the user released the mouse button during the wait time, the mouse up event
+ // is not forwarded to the game script handler. The button appears to be down
+ // until the user moves the mouse outside of the button hotspot.
+ // This happens with the original engine as well.
+ // To work around this issue we run the mouse up script if the mouse is not
+ // pressed anymore at this point.
+ if (!mouseIsDown()) {
+ Common::String buttonName = Common::String::format("combo%d", args[0]);
+ RivenHotspot *button = _vm->getCard()->getHotspotByName(buttonName);
+ RivenScriptPtr mouseUpScript = button->getScript(kMouseUpScript);
+ _vm->_scriptMan->runScript(mouseUpScript, false);
+ }
// It is impossible to get here if Gehn is not trapped. However,
// the original also disallows brute forcing the ending if you have
diff --git a/engines/mohawk/riven_video.h b/engines/mohawk/riven_video.h
index 5b5bf30fd2..ae5a266e04 100644
--- a/engines/mohawk/riven_video.h
+++ b/engines/mohawk/riven_video.h
@@ -130,7 +130,7 @@ private:
class RivenVideoManager {
public:
- RivenVideoManager(MohawkEngine_Riven *vm);
+ explicit RivenVideoManager(MohawkEngine_Riven *vm);
~RivenVideoManager();
void updateMovies();
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 81d83fc7b9..7bd6c63539 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -158,11 +158,16 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
// The sound in the CD version of Riven is encoded in Intel DVI ADPCM
// The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM
if (dataChunk.encoding == kCodecRaw) {
- byte flags = Audio::FLAG_UNSIGNED;
+ byte flags = 0;
if (dataChunk.channels == 2)
flags |= Audio::FLAG_STEREO;
+ if (dataChunk.bitsPerSample == 16)
+ flags |= Audio::FLAG_16BITS;
+ else
+ flags |= Audio::FLAG_UNSIGNED;
+
return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags);
} else if (dataChunk.encoding == kCodecADPCM) {
uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8;
@@ -180,51 +185,18 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
return nullptr;
}
-Sound::Sound(MohawkEngine* vm) : _vm(vm) {
- _midiDriver = NULL;
- _midiParser = NULL;
- _midiData = NULL;
- initMidi();
+Sound::Sound(MohawkEngine* vm) :
+ _vm(vm) {
}
Sound::~Sound() {
stopSound();
-
- if (_midiParser) {
- _midiParser->unloadMusic();
- delete _midiParser;
- }
-
- if (_midiDriver) {
- _midiDriver->close();
- delete _midiDriver;
- }
-
- if (_midiData)
- delete[] _midiData;
-}
-
-void Sound::initMidi() {
- if (!(_vm->getFeatures() & GF_HASMIDI))
- return;
-
- // Let's get our MIDI parser/driver
- _midiParser = MidiParser::createParser_SMF();
- _midiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB|MDT_MIDI));
-
- // Set up everything!
- _midiDriver->open();
- _midiParser->setMidiDriver(_midiDriver);
- _midiParser->setTimerRate(_midiDriver->getBaseTempo());
}
Audio::RewindableAudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) {
- Audio::RewindableAudioStream *audStream = NULL;
+ Audio::RewindableAudioStream *audStream = nullptr;
switch (_vm->getGameType()) {
- case GType_ZOOMBINI:
- audStream = makeMohawkWaveStream(_vm->getResource(ID_SND, id));
- break;
case GType_LIVINGBOOKSV1:
audStream = makeLivingBooksWaveStream_v1(_vm->getResource(ID_WAV, id));
break;
@@ -261,55 +233,7 @@ Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop, CueList
return &handle->handle;
}
- return NULL;
-}
-
-void Sound::playMidi(uint16 id) {
- uint32 idTag;
- if (!(_vm->getFeatures() & GF_HASMIDI)) {
- warning ("Attempting to play MIDI in a game without MIDI");
- return;
- }
-
- assert(_midiDriver && _midiParser);
-
- _midiParser->unloadMusic();
- if (_midiData)
- delete[] _midiData;
-
- Common::SeekableReadStream *midi = _vm->getResource(ID_TMID, id);
-
- idTag = midi->readUint32BE();
- assert(idTag == ID_MHWK);
- midi->readUint32BE(); // Skip size
- idTag = midi->readUint32BE();
- assert(idTag == ID_MIDI);
-
- _midiData = new byte[midi->size() - 12]; // Enough to cover MThd/Prg#/MTrk
-
- // Read the MThd Data
- midi->read(_midiData, 14);
-
- // TODO: Load patches from the Prg# section... skip it for now.
- idTag = midi->readUint32BE();
- assert(idTag == ID_PRG);
- midi->skip(midi->readUint32BE());
-
- // Read the MTrk Data
- uint32 mtrkSize = midi->size() - midi->pos();
- midi->read(_midiData + 14, mtrkSize);
-
- delete midi;
-
- // Now, play it :)
- if (!_midiParser->loadMusic(_midiData, 14 + mtrkSize))
- error ("Could not play MIDI music from tMID %04x\n", id);
-
- _midiDriver->setTimerCallback(_midiParser, MidiParser::timerCallback);
-}
-
-void Sound::stopMidi() {
- _midiParser->unloadMusic();
+ return nullptr;
}
Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index 11fd004513..15ee249177 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -102,13 +102,11 @@ class MohawkEngine;
class Sound {
public:
- Sound(MohawkEngine *vm);
+ explicit Sound(MohawkEngine *vm);
~Sound();
// Generic sound functions
Audio::SoundHandle *playSound(uint16 id, byte volume = Audio::Mixer::kMaxChannelVolume, bool loop = false, CueList *cueList = NULL);
- void playMidi(uint16 id);
- void stopMidi();
void stopSound();
void stopSound(uint16 id);
bool isPlaying(uint16 id);
@@ -117,17 +115,12 @@ public:
private:
MohawkEngine *_vm;
- MidiDriver *_midiDriver;
- MidiParser *_midiParser;
- byte *_midiData;
static Audio::RewindableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
- void initMidi();
Common::Array<SndHandle> _handles;
SndHandle *getHandle();
- Audio::RewindableAudioStream *makeAudioStream(uint16 id, CueList *cueList = NULL);
- uint16 convertMystID(uint16 id);
+ Audio::RewindableAudioStream *makeAudioStream(uint16 id, CueList *cueList = nullptr);
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 994e219b03..ae20a59370 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -38,7 +38,7 @@
namespace Mohawk {
-VideoEntry::VideoEntry() : _video(0), _id(-1), _x(0), _y(0), _loop(false), _enabled(true) {
+VideoEntry::VideoEntry() : _video(nullptr), _id(-1), _x(0), _y(0), _loop(false), _enabled(true) {
}
VideoEntry::VideoEntry(Video::VideoDecoder *video, const Common::String &fileName) : _video(video), _fileName(fileName), _id(-1), _x(0), _y(0), _loop(false), _enabled(true) {
@@ -53,7 +53,7 @@ VideoEntry::~VideoEntry() {
void VideoEntry::close() {
delete _video;
- _video = 0;
+ _video = nullptr;
}
bool VideoEntry::endOfVideo() const {
@@ -230,7 +230,7 @@ bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) {
return false;
}
- Graphics::Surface *convertedFrame = 0;
+ Graphics::Surface *convertedFrame = nullptr;
Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
if (frame->format != pixelFormat) {
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index 1f8b93d467..fdc55a51ab 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -237,7 +237,7 @@ typedef Common::SharedPtr<VideoEntry> VideoEntryPtr;
class VideoManager {
public:
- VideoManager(MohawkEngine *vm);
+ explicit VideoManager(MohawkEngine *vm);
virtual ~VideoManager();
// Generic movie functions
diff --git a/engines/mohawk/view.cpp b/engines/mohawk/view.cpp
index 70d20270a5..ec73723971 100644
--- a/engines/mohawk/view.cpp
+++ b/engines/mohawk/view.cpp
@@ -63,10 +63,10 @@ void Feature::setNodeDefaults(Feature *prev, Feature *next) {
_prev = prev;
_next = next;
- _moveProc = NULL;
- _drawProc = NULL;
- _doneProc = NULL;
- _frameProc = NULL;
+ _moveProc = nullptr;
+ _drawProc = nullptr;
+ _doneProc = nullptr;
+ _frameProc = nullptr;
_data.bounds = Common::Rect();
_data.clipRect = Common::Rect();
@@ -333,7 +333,7 @@ void NewFeature::finishResetFeatureScript() {
}
View::View(MohawkEngine *vm) : _vm(vm) {
- _currentModule = NULL;
+ _currentModule = nullptr;
_backgroundId = 0xffff;
@@ -393,7 +393,7 @@ void View::setModule(Module *module) {
delete _currentModule;
}
- _currentModule = NULL;
+ _currentModule = nullptr;
if (module) {
_currentModule = module;
@@ -572,7 +572,7 @@ Feature *View::getFeaturePtr(uint16 id) {
return node;
}
- return NULL;
+ return nullptr;
}
uint16 View::getNewFeatureId() {
@@ -591,8 +591,8 @@ void View::removeFeature(Feature *feature, bool free) {
feature->_prev->_next = feature->_next;
feature->_next->_prev = feature->_prev;
- feature->_next = NULL;
- feature->_prev = NULL;
+ feature->_next = nullptr;
+ feature->_prev = nullptr;
if (free)
delete feature;
@@ -619,21 +619,21 @@ Feature *View::pointOnFeature(bool topdown, uint32 flags, Common::Point pos) {
else
curr = curr->_next;
}
- return NULL;
+ return nullptr;
}
void View::sortView() {
Feature *base = _rootNode;
Feature *next = base->_next;
- Feature *otherRoot = NULL;
- Feature *otherBase = NULL;
- Feature *objectRoot = NULL;
- Feature *objectBase = NULL;
- Feature *staticRoot = NULL;
- Feature *staticBase = NULL;
+ Feature *otherRoot = nullptr;
+ Feature *otherBase = nullptr;
+ Feature *objectRoot = nullptr;
+ Feature *objectBase = nullptr;
+ Feature *staticRoot = nullptr;
+ Feature *staticBase = nullptr;
// Remove all features.
- base->_next = NULL;
+ base->_next = nullptr;
// Iterate through all the previous features, placing them in the appropriate list.
while (next) {
@@ -645,33 +645,33 @@ void View::sortView() {
// so we insert this node directly after the current base.
base->_next = curr;
curr->_prev = base;
- curr->_next = NULL;
+ curr->_next = nullptr;
base = base->_next;
} else if (curr->_flags & kFeatureSortStatic) {
// Insert this node into the list of static objects.
if (staticBase) {
staticBase->_next = curr;
curr->_prev = staticBase;
- curr->_next = NULL;
+ curr->_next = nullptr;
staticBase = curr;
} else {
staticBase = curr;
staticRoot = curr;
- curr->_prev = NULL;
- curr->_next = NULL;
+ curr->_prev = nullptr;
+ curr->_next = nullptr;
}
} else if (curr->_flags & kFeatureObjectMask) { // This is == 1 or == 2 in old code.
// Insert this node into the list of objects.
if (objectRoot) {
objectBase->_next = curr;
curr->_prev = objectBase;
- curr->_next = NULL;
+ curr->_next = nullptr;
objectBase = curr;
} else {
objectBase = curr;
objectRoot = curr;
- curr->_prev = NULL;
- curr->_next = NULL;
+ curr->_prev = nullptr;
+ curr->_next = nullptr;
}
} else {
if (!(curr->_flags & kFeatureOldSortForeground))
@@ -681,13 +681,13 @@ void View::sortView() {
if (otherRoot) {
otherBase->_next = curr;
curr->_prev = otherBase;
- curr->_next = NULL;
+ curr->_next = nullptr;
otherBase = curr;
} else {
otherBase = curr;
otherRoot = curr;
- curr->_prev = NULL;
- curr->_next = NULL;
+ curr->_prev = nullptr;
+ curr->_next = nullptr;
}
}
}
@@ -700,7 +700,7 @@ void View::sortView() {
base->_next = prev;
prev->_prev = base;
base = base->_next;
- base->_next = NULL;
+ base->_next = nullptr;
}
// Add the other features on top..
@@ -711,12 +711,12 @@ void View::sortView() {
Feature *View::sortOneList(Feature *root) {
if (!root)
- return NULL;
+ return nullptr;
// Save the next feature and then clear the list.
Feature *curr = root->_next;
- root->_next = NULL;
- root->_prev = NULL;
+ root->_next = nullptr;
+ root->_prev = nullptr;
// Iterate over all the features.
while (curr) {
@@ -735,7 +735,7 @@ Feature *View::sortOneList(Feature *root) {
// This is the end of the list: add ourselves there.
check->_next = prev;
prev->_prev = check;
- prev->_next = NULL;
+ prev->_next = nullptr;
break;
}
} else {
@@ -779,7 +779,7 @@ Feature *View::mergeLists(Feature *root, Feature *mergeRoot) {
check = check->_next;
check->_next = prev;
prev->_prev = check;
- prev->_next = NULL;
+ prev->_next = nullptr;
continue;
}
@@ -802,7 +802,7 @@ Feature *View::mergeLists(Feature *root, Feature *mergeRoot) {
// We're at the end of the list, so we have to go here.
check->_next = prev;
prev->_prev = check;
- prev->_next = NULL;
+ prev->_next = nullptr;
base = prev;
break;
}
diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h
index 42d70fcb37..5d00547f4e 100644
--- a/engines/mortevielle/mortevielle.h
+++ b/engines/mortevielle/mortevielle.h
@@ -33,7 +33,6 @@
#include "common/random.h"
#include "common/rect.h"
#include "common/stack.h"
-#include "engines/advancedDetector.h"
#include "engines/engine.h"
#include "common/error.h"
#include "graphics/surface.h"
diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp
index 3065d6c551..078338a0b5 100644
--- a/engines/mortevielle/saveload.cpp
+++ b/engines/mortevielle/saveload.cpp
@@ -92,8 +92,10 @@ bool SavegameManager::loadSavegame(const Common::String &filename) {
if (!strncmp(&buffer[0], &SAVEGAME_ID[0], 4)) {
// Yes, it is, so skip over the savegame header
SavegameHeader header;
- readSavegameHeader(stream, header);
- delete header.thumbnail;
+ if (!readSavegameHeader(stream, header)) {
+ delete stream;
+ return false;
+ }
} else {
stream->seek(0);
}
@@ -208,9 +210,7 @@ void SavegameManager::writeSavegameHeader(Common::OutSaveFile *out, const Common
out->writeSint16LE(td.tm_min);
}
-bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
- header.thumbnail = NULL;
-
+WARN_UNUSED_RESULT bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) {
// Get the savegame version
header.version = in->readByte();
@@ -221,9 +221,9 @@ bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader
header.saveName += ch;
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header.saveYear = in->readSint16LE();
@@ -240,7 +240,6 @@ SaveStateList SavegameManager::listSaves(const Common::String &target) {
pattern += ".###";
Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern);
- sort(files.begin(), files.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = files.begin(); file != files.end(); ++file) {
@@ -264,7 +263,6 @@ SaveStateList SavegameManager::listSaves(const Common::String &target) {
validFlag = readSavegameHeader(in, header);
if (validFlag) {
- delete header.thumbnail;
saveDescription = header.saveName;
}
} else if (file->size() == 497) {
@@ -282,6 +280,7 @@ SaveStateList SavegameManager::listSaves(const Common::String &target) {
}
}
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -311,7 +310,10 @@ SaveStateDescriptor SavegameManager::querySaveMetaInfos(const Common::String &fi
} else {
// Get the savegame header information
SavegameHeader header;
- readSavegameHeader(f, header);
+ if (!readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
delete f;
// Create the return descriptor
diff --git a/engines/mortevielle/saveload.h b/engines/mortevielle/saveload.h
index a0de05b920..18042d9fb4 100644
--- a/engines/mortevielle/saveload.h
+++ b/engines/mortevielle/saveload.h
@@ -33,6 +33,7 @@
#include "graphics/palette.h"
#include "graphics/scaler.h"
#include "graphics/thumbnail.h"
+#include "engines/savestate.h"
#define SAVEGAME_VERSION 1
@@ -65,7 +66,7 @@ public:
Common::Error saveGame(int slot);
void writeSavegameHeader(Common::OutSaveFile *out, const Common::String &saveName);
- static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
static SaveStateList listSaves(const Common::String &target);
static SaveStateDescriptor querySaveMetaInfos(const Common::String &fileName);
};
diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp
index 46605bb2f7..920d149659 100644
--- a/engines/neverhood/detection.cpp
+++ b/engines/neverhood/detection.cpp
@@ -271,7 +271,7 @@ SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const {
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
if (in) {
- if (Neverhood::NeverhoodEngine::readSaveHeader(in, false, header) == Neverhood::NeverhoodEngine::kRSHENoError) {
+ if (Neverhood::NeverhoodEngine::readSaveHeader(in, header) == Neverhood::NeverhoodEngine::kRSHENoError) {
saveList.push_back(SaveStateDescriptor(slotNum, header.description));
}
delete in;
@@ -302,7 +302,7 @@ SaveStateDescriptor NeverhoodMetaEngine::querySaveMetaInfos(const char *target,
Neverhood::NeverhoodEngine::SaveHeader header;
Neverhood::NeverhoodEngine::kReadSaveHeaderError error;
- error = Neverhood::NeverhoodEngine::readSaveHeader(in, true, header);
+ error = Neverhood::NeverhoodEngine::readSaveHeader(in, header, false);
delete in;
if (error == Neverhood::NeverhoodEngine::kRSHENoError) {
diff --git a/engines/neverhood/menumodule.cpp b/engines/neverhood/menumodule.cpp
index e3996a2507..b64f4dcdd2 100644
--- a/engines/neverhood/menumodule.cpp
+++ b/engines/neverhood/menumodule.cpp
@@ -291,7 +291,7 @@ void MenuModule::loadSavegameList() {
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
if (in) {
- if (Neverhood::NeverhoodEngine::readSaveHeader(in, false, header) == Neverhood::NeverhoodEngine::kRSHENoError) {
+ if (Neverhood::NeverhoodEngine::readSaveHeader(in, header) == Neverhood::NeverhoodEngine::kRSHENoError) {
SavegameItem savegameItem;
savegameItem.slotNum = slotNum;
savegameItem.description = header.description;
diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h
index 4c5f9c3303..90055eeb9d 100644
--- a/engines/neverhood/neverhood.h
+++ b/engines/neverhood/neverhood.h
@@ -129,7 +129,7 @@ public:
bool loadgame(const char *filename);
const char *getSavegameFilename(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
- static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
+ WARN_UNUSED_RESULT static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true);
GameState& gameState() { return _gameState; }
GameModule *gameModule() { return _gameModule; }
diff --git a/engines/neverhood/saveload.cpp b/engines/neverhood/saveload.cpp
index 8fe6c9a155..d7e6f1ebfe 100644
--- a/engines/neverhood/saveload.cpp
+++ b/engines/neverhood/saveload.cpp
@@ -32,7 +32,7 @@ namespace Neverhood {
#define NEVERHOOD_SAVEGAME_VERSION 0
-NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
+WARN_UNUSED_RESULT NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) {
header.version = in->readUint32LE();
if (header.version > NEVERHOOD_SAVEGAME_VERSION)
@@ -43,10 +43,8 @@ NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::Se
while (descriptionLen--)
header.description += (char)in->readByte();
- if (loadThumbnail) {
- header.thumbnail = Graphics::loadThumbnail(*in);
- } else {
- Graphics::skipThumbnail(*in);
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
+ return kRSHEIoError;
}
// Not used yet, reserved for future usage
@@ -110,7 +108,7 @@ bool NeverhoodEngine::loadgame(const char *filename) {
SaveHeader header;
- kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
+ kReadSaveHeaderError errorCode = readSaveHeader(in, header);
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
diff --git a/engines/obsolete.cpp b/engines/obsolete.cpp
index d65fb13ec1..ea96cff42e 100644
--- a/engines/obsolete.cpp
+++ b/engines/obsolete.cpp
@@ -55,7 +55,7 @@ void upgradeTargetIfNecessary(const ObsoleteGameID *obsoleteList) {
}
}
-GameDescriptor findGameID(
+PlainGameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *gameids,
const ObsoleteGameID *obsoleteList
@@ -63,7 +63,7 @@ GameDescriptor findGameID(
// First search the list of supported gameids for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, gameids);
if (g)
- return GameDescriptor(*g);
+ return *g;
// If we didn't find the gameid in the main list, check if it
// is an obsolete game id.
@@ -73,16 +73,16 @@ GameDescriptor findGameID(
if (0 == scumm_stricmp(gameid, o->from)) {
g = findPlainGameDescriptor(o->to, gameids);
if (g && g->description)
- return GameDescriptor(gameid, "Obsolete game ID (" + Common::String(g->description) + ")");
+ return PlainGameDescriptor::of(gameid, g->description);
else
- return GameDescriptor(gameid, "Obsolete game ID");
+ return PlainGameDescriptor::of(gameid, "Obsolete game ID");
}
o++;
}
}
// No match found
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
} // End of namespace Engines
diff --git a/engines/obsolete.h b/engines/obsolete.h
index be0963a7dc..7c7249e52b 100644
--- a/engines/obsolete.h
+++ b/engines/obsolete.h
@@ -66,7 +66,7 @@ void upgradeTargetIfNecessary(const ObsoleteGameID *obsoleteList);
* Optionally can take a list of obsolete game ids into account in order
* to support obsolete gameids.
*/
-GameDescriptor findGameID(
+PlainGameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *gameids,
const ObsoleteGameID *obsoleteList = 0
diff --git a/engines/pegasus/items/biochips/pegasuschip.h b/engines/pegasus/items/biochips/pegasuschip.h
index b81df94b39..31cd778d98 100644
--- a/engines/pegasus/items/biochips/pegasuschip.h
+++ b/engines/pegasus/items/biochips/pegasuschip.h
@@ -36,7 +36,7 @@ public:
PegasusChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
virtual ~PegasusChip();
- void select();
+ void select() override;
void takeSharedArea() override;
diff --git a/engines/plumbers/console.cpp b/engines/plumbers/console.cpp
index f005b60769..730a74e2e7 100644
--- a/engines/plumbers/console.cpp
+++ b/engines/plumbers/console.cpp
@@ -27,7 +27,7 @@
namespace Plumbers {
-Console::Console(Plumbers::PlumbersGame *vm) : _vm(vm) {
+Console::Console() {
_allowSkip = false;
registerCmd("allowSkip", WRAP_METHOD(Console, Cmd_allowSkip));
}
diff --git a/engines/plumbers/console.h b/engines/plumbers/console.h
index c849678419..cb50834f36 100644
--- a/engines/plumbers/console.h
+++ b/engines/plumbers/console.h
@@ -30,13 +30,10 @@ namespace Plumbers {
class PlumbersGame;
class Console : public GUI::Debugger {
-private:
- PlumbersGame *_vm;
-
public:
bool _allowSkip;
- explicit Console(Plumbers::PlumbersGame *vm);
+ explicit Console();
virtual ~Console(void) {}
bool Cmd_allowSkip(int argc, const char** argv);
diff --git a/engines/plumbers/plumbers.cpp b/engines/plumbers/plumbers.cpp
index f0445e51eb..5491f81c65 100644
--- a/engines/plumbers/plumbers.cpp
+++ b/engines/plumbers/plumbers.cpp
@@ -89,7 +89,8 @@ static const byte cursorPalette[] = {
Common::Error PlumbersGame::run() {
initGraphics(640, 480);
- _console = new Console(this);
+ _console = new Console();
+ _image = new Image::BitmapDecoder();
CursorMan.replaceCursor(MOUSECURSOR_SCI, 11, 16, 0, 0, 0);
CursorMan.replaceCursorPalette(cursorPalette, 0, 3);
@@ -178,17 +179,11 @@ Common::Error PlumbersGame::run() {
void PlumbersGame::loadImage(const Common::String &dirname, const Common::String &filename) {
Common::String name = dirname + "/" + filename;
debugC(1, kDebugGeneral, "%s : %s", __FUNCTION__, name.c_str());
- Common::File *file = new Common::File();
- if (!file->open(name))
+ Common::File file;
+ if (!file.open(name))
error("unable to load image %s", name.c_str());
- if (_image)
- delete _image;
-
- _image = new Image::BitmapDecoder();
- _image->loadStream(*file);
- file->close();
- delete file;
+ _image->loadStream(file);
}
void PlumbersGame::drawScreen() {
@@ -362,7 +357,6 @@ void PlumbersGame::readTables(const Common::String &fileName) {
file.read(buf, kMaxName);
_bitmaps[i]._filename = Common::String(buf);
}
- file.close();
}
int PlumbersGame::getSceneNumb(int sNo) {
diff --git a/engines/plumbers/plumbers.h b/engines/plumbers/plumbers.h
index 56b27fb745..430c696c6d 100644
--- a/engines/plumbers/plumbers.h
+++ b/engines/plumbers/plumbers.h
@@ -25,7 +25,6 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
-#include "engines/advancedDetector.h"
#include "common/error.h"
#include "engines/engine.h"
@@ -44,6 +43,8 @@
#include "plumbers/console.h"
+struct ADGameDescription;
+
namespace Plumbers {
enum PlumbersDebugChannels {
kDebugGeneral = 1 << 0
@@ -110,7 +111,7 @@ private:
};
Common::Queue<Action> _actions;
-
+
void loadImage(const Common::String &dirname, const Common::String &filename);
void drawScreen();
diff --git a/engines/prince/archive.cpp b/engines/prince/archive.cpp
index 984c078bfb..0ed6e8c753 100644
--- a/engines/prince/archive.cpp
+++ b/engines/prince/archive.cpp
@@ -55,8 +55,8 @@ bool PtcArchive::open(const Common::String &filename) {
uint32 fileTableOffset = _stream->readUint32LE() ^ 0x4D4F4B2D; // MOK-
uint32 fileTableSize = _stream->readUint32LE() ^ 0x534F4654; // SOFT
- //debug("fileTableOffset : %08X", fileTableOffset);
- //debug("fileTableSize: %08X", fileTableSize);
+ debug(8, "fileTableOffset : %08X", fileTableOffset);
+ debug(8, "fileTableSize: %08X", fileTableSize);
_stream->seek(fileTableOffset);
@@ -70,7 +70,7 @@ bool PtcArchive::open(const Common::String &filename) {
Common::String name = (const char*)fileItem;
item._offset = READ_LE_UINT32(fileItem + 24);
item._size = READ_LE_UINT32(fileItem + 28);
- //debug("%12s %8X %d", name.c_str(), item._offset, item._size);
+ debug(8, "%12s %8X %d", name.c_str(), item._offset, item._size);
_items[name] = item;
}
@@ -135,6 +135,8 @@ Common::SeekableReadStream *PtcArchive::createReadStreamForMember(const Common::
return 0;
}
+ debug(8, "PtcArchive::createReadStreamForMember(%s)", name.c_str());
+
const FileEntry &entryHeader = _items[name];
if (entryHeader._size < 4)
@@ -156,9 +158,9 @@ Common::SeekableReadStream *PtcArchive::createReadStreamForMember(const Common::
free(buffer);
size = decompLen;
buffer = decompData;
- }
- //debug("PtcArchive::createReadStreamForMember name %s", name.c_str());
+ debug(8, "PtcArchive::createReadStreamForMember: decompressed %d to %d bytes", entryHeader._size, decompLen);
+ }
return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES);
}
diff --git a/engines/prince/cursor.cpp b/engines/prince/cursor.cpp
index ab3a52eaa2..a4e58dc4a2 100644
--- a/engines/prince/cursor.cpp
+++ b/engines/prince/cursor.cpp
@@ -20,7 +20,12 @@
*
*/
+#include "graphics/cursorman.h"
+
+#include "prince/prince.h"
#include "prince/cursor.h"
+#include "prince/debugger.h"
+#include "prince/script.h"
#include "common/debug.h"
@@ -51,4 +56,98 @@ bool Cursor::loadStream(Common::SeekableReadStream &stream) {
return true;
}
+void PrinceEngine::changeCursor(uint16 curId) {
+ _debugger->_cursorNr = curId;
+ _mouseFlag = curId;
+ _flags->setFlagValue(Flags::MOUSEENABLED, curId);
+
+ const Graphics::Surface *curSurface = nullptr;
+
+ switch (curId) {
+ default:
+ error("Unknown cursor Id: %d", curId);
+ case 0:
+ CursorMan.showMouse(false);
+ _optionsFlag = 0;
+ _selectedMob = -1;
+ return;
+ case 1:
+ curSurface = _cursor1->getSurface();
+ break;
+ case 2:
+ curSurface = _cursor2;
+ break;
+ case 3:
+ curSurface = _cursor3->getSurface();
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ mousePos.x = CLIP(mousePos.x, (int16) 315, (int16) 639);
+ mousePos.y = CLIP(mousePos.y, (int16) 0, (int16) 170);
+ _system->warpMouse(mousePos.x, mousePos.y);
+ break;
+ }
+
+ CursorMan.replaceCursorPalette(_roomBmp->getPalette(), 0, 255);
+ CursorMan.replaceCursor(
+ curSurface->getBasePtr(0, 0),
+ curSurface->w, curSurface->h,
+ 0, 0,
+ 255, false,
+ &curSurface->format
+ );
+ CursorMan.showMouse(true);
+}
+
+void PrinceEngine::makeInvCursor(int itemNr) {
+ const Graphics::Surface *cur1Surface = _cursor1->getSurface();
+ int cur1W = cur1Surface->w;
+ int cur1H = cur1Surface->h;
+ const Common::Rect cur1Rect(0, 0, cur1W, cur1H);
+
+ const Graphics::Surface *itemSurface = _allInvList[itemNr].getSurface();
+ int itemW = itemSurface->w;
+ int itemH = itemSurface->h;
+
+ int cur2W = cur1W + itemW / 2;
+ int cur2H = cur1H + itemH / 2;
+
+ if (_cursor2 != nullptr) {
+ _cursor2->free();
+ delete _cursor2;
+ }
+ _cursor2 = new Graphics::Surface();
+ _cursor2->create(cur2W, cur2H, Graphics::PixelFormat::createFormatCLUT8());
+ Common::Rect cur2Rect(0, 0, cur2W, cur2H);
+ _cursor2->fillRect(cur2Rect, 255);
+ _cursor2->copyRectToSurface(*cur1Surface, 0, 0, cur1Rect);
+
+ const byte *src1 = (const byte *)itemSurface->getBasePtr(0, 0);
+ byte *dst1 = (byte *)_cursor2->getBasePtr(cur1W, cur1H);
+
+ if (itemH % 2) {
+ itemH--;
+ }
+ if (itemW % 2) {
+ itemW--;
+ }
+
+ for (int y = 0; y < itemH; y++) {
+ const byte *src2 = src1;
+ byte *dst2 = dst1;
+ if (y % 2 == 0) {
+ for (int x = 0; x < itemW; x++, src2++) {
+ if (x % 2 == 0) {
+ if (*src2) {
+ *dst2 = *src2;
+ } else {
+ *dst2 = 255;
+ }
+ dst2++;
+ }
+ }
+ dst1 += _cursor2->pitch;
+ }
+ src1 += itemSurface->pitch;
+ }
+}
+
} // End of namespace Prince
diff --git a/engines/prince/decompress.cpp b/engines/prince/decompress.cpp
index 2b563917f7..eda992c093 100644
--- a/engines/prince/decompress.cpp
+++ b/engines/prince/decompress.cpp
@@ -27,145 +27,145 @@
namespace Prince {
static const uint16 table1[] = {
- 0x8000, 0x0002,
- 0x4000, 0x0004,
- 0x2000, 0x0008,
- 0x1000, 0x0010,
- 0x0800, 0x0020,
- 0x0400, 0x0040,
- 0x0200, 0x0080,
- 0x0100, 0x0100,
- 0x0080, 0x0200,
- 0x0040, 0x0400
+ 0x8000, 0x0002,
+ 0x4000, 0x0004,
+ 0x2000, 0x0008,
+ 0x1000, 0x0010,
+ 0x0800, 0x0020,
+ 0x0400, 0x0040,
+ 0x0200, 0x0080,
+ 0x0100, 0x0100,
+ 0x0080, 0x0200,
+ 0x0040, 0x0400
};
static const uint32 table2[] = {
- 0x0000F000,
- 0x0020FC00,
- 0x00A0FF00,
- 0x02A0FF80,
- 0x06A0FFC0,
- 0x0EA0FFE0,
- 0x1EA0FFF0,
- 0x3EA0FFF8
+ 0x0000F000,
+ 0x0020FC00,
+ 0x00A0FF00,
+ 0x02A0FF80,
+ 0x06A0FFC0,
+ 0x0EA0FFE0,
+ 0x1EA0FFF0,
+ 0x3EA0FFF8
};
static const uint16 table3[] = {
- 0x8000, 0x0000,
- 0x4000, 0x0002,
- 0x2000, 0x0006,
- 0x1000, 0x000E,
- 0x0800, 0x001E,
- 0x0400, 0x003E,
- 0x0200, 0x007E,
- 0x0100, 0x00FE,
- 0x0080, 0x01FE,
- 0x0040, 0x03FE,
- 0x0020, 0x07FE,
- 0x0010, 0x0FFE,
- 0x0008, 0x1FFE,
- 0x0004, 0x3FFE,
- 0x0002, 0x7FFE,
- 0x0001, 0xFFFE
+ 0x8000, 0x0000,
+ 0x4000, 0x0002,
+ 0x2000, 0x0006,
+ 0x1000, 0x000E,
+ 0x0800, 0x001E,
+ 0x0400, 0x003E,
+ 0x0200, 0x007E,
+ 0x0100, 0x00FE,
+ 0x0080, 0x01FE,
+ 0x0040, 0x03FE,
+ 0x0020, 0x07FE,
+ 0x0010, 0x0FFE,
+ 0x0008, 0x1FFE,
+ 0x0004, 0x3FFE,
+ 0x0002, 0x7FFE,
+ 0x0001, 0xFFFE
};
void Decompressor::decompress(byte *source, byte *dest, uint32 destSize) {
- byte *destEnd = dest + destSize;
- int more;
- _src = source;
- _dst = dest;
- _bitBuffer = 0x80;
- while (_dst < destEnd) {
- uint32 ebp;
- uint16 offset, length;
- if (getBit()) {
- if (getBit()) {
- if (getBit()) {
- if (getBit()) {
- if (getBit()) {
- if (getBit()) {
- uint32 tableIndex = 0;
- while (getBit())
- tableIndex++;
- length = table3[tableIndex * 2 + 0];
- do {
- more = !(length & 0x8000);
- length = (length << 1) | getBit();
- } while (more);
- length += table3[tableIndex * 2 + 1];
- length++;
- memcpy(_dst, _src, length);
- _src += length;
- _dst += length;
- }
- *_dst++ = *_src++;
- }
- *_dst++ = *_src++;
- }
- *_dst++ = *_src++;
- }
- *_dst++ = *_src++;
- }
- *_dst++ = *_src++;
- }
- if (!getBit()) {
- if (getBit()) {
- uint32 tableIndex = getBit();
- tableIndex = (tableIndex << 1) | getBit();
- tableIndex = (tableIndex << 1) | getBit();
- ebp = table2[tableIndex];
- length = 1;
- } else {
- ebp = 0x0000FF00;
- length = 0;
- }
- } else {
- uint32 tableIndex = 0;
- while (getBit())
- tableIndex++;
- length = table1[tableIndex * 2 + 0];
- do {
- more = !(length & 0x8000);
- length = (length << 1) | getBit();
- } while (more);
- length += table1[tableIndex * 2 + 1];
- tableIndex = getBit();
- tableIndex = (tableIndex << 1) | getBit();
- tableIndex = (tableIndex << 1) | getBit();
- ebp = table2[tableIndex];
- }
- offset = ebp & 0xFFFF;
- do {
- if (_bitBuffer == 0x80) {
- if (offset >= 0xFF00) {
- offset = (offset << 8) | *_src++;
- }
- }
- more = offset & 0x8000;
- offset = (offset << 1) | getBit();
- } while (more);
- offset += (ebp >> 16);
- length += 2;
- while (length--) {
- if (_dst >= destEnd) {
- return;
- }
- *_dst = *(_dst - offset);
- _dst++;
- }
- }
+ byte *destEnd = dest + destSize;
+ int more;
+ _src = source;
+ _dst = dest;
+ _bitBuffer = 0x80;
+ while (_dst < destEnd) {
+ uint32 ebp;
+ uint16 offset, length;
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ uint32 tableIndex = 0;
+ while (getBit())
+ tableIndex++;
+ length = table3[tableIndex * 2 + 0];
+ do {
+ more = !(length & 0x8000);
+ length = (length << 1) | getBit();
+ } while (more);
+ length += table3[tableIndex * 2 + 1];
+ length++;
+ memcpy(_dst, _src, length);
+ _src += length;
+ _dst += length;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ if (!getBit()) {
+ if (getBit()) {
+ uint32 tableIndex = getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ ebp = table2[tableIndex];
+ length = 1;
+ } else {
+ ebp = 0x0000FF00;
+ length = 0;
+ }
+ } else {
+ uint32 tableIndex = 0;
+ while (getBit())
+ tableIndex++;
+ length = table1[tableIndex * 2 + 0];
+ do {
+ more = !(length & 0x8000);
+ length = (length << 1) | getBit();
+ } while (more);
+ length += table1[tableIndex * 2 + 1];
+ tableIndex = getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ ebp = table2[tableIndex];
+ }
+ offset = ebp & 0xFFFF;
+ do {
+ if (_bitBuffer == 0x80) {
+ if (offset >= 0xFF00) {
+ offset = (offset << 8) | *_src++;
+ }
+ }
+ more = offset & 0x8000;
+ offset = (offset << 1) | getBit();
+ } while (more);
+ offset += (ebp >> 16);
+ length += 2;
+ while (length--) {
+ if (_dst >= destEnd) {
+ return;
+ }
+ *_dst = *(_dst - offset);
+ _dst++;
+ }
+ }
}
int Decompressor::getBit() {
- int bit = (_bitBuffer & 0x80) >> 7;
- _bitBuffer <<= 1;
- if (_bitBuffer == 0) {
- _bitBuffer = *_src++;
- bit = (_bitBuffer & 0x80) >> 7;
- _bitBuffer <<= 1;
- _bitBuffer |= 1;
- }
- return bit;
+ int bit = (_bitBuffer & 0x80) >> 7;
+ _bitBuffer <<= 1;
+ if (_bitBuffer == 0) {
+ _bitBuffer = *_src++;
+ bit = (_bitBuffer & 0x80) >> 7;
+ _bitBuffer <<= 1;
+ _bitBuffer |= 1;
+ }
+ return bit;
}
} // End of namespace Prince
diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp
index a8fa305332..2147c23116 100644
--- a/engines/prince/detection.cpp
+++ b/engines/prince/detection.cpp
@@ -21,9 +21,15 @@
*/
#include "prince/prince.h"
+#include "engines/advancedDetector.h"
namespace Prince {
+struct PrinceGameDescription {
+ ADGameDescription desc;
+ PrinceGameType gameType;
+};
+
int PrinceEngine::getGameType() const {
return _gameDescription->gameType;
}
@@ -43,7 +49,7 @@ Common::Language PrinceEngine::getLanguage() const {
} // End of namespace Prince
static const PlainGameDescriptor princeGames[] = {
- {"prince", "Prince Game"},
+ {"prince", "The Prince and the Coward"},
{0, 0}
};
@@ -52,11 +58,11 @@ static const PrinceGameDescription gameDescriptions[] = {
{
{
"prince",
- "Galador",
+ "Galador: Der Fluch des Prinzen",
AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_TESTING,
+ ADGF_USEEXTRAASTITLE | ADGF_TESTING,
GUIO1(GUIO_NONE)
},
kPrinceDataDE
@@ -68,7 +74,7 @@ static const PrinceGameDescription gameDescriptions[] = {
AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298),
Common::PL_POL,
Common::kPlatformWindows,
- ADGF_TESTING,
+ ADGF_USEEXTRAASTITLE | ADGF_TESTING,
GUIO1(GUIO_NONE)
},
kPrinceDataPL
@@ -76,11 +82,11 @@ static const PrinceGameDescription gameDescriptions[] = {
{
{
"prince",
- "Galador",
+ "",
AD_ENTRY1s("talktxt.dat", "02bb2372f19aca3c65896ed81b2cefb3", 125702),
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_TESTING,
+ ADGF_TESTING | GF_EXTRACTED,
GUIO1(GUIO_NONE)
},
kPrinceDataDE
@@ -88,19 +94,19 @@ static const PrinceGameDescription gameDescriptions[] = {
{
{
"prince",
- "Galador",
+ "",
AD_ENTRY1s("databank.ptc", "a67b55730f3d7064921bd2a59e1063a3", 3892982),
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_TESTING,
+ ADGF_TESTING | GF_NOVOICES,
GUIO1(GUIO_NONE)
},
- kPrinceDataPL
+ kPrinceDataDE
},
{
{
"prince",
- "The Prince and the Coward",
+ "",
{
{"databank.ptc", 0, "5fa03833177331214ec1354761b1d2ee", 3565031},
{"prince_translation.dat", 0, 0, -1},
@@ -116,7 +122,7 @@ static const PrinceGameDescription gameDescriptions[] = {
{
{
"prince",
- "The Prince and the Coward",
+ "",
{
{"databank.ptc", 0, "48ec9806bda9d152acbea8ce31c93c49", 3435298},
{"prince_translation.dat", 0, 0, -1},
@@ -169,6 +175,7 @@ bool PrinceMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime) ||
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSimpleSavesNames);
@@ -188,7 +195,6 @@ SaveStateList PrinceMetaEngine::listSaves(const char *target) const {
pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); filename++) {
@@ -209,10 +215,6 @@ SaveStateList PrinceMetaEngine::listSaves(const char *target) const {
// Valid savegame
if (Prince::PrinceEngine::readSavegameHeader(file, header)) {
saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
- if (header.thumbnail) {
- header.thumbnail->free();
- delete header.thumbnail;
- }
}
} else {
// Must be an original format savegame
@@ -224,6 +226,7 @@ SaveStateList PrinceMetaEngine::listSaves(const char *target) const {
}
}
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -239,7 +242,7 @@ SaveStateDescriptor PrinceMetaEngine::querySaveMetaInfos(const char *target, int
f->read(buffer, kSavegameStrSize + 1);
bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) &&
- Prince::PrinceEngine::readSavegameHeader(f, header);
+ Prince::PrinceEngine::readSavegameHeader(f, header, false);
delete f;
if (!hasHeader) {
@@ -252,6 +255,7 @@ SaveStateDescriptor PrinceMetaEngine::querySaveMetaInfos(const char *target, int
desc.setThumbnail(header.thumbnail);
desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
desc.setSaveTime(header.saveHour, header.saveMinutes);
+ desc.setPlayTime(header.playTime * 1000);
return desc;
}
diff --git a/engines/prince/draw.cpp b/engines/prince/draw.cpp
new file mode 100644
index 0000000000..a924f99def
--- /dev/null
+++ b/engines/prince/draw.cpp
@@ -0,0 +1,765 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/palette.h"
+
+#include "prince/prince.h"
+
+#include "prince/animation.h"
+#include "prince/graphics.h"
+#include "prince/hero.h"
+#include "prince/script.h"
+
+namespace Prince {
+
+bool PrinceEngine::spriteCheck(int sprWidth, int sprHeight, int destX, int destY) {
+ destX -= _picWindowX;
+ destY -= _picWindowY;
+
+ // if x1 is on visible part of screen
+ if (destX < 0) {
+ if (destX + sprWidth < 1) {
+ //x2 is negative - out of window
+ return false;
+ }
+ }
+ // if x1 is outside of screen on right side
+ if (destX >= kNormalWidth) {
+ return false;
+ }
+
+ if (destY < 0) {
+ if (destY + sprHeight < 1) {
+ //y2 is negative - out of window
+ return false;
+ }
+ }
+ if (destY >= kNormalHeight) {
+ return false;
+ }
+
+ return true;
+}
+
+// CheckNak
+void PrinceEngine::checkMasks(int x1, int y1, int sprWidth, int sprHeight, int z) {
+ int x2 = x1 + sprWidth - 1;
+ int y2 = y1 + sprHeight - 1;
+ if (x1 < 0) {
+ x1 = 0;
+ }
+ for (uint i = 0; i < _maskList.size(); i++) {
+ if (!_maskList[i]._state && !_maskList[i]._flags) {
+ if (_maskList[i]._z > z) {
+ if (_maskList[i]._x1 <= x2 && _maskList[i]._x2 >= x1) {
+ if (_maskList[i]._y1 <= y2 && _maskList[i]._y2 >= y1) {
+ _maskList[i]._state = 1;
+ }
+ }
+ }
+ }
+ }
+}
+
+// ClsNak
+void PrinceEngine::clsMasks() {
+ for (uint i = 0; i < _maskList.size(); i++) {
+ if (_maskList[i]._state) {
+ _maskList[i]._state = 0;
+ }
+ }
+}
+
+// InsertNakladki
+void PrinceEngine::insertMasks(Graphics::Surface *originalRoomSurface) {
+ for (uint i = 0; i < _maskList.size(); i++) {
+ if (_maskList[i]._state) {
+ if (_maskList[i]._data != nullptr) {
+ showMask(i, originalRoomSurface);
+ } else {
+ error("insertMasks() - Wrong mask data- nr %d", i);
+ }
+ }
+ }
+}
+
+// ShowNak
+void PrinceEngine::showMask(int maskNr, Graphics::Surface *originalRoomSurface) {
+ if (!_maskList[maskNr]._flags) {
+ if (spriteCheck(_maskList[maskNr]._width, _maskList[maskNr]._height, _maskList[maskNr]._x1, _maskList[maskNr]._y1)) {
+ int destX = _maskList[maskNr]._x1 - _picWindowX;
+ int destY = _maskList[maskNr]._y1 - _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = _maskList[maskNr]._z;
+ newDrawNode.width = _maskList[maskNr]._width;
+ newDrawNode.height = _maskList[maskNr]._height;
+ newDrawNode.s = nullptr;
+ newDrawNode.originalRoomSurface = originalRoomSurface;
+ newDrawNode.data = _maskList[maskNr].getMask();
+ newDrawNode.drawFunction = &_graph->drawMaskDrawNode;
+ _drawNodeList.push_back(newDrawNode);
+ }
+ }
+}
+
+void PrinceEngine::showSprite(Graphics::Surface *spriteSurface, int destX, int destY, int destZ) {
+ if (spriteCheck(spriteSurface->w, spriteSurface->h, destX, destY)) {
+ destX -= _picWindowX;
+ destY -= _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = destZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.s = spriteSurface;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = _transTable;
+ newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
+ _drawNodeList.push_back(newDrawNode);
+ }
+}
+
+void PrinceEngine::showSpriteShadow(Graphics::Surface *shadowSurface, int destX, int destY, int destZ) {
+ if (spriteCheck(shadowSurface->w, shadowSurface->h, destX, destY)) {
+ destX -= _picWindowX;
+ destY -= _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = destZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.s = shadowSurface;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = _graph->_shadowTable70;
+ newDrawNode.drawFunction = &_graph->drawAsShadowDrawNode;
+ _drawNodeList.push_back(newDrawNode);
+ }
+}
+
+void PrinceEngine::showAnim(Anim &anim) {
+ //ShowFrameCode
+ //ShowAnimFrame
+ int phase = anim._showFrame;
+ int phaseFrameIndex = anim._animData->getPhaseFrameIndex(phase);
+ int x = anim._x + anim._animData->getPhaseOffsetX(phase);
+ int y = anim._y + anim._animData->getPhaseOffsetY(phase);
+ int animFlag = anim._flags;
+ int checkMaskFlag = (animFlag & 1);
+ int maxFrontFlag = (animFlag & 2);
+ int specialZFlag = anim._nextAnim;
+ int z = anim._nextAnim;
+ Graphics::Surface *animSurface = anim._animData->getFrame(phaseFrameIndex);
+ int frameWidth = animSurface->w;
+ int frameHeight = animSurface->h;
+ int shadowZ = 0;
+
+ if (checkMaskFlag) {
+ if (!anim._nextAnim) {
+ z = y + frameHeight - 1;
+ }
+ checkMasks(x, y, frameWidth, frameHeight, z);
+ }
+
+ if (specialZFlag) {
+ z = specialZFlag;
+ } else if (maxFrontFlag) {
+ z = kMaxPicHeight + 1;
+ } else {
+ z = y + frameHeight - 1;
+ }
+ shadowZ = z;
+
+ anim._currX = x;
+ anim._currY = y;
+ anim._currW = frameWidth;
+ anim._currH = frameHeight;
+ showSprite(animSurface, x, y, z);
+
+ // make_special_shadow
+ if ((anim._flags & 0x80)) {
+ DrawNode newDrawNode;
+ newDrawNode.posX = x;
+ newDrawNode.posY = y + animSurface->h - anim._shadowBack;
+ newDrawNode.posZ = Hero::kHeroShadowZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.scaleValue = _scaleValue;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = this;
+ newDrawNode.drawFunction = &Hero::showHeroShadow;
+ newDrawNode.s = animSurface;
+ _drawNodeList.push_back(newDrawNode);
+ }
+
+ //ShowFrameCodeShadow
+ //ShowAnimFrameShadow
+ if (anim._shadowData != nullptr) {
+ int shadowPhaseFrameIndex = anim._shadowData->getPhaseFrameIndex(phase);
+ int shadowX = anim._shadowData->getBaseX() + anim._shadowData->getPhaseOffsetX(phase);
+ int shadowY = anim._shadowData->getBaseY() + anim._shadowData->getPhaseOffsetY(phase);
+ Graphics::Surface *shadowSurface = anim._shadowData->getFrame(shadowPhaseFrameIndex);
+ int shadowFrameWidth = shadowSurface->w;
+ int shadowFrameHeight = shadowSurface->h;
+
+ if (checkMaskFlag) {
+ checkMasks(shadowX, shadowY, shadowFrameWidth, shadowFrameHeight, shadowY + shadowFrameWidth - 1);
+ }
+
+ if (!shadowZ) {
+ if (maxFrontFlag) {
+ shadowZ = kMaxPicHeight + 1;
+ } else {
+ shadowZ = shadowY + shadowFrameWidth - 1;
+ }
+ }
+ showSpriteShadow(shadowSurface, shadowX, shadowY, shadowZ);
+ }
+}
+
+void PrinceEngine::showNormAnims() {
+ for (int i = 0; i < kMaxNormAnims; i++) {
+ Anim &anim = _normAnimList[i];
+ if (anim._animData != nullptr) {
+ int phaseCount = anim._animData->getPhaseCount();
+ if (!anim._state) {
+ if (anim._frame == anim._lastFrame - 1) {
+ if (anim._loopType) {
+ if (anim._loopType == 1) {
+ anim._frame = anim._loopFrame;
+ } else {
+ continue;
+ }
+ }
+ } else {
+ anim._frame++;
+ }
+ anim._showFrame = anim._frame;
+ if (anim._showFrame >= phaseCount) {
+ anim._showFrame = phaseCount - 1;
+ }
+ showAnim(anim);
+ }
+ }
+ }
+}
+
+void PrinceEngine::setBackAnim(Anim &backAnim) {
+ int start = backAnim._basaData._start;
+ if (start != -1) {
+ backAnim._frame = start;
+ backAnim._showFrame = start;
+ backAnim._loopFrame = start;
+ }
+ int end = backAnim._basaData._end;
+ if (end != -1) {
+ backAnim._lastFrame = end;
+ }
+ backAnim._state = 0;
+}
+
+void PrinceEngine::showBackAnims() {
+ for (int i = 0; i < kMaxBackAnims; i++) {
+ BAS &seq = _backAnimList[i]._seq;
+ int activeSubAnim = seq._currRelative;
+ if (!_backAnimList[i].backAnims.empty()) {
+ if (_backAnimList[i].backAnims[activeSubAnim]._animData != nullptr) {
+ if (!_backAnimList[i].backAnims[activeSubAnim]._state) {
+ seq._counter++;
+ if (seq._type == 2) {
+ if (!seq._currRelative) {
+ if (seq._counter >= seq._data) {
+ if (seq._anims > 2) {
+ seq._currRelative = _randomSource.getRandomNumber(seq._anims - 2) + 1;
+ activeSubAnim = seq._currRelative;
+ seq._current = _backAnimList[i].backAnims[activeSubAnim]._basaData._num;
+ }
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ seq._counter = 0;
+ }
+ }
+ }
+
+ if (seq._type == 3) {
+ if (!seq._currRelative) {
+ if (seq._counter < seq._data2) {
+ continue;
+ } else {
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ }
+ }
+ }
+
+ if (_backAnimList[i].backAnims[activeSubAnim]._frame == _backAnimList[i].backAnims[activeSubAnim]._lastFrame - 1) {
+ _backAnimList[i].backAnims[activeSubAnim]._frame = _backAnimList[i].backAnims[activeSubAnim]._loopFrame;
+ switch (seq._type) {
+ case 1:
+ if (seq._anims > 1) {
+ int rnd;
+ do {
+ rnd = _randomSource.getRandomNumber(seq._anims - 1);
+ } while (rnd == seq._currRelative);
+ seq._currRelative = rnd;
+ seq._current = _backAnimList[i].backAnims[rnd]._basaData._num;
+ activeSubAnim = rnd;
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ seq._counter = 0;
+ }
+ break;
+ case 2:
+ if (seq._currRelative) {
+ seq._currRelative = 0;
+ seq._current = _backAnimList[i].backAnims[0]._basaData._num;
+ activeSubAnim = 0;
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ seq._counter = 0;
+ }
+ break;
+ case 3:
+ seq._currRelative = 0;
+ seq._current = _backAnimList[i].backAnims[0]._basaData._num;
+ seq._counter = 0;
+ seq._data2 = _randomSource.getRandomNumber(seq._data - 1);
+ continue; // for bug in original game
+ break;
+ }
+ } else {
+ _backAnimList[i].backAnims[activeSubAnim]._frame++;
+ }
+ _backAnimList[i].backAnims[activeSubAnim]._showFrame = _backAnimList[i].backAnims[activeSubAnim]._frame;
+ showAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ }
+ }
+ }
+ }
+}
+
+void PrinceEngine::removeSingleBackAnim(int slot) {
+ if (!_backAnimList[slot].backAnims.empty()) {
+ for (uint j = 0; j < _backAnimList[slot].backAnims.size(); j++) {
+ if (_backAnimList[slot].backAnims[j]._animData != nullptr) {
+ delete _backAnimList[slot].backAnims[j]._animData;
+ _backAnimList[slot].backAnims[j]._animData = nullptr;
+ }
+ if (_backAnimList[slot].backAnims[j]._shadowData != nullptr) {
+ delete _backAnimList[slot].backAnims[j]._shadowData;
+ _backAnimList[slot].backAnims[j]._shadowData = nullptr;
+ }
+ }
+ _backAnimList[slot].backAnims.clear();
+ _backAnimList[slot]._seq._currRelative = 0;
+ }
+}
+
+void PrinceEngine::clearBackAnimList() {
+ for (int i = 0; i < kMaxBackAnims; i++) {
+ removeSingleBackAnim(i);
+ }
+}
+
+void PrinceEngine::grabMap() {
+ _graph->_frontScreen->copyFrom(*_roomBmp->getSurface());
+ showObjects();
+ runDrawNodes();
+ _graph->_mapScreen->copyFrom(*_graph->_frontScreen);
+}
+
+void PrinceEngine::initZoomIn(int slot) {
+ freeZoomObject(slot);
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *zoomSource = object->getSurface();
+ if (zoomSource != nullptr) {
+ object->_flags |= 0x8000;
+ object->_zoomSurface = new Graphics::Surface();
+ object->_zoomSurface->create(zoomSource->w, zoomSource->h, Graphics::PixelFormat::createFormatCLUT8());
+ object->_zoomSurface->fillRect(Common::Rect(zoomSource->w, zoomSource->h), 0xFF);
+ object->_zoomTime = 20;
+ }
+ }
+}
+
+void PrinceEngine::initZoomOut(int slot) {
+ freeZoomObject(slot);
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *zoomSource = object->getSurface();
+ if (zoomSource != nullptr) {
+ object->_flags |= 0x4000;
+ object->_zoomSurface = new Graphics::Surface();
+ object->_zoomSurface->copyFrom(*zoomSource);
+ object->_zoomTime = 10;
+ }
+ }
+}
+
+void PrinceEngine::doZoomIn(int slot) {
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *orgSurface = object->getSurface();
+ if (orgSurface != nullptr) {
+ byte *src1 = (byte *)orgSurface->getBasePtr(0, 0);
+ byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
+ int x = 0;
+ int surfaceHeight = orgSurface->h;
+ for (int y = 0; y < surfaceHeight; y++) {
+ byte *src2 = src1;
+ byte *dst2 = dst1;
+ int w = orgSurface->w - x;
+ src2 += x;
+ dst2 += x;
+ while (w > 0) {
+ int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
+ if (randVal < w) {
+ *(dst2 + randVal) = *(src2 + randVal);
+ src2 += zoomInStep;
+ dst2 += zoomInStep;
+ } else if (y + 1 != surfaceHeight) {
+ *(dst1 + orgSurface->pitch + randVal - w) = *(src1 + orgSurface->pitch + randVal - w);
+ }
+ w -= zoomInStep;
+ }
+ x = -1 * w;
+ src1 += orgSurface->pitch;
+ dst1 += orgSurface->pitch;
+ }
+ }
+ }
+}
+
+void PrinceEngine::doZoomOut(int slot) {
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *orgSurface = object->getSurface();
+ if (orgSurface != nullptr) {
+ byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
+ int x = 0;
+ int surfaceHeight = orgSurface->h;
+ for (int y = 0; y < surfaceHeight; y++) {
+ byte *dst2 = dst1;
+ int w = orgSurface->w - x;
+ dst2 += x;
+ while (w > 0) {
+ int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
+ if (randVal < w) {
+ *(dst2 + randVal) = 255;
+ dst2 += zoomInStep;
+ } else if (y + 1 != surfaceHeight) {
+ *(dst1 + orgSurface->pitch + randVal - w) = 255;
+ }
+ w -= zoomInStep;
+ }
+ x = -1 * w;
+ dst1 += orgSurface->pitch;
+ }
+ }
+ }
+}
+
+void PrinceEngine::freeZoomObject(int slot) {
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ if (object->_zoomSurface != nullptr) {
+ object->_zoomSurface->free();
+ delete object->_zoomSurface;
+ object->_zoomSurface = nullptr;
+ }
+ }
+}
+
+void PrinceEngine::showObjects() {
+ for (int i = 0; i < kMaxObjects; i++) {
+ int nr = _objSlot[i];
+ if (nr != 0xFF) {
+ Graphics::Surface *objSurface = nullptr;
+ if ((_objList[nr]->_flags & 0x8000)) {
+ _objList[nr]->_zoomTime--;
+ if (!_objList[nr]->_zoomTime) {
+ freeZoomObject(nr);
+ _objList[nr]->_flags &= 0x7FFF;
+ objSurface = _objList[nr]->getSurface();
+ } else {
+ doZoomIn(nr);
+ objSurface = _objList[nr]->_zoomSurface;
+ }
+ } else if ((_objList[nr]->_flags & 0x4000)) {
+ _objList[nr]->_zoomTime--;
+ if (!_objList[nr]->_zoomTime) {
+ freeZoomObject(nr);
+ _objList[nr]->_flags &= 0xBFFF;
+ objSurface = _objList[nr]->getSurface();
+ } else {
+ doZoomOut(nr);
+ objSurface = _objList[nr]->_zoomSurface;
+ }
+ } else {
+ objSurface = _objList[nr]->getSurface();
+ }
+
+ if (objSurface != nullptr) {
+ if (spriteCheck(objSurface->w, objSurface->h, _objList[nr]->_x, _objList[nr]->_y)) {
+ int destX = _objList[nr]->_x - _picWindowX;
+ int destY = _objList[nr]->_y - _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = _objList[nr]->_z;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.s = objSurface;
+ newDrawNode.originalRoomSurface = nullptr;
+ if ((_objList[nr]->_flags & 0x2000)) {
+ newDrawNode.data = nullptr;
+ newDrawNode.drawFunction = &_graph->drawBackSpriteDrawNode;
+ } else {
+ newDrawNode.data = _transTable;
+ if (_flags->getFlagValue(Flags::NOANTIALIAS)) {
+ newDrawNode.drawFunction = &_graph->drawTransparentDrawNode;
+ } else {
+ newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
+ }
+ }
+ _drawNodeList.push_back(newDrawNode);
+ }
+
+ if ((_objList[nr]->_flags & 1)) {
+ checkMasks(_objList[nr]->_x, _objList[nr]->_y, objSurface->w, objSurface->h, _objList[nr]->_z);
+ }
+ }
+ }
+ }
+}
+
+void PrinceEngine::showParallax() {
+ if (!_pscrList.empty()) {
+ for (uint i = 0; i < _pscrList.size(); i++) {
+ Graphics::Surface *pscrSurface = _pscrList[i]->getSurface();
+ if (pscrSurface != nullptr) {
+ int x = _pscrList[i]->_x - (_pscrList[i]->_step * _picWindowX / 4);
+ int y = _pscrList[i]->_y;
+ int z = PScr::kPScrZ;
+ if (spriteCheck(pscrSurface->w, pscrSurface->h, x, y)) {
+ showSprite(pscrSurface, x, y, z);
+ }
+ }
+ }
+ }
+}
+
+bool PrinceEngine::compareDrawNodes(DrawNode d1, DrawNode d2) {
+ if (d1.posZ < d2.posZ) {
+ return true;
+ }
+ return false;
+}
+
+void PrinceEngine::runDrawNodes() {
+ Common::sort(_drawNodeList.begin(), _drawNodeList.end(), compareDrawNodes);
+
+ for (uint i = 0; i < _drawNodeList.size(); i++) {
+ (*_drawNodeList[i].drawFunction)(_graph->_frontScreen, &_drawNodeList[i]);
+ }
+ _graph->change();
+}
+
+void PrinceEngine::drawScreen() {
+ if (!_showInventoryFlag || _inventoryBackgroundRemember) {
+ clsMasks();
+
+ _mainHero->showHero();
+ _mainHero->scrollHero();
+ _mainHero->drawHero();
+
+ _secondHero->showHero();
+ _secondHero->_drawX -= _picWindowX;
+ _secondHero->drawHero();
+
+ const Graphics::Surface *roomSurface;
+ if (_locationNr != 50) {
+ roomSurface = _roomBmp->getSurface();
+ } else {
+ roomSurface = _graph->_mapScreen;
+ }
+ Graphics::Surface visiblePart;
+ if (roomSurface) {
+ visiblePart = roomSurface->getSubArea(Common::Rect(_picWindowX, 0, roomSurface->w, roomSurface->h));
+ _graph->draw(_graph->_frontScreen, &visiblePart);
+ }
+
+ showBackAnims();
+
+ showNormAnims();
+
+ playNextFLCFrame();
+
+ showObjects();
+
+ if (roomSurface) {
+ insertMasks(&visiblePart);
+ }
+
+ showParallax();
+
+ runDrawNodes();
+
+ _drawNodeList.clear();
+
+ if (!_inventoryBackgroundRemember && !_dialogFlag) {
+ if (!_optionsFlag) {
+ _selectedMob = checkMob(_graph->_frontScreen, _mobList, true);
+ }
+ showTexts(_graph->_frontScreen);
+ checkOptions();
+ } else {
+ _inventoryBackgroundRemember = false;
+ }
+
+ showPower();
+
+ getDebugger()->onFrame();
+
+ } else {
+ displayInventory();
+ }
+}
+
+void PrinceEngine::blackPalette() {
+ byte *paletteBackup = (byte *)malloc(256 * 3);
+ byte *blackPalette1 = (byte *)malloc(256 * 3);
+
+ int fadeStep = kFadeStep - 1;
+ for (int i = 0; i < kFadeStep; i++) {
+ _system->getPaletteManager()->grabPalette(paletteBackup, 0, 256);
+ for (int j = 0; j < 256; j++) {
+ blackPalette1[3 * j] = paletteBackup[3 * j] * fadeStep / 4;
+ blackPalette1[3 * j + 1] = paletteBackup[3 * j + 1] * fadeStep / 4;
+ blackPalette1[3 * j + 2] = paletteBackup[3 * j + 2] * fadeStep / 4;
+ }
+ fadeStep--;
+ _graph->setPalette(blackPalette1);
+ _system->updateScreen();
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ free(paletteBackup);
+ free(blackPalette1);
+ return;
+ }
+ pausePrinceEngine();
+ }
+ free(paletteBackup);
+ free(blackPalette1);
+}
+
+void PrinceEngine::setPalette(const byte *palette) {
+ if (palette != nullptr) {
+ byte *blackPalette_ = (byte *)malloc(256 * 3);
+ int fadeStep = 0;
+ for (int i = 0; i <= kFadeStep; i++) {
+ for (int j = 0; j < 256; j++) {
+ blackPalette_[3 * j] = palette[3 * j] * fadeStep / 4;
+ blackPalette_[3 * j + 1] = palette[3 * j + 1] * fadeStep / 4;
+ blackPalette_[3 * j + 2] = palette[3 * j + 2] * fadeStep / 4;
+ }
+ fadeStep++;
+ _graph->setPalette(blackPalette_);
+ _system->updateScreen();
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ _graph->setPalette(palette);
+ free(blackPalette_);
+ return;
+ }
+ pausePrinceEngine();
+ }
+ _graph->setPalette(palette);
+ free(blackPalette_);
+ }
+}
+
+void PrinceEngine::doTalkAnim(int animNumber, int slot, AnimType animType) {
+ Text &text = _textSlots[slot];
+ int lines = calcTextLines((const char *)_interpreter->getString());
+ int time = lines * 30;
+ if (animType == kNormalAnimation) {
+ Anim &normAnim = _normAnimList[animNumber];
+ if (normAnim._animData != nullptr) {
+ if (!normAnim._state) {
+ if (normAnim._currW && normAnim._currH) {
+ text._color = _flags->getFlagValue(Flags::KOLOR);
+ text._x = normAnim._currX + normAnim._currW / 2;
+ text._y = normAnim._currY - 10;
+ }
+ }
+ }
+ } else if (animType == kBackgroundAnimation) {
+ if (!_backAnimList[animNumber].backAnims.empty()) {
+ int currAnim = _backAnimList[animNumber]._seq._currRelative;
+ Anim &backAnim = _backAnimList[animNumber].backAnims[currAnim];
+ if (backAnim._animData != nullptr) {
+ if (!backAnim._state) {
+ if (backAnim._currW && backAnim._currH) {
+ text._color = _flags->getFlagValue(Flags::KOLOR);
+ text._x = backAnim._currX + backAnim._currW / 2;
+ text._y = backAnim._currY - 10;
+ }
+ }
+ }
+ }
+ } else {
+ error("doTalkAnim() - wrong animType: %d", animType);
+ }
+ text._time = time;
+ if (getLanguage() == Common::DE_DEU) {
+ correctStringDEU((char *)_interpreter->getString());
+ }
+ text._str = (const char *)_interpreter->getString();
+ _interpreter->increaseString();
+}
+
+void PrinceEngine::freeNormAnim(int slot) {
+ if (!_normAnimList.empty()) {
+ _normAnimList[slot]._state = 1;
+ if (_normAnimList[slot]._animData != nullptr) {
+ delete _normAnimList[slot]._animData;
+ _normAnimList[slot]._animData = nullptr;
+ }
+ if (_normAnimList[slot]._shadowData != nullptr) {
+ delete _normAnimList[slot]._shadowData;
+ _normAnimList[slot]._shadowData = nullptr;
+ }
+ }
+}
+
+void PrinceEngine::freeAllNormAnims() {
+ for (int i = 0; i < kMaxNormAnims; i++) {
+ freeNormAnim(i);
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/hero.cpp b/engines/prince/hero.cpp
index 037f11e95a..8ade649a9f 100644
--- a/engines/prince/hero.cpp
+++ b/engines/prince/hero.cpp
@@ -68,7 +68,7 @@ bool Hero::loadAnimSet(uint32 animSetNr) {
_moveSet.resize(kMoveSetSize);
for (uint32 i = 0; i < kMoveSetSize; i++) {
- debug("Anim set item %d %s", i, animSet[i]);
+ debug(5, "Anim set item %d %s", i, animSet[i]);
Animation *anim = nullptr;
if (animSet[i] != nullptr) {
anim = new Animation();
diff --git a/engines/prince/inventory.cpp b/engines/prince/inventory.cpp
new file mode 100644
index 0000000000..3183b94334
--- /dev/null
+++ b/engines/prince/inventory.cpp
@@ -0,0 +1,709 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/prince.h"
+
+#include "prince/graphics.h"
+#include "prince/hero.h"
+#include "prince/script.h"
+#include "prince/mhwanh.h"
+#include "prince/variatxt.h"
+#include "prince/option_text.h"
+#include "prince/font.h"
+
+namespace Prince {
+
+void PrinceEngine::addInv(int heroId, int item, bool addItemQuiet) {
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+ if (hero != nullptr) {
+ if (hero->_inventory.size() < kMaxItems) {
+ if (item != 0x7FFF) {
+ hero->_inventory.push_back(item);
+ }
+ if (!addItemQuiet) {
+ addInvObj();
+ }
+ _interpreter->setResult(0);
+ } else {
+ _interpreter->setResult(1);
+ }
+ }
+}
+
+void PrinceEngine::remInv(int heroId, int item) {
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+ if (hero != nullptr) {
+ for (uint i = 0; i < hero->_inventory.size(); i++) {
+ if (hero->_inventory[i] == item) {
+ hero->_inventory.remove_at(i);
+ _interpreter->setResult(0);
+ return;
+ }
+ }
+ }
+ _interpreter->setResult(1);
+}
+
+void PrinceEngine::clearInv(int heroId) {
+ switch (heroId) {
+ case 0:
+ _mainHero->_inventory.clear();
+ break;
+ case 1:
+ _secondHero->_inventory.clear();
+ break;
+ default:
+ error("clearInv() - wrong hero slot");
+ break;
+ }
+}
+
+void PrinceEngine::swapInv(int heroId) {
+ Common::Array<int> tempInv;
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+ if (hero != nullptr) {
+ for (uint i = 0; i < hero->_inventory.size(); i++) {
+ tempInv.push_back(hero->_inventory[i]);
+ }
+ hero->_inventory.clear();
+ for (uint i = 0; i < hero->_inventory2.size(); i++) {
+ hero->_inventory.push_back(hero->_inventory2[i]);
+ }
+ hero->_inventory2.clear();
+ for (uint i = 0; i < tempInv.size(); i++) {
+ hero->_inventory2.push_back(tempInv[i]);
+ }
+ tempInv.clear();
+ }
+}
+
+void PrinceEngine::addInvObj() {
+ changeCursor(0);
+ prepareInventoryToView();
+
+ _inventoryBackgroundRemember = true;
+ drawScreen();
+
+ Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
+
+ if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
+
+ loadSample(27, "PRZEDMIO.WAV");
+ playSample(27, 0);
+
+ _mst_shadow2 = 1;
+
+ while (_mst_shadow2 < 512) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 += 50;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ while (_mst_shadow2 > 256) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 -= 42;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ } else {
+ //CURSEBLINK:
+ for (int i = 0; i < 3; i++) {
+ _mst_shadow2 = 256;
+ while (_mst_shadow2 < 512) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 += 50;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ while (_mst_shadow2 > 256) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 -= 50;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ }
+ }
+ _mst_shadow2 = 0;
+ for (int i = 0; i < 20; i++) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+}
+
+void PrinceEngine::rememberScreenInv() {
+ _graph->_screenForInventory->copyFrom(*_graph->_frontScreen);
+}
+
+void PrinceEngine::inventoryFlagChange(bool inventoryState) {
+ if (inventoryState) {
+ _showInventoryFlag = true;
+ _inventoryBackgroundRemember = true;
+ } else {
+ _showInventoryFlag = false;
+ }
+}
+
+void PrinceEngine::prepareInventoryToView() {
+ _invMobList.clear();
+ int invItem = _mainHero->_inventory.size();
+ _invLine = invItem / 3;
+ if (invItem % 3) {
+ _invLine++;
+ }
+ if (_invLine < 4) {
+ _invLine = 4;
+ }
+ _maxInvW = (374 - 2 * _invLine) / _invLine;
+ _invLineW = _maxInvW - 2;
+
+ int currInvX = _invLineX;
+ int currInvY = _invLineY;
+
+ Common::MemoryReadStream stream(_invTxt, _invTxtSize);
+ byte c;
+
+ uint item = 0;
+ for (int i = 0; i < _invLines; i++) {
+ for (int j = 0; j < _invLine; j++) {
+ Mob tempMobItem;
+ if (item < _mainHero->_inventory.size()) {
+ int itemNr = _mainHero->_inventory[item];
+ tempMobItem._visible = 0;
+ tempMobItem._mask = itemNr;
+ tempMobItem._rect = Common::Rect(currInvX + _picWindowX, currInvY, currInvX + _picWindowX + _invLineW - 1, currInvY + _invLineH - 1);
+ tempMobItem._type = 0; // to work with checkMob()
+
+ tempMobItem._name = "";
+ tempMobItem._examText = "";
+ int txtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8]);
+ int examTxtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8 + 4]);
+
+ stream.seek(txtOffset);
+ while ((c = stream.readByte())) {
+ tempMobItem._name += c;
+ }
+
+ stream.seek(examTxtOffset);
+ while ((c = stream.readByte())) {
+ tempMobItem._examText += c;
+ }
+ _invMobList.push_back(tempMobItem);
+ }
+ currInvX += _invLineW + _invLineSkipX;
+ item++;
+ }
+ currInvX = _invLineX;
+ currInvY += _invLineSkipY + _invLineH;
+ }
+}
+
+void PrinceEngine::drawInvItems() {
+ int currInvX = _invLineX;
+ int currInvY = _invLineY;
+ uint item = 0;
+ for (int i = 0; i < _invLines; i++) {
+ for (int j = 0; j < _invLine; j++) {
+ if (item < _mainHero->_inventory.size()) {
+ int itemNr = _mainHero->_inventory[item];
+ _mst_shadow = 0;
+ if (_mst_shadow2) {
+ if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
+ if (item + 1 == _mainHero->_inventory.size()) { // last item in inventory
+ _mst_shadow = 1;
+ }
+ } else if (itemNr == 1 || itemNr == 3 || itemNr == 4 || itemNr == 7) {
+ _mst_shadow = 1;
+ }
+ }
+
+ int drawX = currInvX;
+ int drawY = currInvY;
+ Graphics::Surface *itemSurface = nullptr;
+ if (itemNr != 68) {
+ itemSurface = _allInvList[itemNr].getSurface();
+ if (itemSurface->h < _maxInvH) {
+ drawY += (_maxInvH - itemSurface->h) / 2;
+ }
+ } else {
+ // candle item:
+ if (_candleCounter == 8) {
+ _candleCounter = 0;
+ }
+ itemNr = _candleCounter;
+ _candleCounter++;
+ itemNr &= 7;
+ itemNr += 71;
+ itemSurface = _allInvList[itemNr].getSurface();
+ drawY += _allInvList[itemNr]._y + (_maxInvH - 76) / 2 - 200;
+ }
+ if (itemSurface->w < _maxInvW) {
+ drawX += (_maxInvW - itemSurface->w) / 2;
+ }
+ if (!_mst_shadow) {
+ _graph->drawTransparentSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
+ } else {
+ _mst_shadow = _mst_shadow2;
+ _graph->drawTransparentWithBlendSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
+ }
+ }
+ currInvX += _invLineW + _invLineSkipX;
+ item++;
+ }
+ currInvX = _invLineX;
+ currInvY += _invLineSkipY + _invLineH;
+ }
+}
+
+void PrinceEngine::inventoryLeftMouseButton() {
+ if (!_mouseFlag) {
+ _textSlots[0]._time = 0;
+ _textSlots[0]._str = nullptr;
+ stopSample(28);
+ }
+
+ if (_optionsFlag == 1) {
+ if (_selectedMob != -1) {
+ if (_optionEnabled < _invOptionsNumber) {
+ _optionsFlag = 0;
+ } else {
+ return;
+ }
+ } else {
+ error("PrinceEngine::inventoryLeftMouseButton() - optionsFlag = 1, selectedMob = 0");
+ if (_currentPointerNumber == 2) {
+ changeCursor(1);
+ _currentPointerNumber = 1;
+ _selectedMob = -1;
+ _optionsMob = -1;
+ return;
+ } else {
+ return;
+ }
+ }
+ } else {
+ if (_selectedMob != -1) {
+ if (_currentPointerNumber != 2) {
+ if (_invMobList[_selectedMob]._mask != 29) {
+ _optionEnabled = 0;
+ } else {
+ // map item
+ _optionEnabled = 1;
+ }
+ } else {
+ //use_item_on_item
+ int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
+ if (invObjUU == -1) {
+ int textNr = 80011; // "I can't do it."
+ if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
+ textNr = 80020; // "Nothing is happening."
+ }
+ _interpreter->setCurrentString(textNr);
+ printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
+ setVoice(0, 28, 1);
+ playSample(28, 0);
+ _selectedMob = -1;
+ _optionsMob = -1;
+ return;
+ } else {
+ _interpreter->storeNewPC(invObjUU);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ }
+ } else {
+ return;
+ }
+ }
+ //do_option
+ if (_optionEnabled == 0) {
+ int invObjExamEvent = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjExam);
+ if (invObjExamEvent == -1) {
+ // do_standard
+ // FIXME: UB?
+ // Constness of the pointer returned by c_str() is cast away (which generates a compiler warning)
+ // while it potentially gets modified inside printAt()
+ printAt(0, 216, (char *)_invMobList[_selectedMob]._examText.c_str(), kNormalWidth / 2, _invExamY);
+ _interpreter->setCurrentString(_invMobList[_selectedMob]._mask + 70000);
+ setVoice(0, 28, 1);
+ playSample(28, 0);
+ // disableuseuse
+ changeCursor(0);
+ _currentPointerNumber = 1;
+ } else {
+ _interpreter->storeNewPC(invObjExamEvent);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ } else if (_optionEnabled == 1) {
+ // not_examine
+ int invObjUse = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUse);
+ if (invObjUse == -1) {
+ // do_standard_use
+ _selectedMode = 0;
+ _selectedItem = _invMobList[_selectedMob]._mask;
+ makeInvCursor(_invMobList[_selectedMob]._mask);
+ _currentPointerNumber = 2;
+ changeCursor(2);
+ } else {
+ _interpreter->storeNewPC(invObjUse);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ } else if (_optionEnabled == 4) {
+ // do_standard_give
+ _selectedMode = 1;
+ _selectedItem = _invMobList[_selectedMob]._mask;
+ makeInvCursor(_invMobList[_selectedMob]._mask);
+ _currentPointerNumber = 2;
+ changeCursor(2);
+ } else {
+ // use_item_on_item
+ int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
+ if (invObjUU == -1) {
+ int textNr = 80011; // "I can't do it."
+ if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
+ textNr = 80020; // "Nothing is happening."
+ }
+ _interpreter->setCurrentString(textNr);
+ printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
+ setVoice(0, 28, 1);
+ playSample(28, 0);
+ } else {
+ _interpreter->storeNewPC(invObjUU);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ }
+ _selectedMob = -1;
+ _optionsMob = -1;
+}
+
+void PrinceEngine::inventoryRightMouseButton() {
+ if (_textSlots[0]._str == nullptr) {
+ enableOptions(false);
+ }
+}
+
+void PrinceEngine::enableOptions(bool checkType) {
+ if (_optionsFlag != 1) {
+ changeCursor(1);
+ _currentPointerNumber = 1;
+ if (_selectedMob != -1) {
+ if (checkType) {
+ if (_mobList[_selectedMob]._type & 0x100) {
+ return;
+ }
+ }
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ int x1 = mousePos.x - _optionsWidth / 2;
+ int x2 = mousePos.x + _optionsWidth / 2;
+ if (x1 < 0) {
+ x1 = 0;
+ x2 = _optionsWidth;
+ } else if (x2 >= kNormalWidth) {
+ x1 = kNormalWidth - _optionsWidth;
+ x2 = kNormalWidth;
+ }
+ int y1 = mousePos.y - 10;
+ if (y1 < 0) {
+ y1 = 0;
+ }
+ if (y1 + _optionsHeight >= kNormalHeight) {
+ y1 = kNormalHeight - _optionsHeight;
+ }
+ _optionsMob = _selectedMob;
+ _optionsX = x1;
+ _optionsY = y1;
+ _optionsFlag = 1;
+ }
+ }
+}
+
+void PrinceEngine::checkOptions() {
+ if (_optionsFlag) {
+ Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _optionsWidth, _optionsY + _optionsHeight);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ if (!optionsRect.contains(mousePos)) {
+ _optionsFlag = 0;
+ _selectedMob = -1;
+ return;
+ }
+ _graph->drawAsShadowSurface(_graph->_frontScreen, _optionsX, _optionsY, _optionsPic, _graph->_shadowTable50);
+
+ _optionEnabled = -1;
+ int optionsYCord = mousePos.y - (_optionsY + 16);
+ if (optionsYCord >= 0) {
+ int selectedOptionNr = optionsYCord / _optionsStep;
+ if (selectedOptionNr < _optionsNumber) {
+ _optionEnabled = selectedOptionNr;
+ }
+ }
+ int optionsColor;
+ int textY = _optionsY + 16;
+ for (int i = 0; i < _optionsNumber; i++) {
+ if (i != _optionEnabled) {
+ optionsColor = _optionsColor1;
+ } else {
+ optionsColor = _optionsColor2;
+ }
+ Common::String optText;
+ switch(getLanguage()) {
+ case Common::PL_POL:
+ optText = optionsTextPL[i];
+ break;
+ case Common::DE_DEU:
+ optText = optionsTextDE[i];
+ break;
+ case Common::EN_ANY:
+ optText = optionsTextEN[i];
+ break;
+ case Common::RU_RUS:
+ optText = optionsTextRU[i];
+ break;
+ default:
+ break;
+ };
+ uint16 textW = getTextWidth(optText.c_str());
+ uint16 textX = _optionsX + _optionsWidth / 2 - textW / 2;
+ _font->drawString(_graph->_frontScreen, optText, textX, textY, textW, optionsColor);
+ textY += _optionsStep;
+ }
+ }
+}
+
+void PrinceEngine::checkInvOptions() {
+ if (_optionsFlag) {
+ Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _invOptionsWidth, _optionsY + _invOptionsHeight);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ if (!optionsRect.contains(mousePos)) {
+ _optionsFlag = 0;
+ _selectedMob = -1;
+ return;
+ }
+ _graph->drawAsShadowSurface(_graph->_screenForInventory, _optionsX, _optionsY, _optionsPicInInventory, _graph->_shadowTable50);
+
+ _optionEnabled = -1;
+ int optionsYCord = mousePos.y - (_optionsY + 16);
+ if (optionsYCord >= 0) {
+ int selectedOptionNr = optionsYCord / _invOptionsStep;
+ if (selectedOptionNr < _invOptionsNumber) {
+ _optionEnabled = selectedOptionNr;
+ }
+ }
+ int optionsColor;
+ int textY = _optionsY + 16;
+ for (int i = 0; i < _invOptionsNumber; i++) {
+ if (i != _optionEnabled) {
+ optionsColor = _optionsColor1;
+ } else {
+ optionsColor = _optionsColor2;
+ }
+ Common::String invText;
+ switch(getLanguage()) {
+ case Common::PL_POL:
+ invText = invOptionsTextPL[i];
+ break;
+ case Common::DE_DEU:
+ invText = invOptionsTextDE[i];
+ break;
+ case Common::EN_ANY:
+ invText = invOptionsTextEN[i];
+ break;
+ case Common::RU_RUS:
+ invText = invOptionsTextRU[i];
+ break;
+ default:
+ error("Unknown game language %d", getLanguage());
+ break;
+ };
+ uint16 textW = getTextWidth(invText.c_str());
+ uint16 textX = _optionsX + _invOptionsWidth / 2 - textW / 2;
+ _font->drawString(_graph->_screenForInventory, invText, textX, textY, _graph->_screenForInventory->w, optionsColor);
+ textY += _invOptionsStep;
+ }
+ }
+}
+
+void PrinceEngine::displayInventory() {
+
+ _mainHero->freeOldMove();
+ _secondHero->freeOldMove();
+
+ _interpreter->setFgOpcodePC(0);
+
+ stopAllSamples();
+
+ prepareInventoryToView();
+
+ while (!shouldQuit()) {
+
+ if (_textSlots[0]._str != nullptr) {
+ changeCursor(0);
+ } else {
+ changeCursor(_currentPointerNumber);
+
+ Common::Rect inventoryRect(_invX1, _invY1, _invX1 + _invWidth, _invY1 + _invHeight);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+
+ if (!_invCurInside && inventoryRect.contains(mousePos)) {
+ _invCurInside = true;
+ }
+
+ if (_invCurInside && !inventoryRect.contains(mousePos)) {
+ inventoryFlagChange(false);
+ _invCurInside = false;
+ break;
+ }
+ }
+
+ rememberScreenInv();
+
+ Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+
+ drawInvItems();
+
+ showTexts(_graph->_screenForInventory);
+
+ if (!_optionsFlag && _textSlots[0]._str == nullptr) {
+ _selectedMob = checkMob(_graph->_screenForInventory, _invMobList, false);
+ }
+
+ checkInvOptions();
+
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ keyHandler(event);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ inventoryLeftMouseButton();
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ inventoryRightMouseButton();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!_showInventoryFlag) {
+ break;
+ }
+
+ if (shouldQuit())
+ return;
+
+ getDebugger()->onFrame();
+ _graph->update(_graph->_screenForInventory);
+ pausePrinceEngine();
+ }
+
+ if (_currentPointerNumber == 2) {
+ _flags->setFlagValue(Flags::SELITEM, _selectedItem);
+ } else {
+ _flags->setFlagValue(Flags::SELITEM, 0);
+ }
+}
+
+void PrinceEngine::openInventoryCheck() {
+ if (!_optionsFlag) {
+ if (_mouseFlag == 1 || _mouseFlag == 2) {
+ if (_mainHero->_visible) {
+ if (!_flags->getFlagValue(Flags::INVALLOWED)) {
+ // 29 - Basement, 50 - Map
+ if (_locationNr != 29 && _locationNr != 50) {
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ if (mousePos.y < 4 && !_showInventoryFlag) {
+ _invCounter++;
+ } else {
+ _invCounter = 0;
+ }
+ if (_invCounter >= _invMaxCount) {
+ inventoryFlagChange(true);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/mob.cpp b/engines/prince/mob.cpp
index b170ba324b..de15991dba 100644
--- a/engines/prince/mob.cpp
+++ b/engines/prince/mob.cpp
@@ -20,7 +20,11 @@
*
*/
+#include "prince/prince.h"
+
#include "prince/mob.h"
+#include "prince/animation.h"
+#include "prince/font.h"
namespace Prince {
@@ -105,4 +109,158 @@ uint16 Mob::getData(AttrId dataId) {
}
}
+int PrinceEngine::getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY) {
+
+ Common::Point pointPos(posX, posY);
+
+ int mobListSize;
+ if (usePriorityList) {
+ mobListSize = _mobPriorityList.size();
+ } else {
+ mobListSize = mobList.size();
+ }
+
+ for (int mobNumber = 0; mobNumber < mobListSize; mobNumber++) {
+ Mob *mob = nullptr;
+ if (usePriorityList) {
+ mob = &mobList[_mobPriorityList[mobNumber]];
+ } else {
+ mob = &mobList[mobNumber];
+ }
+
+ if (mob->_visible) {
+ continue;
+ }
+
+ int type = mob->_type & 7;
+ switch (type) {
+ case 0:
+ case 1:
+ //normal_mob
+ if (!mob->_rect.contains(pointPos)) {
+ continue;
+ }
+ break;
+ case 3:
+ //mob_obj
+ if (mob->_mask < kMaxObjects) {
+ int nr = _objSlot[mob->_mask];
+ if (nr != 0xFF) {
+ Object &obj = *_objList[nr];
+ Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
+ if (objectRect.contains(pointPos)) {
+ Graphics::Surface *objSurface = obj.getSurface();
+ byte *pixel = (byte *)objSurface->getBasePtr(posX - obj._x, posY - obj._y);
+ if (*pixel != 255) {
+ break;
+ }
+ }
+ }
+ }
+ continue;
+ break;
+ case 2:
+ case 5:
+ //check_ba_mob
+ if (!_backAnimList[mob->_mask].backAnims.empty()) {
+ int currentAnim = _backAnimList[mob->_mask]._seq._currRelative;
+ Anim &backAnim = _backAnimList[mob->_mask].backAnims[currentAnim];
+ if (backAnim._animData != nullptr) {
+ if (!backAnim._state) {
+ Common::Rect backAnimRect(backAnim._currX, backAnim._currY, backAnim._currX + backAnim._currW, backAnim._currY + backAnim._currH);
+ if (backAnimRect.contains(pointPos)) {
+ int phase = backAnim._showFrame;
+ int phaseFrameIndex = backAnim._animData->getPhaseFrameIndex(phase);
+ Graphics::Surface *backAnimSurface = backAnim._animData->getFrame(phaseFrameIndex);
+ byte pixel = *(byte *)backAnimSurface->getBasePtr(posX - backAnim._currX, posY - backAnim._currY);
+ if (pixel != 255) {
+ if (type == 5) {
+ if (mob->_rect.contains(pointPos)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ continue;
+ break;
+ default:
+ //not_part_ba
+ continue;
+ break;
+ }
+
+ if (usePriorityList) {
+ return _mobPriorityList[mobNumber];
+ } else {
+ return mobNumber;
+ }
+ }
+ return -1;
+}
+
+int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) {
+ if (_mouseFlag == 0 || _mouseFlag == 3) {
+ return -1;
+ }
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y);
+
+ if (mobNumber != -1) {
+ Common::String mobName = mobList[mobNumber]._name;
+
+ if (getLanguage() == Common::DE_DEU) {
+ for (uint i = 0; i < mobName.size(); i++) {
+ switch (mobName[i]) {
+ case '\xc4':
+ mobName.setChar('\x83', i);
+ break;
+ case '\xd6':
+ mobName.setChar('\x84', i);
+ break;
+ case '\xdc':
+ mobName.setChar('\x85', i);
+ break;
+ case '\xdf':
+ mobName.setChar('\x7f', i);
+ break;
+ case '\xe4':
+ mobName.setChar('\x80', i);
+ break;
+ case '\xf6':
+ mobName.setChar('\x81', i);
+ break;
+ case '\xfc':
+ mobName.setChar('\x82', i);
+ break;
+ }
+ }
+ }
+
+ uint16 textW = getTextWidth(mobName.c_str());
+
+ uint16 x = mousePos.x - textW / 2;
+ if (x > screen->w) {
+ x = 0;
+ }
+
+ if (x + textW > screen->w) {
+ x = screen->w - textW;
+ }
+
+ uint16 y = mousePos.y - _font->getFontHeight();
+ if (y > screen->h) {
+ y = _font->getFontHeight() - 2;
+ }
+
+ _font->drawString(screen, mobName, x, y, screen->w, 216);
+ }
+
+ return mobNumber;
+}
+
} // End of namespace Prince
diff --git a/engines/prince/module.mk b/engines/prince/module.mk
index 27bbc21700..0a24c0c243 100644
--- a/engines/prince/module.mk
+++ b/engines/prince/module.mk
@@ -7,20 +7,25 @@ MODULE_OBJS = \
debugger.o \
decompress.o \
detection.o \
+ draw.o \
flags.o \
font.o \
graphics.o \
hero.o \
+ inventory.o \
mhwanh.o \
+ music.o \
mob.o \
object.o \
prince.o \
pscr.o \
+ resource.o \
saveload.o \
script.o \
sound.o \
variatxt.o \
- videoplayer.o
+ videoplayer.o \
+ walk.o
# This module can be built as a plugin
ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN)
diff --git a/engines/prince/music.cpp b/engines/prince/music.cpp
new file mode 100644
index 0000000000..58a1c1c02a
--- /dev/null
+++ b/engines/prince/music.cpp
@@ -0,0 +1,236 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/prince.h"
+#include "prince/music.h"
+#include "prince/musNum.h"
+#include "prince/resource.h"
+
+#include "common/archive.h"
+#include "common/debug.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+
+namespace Prince {
+
+const char *MusicPlayer::_musTable[] = {
+ "",
+ "Battlfld.mid",
+ "Cave.mid",
+ "Cemetery.mid",
+ "Credits.mid",
+ "Fjord.mid",
+ "Guitar.mid",
+ "Hell.mid",
+ "Jingle.mid",
+ "Main.mid",
+ "Night.mid",
+ "Reality.mid",
+ "Sunlord.mid",
+ "Tavern.mid",
+ "Temple.mid",
+ "Boruta.mid",
+ "Intro.mid"
+};
+
+const uint8 MusicPlayer::_musRoomTable[] = {
+ 0,
+ ROOM01MUS,
+ ROOM02MUS,
+ ROOM03MUS,
+ ROOM04MUS,
+ ROOM05MUS,
+ ROOM06MUS,
+ ROOM07MUS,
+ ROOM08MUS,
+ ROOM09MUS,
+ ROOM10MUS,
+ ROOM11MUS,
+ ROOM12MUS,
+ ROOM13MUS,
+ ROOM14MUS,
+ ROOM15MUS,
+ ROOM16MUS,
+ ROOM17MUS,
+ ROOM18MUS,
+ ROOM19MUS,
+ ROOM20MUS,
+ ROOM21MUS,
+ ROOM22MUS,
+ ROOM23MUS,
+ ROOM24MUS,
+ ROOM25MUS,
+ ROOM26MUS,
+ ROOM27MUS,
+ ROOM28MUS,
+ ROOM29MUS,
+ ROOM30MUS,
+ ROOM31MUS,
+ ROOM32MUS,
+ ROOM33MUS,
+ ROOM34MUS,
+ ROOM35MUS,
+ ROOM36MUS,
+ ROOM37MUS,
+ ROOM38MUS,
+ ROOM39MUS,
+ ROOM40MUS,
+ ROOM41MUS,
+ ROOM42MUS,
+ ROOM43MUS,
+ 0,
+ 0,
+ ROOM46MUS,
+ ROOM47MUS,
+ ROOM48MUS,
+ ROOM49MUS,
+ ROOM50MUS,
+ ROOM51MUS,
+ ROOM52MUS,
+ ROOM53MUS,
+ ROOM54MUS,
+ ROOM55MUS,
+ ROOM56MUS,
+ ROOM57MUS,
+ ROOM58MUS,
+ ROOM59MUS,
+ ROOM60MUS,
+ ROOM61MUS
+};
+
+
+MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) {
+ _data = nullptr;
+ _dataSize = 0;
+ _isGM = false;
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+MusicPlayer::~MusicPlayer() {
+ killMidi();
+}
+
+void MusicPlayer::killMidi() {
+ Audio::MidiPlayer::stop();
+
+ free(_data);
+ _data = nullptr;
+}
+
+void MusicPlayer::loadMidi(const char *name) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name);
+ if (!stream) {
+ warning("Can't load midi stream %s", name);
+ return;
+ }
+
+ stream = Resource::getDecompressedStream(stream);
+
+ // Stop any currently playing MIDI file
+ killMidi();
+
+ // Read in the data for the file
+ _dataSize = stream->size();
+ _data = (byte *)malloc(_dataSize);
+ stream->read(_data, _dataSize);
+
+ delete stream;
+
+ // Start playing the music
+ sndMidiStart();
+}
+
+void MusicPlayer::sndMidiStart() {
+ _isGM = true;
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_data, _dataSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ // Al the tracks are supposed to loop
+ _isLooping = true;
+ _isPlaying = true;
+ }
+}
+
+void MusicPlayer::send(uint32 b) {
+ if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+
+ Audio::MidiPlayer::send(b);
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+bool PrinceEngine::loadMusic(int musNumber) {
+ uint8 midiNumber = MusicPlayer::_musRoomTable[musNumber];
+ if (midiNumber) {
+ if (midiNumber != 100) {
+ if (_currentMidi != midiNumber) {
+ _currentMidi = midiNumber;
+ const char *musName = MusicPlayer::_musTable[_currentMidi];
+ _midiPlayer->loadMidi(musName);
+ }
+ }
+ } else {
+ stopMusic();
+ }
+ return true;
+}
+
+void PrinceEngine::stopMusic() {
+ if (_midiPlayer->isPlaying()) {
+ _midiPlayer->stop();
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/sound.h b/engines/prince/music.h
index 21f9e48b37..061e10c8b8 100644
--- a/engines/prince/sound.h
+++ b/engines/prince/music.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef PRINCE_SOUND_H
-#define PRINCE_SOUND_H
+#ifndef PRINCE_MUSIC_H
+#define PRINCE_MUSIC_H
#include "audio/midiplayer.h"
#include "common/memstream.h"
diff --git a/engines/prince/object.cpp b/engines/prince/object.cpp
index e4a3eda689..109d180355 100644
--- a/engines/prince/object.cpp
+++ b/engines/prince/object.cpp
@@ -28,6 +28,7 @@
#include "graphics/surface.h"
#include "prince/object.h"
+#include "prince/resource.h"
namespace Prince {
@@ -73,6 +74,8 @@ bool Object::loadFromStream(Common::SeekableReadStream &stream) {
const Common::String obStreamName = Common::String::format("OB%02d", stream.readUint16LE());
Common::SeekableReadStream *obStream = SearchMan.createReadStreamForMember(obStreamName);
if (obStream) {
+ obStream = Resource::getDecompressedStream(obStream);
+
loadSurface(*obStream);
}
delete obStream;
diff --git a/engines/prince/option_text.h b/engines/prince/option_text.h
index f56dd421ec..cc97f042af 100644
--- a/engines/prince/option_text.h
+++ b/engines/prince/option_text.h
@@ -82,4 +82,23 @@ const char *optionsTextEN[] = {
"Talk to"
};
+// RU
+const char *invOptionsTextRU[] = {
+ "Cvjnhtnm",
+ "Bcgjkmp.",
+ "Jnrhsnm/""\x83""bnm ",
+ "Pfrhsnm/Nzyenm ",
+ "Lfnm "
+};
+
+const char *optionsTextRU[] = {
+ "Gjlevfnm",
+ "Jcvjnhtnm",
+ "Dpznm ",
+ "Bcgjkmp.",
+ "Jnrhsnm/""\x83""bnm ",
+ "Pfrhsnm/Nzyenm ",
+ "Ujdjhbnm "
+};
+
} // End of namespace Prince
diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp
index 016428935c..cb314aa058 100644
--- a/engines/prince/prince.cpp
+++ b/engines/prince/prince.cpp
@@ -32,34 +32,25 @@
#include "common/substream.h"
#include "common/str.h"
-#include "graphics/cursorman.h"
#include "graphics/surface.h"
-#include "graphics/palette.h"
#include "graphics/pixelformat.h"
#include "engines/util.h"
-#include "audio/audiostream.h"
-#include "audio/decoders/wave.h"
-
#include "prince/prince.h"
-#include "prince/font.h"
#include "prince/graphics.h"
#include "prince/script.h"
#include "prince/debugger.h"
#include "prince/object.h"
#include "prince/mob.h"
-#include "prince/sound.h"
+#include "prince/music.h"
#include "prince/variatxt.h"
-#include "prince/flags.h"
#include "prince/font.h"
#include "prince/mhwanh.h"
#include "prince/cursor.h"
#include "prince/archive.h"
#include "prince/hero.h"
-#include "prince/resource.h"
#include "prince/animation.h"
-#include "prince/option_text.h"
#include "prince/curve_values.h"
namespace Prince {
@@ -217,14 +208,17 @@ void PrinceEngine::init() {
debugEngine("Adding all path: %s", gameDataDir.getPath().c_str());
- if (getLanguage() != Common::RU_RUS) {
+ if (!(getFeatures() & GF_EXTRACTED)) {
PtcArchive *all = new PtcArchive();
if (!all->open("all/databank.ptc"))
error("Can't open all/databank.ptc");
PtcArchive *voices = new PtcArchive();
- if (!voices->open("voices/databank.ptc"))
- error("Can't open voices/databank.ptc");
+
+ if (!(getFeatures() & GF_NOVOICES)) {
+ if (!voices->open("voices/databank.ptc"))
+ error("Can't open voices/databank.ptc");
+ }
PtcArchive *sound = new PtcArchive();
if (!sound->open("sound/databank.ptc"))
@@ -331,6 +325,9 @@ void PrinceEngine::init() {
error("Can't load dialogDatStream");
return;
}
+
+ dialogDatStream = Resource::getDecompressedStream(dialogDatStream);
+
_dialogDatSize = dialogDatStream->size();
_dialogDat = (byte *)malloc(_dialogDatSize);
dialogDatStream->read(_dialogDat, _dialogDatSize);
@@ -464,148 +461,11 @@ void PrinceEngine::pauseEngineIntern(bool pause) {
Engine::pauseEngineIntern(pause);
if (pause) {
_midiPlayer->pause();
- }
- else {
+ } else {
_midiPlayer->resume();
}
}
-bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) {
- int32 pos = stream.pos();
-
- uint16 type = stream.readUint16LE();
- if (type == 0xFFFF) {
- return false;
- }
- _type = type;
- _fileNumber = stream.readUint16LE();
- _startPhase = stream.readUint16LE();
- _endPhase = stream.readUint16LE();
- _loopPhase = stream.readUint16LE();
- _x = stream.readSint16LE();
- _y = stream.readSint16LE();
- _loopType = stream.readUint16LE();
- _nextAnim = stream.readUint16LE();
- _flags = stream.readUint16LE();
-
- //debug("AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags);
- //debug("startPhase %d, endPhase %d, loopPhase %d", _startPhase, _endPhase, _loopPhase);
-
- // 32 byte aligment
- stream.seek(pos + 32);
-
- return true;
-}
-
-bool PrinceEngine::loadLocation(uint16 locationNr) {
-
- blackPalette();
-
- _flicPlayer.close();
-
- memset(_textSlots, 0, sizeof(_textSlots));
- freeAllSamples();
-
- debugEngine("PrinceEngine::loadLocation %d", locationNr);
- const Common::FSNode gameDataDir(ConfMan.get("path"));
- SearchMan.remove(Common::String::format("%02d", _locationNr));
-
- _locationNr = locationNr;
- _debugger->_locationNr = locationNr;
-
- _flags->setFlagValue(Flags::CURRROOM, _locationNr);
- _interpreter->stopBg();
-
- changeCursor(0);
-
- const Common::String locationNrStr = Common::String::format("%02d", _locationNr);
- debugEngine("loadLocation %s", locationNrStr.c_str());
-
- PtcArchive *locationArchive = new PtcArchive();
- if (!locationArchive->open(locationNrStr + "/databank.ptc"))
- error("Can't open location %s", locationNrStr.c_str());
-
- SearchMan.add(locationNrStr, locationArchive);
-
- loadMusic(_locationNr);
-
- // load location background, replace old one
- Resource::loadResource(_roomBmp, "room", true);
- if (_roomBmp->getSurface()) {
- _sceneWidth = _roomBmp->getSurface()->w;
- }
-
- loadZoom(_zoomBitmap, kZoomBitmapLen, "zoom");
- loadShadow(_shadowBitmap, kShadowBitmapSize, "shadow", "shadow2");
- loadTrans(_transTable, "trans");
- loadPath("path");
-
- for (uint32 i = 0; i < _pscrList.size(); i++) {
- delete _pscrList[i];
- }
- _pscrList.clear();
- Resource::loadResource(_pscrList, "pscr.lst", false);
-
- loadMobPriority("mobpri");
-
- _mobList.clear();
- if (getGameType() == kPrinceDataDE) {
- const Common::String mobLstName = Common::String::format("mob%02d.lst", _locationNr);
- debug("name: %s", mobLstName.c_str());
- Resource::loadResource(_mobList, mobLstName.c_str(), false);
- } else if (getGameType() == kPrinceDataPL) {
- Resource::loadResource(_mobList, "mob.lst", false);
- }
- if (getFeatures() & GF_TRANSLATED) {
- // update Mob texts for translated version
- setMobTranslationTexts();
- }
-
- _animList.clear();
- Resource::loadResource(_animList, "anim.lst", false);
-
- for (uint32 i = 0; i < _objList.size(); i++) {
- delete _objList[i];
- }
- _objList.clear();
- Resource::loadResource(_objList, "obj.lst", false);
-
- _room->loadRoom(_script->getRoomOffset(_locationNr));
-
- for (uint i = 0; i < _maskList.size(); i++) {
- free(_maskList[i]._data);
- }
- _maskList.clear();
- _script->loadAllMasks(_maskList, _room->_nak);
-
- _picWindowX = 0;
-
- _lightX = _script->getLightX(_locationNr);
- _lightY = _script->getLightY(_locationNr);
- setShadowScale(_script->getShadowScale(_locationNr));
-
- for (uint i = 0; i < _mobList.size(); i++) {
- _mobList[i]._visible = _script->getMobVisible(_room->_mobs, i);
- }
-
- _script->installObjects(_room->_obj);
-
- freeAllNormAnims();
-
- clearBackAnimList();
- _script->installBackAnims(_backAnimList, _room->_backAnim);
-
- _graph->makeShadowTable(70, _graph->_shadowTable70);
- _graph->makeShadowTable(50, _graph->_shadowTable50);
-
- _mainHero->freeOldMove();
- _secondHero->freeOldMove();
-
- _mainHero->scrollHero();
-
- return true;
-}
-
void PrinceEngine::setShadowScale(int32 shadowScale) {
shadowScale = 100 - shadowScale;
if (!shadowScale) {
@@ -622,122 +482,6 @@ void PrinceEngine::plotShadowLinePoint(int x, int y, int color, void *data) {
vm->_shadLineLen++;
}
-void PrinceEngine::changeCursor(uint16 curId) {
- _debugger->_cursorNr = curId;
- _mouseFlag = curId;
- _flags->setFlagValue(Flags::MOUSEENABLED, curId);
-
- const Graphics::Surface *curSurface = nullptr;
-
- switch (curId) {
- default:
- error("Unknown cursor Id: %d", curId);
- case 0:
- CursorMan.showMouse(false);
- _optionsFlag = 0;
- _selectedMob = -1;
- return;
- case 1:
- curSurface = _cursor1->getSurface();
- break;
- case 2:
- curSurface = _cursor2;
- break;
- case 3:
- curSurface = _cursor3->getSurface();
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- mousePos.x = CLIP(mousePos.x, (int16) 315, (int16) 639);
- mousePos.y = CLIP(mousePos.y, (int16) 0, (int16) 170);
- _system->warpMouse(mousePos.x, mousePos.y);
- break;
- }
-
- CursorMan.replaceCursorPalette(_roomBmp->getPalette(), 0, 255);
- CursorMan.replaceCursor(
- curSurface->getBasePtr(0, 0),
- curSurface->w, curSurface->h,
- 0, 0,
- 255, false,
- &curSurface->format
- );
- CursorMan.showMouse(true);
-}
-
-void PrinceEngine::makeInvCursor(int itemNr) {
- const Graphics::Surface *cur1Surface = _cursor1->getSurface();
- int cur1W = cur1Surface->w;
- int cur1H = cur1Surface->h;
- const Common::Rect cur1Rect(0, 0, cur1W, cur1H);
-
- const Graphics::Surface *itemSurface = _allInvList[itemNr].getSurface();
- int itemW = itemSurface->w;
- int itemH = itemSurface->h;
-
- int cur2W = cur1W + itemW / 2;
- int cur2H = cur1H + itemH / 2;
-
- if (_cursor2 != nullptr) {
- _cursor2->free();
- delete _cursor2;
- }
- _cursor2 = new Graphics::Surface();
- _cursor2->create(cur2W, cur2H, Graphics::PixelFormat::createFormatCLUT8());
- Common::Rect cur2Rect(0, 0, cur2W, cur2H);
- _cursor2->fillRect(cur2Rect, 255);
- _cursor2->copyRectToSurface(*cur1Surface, 0, 0, cur1Rect);
-
- const byte *src1 = (const byte *)itemSurface->getBasePtr(0, 0);
- byte *dst1 = (byte *)_cursor2->getBasePtr(cur1W, cur1H);
-
- if (itemH % 2) {
- itemH--;
- }
- if (itemW % 2) {
- itemW--;
- }
-
- for (int y = 0; y < itemH; y++) {
- const byte *src2 = src1;
- byte *dst2 = dst1;
- if (y % 2 == 0) {
- for (int x = 0; x < itemW; x++, src2++) {
- if (x % 2 == 0) {
- if (*src2) {
- *dst2 = *src2;
- } else {
- *dst2 = 255;
- }
- dst2++;
- }
- }
- dst1 += _cursor2->pitch;
- }
- src1 += itemSurface->pitch;
- }
-}
-
-bool PrinceEngine::loadMusic(int musNumber) {
- uint8 midiNumber = MusicPlayer::_musRoomTable[musNumber];
- if (midiNumber) {
- if (midiNumber != 100) {
- if (_currentMidi != midiNumber) {
- _currentMidi = midiNumber;
- const char *musName = MusicPlayer::_musTable[_currentMidi];
- _midiPlayer->loadMidi(musName);
- }
- }
- } else {
- stopMusic();
- }
- return true;
-}
-
-void PrinceEngine::stopMusic() {
- if (_midiPlayer->isPlaying()) {
- _midiPlayer->stop();
- }
-}
-
bool PrinceEngine::playNextFLCFrame() {
if (!_flicPlayer.isVideoLoaded())
return false;
@@ -758,285 +502,6 @@ bool PrinceEngine::playNextFLCFrame() {
return true;
}
-void PrinceEngine::playSample(uint16 sampleId, uint16 loopType) {
- if (_audioStream[sampleId]) {
- if (_mixer->isSoundIDActive(sampleId)) {
- return;
- }
- _audioStream[sampleId]->rewind();
- if (sampleId < 28) {
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
- } else {
- _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
- }
- }
-}
-
-void PrinceEngine::stopSample(uint16 sampleId) {
- _mixer->stopID(sampleId);
-}
-
-void PrinceEngine::stopAllSamples() {
- _mixer->stopAll();
-}
-
-void PrinceEngine::freeSample(uint16 sampleId) {
- stopSample(sampleId);
- if (_audioStream[sampleId] != nullptr) {
- delete _audioStream[sampleId];
- _audioStream[sampleId] = nullptr;
- }
-}
-
-void PrinceEngine::freeAllSamples() {
- for (int sampleId = 0; sampleId < kMaxSamples; sampleId++) {
- freeSample(sampleId);
- }
-}
-
-bool PrinceEngine::loadSample(uint32 sampleSlot, const Common::String &streamName) {
- // FIXME: This is just a workaround streamName is a path
- // SOUND\\SCIERKA1.WAV for now only last path component is used
- Common::String normalizedPath = lastPathComponent(streamName, '\\');
-
- // WALKAROUND: Wrong name in script, not existing sound in data files
- if (!normalizedPath.compareTo("9997BEKA.WAV")) {
- return 0;
- }
-
- debugEngine("loadSample slot %d, name %s", sampleSlot, normalizedPath.c_str());
-
- freeSample(sampleSlot);
- Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(normalizedPath);
- if (sampleStream == nullptr) {
- delete sampleStream;
- error("Can't load sample %s to slot %d", normalizedPath.c_str(), sampleSlot);
- }
- _audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream, DisposeAfterUse::NO);
- delete sampleStream;
- return true;
-}
-
-bool PrinceEngine::loadVoice(uint32 slot, uint32 sampleSlot, const Common::String &streamName) {
- debugEngine("Loading wav %s slot %d", streamName.c_str(), slot);
-
- if (slot >= kMaxTexts) {
- error("Text slot bigger than MAXTEXTS %d", kMaxTexts - 1);
- return false;
- }
-
- freeSample(sampleSlot);
- Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(streamName);
- if (sampleStream == nullptr) {
- debug("Can't open %s", streamName.c_str());
- return false;
- }
-
- uint32 id = sampleStream->readUint32LE();
- if (id != MKTAG('F', 'F', 'I', 'R')) {
- error("It's not RIFF file %s", streamName.c_str());
- return false;
- }
-
- sampleStream->skip(0x20);
- id = sampleStream->readUint32LE();
- if (id != MKTAG('a', 't', 'a', 'd')) {
- error("No data section in %s id %04x", streamName.c_str(), id);
- return false;
- }
-
- id = sampleStream->readUint32LE();
- debugEngine("SetVoice slot %d time %04x", slot, id);
- id <<= 3;
- id /= 22050;
- id += 2;
-
- _textSlots[slot]._time = id;
- if (!slot) {
- _mainHero->_talkTime = id;
- } else if (slot == 1) {
- _secondHero->_talkTime = id;
- }
-
- debugEngine("SetVoice slot %d time %04x", slot, id);
- sampleStream->seek(SEEK_SET);
- _audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream, DisposeAfterUse::NO);
- delete sampleStream;
- return true;
-}
-
-void PrinceEngine::setVoice(uint16 slot, uint32 sampleSlot, uint16 flag) {
- Common::String sampleName;
- uint32 currentString = _interpreter->getCurrentString();
-
- if (currentString >= 80000) {
- uint32 nr = currentString - 80000;
- sampleName = Common::String::format("%02d0%02d-%02d.WAV", nr / 100, nr % 100, flag);
- } else if (currentString >= 70000) {
- sampleName = Common::String::format("inv%02d-01.WAV", currentString - 70000);
- } else if (currentString >= 60000) {
- sampleName = Common::String::format("M%04d-%02d.WAV", currentString - 60000, flag);
- } else if (currentString >= 2000) {
- return;
- } else if (flag >= 100) {
- sampleName = Common::String::format("%03d-%03d.WAV", currentString, flag);
- } else {
- sampleName = Common::String::format("%03d-%02d.WAV", currentString, flag);
- }
-
- loadVoice(slot, sampleSlot, sampleName);
-}
-
-bool PrinceEngine::loadAnim(uint16 animNr, bool loop) {
- Common::String streamName = Common::String::format("AN%02d", animNr);
- Common::SeekableReadStream *flicStream = SearchMan.createReadStreamForMember(streamName);
-
- if (!flicStream) {
- error("Can't open %s", streamName.c_str());
- return false;
- }
-
- if (!_flicPlayer.loadStream(flicStream)) {
- error("Can't load flic stream %s", streamName.c_str());
- }
-
- debugEngine("%s loaded", streamName.c_str());
- _flicLooped = loop;
- _flicPlayer.start();
- playNextFLCFrame();
- return true;
-}
-
-bool PrinceEngine::loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName) {
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
- if (!stream) {
- delete stream;
- return false;
- }
- if (stream->read(zoomBitmap, dataSize) != dataSize) {
- free(zoomBitmap);
- delete stream;
- return false;
- }
- delete stream;
- return true;
-}
-
-bool PrinceEngine::loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2) {
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName1);
- if (!stream) {
- delete stream;
- return false;
- }
-
- if (stream->read(shadowBitmap, dataSize) != dataSize) {
- free(shadowBitmap);
- delete stream;
- return false;
- }
-
- Common::SeekableReadStream *stream2 = SearchMan.createReadStreamForMember(resourceName2);
- if (!stream2) {
- delete stream;
- delete stream2;
- return false;
- }
-
- byte *shadowBitmap2 = shadowBitmap + dataSize;
- if (stream2->read(shadowBitmap2, dataSize) != dataSize) {
- free(shadowBitmap);
- delete stream;
- delete stream2;
- return false;
- }
-
- delete stream;
- delete stream2;
- return true;
-}
-
-bool PrinceEngine::loadTrans(byte *transTable, const char *resourceName) {
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
- if (!stream) {
- delete stream;
- for (int i = 0; i < 256; i++) {
- for (int j = 0; j < 256; j++) {
- transTable[i * 256 + j] = j;
- }
- }
- return true;
- }
- if (stream->read(transTable, kTransTableSize) != kTransTableSize) {
- delete stream;
- return false;
- }
- delete stream;
- return true;
-}
-
-bool PrinceEngine::loadPath(const char *resourceName) {
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
- if (!stream) {
- delete stream;
- return false;
- }
- if (stream->read(_roomPathBitmap, kPathBitmapLen) != kPathBitmapLen) {
- delete stream;
- return false;
- }
- delete stream;
- return true;
-}
-
-bool PrinceEngine::loadAllInv() {
- for (int i = 0; i < kMaxInv; i++) {
- InvItem tempInvItem;
-
- const Common::String invStreamName = Common::String::format("INV%02d", i);
- Common::SeekableReadStream *invStream = SearchMan.createReadStreamForMember(invStreamName);
- if (!invStream) {
- delete invStream;
- return true;
- }
-
- tempInvItem._x = invStream->readUint16LE();
- tempInvItem._y = invStream->readUint16LE();
- int width = invStream->readUint16LE();
- int height = invStream->readUint16LE();
- tempInvItem._surface = new Graphics::Surface();
- tempInvItem._surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
-
- for (int h = 0; h < tempInvItem._surface->h; h++) {
- invStream->read(tempInvItem._surface->getBasePtr(0, h), tempInvItem._surface->w);
- }
-
- _allInvList.push_back(tempInvItem);
- delete invStream;
- }
-
- return true;
-}
-
-bool PrinceEngine::loadMobPriority(const char *resourceName) {
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
- if (!stream) {
- delete stream;
- return false;
- }
-
- _mobPriorityList.clear();
- uint mobId;
- while (1) {
- mobId = stream->readUint32LE();
- if (mobId == 0xFFFFFFFF) {
- break;
- }
- _mobPriorityList.push_back(mobId);
- }
- delete stream;
- return true;
-}
-
void PrinceEngine::loadMobTranslationTexts() {
Common::SeekableReadStream *mobTranslationStream = SearchMan.createReadStreamForMember("mob_translate.dat");
if (!mobTranslationStream) {
@@ -1079,6 +544,14 @@ void PrinceEngine::setMobTranslationTexts() {
void PrinceEngine::keyHandler(Common::Event event) {
uint16 nChar = event.kbd.keycode;
switch (nChar) {
+ case Common::KEYCODE_F1:
+ if (canLoadGameStateCurrently())
+ scummVMSaveLoadDialog(false);
+ break;
+ case Common::KEYCODE_F2:
+ if (canSaveGameStateCurrently())
+ scummVMSaveLoadDialog(true);
+ break;
case Common::KEYCODE_d:
if (event.kbd.hasFlags(Common::KBD_CTRL)) {
getDebugger()->attach();
@@ -1100,160 +573,6 @@ void PrinceEngine::keyHandler(Common::Event event) {
}
}
-int PrinceEngine::getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY) {
-
- Common::Point pointPos(posX, posY);
-
- int mobListSize;
- if (usePriorityList) {
- mobListSize = _mobPriorityList.size();
- } else {
- mobListSize = mobList.size();
- }
-
- for (int mobNumber = 0; mobNumber < mobListSize; mobNumber++) {
- Mob *mob = nullptr;
- if (usePriorityList) {
- mob = &mobList[_mobPriorityList[mobNumber]];
- } else {
- mob = &mobList[mobNumber];
- }
-
- if (mob->_visible) {
- continue;
- }
-
- int type = mob->_type & 7;
- switch (type) {
- case 0:
- case 1:
- //normal_mob
- if (!mob->_rect.contains(pointPos)) {
- continue;
- }
- break;
- case 3:
- //mob_obj
- if (mob->_mask < kMaxObjects) {
- int nr = _objSlot[mob->_mask];
- if (nr != 0xFF) {
- Object &obj = *_objList[nr];
- Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
- if (objectRect.contains(pointPos)) {
- Graphics::Surface *objSurface = obj.getSurface();
- byte *pixel = (byte *)objSurface->getBasePtr(posX - obj._x, posY - obj._y);
- if (*pixel != 255) {
- break;
- }
- }
- }
- }
- continue;
- break;
- case 2:
- case 5:
- //check_ba_mob
- if (!_backAnimList[mob->_mask].backAnims.empty()) {
- int currentAnim = _backAnimList[mob->_mask]._seq._currRelative;
- Anim &backAnim = _backAnimList[mob->_mask].backAnims[currentAnim];
- if (backAnim._animData != nullptr) {
- if (!backAnim._state) {
- Common::Rect backAnimRect(backAnim._currX, backAnim._currY, backAnim._currX + backAnim._currW, backAnim._currY + backAnim._currH);
- if (backAnimRect.contains(pointPos)) {
- int phase = backAnim._showFrame;
- int phaseFrameIndex = backAnim._animData->getPhaseFrameIndex(phase);
- Graphics::Surface *backAnimSurface = backAnim._animData->getFrame(phaseFrameIndex);
- byte pixel = *(byte *)backAnimSurface->getBasePtr(posX - backAnim._currX, posY - backAnim._currY);
- if (pixel != 255) {
- if (type == 5) {
- if (mob->_rect.contains(pointPos)) {
- break;
- }
- } else {
- break;
- }
- }
- }
- }
- }
- }
- continue;
- break;
- default:
- //not_part_ba
- continue;
- break;
- }
-
- if (usePriorityList) {
- return _mobPriorityList[mobNumber];
- } else {
- return mobNumber;
- }
- }
- return -1;
-}
-
-int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) {
- if (_mouseFlag == 0 || _mouseFlag == 3) {
- return -1;
- }
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y);
-
- if (mobNumber != -1) {
- Common::String mobName = mobList[mobNumber]._name;
-
- if (getLanguage() == Common::DE_DEU) {
- for (uint i = 0; i < mobName.size(); i++) {
- switch (mobName[i]) {
- case '\xc4':
- mobName.setChar('\x83', i);
- break;
- case '\xd6':
- mobName.setChar('\x84', i);
- break;
- case '\xdc':
- mobName.setChar('\x85', i);
- break;
- case '\xdf':
- mobName.setChar('\x7f', i);
- break;
- case '\xe4':
- mobName.setChar('\x80', i);
- break;
- case '\xf6':
- mobName.setChar('\x81', i);
- break;
- case '\xfc':
- mobName.setChar('\x82', i);
- break;
- }
- }
- }
-
- uint16 textW = getTextWidth(mobName.c_str());
-
- uint16 x = mousePos.x - textW / 2;
- if (x > screen->w) {
- x = 0;
- }
-
- if (x + textW > screen->w) {
- x = screen->w - textW;
- }
-
- uint16 y = mousePos.y - _font->getFontHeight();
- if (y > screen->h) {
- y = _font->getFontHeight() - 2;
- }
-
- _font->drawString(screen, mobName, x, y, screen->w, 216);
- }
-
- return mobNumber;
-}
-
void PrinceEngine::printAt(uint32 slot, uint8 color, char *s, uint16 x, uint16 y) {
debugC(1, DebugChannel::kEngine, "PrinceEngine::printAt slot %d, color %d, x %02d, y %02d, str %s", slot, color, x, y, s);
@@ -1383,677 +702,6 @@ void PrinceEngine::showTexts(Graphics::Surface *screen) {
}
}
-bool PrinceEngine::spriteCheck(int sprWidth, int sprHeight, int destX, int destY) {
- destX -= _picWindowX;
- destY -= _picWindowY;
-
- // if x1 is on visible part of screen
- if (destX < 0) {
- if (destX + sprWidth < 1) {
- //x2 is negative - out of window
- return false;
- }
- }
- // if x1 is outside of screen on right side
- if (destX >= kNormalWidth) {
- return false;
- }
-
- if (destY < 0) {
- if (destY + sprHeight < 1) {
- //y2 is negative - out of window
- return false;
- }
- }
- if (destY >= kNormalHeight) {
- return false;
- }
-
- return true;
-}
-
-// CheckNak
-void PrinceEngine::checkMasks(int x1, int y1, int sprWidth, int sprHeight, int z) {
- int x2 = x1 + sprWidth - 1;
- int y2 = y1 + sprHeight - 1;
- if (x1 < 0) {
- x1 = 0;
- }
- for (uint i = 0; i < _maskList.size(); i++) {
- if (!_maskList[i]._state && !_maskList[i]._flags) {
- if (_maskList[i]._z > z) {
- if (_maskList[i]._x1 <= x2 && _maskList[i]._x2 >= x1) {
- if (_maskList[i]._y1 <= y2 && _maskList[i]._y2 >= y1) {
- _maskList[i]._state = 1;
- }
- }
- }
- }
- }
-}
-
-// ClsNak
-void PrinceEngine::clsMasks() {
- for (uint i = 0; i < _maskList.size(); i++) {
- if (_maskList[i]._state) {
- _maskList[i]._state = 0;
- }
- }
-}
-
-// InsertNakladki
-void PrinceEngine::insertMasks(Graphics::Surface *originalRoomSurface) {
- for (uint i = 0; i < _maskList.size(); i++) {
- if (_maskList[i]._state) {
- if (_maskList[i]._data != nullptr) {
- showMask(i, originalRoomSurface);
- } else {
- error("insertMasks() - Wrong mask data- nr %d", i);
- }
- }
- }
-}
-
-// ShowNak
-void PrinceEngine::showMask(int maskNr, Graphics::Surface *originalRoomSurface) {
- if (!_maskList[maskNr]._flags) {
- if (spriteCheck(_maskList[maskNr]._width, _maskList[maskNr]._height, _maskList[maskNr]._x1, _maskList[maskNr]._y1)) {
- int destX = _maskList[maskNr]._x1 - _picWindowX;
- int destY = _maskList[maskNr]._y1 - _picWindowY;
- DrawNode newDrawNode;
- newDrawNode.posX = destX;
- newDrawNode.posY = destY;
- newDrawNode.posZ = _maskList[maskNr]._z;
- newDrawNode.width = _maskList[maskNr]._width;
- newDrawNode.height = _maskList[maskNr]._height;
- newDrawNode.s = nullptr;
- newDrawNode.originalRoomSurface = originalRoomSurface;
- newDrawNode.data = _maskList[maskNr].getMask();
- newDrawNode.drawFunction = &_graph->drawMaskDrawNode;
- _drawNodeList.push_back(newDrawNode);
- }
- }
-}
-
-void PrinceEngine::showSprite(Graphics::Surface *spriteSurface, int destX, int destY, int destZ) {
- if (spriteCheck(spriteSurface->w, spriteSurface->h, destX, destY)) {
- destX -= _picWindowX;
- destY -= _picWindowY;
- DrawNode newDrawNode;
- newDrawNode.posX = destX;
- newDrawNode.posY = destY;
- newDrawNode.posZ = destZ;
- newDrawNode.width = 0;
- newDrawNode.height = 0;
- newDrawNode.s = spriteSurface;
- newDrawNode.originalRoomSurface = nullptr;
- newDrawNode.data = _transTable;
- newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
- _drawNodeList.push_back(newDrawNode);
- }
-}
-
-void PrinceEngine::showSpriteShadow(Graphics::Surface *shadowSurface, int destX, int destY, int destZ) {
- if (spriteCheck(shadowSurface->w, shadowSurface->h, destX, destY)) {
- destX -= _picWindowX;
- destY -= _picWindowY;
- DrawNode newDrawNode;
- newDrawNode.posX = destX;
- newDrawNode.posY = destY;
- newDrawNode.posZ = destZ;
- newDrawNode.width = 0;
- newDrawNode.height = 0;
- newDrawNode.s = shadowSurface;
- newDrawNode.originalRoomSurface = nullptr;
- newDrawNode.data = _graph->_shadowTable70;
- newDrawNode.drawFunction = &_graph->drawAsShadowDrawNode;
- _drawNodeList.push_back(newDrawNode);
- }
-}
-
-void PrinceEngine::showAnim(Anim &anim) {
- //ShowFrameCode
- //ShowAnimFrame
- int phase = anim._showFrame;
- int phaseFrameIndex = anim._animData->getPhaseFrameIndex(phase);
- int x = anim._x + anim._animData->getPhaseOffsetX(phase);
- int y = anim._y + anim._animData->getPhaseOffsetY(phase);
- int animFlag = anim._flags;
- int checkMaskFlag = (animFlag & 1);
- int maxFrontFlag = (animFlag & 2);
- int specialZFlag = anim._nextAnim;
- int z = anim._nextAnim;
- Graphics::Surface *animSurface = anim._animData->getFrame(phaseFrameIndex);
- int frameWidth = animSurface->w;
- int frameHeight = animSurface->h;
- int shadowZ = 0;
-
- if (checkMaskFlag) {
- if (!anim._nextAnim) {
- z = y + frameHeight - 1;
- }
- checkMasks(x, y, frameWidth, frameHeight, z);
- }
-
- if (specialZFlag) {
- z = specialZFlag;
- } else if (maxFrontFlag) {
- z = kMaxPicHeight + 1;
- } else {
- z = y + frameHeight - 1;
- }
- shadowZ = z;
-
- anim._currX = x;
- anim._currY = y;
- anim._currW = frameWidth;
- anim._currH = frameHeight;
- showSprite(animSurface, x, y, z);
-
- // make_special_shadow
- if ((anim._flags & 0x80)) {
- DrawNode newDrawNode;
- newDrawNode.posX = x;
- newDrawNode.posY = y + animSurface->h - anim._shadowBack;
- newDrawNode.posZ = Hero::kHeroShadowZ;
- newDrawNode.width = 0;
- newDrawNode.height = 0;
- newDrawNode.scaleValue = _scaleValue;
- newDrawNode.originalRoomSurface = nullptr;
- newDrawNode.data = this;
- newDrawNode.drawFunction = &Hero::showHeroShadow;
- newDrawNode.s = animSurface;
- _drawNodeList.push_back(newDrawNode);
- }
-
- //ShowFrameCodeShadow
- //ShowAnimFrameShadow
- if (anim._shadowData != nullptr) {
- int shadowPhaseFrameIndex = anim._shadowData->getPhaseFrameIndex(phase);
- int shadowX = anim._shadowData->getBaseX() + anim._shadowData->getPhaseOffsetX(phase);
- int shadowY = anim._shadowData->getBaseY() + anim._shadowData->getPhaseOffsetY(phase);
- Graphics::Surface *shadowSurface = anim._shadowData->getFrame(shadowPhaseFrameIndex);
- int shadowFrameWidth = shadowSurface->w;
- int shadowFrameHeight = shadowSurface->h;
-
- if (checkMaskFlag) {
- checkMasks(shadowX, shadowY, shadowFrameWidth, shadowFrameHeight, shadowY + shadowFrameWidth - 1);
- }
-
- if (!shadowZ) {
- if (maxFrontFlag) {
- shadowZ = kMaxPicHeight + 1;
- } else {
- shadowZ = shadowY + shadowFrameWidth - 1;
- }
- }
- showSpriteShadow(shadowSurface, shadowX, shadowY, shadowZ);
- }
-}
-
-void PrinceEngine::showNormAnims() {
- for (int i = 0; i < kMaxNormAnims; i++) {
- Anim &anim = _normAnimList[i];
- if (anim._animData != nullptr) {
- int phaseCount = anim._animData->getPhaseCount();
- if (!anim._state) {
- if (anim._frame == anim._lastFrame - 1) {
- if (anim._loopType) {
- if (anim._loopType == 1) {
- anim._frame = anim._loopFrame;
- } else {
- continue;
- }
- }
- } else {
- anim._frame++;
- }
- anim._showFrame = anim._frame;
- if (anim._showFrame >= phaseCount) {
- anim._showFrame = phaseCount - 1;
- }
- showAnim(anim);
- }
- }
- }
-}
-
-void PrinceEngine::setBackAnim(Anim &backAnim) {
- int start = backAnim._basaData._start;
- if (start != -1) {
- backAnim._frame = start;
- backAnim._showFrame = start;
- backAnim._loopFrame = start;
- }
- int end = backAnim._basaData._end;
- if (end != -1) {
- backAnim._lastFrame = end;
- }
- backAnim._state = 0;
-}
-
-void PrinceEngine::showBackAnims() {
- for (int i = 0; i < kMaxBackAnims; i++) {
- BAS &seq = _backAnimList[i]._seq;
- int activeSubAnim = seq._currRelative;
- if (!_backAnimList[i].backAnims.empty()) {
- if (_backAnimList[i].backAnims[activeSubAnim]._animData != nullptr) {
- if (!_backAnimList[i].backAnims[activeSubAnim]._state) {
- seq._counter++;
- if (seq._type == 2) {
- if (!seq._currRelative) {
- if (seq._counter >= seq._data) {
- if (seq._anims > 2) {
- seq._currRelative = _randomSource.getRandomNumber(seq._anims - 2) + 1;
- activeSubAnim = seq._currRelative;
- seq._current = _backAnimList[i].backAnims[activeSubAnim]._basaData._num;
- }
- setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
- seq._counter = 0;
- }
- }
- }
-
- if (seq._type == 3) {
- if (!seq._currRelative) {
- if (seq._counter < seq._data2) {
- continue;
- } else {
- setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
- }
- }
- }
-
- if (_backAnimList[i].backAnims[activeSubAnim]._frame == _backAnimList[i].backAnims[activeSubAnim]._lastFrame - 1) {
- _backAnimList[i].backAnims[activeSubAnim]._frame = _backAnimList[i].backAnims[activeSubAnim]._loopFrame;
- switch (seq._type) {
- case 1:
- if (seq._anims > 1) {
- int rnd;
- do {
- rnd = _randomSource.getRandomNumber(seq._anims - 1);
- } while (rnd == seq._currRelative);
- seq._currRelative = rnd;
- seq._current = _backAnimList[i].backAnims[rnd]._basaData._num;
- activeSubAnim = rnd;
- setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
- seq._counter = 0;
- }
- break;
- case 2:
- if (seq._currRelative) {
- seq._currRelative = 0;
- seq._current = _backAnimList[i].backAnims[0]._basaData._num;
- activeSubAnim = 0;
- setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
- seq._counter = 0;
- }
- break;
- case 3:
- seq._currRelative = 0;
- seq._current = _backAnimList[i].backAnims[0]._basaData._num;
- seq._counter = 0;
- seq._data2 = _randomSource.getRandomNumber(seq._data - 1);
- continue; // for bug in original game
- break;
- }
- } else {
- _backAnimList[i].backAnims[activeSubAnim]._frame++;
- }
- _backAnimList[i].backAnims[activeSubAnim]._showFrame = _backAnimList[i].backAnims[activeSubAnim]._frame;
- showAnim(_backAnimList[i].backAnims[activeSubAnim]);
- }
- }
- }
- }
-}
-
-void PrinceEngine::removeSingleBackAnim(int slot) {
- if (!_backAnimList[slot].backAnims.empty()) {
- for (uint j = 0; j < _backAnimList[slot].backAnims.size(); j++) {
- if (_backAnimList[slot].backAnims[j]._animData != nullptr) {
- delete _backAnimList[slot].backAnims[j]._animData;
- _backAnimList[slot].backAnims[j]._animData = nullptr;
- }
- if (_backAnimList[slot].backAnims[j]._shadowData != nullptr) {
- delete _backAnimList[slot].backAnims[j]._shadowData;
- _backAnimList[slot].backAnims[j]._shadowData = nullptr;
- }
- }
- _backAnimList[slot].backAnims.clear();
- _backAnimList[slot]._seq._currRelative = 0;
- }
-}
-
-void PrinceEngine::clearBackAnimList() {
- for (int i = 0; i < kMaxBackAnims; i++) {
- removeSingleBackAnim(i);
- }
-}
-
-void PrinceEngine::grabMap() {
- _graph->_frontScreen->copyFrom(*_roomBmp->getSurface());
- showObjects();
- runDrawNodes();
- _graph->_mapScreen->copyFrom(*_graph->_frontScreen);
-}
-
-void PrinceEngine::initZoomIn(int slot) {
- freeZoomObject(slot);
- Object *object = _objList[slot];
- if (object != nullptr) {
- Graphics::Surface *zoomSource = object->getSurface();
- if (zoomSource != nullptr) {
- object->_flags |= 0x8000;
- object->_zoomSurface = new Graphics::Surface();
- object->_zoomSurface->create(zoomSource->w, zoomSource->h, Graphics::PixelFormat::createFormatCLUT8());
- object->_zoomSurface->fillRect(Common::Rect(zoomSource->w, zoomSource->h), 0xFF);
- object->_zoomTime = 20;
- }
- }
-}
-
-void PrinceEngine::initZoomOut(int slot) {
- freeZoomObject(slot);
- Object *object = _objList[slot];
- if (object != nullptr) {
- Graphics::Surface *zoomSource = object->getSurface();
- if (zoomSource != nullptr) {
- object->_flags |= 0x4000;
- object->_zoomSurface = new Graphics::Surface();
- object->_zoomSurface->copyFrom(*zoomSource);
- object->_zoomTime = 10;
- }
- }
-}
-
-void PrinceEngine::doZoomIn(int slot) {
- Object *object = _objList[slot];
- if (object != nullptr) {
- Graphics::Surface *orgSurface = object->getSurface();
- if (orgSurface != nullptr) {
- byte *src1 = (byte *)orgSurface->getBasePtr(0, 0);
- byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
- int x = 0;
- int surfaceHeight = orgSurface->h;
- for (int y = 0; y < surfaceHeight; y++) {
- byte *src2 = src1;
- byte *dst2 = dst1;
- int w = orgSurface->w - x;
- src2 += x;
- dst2 += x;
- while (w > 0) {
- int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
- if (randVal < w) {
- *(dst2 + randVal) = *(src2 + randVal);
- src2 += zoomInStep;
- dst2 += zoomInStep;
- } else if (y + 1 != surfaceHeight) {
- *(dst1 + orgSurface->pitch + randVal - w) = *(src1 + orgSurface->pitch + randVal - w);
- }
- w -= zoomInStep;
- }
- x = -1 * w;
- src1 += orgSurface->pitch;
- dst1 += orgSurface->pitch;
- }
- }
- }
-}
-
-void PrinceEngine::doZoomOut(int slot) {
- Object *object = _objList[slot];
- if (object != nullptr) {
- Graphics::Surface *orgSurface = object->getSurface();
- if (orgSurface != nullptr) {
- byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
- int x = 0;
- int surfaceHeight = orgSurface->h;
- for (int y = 0; y < surfaceHeight; y++) {
- byte *dst2 = dst1;
- int w = orgSurface->w - x;
- dst2 += x;
- while (w > 0) {
- int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
- if (randVal < w) {
- *(dst2 + randVal) = 255;
- dst2 += zoomInStep;
- } else if (y + 1 != surfaceHeight) {
- *(dst1 + orgSurface->pitch + randVal - w) = 255;
- }
- w -= zoomInStep;
- }
- x = -1 * w;
- dst1 += orgSurface->pitch;
- }
- }
- }
-}
-
-void PrinceEngine::freeZoomObject(int slot) {
- Object *object = _objList[slot];
- if (object != nullptr) {
- if (object->_zoomSurface != nullptr) {
- object->_zoomSurface->free();
- delete object->_zoomSurface;
- object->_zoomSurface = nullptr;
- }
- }
-}
-
-void PrinceEngine::showObjects() {
- for (int i = 0; i < kMaxObjects; i++) {
- int nr = _objSlot[i];
- if (nr != 0xFF) {
- Graphics::Surface *objSurface = nullptr;
- if ((_objList[nr]->_flags & 0x8000)) {
- _objList[nr]->_zoomTime--;
- if (!_objList[nr]->_zoomTime) {
- freeZoomObject(nr);
- _objList[nr]->_flags &= 0x7FFF;
- objSurface = _objList[nr]->getSurface();
- } else {
- doZoomIn(nr);
- objSurface = _objList[nr]->_zoomSurface;
- }
- } else if ((_objList[nr]->_flags & 0x4000)) {
- _objList[nr]->_zoomTime--;
- if (!_objList[nr]->_zoomTime) {
- freeZoomObject(nr);
- _objList[nr]->_flags &= 0xBFFF;
- objSurface = _objList[nr]->getSurface();
- } else {
- doZoomOut(nr);
- objSurface = _objList[nr]->_zoomSurface;
- }
- } else {
- objSurface = _objList[nr]->getSurface();
- }
-
- if (objSurface != nullptr) {
- if (spriteCheck(objSurface->w, objSurface->h, _objList[nr]->_x, _objList[nr]->_y)) {
- int destX = _objList[nr]->_x - _picWindowX;
- int destY = _objList[nr]->_y - _picWindowY;
- DrawNode newDrawNode;
- newDrawNode.posX = destX;
- newDrawNode.posY = destY;
- newDrawNode.posZ = _objList[nr]->_z;
- newDrawNode.width = 0;
- newDrawNode.height = 0;
- newDrawNode.s = objSurface;
- newDrawNode.originalRoomSurface = nullptr;
- if ((_objList[nr]->_flags & 0x2000)) {
- newDrawNode.data = nullptr;
- newDrawNode.drawFunction = &_graph->drawBackSpriteDrawNode;
- } else {
- newDrawNode.data = _transTable;
- if (_flags->getFlagValue(Flags::NOANTIALIAS)) {
- newDrawNode.drawFunction = &_graph->drawTransparentDrawNode;
- } else {
- newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
- }
- }
- _drawNodeList.push_back(newDrawNode);
- }
-
- if ((_objList[nr]->_flags & 1)) {
- checkMasks(_objList[nr]->_x, _objList[nr]->_y, objSurface->w, objSurface->h, _objList[nr]->_z);
- }
- }
- }
- }
-}
-
-void PrinceEngine::showParallax() {
- if (!_pscrList.empty()) {
- for (uint i = 0; i < _pscrList.size(); i++) {
- Graphics::Surface *pscrSurface = _pscrList[i]->getSurface();
- if (pscrSurface != nullptr) {
- int x = _pscrList[i]->_x - (_pscrList[i]->_step * _picWindowX / 4);
- int y = _pscrList[i]->_y;
- int z = PScr::kPScrZ;
- if (spriteCheck(pscrSurface->w, pscrSurface->h, x, y)) {
- showSprite(pscrSurface, x, y, z);
- }
- }
- }
- }
-}
-
-bool PrinceEngine::compareDrawNodes(DrawNode d1, DrawNode d2) {
- if (d1.posZ < d2.posZ) {
- return true;
- }
- return false;
-}
-
-void PrinceEngine::runDrawNodes() {
- Common::sort(_drawNodeList.begin(), _drawNodeList.end(), compareDrawNodes);
-
- for (uint i = 0; i < _drawNodeList.size(); i++) {
- (*_drawNodeList[i].drawFunction)(_graph->_frontScreen, &_drawNodeList[i]);
- }
- _graph->change();
-}
-
-void PrinceEngine::drawScreen() {
- if (!_showInventoryFlag || _inventoryBackgroundRemember) {
- clsMasks();
-
- _mainHero->showHero();
- _mainHero->scrollHero();
- _mainHero->drawHero();
-
- _secondHero->showHero();
- _secondHero->_drawX -= _picWindowX;
- _secondHero->drawHero();
-
- const Graphics::Surface *roomSurface;
- if (_locationNr != 50) {
- roomSurface = _roomBmp->getSurface();
- } else {
- roomSurface = _graph->_mapScreen;
- }
- Graphics::Surface visiblePart;
- if (roomSurface) {
- visiblePart = roomSurface->getSubArea(Common::Rect(_picWindowX, 0, roomSurface->w, roomSurface->h));
- _graph->draw(_graph->_frontScreen, &visiblePart);
- }
-
- showBackAnims();
-
- showNormAnims();
-
- playNextFLCFrame();
-
- showObjects();
-
- if (roomSurface) {
- insertMasks(&visiblePart);
- }
-
- showParallax();
-
- runDrawNodes();
-
- _drawNodeList.clear();
-
- if (!_inventoryBackgroundRemember && !_dialogFlag) {
- if (!_optionsFlag) {
- _selectedMob = checkMob(_graph->_frontScreen, _mobList, true);
- }
- showTexts(_graph->_frontScreen);
- checkOptions();
- } else {
- _inventoryBackgroundRemember = false;
- }
-
- showPower();
-
- getDebugger()->onFrame();
-
- } else {
- displayInventory();
- }
-}
-
-void PrinceEngine::blackPalette() {
- byte *paletteBackup = (byte *)malloc(256 * 3);
- byte *blackPalette1 = (byte *)malloc(256 * 3);
-
- int fadeStep = kFadeStep - 1;
- for (int i = 0; i < kFadeStep; i++) {
- _system->getPaletteManager()->grabPalette(paletteBackup, 0, 256);
- for (int j = 0; j < 256; j++) {
- blackPalette1[3 * j] = paletteBackup[3 * j] * fadeStep / 4;
- blackPalette1[3 * j + 1] = paletteBackup[3 * j + 1] * fadeStep / 4;
- blackPalette1[3 * j + 2] = paletteBackup[3 * j + 2] * fadeStep / 4;
- }
- fadeStep--;
- _graph->setPalette(blackPalette1);
- _system->updateScreen();
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- free(paletteBackup);
- free(blackPalette1);
- return;
- }
- pausePrinceEngine();
- }
- free(paletteBackup);
- free(blackPalette1);
-}
-
-void PrinceEngine::setPalette(const byte *palette) {
- if (palette != nullptr) {
- byte *blackPalette_ = (byte *)malloc(256 * 3);
- int fadeStep = 0;
- for (int i = 0; i <= kFadeStep; i++) {
- for (int j = 0; j < 256; j++) {
- blackPalette_[3 * j] = palette[3 * j] * fadeStep / 4;
- blackPalette_[3 * j + 1] = palette[3 * j + 1] * fadeStep / 4;
- blackPalette_[3 * j + 2] = palette[3 * j + 2] * fadeStep / 4;
- }
- fadeStep++;
- _graph->setPalette(blackPalette_);
- _system->updateScreen();
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- _graph->setPalette(palette);
- free(blackPalette_);
- return;
- }
- pausePrinceEngine();
- }
- _graph->setPalette(palette);
- free(blackPalette_);
- }
-}
-
void PrinceEngine::pausePrinceEngine(int fps) {
int delay = 1000 / fps - int32(_system->getMillis() - _currentTime);
delay = delay < 0 ? 0 : delay;
@@ -2061,369 +709,6 @@ void PrinceEngine::pausePrinceEngine(int fps) {
_currentTime = _system->getMillis();
}
-void PrinceEngine::addInv(int heroId, int item, bool addItemQuiet) {
- Hero *hero = nullptr;
- if (!heroId) {
- hero = _mainHero;
- } else if (heroId == 1) {
- hero = _secondHero;
- }
- if (hero != nullptr) {
- if (hero->_inventory.size() < kMaxItems) {
- if (item != 0x7FFF) {
- hero->_inventory.push_back(item);
- }
- if (!addItemQuiet) {
- addInvObj();
- }
- _interpreter->setResult(0);
- } else {
- _interpreter->setResult(1);
- }
- }
-}
-
-void PrinceEngine::remInv(int heroId, int item) {
- Hero *hero = nullptr;
- if (!heroId) {
- hero = _mainHero;
- } else if (heroId == 1) {
- hero = _secondHero;
- }
- if (hero != nullptr) {
- for (uint i = 0; i < hero->_inventory.size(); i++) {
- if (hero->_inventory[i] == item) {
- hero->_inventory.remove_at(i);
- _interpreter->setResult(0);
- return;
- }
- }
- }
- _interpreter->setResult(1);
-}
-
-void PrinceEngine::clearInv(int heroId) {
- switch (heroId) {
- case 0:
- _mainHero->_inventory.clear();
- break;
- case 1:
- _secondHero->_inventory.clear();
- break;
- default:
- error("clearInv() - wrong hero slot");
- break;
- }
-}
-
-void PrinceEngine::swapInv(int heroId) {
- Common::Array<int> tempInv;
- Hero *hero = nullptr;
- if (!heroId) {
- hero = _mainHero;
- } else if (heroId == 1) {
- hero = _secondHero;
- }
- if (hero != nullptr) {
- for (uint i = 0; i < hero->_inventory.size(); i++) {
- tempInv.push_back(hero->_inventory[i]);
- }
- hero->_inventory.clear();
- for (uint i = 0; i < hero->_inventory2.size(); i++) {
- hero->_inventory.push_back(hero->_inventory2[i]);
- }
- hero->_inventory2.clear();
- for (uint i = 0; i < tempInv.size(); i++) {
- hero->_inventory2.push_back(tempInv[i]);
- }
- tempInv.clear();
- }
-}
-
-void PrinceEngine::addInvObj() {
- changeCursor(0);
- prepareInventoryToView();
-
- _inventoryBackgroundRemember = true;
- drawScreen();
-
- Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
-
- if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
-
- loadSample(27, "PRZEDMIO.WAV");
- playSample(27, 0);
-
- _mst_shadow2 = 1;
-
- while (_mst_shadow2 < 512) {
- rememberScreenInv();
- _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
- drawInvItems();
- _graph->update(_graph->_screenForInventory);
- _mst_shadow2 += 50;
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- return;
- }
- pausePrinceEngine();
- }
- while (_mst_shadow2 > 256) {
- rememberScreenInv();
- _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
- drawInvItems();
- _graph->update(_graph->_screenForInventory);
- _mst_shadow2 -= 42;
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- return;
- }
- pausePrinceEngine();
- }
- } else {
- //CURSEBLINK:
- for (int i = 0; i < 3; i++) {
- _mst_shadow2 = 256;
- while (_mst_shadow2 < 512) {
- rememberScreenInv();
- _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
- drawInvItems();
- _graph->update(_graph->_screenForInventory);
- _mst_shadow2 += 50;
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- return;
- }
- pausePrinceEngine();
- }
- while (_mst_shadow2 > 256) {
- rememberScreenInv();
- _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
- drawInvItems();
- _graph->update(_graph->_screenForInventory);
- _mst_shadow2 -= 50;
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- return;
- }
- pausePrinceEngine();
- }
- }
- }
- _mst_shadow2 = 0;
- for (int i = 0; i < 20; i++) {
- rememberScreenInv();
- _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
- drawInvItems();
- _graph->update(_graph->_screenForInventory);
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- eventMan->pollEvent(event);
- if (shouldQuit()) {
- return;
- }
- pausePrinceEngine();
- }
-}
-
-void PrinceEngine::rememberScreenInv() {
- _graph->_screenForInventory->copyFrom(*_graph->_frontScreen);
-}
-
-void PrinceEngine::inventoryFlagChange(bool inventoryState) {
- if (inventoryState) {
- _showInventoryFlag = true;
- _inventoryBackgroundRemember = true;
- } else {
- _showInventoryFlag = false;
- }
-}
-
-void PrinceEngine::prepareInventoryToView() {
- _invMobList.clear();
- int invItem = _mainHero->_inventory.size();
- _invLine = invItem / 3;
- if (invItem % 3) {
- _invLine++;
- }
- if (_invLine < 4) {
- _invLine = 4;
- }
- _maxInvW = (374 - 2 * _invLine) / _invLine;
- _invLineW = _maxInvW - 2;
-
- int currInvX = _invLineX;
- int currInvY = _invLineY;
-
- Common::MemoryReadStream stream(_invTxt, _invTxtSize);
- byte c;
-
- uint item = 0;
- for (int i = 0; i < _invLines; i++) {
- for (int j = 0; j < _invLine; j++) {
- Mob tempMobItem;
- if (item < _mainHero->_inventory.size()) {
- int itemNr = _mainHero->_inventory[item];
- tempMobItem._visible = 0;
- tempMobItem._mask = itemNr;
- tempMobItem._rect = Common::Rect(currInvX + _picWindowX, currInvY, currInvX + _picWindowX + _invLineW - 1, currInvY + _invLineH - 1);
- tempMobItem._type = 0; // to work with checkMob()
-
- tempMobItem._name = "";
- tempMobItem._examText = "";
- int txtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8]);
- int examTxtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8 + 4]);
-
- stream.seek(txtOffset);
- while ((c = stream.readByte())) {
- tempMobItem._name += c;
- }
-
- stream.seek(examTxtOffset);
- while ((c = stream.readByte())) {
- tempMobItem._examText += c;
- }
- _invMobList.push_back(tempMobItem);
- }
- currInvX += _invLineW + _invLineSkipX;
- item++;
- }
- currInvX = _invLineX;
- currInvY += _invLineSkipY + _invLineH;
- }
-}
-
-void PrinceEngine::drawInvItems() {
- int currInvX = _invLineX;
- int currInvY = _invLineY;
- uint item = 0;
- for (int i = 0; i < _invLines; i++) {
- for (int j = 0; j < _invLine; j++) {
- if (item < _mainHero->_inventory.size()) {
- int itemNr = _mainHero->_inventory[item];
- _mst_shadow = 0;
- if (_mst_shadow2) {
- if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
- if (item + 1 == _mainHero->_inventory.size()) { // last item in inventory
- _mst_shadow = 1;
- }
- } else if (itemNr == 1 || itemNr == 3 || itemNr == 4 || itemNr == 7) {
- _mst_shadow = 1;
- }
- }
-
- int drawX = currInvX;
- int drawY = currInvY;
- Graphics::Surface *itemSurface = nullptr;
- if (itemNr != 68) {
- itemSurface = _allInvList[itemNr].getSurface();
- if (itemSurface->h < _maxInvH) {
- drawY += (_maxInvH - itemSurface->h) / 2;
- }
- } else {
- // candle item:
- if (_candleCounter == 8) {
- _candleCounter = 0;
- }
- itemNr = _candleCounter;
- _candleCounter++;
- itemNr &= 7;
- itemNr += 71;
- itemSurface = _allInvList[itemNr].getSurface();
- drawY += _allInvList[itemNr]._y + (_maxInvH - 76) / 2 - 200;
- }
- if (itemSurface->w < _maxInvW) {
- drawX += (_maxInvW - itemSurface->w) / 2;
- }
- if (!_mst_shadow) {
- _graph->drawTransparentSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
- } else {
- _mst_shadow = _mst_shadow2;
- _graph->drawTransparentWithBlendSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
- }
- }
- currInvX += _invLineW + _invLineSkipX;
- item++;
- }
- currInvX = _invLineX;
- currInvY += _invLineSkipY + _invLineH;
- }
-}
-
-void PrinceEngine::walkTo() {
- if (_mainHero->_visible) {
- _mainHero->freeHeroAnim();
- _mainHero->freeOldMove();
- _interpreter->storeNewPC(_script->_scriptInfo.usdCode);
- int destX, destY;
- if (_optionsMob != -1) {
- destX = _mobList[_optionsMob]._examPosition.x;
- destY = _mobList[_optionsMob]._examPosition.y;
- _mainHero->_destDirection = _mobList[_optionsMob]._examDirection;
- } else {
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- destX = mousePos.x + _picWindowX;
- destY = mousePos.y + _picWindowY;
- _mainHero->_destDirection = 0;
- }
- _mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY);
- if (_mainHero->_coords != nullptr) {
- _mainHero->_currCoords = _mainHero->_coords;
- _mainHero->_dirTab = _directionTable;
- _mainHero->_currDirTab = _directionTable;
- _directionTable = nullptr;
- _mainHero->_state = Hero::kHeroStateMove;
- moveShandria();
- }
- }
-}
-
-void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) {
- Hero *hero = nullptr;
- if (!heroId) {
- hero = _mainHero;
- } else if (heroId == 1) {
- hero = _secondHero;
- }
-
- if (hero != nullptr) {
- if (dir) {
- hero->_destDirection = dir;
- }
- if (x || y) {
- hero->freeOldMove();
- hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y);
- if (hero->_coords != nullptr) {
- hero->_currCoords = hero->_coords;
- hero->_dirTab = _directionTable;
- hero->_currDirTab = _directionTable;
- _directionTable = nullptr;
- if (runHeroFlag) {
- hero->_state = Hero::kHeroStateRun;
- } else {
- hero->_state = Hero::kHeroStateMove;
- }
- if (heroId == kMainHero && _mouseFlag) {
- moveShandria();
- }
- }
- } else {
- hero->freeOldMove();
- hero->_state = Hero::kHeroStateTurn;
- }
- hero->freeHeroAnim();
- hero->_visible = 1;
- }
-}
-
void PrinceEngine::leftMouseButton() {
_flags->setFlagValue(Flags::ESCAPED2, 1); // skip intro animation
_flags->setFlagValue(Flags::LMOUSE, 1);
@@ -2524,351 +809,6 @@ void PrinceEngine::rightMouseButton() {
}
}
-void PrinceEngine::inventoryLeftMouseButton() {
- if (!_mouseFlag) {
- _textSlots[0]._time = 0;
- _textSlots[0]._str = nullptr;
- stopSample(28);
- }
-
- if (_optionsFlag == 1) {
- if (_selectedMob != -1) {
- if (_optionEnabled < _invOptionsNumber) {
- _optionsFlag = 0;
- } else {
- return;
- }
- } else {
- error("PrinceEngine::inventoryLeftMouseButton() - optionsFlag = 1, selectedMob = 0");
- if (_currentPointerNumber == 2) {
- changeCursor(1);
- _currentPointerNumber = 1;
- _selectedMob = -1;
- _optionsMob = -1;
- return;
- } else {
- return;
- }
- }
- } else {
- if (_selectedMob != -1) {
- if (_currentPointerNumber != 2) {
- if (_invMobList[_selectedMob]._mask != 29) {
- _optionEnabled = 0;
- } else {
- // map item
- _optionEnabled = 1;
- }
- } else {
- //use_item_on_item
- int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
- if (invObjUU == -1) {
- int textNr = 80011; // "I can't do it."
- if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
- textNr = 80020; // "Nothing is happening."
- }
- _interpreter->setCurrentString(textNr);
- printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
- setVoice(0, 28, 1);
- playSample(28, 0);
- _selectedMob = -1;
- _optionsMob = -1;
- return;
- } else {
- _interpreter->storeNewPC(invObjUU);
- _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
- _showInventoryFlag = false;
- }
- }
- } else {
- return;
- }
- }
- //do_option
- if (_optionEnabled == 0) {
- int invObjExamEvent = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjExam);
- if (invObjExamEvent == -1) {
- // do_standard
- printAt(0, 216, (char *)_invMobList[_selectedMob]._examText.c_str(), kNormalWidth / 2, _invExamY);
- _interpreter->setCurrentString(_invMobList[_selectedMob]._mask + 70000);
- setVoice(0, 28, 1);
- playSample(28, 0);
- // disableuseuse
- changeCursor(0);
- _currentPointerNumber = 1;
- } else {
- _interpreter->storeNewPC(invObjExamEvent);
- _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
- _showInventoryFlag = false;
- }
- } else if (_optionEnabled == 1) {
- // not_examine
- int invObjUse = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUse);
- if (invObjUse == -1) {
- // do_standard_use
- _selectedMode = 0;
- _selectedItem = _invMobList[_selectedMob]._mask;
- makeInvCursor(_invMobList[_selectedMob]._mask);
- _currentPointerNumber = 2;
- changeCursor(2);
- } else {
- _interpreter->storeNewPC(invObjUse);
- _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
- _showInventoryFlag = false;
- }
- } else if (_optionEnabled == 4) {
- // do_standard_give
- _selectedMode = 1;
- _selectedItem = _invMobList[_selectedMob]._mask;
- makeInvCursor(_invMobList[_selectedMob]._mask);
- _currentPointerNumber = 2;
- changeCursor(2);
- } else {
- // use_item_on_item
- int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
- if (invObjUU == -1) {
- int textNr = 80011; // "I can't do it."
- if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
- textNr = 80020; // "Nothing is happening."
- }
- _interpreter->setCurrentString(textNr);
- printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
- setVoice(0, 28, 1);
- playSample(28, 0);
- } else {
- _interpreter->storeNewPC(invObjUU);
- _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
- _showInventoryFlag = false;
- }
- }
- _selectedMob = -1;
- _optionsMob = -1;
-}
-
-void PrinceEngine::inventoryRightMouseButton() {
- if (_textSlots[0]._str == nullptr) {
- enableOptions(false);
- }
-}
-
-void PrinceEngine::enableOptions(bool checkType) {
- if (_optionsFlag != 1) {
- changeCursor(1);
- _currentPointerNumber = 1;
- if (_selectedMob != -1) {
- if (checkType) {
- if (_mobList[_selectedMob]._type & 0x100) {
- return;
- }
- }
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- int x1 = mousePos.x - _optionsWidth / 2;
- int x2 = mousePos.x + _optionsWidth / 2;
- if (x1 < 0) {
- x1 = 0;
- x2 = _optionsWidth;
- } else if (x2 >= kNormalWidth) {
- x1 = kNormalWidth - _optionsWidth;
- x2 = kNormalWidth;
- }
- int y1 = mousePos.y - 10;
- if (y1 < 0) {
- y1 = 0;
- }
- if (y1 + _optionsHeight >= kNormalHeight) {
- y1 = kNormalHeight - _optionsHeight;
- }
- _optionsMob = _selectedMob;
- _optionsX = x1;
- _optionsY = y1;
- _optionsFlag = 1;
- }
- }
-}
-
-void PrinceEngine::checkOptions() {
- if (_optionsFlag) {
- Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _optionsWidth, _optionsY + _optionsHeight);
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- if (!optionsRect.contains(mousePos)) {
- _optionsFlag = 0;
- _selectedMob = -1;
- return;
- }
- _graph->drawAsShadowSurface(_graph->_frontScreen, _optionsX, _optionsY, _optionsPic, _graph->_shadowTable50);
-
- _optionEnabled = -1;
- int optionsYCord = mousePos.y - (_optionsY + 16);
- if (optionsYCord >= 0) {
- int selectedOptionNr = optionsYCord / _optionsStep;
- if (selectedOptionNr < _optionsNumber) {
- _optionEnabled = selectedOptionNr;
- }
- }
- int optionsColor;
- int textY = _optionsY + 16;
- for (int i = 0; i < _optionsNumber; i++) {
- if (i != _optionEnabled) {
- optionsColor = _optionsColor1;
- } else {
- optionsColor = _optionsColor2;
- }
- Common::String optText;
- switch(getLanguage()) {
- case Common::PL_POL:
- optText = optionsTextPL[i];
- break;
- case Common::DE_DEU:
- optText = optionsTextDE[i];
- break;
- case Common::EN_ANY:
- optText = optionsTextEN[i];
- break;
- default:
- break;
- };
- uint16 textW = getTextWidth(optText.c_str());
- uint16 textX = _optionsX + _optionsWidth / 2 - textW / 2;
- _font->drawString(_graph->_frontScreen, optText, textX, textY, textW, optionsColor);
- textY += _optionsStep;
- }
- }
-}
-
-void PrinceEngine::checkInvOptions() {
- if (_optionsFlag) {
- Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _invOptionsWidth, _optionsY + _invOptionsHeight);
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- if (!optionsRect.contains(mousePos)) {
- _optionsFlag = 0;
- _selectedMob = -1;
- return;
- }
- _graph->drawAsShadowSurface(_graph->_screenForInventory, _optionsX, _optionsY, _optionsPicInInventory, _graph->_shadowTable50);
-
- _optionEnabled = -1;
- int optionsYCord = mousePos.y - (_optionsY + 16);
- if (optionsYCord >= 0) {
- int selectedOptionNr = optionsYCord / _invOptionsStep;
- if (selectedOptionNr < _invOptionsNumber) {
- _optionEnabled = selectedOptionNr;
- }
- }
- int optionsColor;
- int textY = _optionsY + 16;
- for (int i = 0; i < _invOptionsNumber; i++) {
- if (i != _optionEnabled) {
- optionsColor = _optionsColor1;
- } else {
- optionsColor = _optionsColor2;
- }
- Common::String invText;
- switch(getLanguage()) {
- case Common::PL_POL:
- invText = invOptionsTextPL[i];
- break;
- case Common::DE_DEU:
- invText = invOptionsTextDE[i];
- break;
- case Common::EN_ANY:
- invText = invOptionsTextEN[i];
- break;
- default:
- error("Unknown game language %d", getLanguage());
- break;
- };
- uint16 textW = getTextWidth(invText.c_str());
- uint16 textX = _optionsX + _invOptionsWidth / 2 - textW / 2;
- _font->drawString(_graph->_screenForInventory, invText, textX, textY, _graph->_screenForInventory->w, optionsColor);
- textY += _invOptionsStep;
- }
- }
-}
-
-void PrinceEngine::displayInventory() {
-
- _mainHero->freeOldMove();
- _secondHero->freeOldMove();
-
- _interpreter->setFgOpcodePC(0);
-
- stopAllSamples();
-
- prepareInventoryToView();
-
- while (!shouldQuit()) {
-
- if (_textSlots[0]._str != nullptr) {
- changeCursor(0);
- } else {
- changeCursor(_currentPointerNumber);
-
- Common::Rect inventoryRect(_invX1, _invY1, _invX1 + _invWidth, _invY1 + _invHeight);
- Common::Point mousePos = _system->getEventManager()->getMousePos();
-
- if (!_invCurInside && inventoryRect.contains(mousePos)) {
- _invCurInside = true;
- }
-
- if (_invCurInside && !inventoryRect.contains(mousePos)) {
- inventoryFlagChange(false);
- _invCurInside = false;
- break;
- }
- }
-
- rememberScreenInv();
-
- Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
- _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
-
- drawInvItems();
-
- showTexts(_graph->_screenForInventory);
-
- if (!_optionsFlag && _textSlots[0]._str == nullptr) {
- _selectedMob = checkMob(_graph->_screenForInventory, _invMobList, false);
- }
-
- checkInvOptions();
-
- Common::Event event;
- Common::EventManager *eventMan = _system->getEventManager();
- while (eventMan->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_KEYDOWN:
- keyHandler(event);
- break;
- case Common::EVENT_LBUTTONDOWN:
- inventoryLeftMouseButton();
- break;
- case Common::EVENT_RBUTTONDOWN:
- inventoryRightMouseButton();
- break;
- default:
- break;
- }
- }
-
- if (!_showInventoryFlag) {
- break;
- }
-
- if (shouldQuit())
- return;
-
- getDebugger()->onFrame();
- _graph->update(_graph->_screenForInventory);
- pausePrinceEngine();
- }
-
- if (_currentPointerNumber == 2) {
- _flags->setFlagValue(Flags::SELITEM, _selectedItem);
- } else {
- _flags->setFlagValue(Flags::SELITEM, 0);
- }
-}
-
void PrinceEngine::createDialogBox(int dialogBoxNr) {
_dialogLines = 0;
int amountOfDialogOptions = 0;
@@ -3037,66 +977,6 @@ void PrinceEngine::talkHero(int slot) {
_interpreter->increaseString();
}
-void PrinceEngine::doTalkAnim(int animNumber, int slot, AnimType animType) {
- Text &text = _textSlots[slot];
- int lines = calcTextLines((const char *)_interpreter->getString());
- int time = lines * 30;
- if (animType == kNormalAnimation) {
- Anim &normAnim = _normAnimList[animNumber];
- if (normAnim._animData != nullptr) {
- if (!normAnim._state) {
- if (normAnim._currW && normAnim._currH) {
- text._color = _flags->getFlagValue(Flags::KOLOR);
- text._x = normAnim._currX + normAnim._currW / 2;
- text._y = normAnim._currY - 10;
- }
- }
- }
- } else if (animType == kBackgroundAnimation) {
- if (!_backAnimList[animNumber].backAnims.empty()) {
- int currAnim = _backAnimList[animNumber]._seq._currRelative;
- Anim &backAnim = _backAnimList[animNumber].backAnims[currAnim];
- if (backAnim._animData != nullptr) {
- if (!backAnim._state) {
- if (backAnim._currW && backAnim._currH) {
- text._color = _flags->getFlagValue(Flags::KOLOR);
- text._x = backAnim._currX + backAnim._currW / 2;
- text._y = backAnim._currY - 10;
- }
- }
- }
- }
- } else {
- error("doTalkAnim() - wrong animType: %d", animType);
- }
- text._time = time;
- if (getLanguage() == Common::DE_DEU) {
- correctStringDEU((char *)_interpreter->getString());
- }
- text._str = (const char *)_interpreter->getString();
- _interpreter->increaseString();
-}
-
-void PrinceEngine::freeNormAnim(int slot) {
- if (!_normAnimList.empty()) {
- _normAnimList[slot]._state = 1;
- if (_normAnimList[slot]._animData != nullptr) {
- delete _normAnimList[slot]._animData;
- _normAnimList[slot]._animData = nullptr;
- }
- if (_normAnimList[slot]._shadowData != nullptr) {
- delete _normAnimList[slot]._shadowData;
- _normAnimList[slot]._shadowData = nullptr;
- }
- }
-}
-
-void PrinceEngine::freeAllNormAnims() {
- for (int i = 0; i < kMaxNormAnims; i++) {
- freeNormAnim(i);
- }
-}
-
void PrinceEngine::getCurve() {
_flags->setFlagValue(Flags::TORX1, _curveData[_curvPos]);
_flags->setFlagValue(Flags::TORY1, _curveData[_curvPos + 1]);
@@ -3270,1544 +1150,6 @@ void PrinceEngine::scrollCredits() {
blackPalette();
}
-// Modified version of Graphics::drawLine() to allow breaking the loop and return value
-int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) {
- // Bresenham's line algorithm, as described by Wikipedia
- const bool steep = ABS(y1 - y0) > ABS(x1 - x0);
-
- if (steep) {
- SWAP(x0, y0);
- SWAP(x1, y1);
- }
-
- const int delta_x = ABS(x1 - x0);
- const int delta_y = ABS(y1 - y0);
- const int delta_err = delta_y;
- int x = x0;
- int y = y0;
- int err = 0;
-
- const int x_step = (x0 < x1) ? 1 : -1;
- const int y_step = (y0 < y1) ? 1 : -1;
-
- int stopFlag = 0;
- if (steep)
- stopFlag = (*plotProc)(y, x, data);
- else
- stopFlag = (*plotProc)(x, y, data);
-
- while (x != x1 && !stopFlag) {
- x += x_step;
- err += delta_err;
- if (2 * err > delta_x) {
- y += y_step;
- err -= delta_x;
- }
- if (steep)
- stopFlag = (*plotProc)(y, x, data);
- else
- stopFlag = (*plotProc)(x, y, data);
- }
- return stopFlag;
-}
-
-int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) {
- int mask = 128 >> (x & 7);
- byte value = pathBitmap[x / 8 + y * 80];
- return (mask & value);
-}
-
-void PrinceEngine::findPoint(int x, int y) {
- _fpX = x;
- _fpY = y;
-
- if (getPixelAddr(_roomPathBitmap, x, y)) {
- return;
- }
-
- int fpL = x;
- int fpU = y;
- int fpR = x;
- int fpD = y;
-
- while (1) {
- if (fpD != kMaxPicHeight) {
- if (getPixelAddr(_roomPathBitmap, x, fpD)) {
- _fpX = x;
- _fpY = fpD;
- break;
- }
- fpD++;
- }
- if (fpU) {
- if (getPixelAddr(_roomPathBitmap, x, fpU)) {
- _fpX = x;
- _fpY = fpU;
- break;
- }
- fpU--;
- }
- if (fpL) {
- if (getPixelAddr(_roomPathBitmap, fpL, y)) {
- _fpX = fpL;
- _fpY = y;
- break;
- }
- fpL--;
- }
- if (fpR != _sceneWidth) {
- if (getPixelAddr(_roomPathBitmap, fpR, y)) {
- _fpX = fpR;
- _fpY = y;
- break;
- }
- fpR++;
- }
- if (!fpU && (fpD == kMaxPicHeight)) {
- if (!fpL && (fpR == _sceneWidth)) {
- break;
- }
- }
- }
-}
-
-Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) {
- if (x1 != x2) {
- if (y1 != y2) {
- if (x1 > x2) {
- if (y1 > y2) {
- if (x1 - x2 >= y1 - y2) {
- return kDirLU;
- } else {
- return kDirUL;
- }
- } else {
- if (x1 - x2 >= y2 - y1) {
- return kDirLD;
- } else {
- return kDirDL;
- }
- }
- } else {
- if (y1 > y2) {
- if (x2 - x1 >= y1 - y2) {
- return kDirRU;
- } else {
- return kDirUR;
- }
- } else {
- if (x2 - x1 >= y2 - y1) {
- return kDirRD;
- } else {
- return kDirDR;
- }
- }
- }
- } else {
- if (x1 >= x2) {
- return kDirL;
- } else {
- return kDirR;
- }
- }
- } else {
- if (y1 >= y2) {
- return kDirU;
- } else {
- return kDirD;
- }
- }
-}
-
-void PrinceEngine::specialPlot(int x, int y) {
- if (_coords < _coordsBufEnd) {
- WRITE_LE_UINT16(_coords, x);
- _coords += 2;
- WRITE_LE_UINT16(_coords, y);
- _coords += 2;
- specialPlot2(x, y);
- }
-}
-
-void PrinceEngine::specialPlot2(int x, int y) {
- int mask = 128 >> (x & 7);
- _roomPathBitmapTemp[x / 8 + y * 80] |= mask;
-}
-
-void PrinceEngine::specialPlotInside(int x, int y) {
- if (_coords < _coordsBufEnd) {
- WRITE_LE_UINT16(_coords, x);
- _coords += 2;
- WRITE_LE_UINT16(_coords, y);
- _coords += 2;
- }
-}
-
-int PrinceEngine::plotTraceLine(int x, int y, void *data) {
- PrinceEngine *traceLine = (PrinceEngine *)data;
- if (!traceLine->_traceLineFirstPointFlag) {
- if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) {
- if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) {
- traceLine->specialPlotInside(x, y);
- traceLine->_traceLineLen++;
- return 0;
- } else {
- return -1;
- }
- } else {
- return 1;
- }
- } else {
- traceLine->_traceLineFirstPointFlag = false;
- return 0;
- }
-}
-
-int PrinceEngine::leftDownDir() {
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::leftDir() {
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::leftUpDir() {
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::rightDownDir() {
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::rightDir() {
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::rightUpDir() {
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::upLeftDir() {
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::upDir() {
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::upRightDir() {
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::downLeftDir() {
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::downDir() {
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::downRightDir() {
- if (!checkRightDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDownDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkRightUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- if (!checkLeftUpDir()) {
- specialPlot(_checkX, _checkY);
- return 0;
- }
- return -1;
-}
-
-int PrinceEngine::cpe() {
- if ((*(_checkBitmap - kPBW) & _checkMask)) {
- if ((*(_checkBitmap + kPBW) & _checkMask)) {
- int value;
- switch (_checkMask) {
- case 128:
- value = READ_LE_UINT16(_checkBitmap - 1);
- value &= 0x4001;
- if (value != 0x4001) {
- return 0;
- }
- break;
- case 64:
- value = *_checkBitmap;
- value &= 0xA0;
- if (value != 0xA0) {
- return 0;
- }
- break;
- case 32:
- value = *_checkBitmap;
- value &= 0x50;
- if (value != 0x50) {
- return 0;
- }
- break;
- case 16:
- value = *_checkBitmap;
- value &= 0x28;
- if (value != 0x28) {
- return 0;
- }
- break;
- case 8:
- value = *_checkBitmap;
- value &= 0x14;
- if (value != 0x14) {
- return 0;
- }
- break;
- case 4:
- value = *_checkBitmap;
- value &= 0xA;
- if (value != 0xA) {
- return 0;
- }
- break;
- case 2:
- value = *_checkBitmap;
- value &= 0x5;
- if (value != 0x5) {
- return 0;
- }
- break;
- case 1:
- value = READ_LE_UINT16(_checkBitmap);
- value &= 0x8002;
- if (value != 0x8002) {
- return 0;
- }
- break;
- default:
- error("Wrong _checkMask value - cpe()");
- break;
- }
- _checkX = _rembX;
- _checkY = _rembY;
- _checkBitmapTemp = _rembBitmapTemp;
- _checkBitmap = _rembBitmap;
- _checkMask = _rembMask;
- return -1;
- }
- return 0;
- }
- return 0;
-}
-
-int PrinceEngine::checkLeftDownDir() {
- if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) {
- int tempMask = _checkMask;
- if (tempMask != 128) {
- tempMask <<= 1;
- if ((*(_checkBitmap + kPBW) & tempMask)) {
- if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
- _checkBitmap += kPBW;
- _checkBitmapTemp += kPBW;
- _checkMask = tempMask;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- if ((*(_checkBitmap + kPBW - 1) & 1)) {
- if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) {
- _checkBitmap += (kPBW - 1);
- _checkBitmapTemp += (kPBW - 1);
- _checkMask = 1;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- }
- _checkX--;
- _checkY++;
- return cpe();
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkLeftDir() {
- if (_checkX) {
- int tempMask = _checkMask;
- if (tempMask != 128) {
- tempMask <<= 1;
- if ((*(_checkBitmap) & tempMask)) {
- if (!(*(_checkBitmapTemp) & tempMask)) {
- _checkMask = tempMask;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- if ((*(_checkBitmap - 1) & 1)) {
- if (!(*(_checkBitmapTemp - 1) & 1)) {
- _checkBitmap--;
- _checkBitmapTemp--;
- _checkMask = 1;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- }
- _checkX--;
- return cpe();
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkDownDir() {
- if (_checkY != (kMaxPicHeight / 2 - 1)) {
- if ((*(_checkBitmap + kPBW) & _checkMask)) {
- if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) {
- _checkBitmap += kPBW;
- _checkBitmapTemp += kPBW;
- _checkY++;
- return cpe();
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkUpDir() {
- if (_checkY) {
- if ((*(_checkBitmap - kPBW) & _checkMask)) {
- if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) {
- _checkBitmap -= kPBW;
- _checkBitmapTemp -= kPBW;
- _checkY--;
- return cpe();
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkRightDir() {
- if (_checkX != (kMaxPicWidth / 2 - 1)) {
- int tempMask = _checkMask;
- if (tempMask != 1) {
- tempMask >>= 1;
- if ((*(_checkBitmap) & tempMask)) {
- if (!(*(_checkBitmapTemp) & tempMask)) {
- _checkMask = tempMask;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- if ((*(_checkBitmap + 1) & 128)) {
- if (!(*(_checkBitmapTemp + 1) & 128)) {
- _checkBitmap++;
- _checkBitmapTemp++;
- _checkMask = 128;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- }
- _checkX++;
- return cpe();
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkLeftUpDir() {
- if (_checkX && _checkY) {
- int tempMask = _checkMask;
- if (tempMask != 128) {
- tempMask <<= 1;
- if ((*(_checkBitmap - kPBW) & tempMask)) {
- if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
- _checkBitmap -= kPBW;
- _checkBitmapTemp -= kPBW;
- _checkMask = tempMask;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- if ((*(_checkBitmap - (kPBW + 1)) & 1)) {
- if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) {
- _checkBitmap -= (kPBW + 1);
- _checkBitmapTemp -= (kPBW + 1);
- _checkMask = 1;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- }
- _checkX--;
- _checkY--;
- return cpe();
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkRightDownDir() {
- if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) {
- int tempMask = _checkMask;
- if (tempMask != 1) {
- tempMask >>= 1;
- if ((*(_checkBitmap + kPBW) & tempMask)) {
- if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
- _checkBitmap += kPBW;
- _checkBitmapTemp += kPBW;
- _checkMask = tempMask;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- if ((*(_checkBitmap + kPBW + 1) & 128)) {
- if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) {
- _checkBitmap += kPBW + 1;
- _checkBitmapTemp += kPBW + 1;
- _checkMask = 128;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- }
- _checkX++;
- _checkY++;
- return cpe();
- } else {
- return -1;
- }
-}
-
-int PrinceEngine::checkRightUpDir() {
- if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) {
- int tempMask = _checkMask;
- if (tempMask != 1) {
- tempMask >>= 1;
- if ((*(_checkBitmap - kPBW) & tempMask)) {
- if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
- _checkBitmap -= kPBW;
- _checkBitmapTemp -= kPBW;
- _checkMask = tempMask;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- } else {
- if ((*(_checkBitmap - kPBW + 1) & 128)) {
- if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) {
- _checkBitmap -= (kPBW - 1);
- _checkBitmapTemp -= (kPBW - 1);
- _checkMask = 128;
- } else {
- return 1;
- }
- } else {
- return -1;
- }
- }
- _checkX++;
- _checkY--;
- return cpe();
- } else {
- return -1;
- }
-}
-
-bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) {
- for (uint i = 0; i < kPathBitmapLen; i++) {
- _roomPathBitmapTemp[i] = 0;
- }
- if (x1 != x2 || y1 != y2) {
- if (getPixelAddr(_roomPathBitmap, x1, y1)) {
- if (getPixelAddr(_roomPathBitmap, x2, y2)) {
- _coords = _coordsBuf;
- specialPlot(x1, y1);
-
- int x = x1;
- int y = y1;
-
- while (1) {
- int btx = x;
- int bty = y;
- byte *bcad = _coords;
-
- _traceLineLen = 0;
- _traceLineFirstPointFlag = true;
- int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this);
-
- if (!drawLineFlag) {
- return true;
- } else if (drawLineFlag == -1 && _traceLineLen >= 2) {
- byte *tempCorrds = bcad;
- while (tempCorrds != _coords) {
- x = READ_LE_UINT16(tempCorrds);
- y = READ_LE_UINT16(tempCorrds + 2);
- tempCorrds += 4;
- specialPlot2(x, y);
- }
- } else {
- _coords = bcad;
- x = btx;
- y = bty;
- }
-
- Direction dir = makeDirection(x, y, x2, y2);
-
- _rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80];
- _rembBitmap = &_roomPathBitmap[x / 8 + y * 80];
- _rembMask = 128 >> (x & 7);
- _rembX = x;
- _rembY = y;
-
- _checkBitmapTemp = _rembBitmapTemp;
- _checkBitmap = _rembBitmap;
- _checkMask = _rembMask;
- _checkX = _rembX;
- _checkY = _rembY;
-
- int result;
- switch (dir) {
- case kDirLD:
- result = leftDownDir();
- break;
- case kDirL:
- result = leftDir();
- break;
- case kDirLU:
- result = leftUpDir();
- break;
- case kDirRD:
- result = rightDownDir();
- break;
- case kDirR:
- result = rightDir();
- break;
- case kDirRU:
- result = rightUpDir();
- break;
- case kDirUL:
- result = upLeftDir();
- break;
- case kDirU:
- result = upDir();
- break;
- case kDirUR:
- result = upRightDir();
- break;
- case kDirDL:
- result = downLeftDir();
- break;
- case kDirD:
- result = downDir();
- break;
- case kDirDR:
- result = downRightDir();
- break;
- default:
- result = -1;
- error("tracePath: wrong direction %d", dir);
- break;
- }
-
- if (result) {
- byte *tempCoords = _coords;
- tempCoords -= 4;
- if (tempCoords > _coordsBuf) {
- int tempX = READ_LE_UINT16(tempCoords);
- int tempY = READ_LE_UINT16(tempCoords + 2);
- if (_checkX == tempX && _checkY == tempY) {
- _coords = tempCoords;
- }
- x = READ_LE_UINT16(tempCoords);
- y = READ_LE_UINT16(tempCoords + 2);
- } else {
- return false;
- }
- } else {
- x = _checkX;
- y = _checkY;
- }
- }
- return true;
- } else {
- error("tracePath: wrong destination point");
- }
- } else {
- error("tracePath: wrong start point");
- }
- } else {
- error("tracePath: same point");
- }
-}
-
-void PrinceEngine::specialPlotInside2(int x, int y) {
- WRITE_LE_UINT16(_coords2, x);
- _coords2 += 2;
- WRITE_LE_UINT16(_coords2, y);
- _coords2 += 2;
-}
-
-int PrinceEngine::plotTracePoint(int x, int y, void *data) {
- PrinceEngine *tracePoint = (PrinceEngine *)data;
- if (!tracePoint->_tracePointFirstPointFlag) {
- if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) {
- tracePoint->specialPlotInside2(x, y);
- return 0;
- } else {
- return -1;
- }
- } else {
- tracePoint->_tracePointFirstPointFlag = false;
- return 0;
- }
-}
-
-void PrinceEngine::approxPath() {
- byte *oldCoords;
- _coords2 = _coordsBuf2;
- byte *tempCoordsBuf = _coordsBuf; // first point on path
- byte *tempCoords = _coords;
- if (tempCoordsBuf != tempCoords) {
- tempCoords -= 4; // last point on path
- while (tempCoordsBuf != tempCoords) {
- int x1 = READ_LE_UINT16(tempCoords);
- int y1 = READ_LE_UINT16(tempCoords + 2);
- int x2 = READ_LE_UINT16(tempCoordsBuf);
- int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
- tempCoordsBuf += 4;
- //TracePoint
- oldCoords = _coords2;
- if (_coords2 == _coordsBuf2) {
- WRITE_LE_UINT16(_coords2, x1);
- WRITE_LE_UINT16(_coords2 + 2, y1);
- _coords2 += 4;
- } else {
- int testX = READ_LE_UINT16(_coords2 - 4);
- int testY = READ_LE_UINT16(_coords2 - 2);
- if (testX != x1 || testY != y1) {
- WRITE_LE_UINT16(_coords2, x1);
- WRITE_LE_UINT16(_coords2 + 2, y1);
- _coords2 += 4;
- }
- }
- _tracePointFirstPointFlag = true;
- bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this);
- if (!drawLineFlag) {
- tempCoords = tempCoordsBuf - 4;
- tempCoordsBuf = _coordsBuf;
- } else {
- _coords2 = oldCoords;
- }
- }
- }
-}
-
-void PrinceEngine::freeDirectionTable() {
- if (_directionTable != nullptr) {
- free(_directionTable);
- _directionTable = nullptr;
- }
-}
-
-int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) {
-
- int tempX, tempY, direction;
-
- tempX = Hero::kHeroDirLeft;
- if (xDiff < 0) {
- tempX = Hero::kHeroDirRight;
- }
-
- tempY = Hero::kHeroDirUp;
- if (yDiff < 0) {
- tempY = Hero::kHeroDirDown;
- }
-
- while (1) {
- int againPointX1 = READ_LE_UINT16(tempCoordsBuf);
- int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2);
- tempCoordsBuf += 4;
-
- if (tempCoordsBuf == _coords) {
- direction = tempX;
- break;
- }
-
- int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf);
- int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2);
-
- if (dX != xDiff) {
- direction = tempY;
- break;
- }
-
- if (dY != yDiff) {
- direction = tempX;
- break;
- }
- }
- return direction;
-}
-
-void PrinceEngine::scanDirections() {
- freeDirectionTable();
- byte *tempCoordsBuf = _coordsBuf;
- if (tempCoordsBuf != _coords) {
- int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker
- _directionTable = (byte *)malloc(size);
- byte *tempDirTab = _directionTable;
- int direction = -1;
- int lastDirection = -1;
-
- while (1) {
- int x1 = READ_LE_UINT16(tempCoordsBuf);
- int y1 = READ_LE_UINT16(tempCoordsBuf + 2);
- tempCoordsBuf += 4;
- if (tempCoordsBuf == _coords) {
- break;
- }
- int x2 = READ_LE_UINT16(tempCoordsBuf);
- int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
-
- int xDiff = x1 - x2;
- int yDiff = y1 - y2;
-
- if (xDiff) {
- if (yDiff) {
- if (lastDirection != -1) {
- direction = lastDirection;
- if (direction == Hero::kHeroDirLeft) {
- if (xDiff < 0) {
- direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
- }
- } else if (direction == Hero::kHeroDirRight) {
- if (xDiff >= 0) {
- direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
- }
- } else if (direction == Hero::kHeroDirUp) {
- if (yDiff < 0) {
- direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
- }
- } else {
- if (yDiff >= 0) {
- direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
- }
- }
- } else {
- direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
- }
- } else {
- direction = Hero::kHeroDirLeft;
- if (xDiff < 0) {
- direction = Hero::kHeroDirRight;
- }
- }
- } else {
- if (yDiff) {
- direction = Hero::kHeroDirUp;
- if (yDiff < 0) {
- direction = Hero::kHeroDirDown;
- }
- } else {
- direction = lastDirection;
- }
- }
- lastDirection = direction;
- *tempDirTab = direction;
- tempDirTab++;
- }
- *tempDirTab = *(tempDirTab - 1);
- tempDirTab++;
- *tempDirTab = 0;
- }
-}
-
-void PrinceEngine::moveShandria() {
- int shanLen1 = _shanLen;
- if (_flags->getFlagValue(Flags::SHANDOG)) {
- _secondHero->freeHeroAnim();
- _secondHero->freeOldMove();
- byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4;
- int shanX = READ_LE_UINT16(shanCoords - 4);
- int shanY = READ_LE_UINT16(shanCoords - 2);
- int xDiff = shanX - _secondHero->_middleX;
- if (xDiff < 0) {
- xDiff *= -1;
- }
- int yDiff = shanY - _secondHero->_middleY;
- if (yDiff < 0) {
- yDiff *= -1;
- }
- shanCoords -= 4;
- if (shanCoords != _mainHero->_currCoords) {
- yDiff *= 1.5;
- int shanDis = xDiff * xDiff + yDiff * yDiff;
- if (shanDis >= kMinDistance) {
- while (1) {
- shanCoords -= 4;
- if (shanCoords == _mainHero->_currCoords) {
- break;
- }
- int x = READ_LE_UINT16(shanCoords);
- int y = READ_LE_UINT16(shanCoords + 2);
- int pointDiffX = x - shanX;
- if (pointDiffX < 0) {
- pointDiffX *= -1;
- }
- int pointDiffY = y - shanY;
- if (pointDiffY < 0) {
- pointDiffY *= -1;
- }
- pointDiffY *= 1.5;
- int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY;
- if (distance >= kMinDistance) {
- break;
- }
- }
- int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4;
- int destDir = *(_mainHero->_currDirTab + pathSizeDiff);
- _secondHero->_destDirection = destDir;
- int destX = READ_LE_UINT16(shanCoords);
- int destY = READ_LE_UINT16(shanCoords + 2);
- _secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY);
- if (_secondHero->_coords != nullptr) {
- _secondHero->_currCoords = _secondHero->_coords;
- int delay = shanLen1 - _shanLen;
- if (delay < 6) {
- delay = 6;
- }
- _secondHero->_moveDelay = delay / 2;
- _secondHero->_state = Hero::kHeroStateDelayMove;
- _secondHero->_dirTab = _directionTable;
- _secondHero->_currDirTab = _directionTable;
- _directionTable = nullptr;
- }
- }
- }
- }
-}
-
-byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) {
- int realDestX = destX;
- int realDestY = destY;
- _flags->setFlagValue(Flags::MOVEDESTX, destX);
- _flags->setFlagValue(Flags::MOVEDESTY, destY);
-
- int x1 = currX / 2;
- int y1 = currY / 2;
- int x2 = destX / 2;
- int y2 = destY / 2;
-
- if ((x1 != x2) || (y1 != y2)) {
- findPoint(x1, y1);
- if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
- return nullptr;
- }
- if ((x1 != _fpX) || (y1 != _fpY)) {
- x1 = _fpX;
- y1 = _fpY;
- }
- findPoint(x2, y2);
- if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
- return nullptr;
- }
- if ((x2 != _fpX) || (y2 != _fpY)) {
- x2 = _fpX;
- y2 = _fpY;
- if (!_flags->getFlagValue(Flags::EXACTMOVE)) {
- realDestX = x2 * 2;
- realDestY = y2 * 2;
- _flags->setFlagValue(Flags::MOVEDESTX, realDestX);
- _flags->setFlagValue(Flags::MOVEDESTY, realDestY);
- } else {
- return nullptr;
- }
- }
-
- if ((x1 == x2) && (y1 == y2)) {
- if (!heroId) {
- _mainHero->freeOldMove();
- _mainHero->_state = Hero::kHeroStateTurn;
- } else if (heroId == 1) {
- _secondHero->freeOldMove();
- _secondHero->_state = Hero::kHeroStateTurn;
- }
- return nullptr;
- }
-
- int pathLen1 = 0;
- int pathLen2 = 0;
- int stX = x1;
- int stY = y1;
- int sizeCoords2 = 0;
-
- if (tracePath(x1, y1, x2, y2)) {
- allocCoords2();
- approxPath();
- sizeCoords2 = _coords2 - _coordsBuf2;
- for (int i = 0; i < sizeCoords2; i++) {
- _coordsBuf[i] = _coordsBuf2[i];
- }
- _coords = _coordsBuf + sizeCoords2;
- approxPath();
- _coordsBuf3 = _coordsBuf2;
- _coordsBuf2 = nullptr;
- _coords3 = _coords2;
- _coords2 = nullptr;
- pathLen1 = _coords3 - _coordsBuf3;
- }
- if (tracePath(x2, y2, x1, y1)) {
- allocCoords2();
- approxPath();
- sizeCoords2 = _coords2 - _coordsBuf2;
- for (int i = 0; i < sizeCoords2; i++) {
- _coordsBuf[i] = _coordsBuf2[i];
- }
- _coords = _coordsBuf + sizeCoords2;
- approxPath();
- pathLen2 = _coords2 - _coordsBuf2;
- }
-
- byte *chosenCoordsBuf = _coordsBuf2;
- byte *choosenCoords = _coords2;
- int choosenLength = pathLen1;
- if (pathLen1 < pathLen2) {
- chosenCoordsBuf = _coordsBuf3;
- choosenCoords = _coords3;
- choosenLength = pathLen2;
- }
-
- if (choosenLength) {
- if (chosenCoordsBuf != nullptr) {
- int tempXBegin = READ_LE_UINT16(chosenCoordsBuf);
- int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2);
- if (stX != tempXBegin || stY != tempYBegin) {
- SWAP(chosenCoordsBuf, choosenCoords);
- chosenCoordsBuf -= 4;
- byte *tempCoordsBuf = _coordsBuf;
- while (1) {
- int cord = READ_LE_UINT32(chosenCoordsBuf);
- WRITE_LE_UINT32(tempCoordsBuf, cord);
- tempCoordsBuf += 4;
- if (chosenCoordsBuf == choosenCoords) {
- break;
- }
- chosenCoordsBuf -= 4;
- }
- _coords = tempCoordsBuf;
- } else {
- int sizeChoosen = choosenCoords - chosenCoordsBuf;
- for (int i = 0; i < sizeChoosen; i++) {
- _coordsBuf[i] = chosenCoordsBuf[i];
- }
- _coords = _coordsBuf + sizeChoosen;
- }
- WRITE_LE_UINT32(_coords, 0xFFFFFFFF);
- freeCoords2();
- freeCoords3();
- scanDirections();
-
- byte *tempCoordsBuf = _coordsBuf;
- byte *tempCoords = _coords;
- byte *newCoords;
- if (tempCoordsBuf != tempCoords) {
- int normCoordsSize = _coords - _coordsBuf + 4;
- newCoords = (byte *)malloc(normCoordsSize);
- byte *newCoordsBegin = newCoords;
- while (tempCoordsBuf != tempCoords) {
- int newValueX = READ_LE_UINT16(tempCoordsBuf);
- WRITE_LE_UINT16(newCoords, newValueX * 2);
- newCoords += 2;
- int newValueY = READ_LE_UINT16(tempCoordsBuf + 2);
- WRITE_LE_UINT16(newCoords, newValueY * 2);
- newCoords += 2;
- tempCoordsBuf += 4;
- }
- WRITE_LE_UINT16(newCoords - 4, realDestX);
- WRITE_LE_UINT16(newCoords - 2, realDestY);
- WRITE_LE_UINT32(newCoords, 0xFFFFFFFF);
- newCoords += 4;
- _shanLen = (newCoords - newCoordsBegin);
- _shanLen /= 4;
- return newCoordsBegin;
- }
- }
- }
- _coords = _coordsBuf;
- freeCoords2();
- freeCoords3();
- return nullptr;
- } else {
- if (!heroId) {
- _mainHero->freeOldMove();
- _mainHero->_state = Hero::kHeroStateTurn;
- } else if (heroId == 1) {
- _secondHero->freeOldMove();
- _secondHero->_state = Hero::kHeroStateTurn;
- }
- return nullptr;
- }
-}
-
-void PrinceEngine::allocCoords2() {
- if (_coordsBuf2 == nullptr) {
- _coordsBuf2 = (byte *)malloc(kTracePts * 4);
- _coords2 = _coordsBuf2;
- }
-}
-
-void PrinceEngine::freeCoords2() {
- if (_coordsBuf2 != nullptr) {
- free(_coordsBuf2);
- _coordsBuf2 = nullptr;
- _coords2 = nullptr;
- }
-}
-
-void PrinceEngine::freeCoords3() {
- if (_coordsBuf3 != nullptr) {
- free(_coordsBuf3);
- _coordsBuf3 = nullptr;
- _coords3 = nullptr;
- }
-}
-
-void PrinceEngine::openInventoryCheck() {
- if (!_optionsFlag) {
- if (_mouseFlag == 1 || _mouseFlag == 2) {
- if (_mainHero->_visible) {
- if (!_flags->getFlagValue(Flags::INVALLOWED)) {
- // 29 - Basement, 50 - Map
- if (_locationNr != 29 && _locationNr != 50) {
- Common::Point mousePos = _system->getEventManager()->getMousePos();
- if (mousePos.y < 4 && !_showInventoryFlag) {
- _invCounter++;
- } else {
- _invCounter = 0;
- }
- if (_invCounter >= _invMaxCount) {
- inventoryFlagChange(true);
- }
- }
- }
- }
- }
- }
-}
-
void PrinceEngine::mainLoop() {
changeCursor(0);
_currentTime = _system->getMillis();
diff --git a/engines/prince/prince.h b/engines/prince/prince.h
index 32e37e0774..e0b9490c37 100644
--- a/engines/prince/prince.h
+++ b/engines/prince/prince.h
@@ -38,7 +38,6 @@
#include "gui/debugger.h"
-#include "engines/advancedDetector.h"
#include "engines/engine.h"
#include "engines/util.h"
@@ -58,14 +57,10 @@ enum PrinceGameType {
kPrinceDataPL
};
-struct PrinceGameDescription {
- ADGameDescription desc;
- PrinceGameType gameType;
-};
-
struct SavegameHeader;
class PrinceEngine;
+struct PrinceGameDescription;
class GraphicsMan;
class Script;
class Interpreter;
@@ -82,15 +77,18 @@ class Room;
class Pscr;
enum {
- GF_TRANSLATED = 1 << 0
+ GF_TRANSLATED = 1 << 0,
+ GF_EXTRACTED = 1 << 1,
+ GF_NOVOICES = 1 << 2
};
struct SavegameHeader {
uint8 version;
Common::String saveName;
Graphics::Surface *thumbnail;
- int saveYear, saveMonth, saveDay;
- int saveHour, saveMinutes;
+ int16 saveYear, saveMonth, saveDay;
+ int16 saveHour, saveMinutes;
+ uint32 playTime;
};
#define kSavegameStrSize 14
@@ -281,6 +279,8 @@ public:
PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc);
virtual ~PrinceEngine();
+ bool scummVMSaveLoadDialog(bool isSave);
+
virtual bool hasFeature(EngineFeature f) const;
virtual void pauseEngineIntern(bool pause);
virtual bool canSaveGameStateCurrently();
@@ -290,7 +290,7 @@ public:
void playVideo(Common::String videoFilename);
- static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true);
Common::String generateSaveName(int slot);
void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
diff --git a/engines/prince/pscr.cpp b/engines/prince/pscr.cpp
index 4f79704e62..481d17cace 100644
--- a/engines/prince/pscr.cpp
+++ b/engines/prince/pscr.cpp
@@ -24,6 +24,7 @@
#include "common/stream.h"
#include "prince/pscr.h"
+#include "prince/resource.h"
namespace Prince {
@@ -64,6 +65,8 @@ bool PScr::loadFromStream(Common::SeekableReadStream &stream) {
const Common::String pscrStreamName = Common::String::format("PS%02d", file);
Common::SeekableReadStream *pscrStream = SearchMan.createReadStreamForMember(pscrStreamName);
if (pscrStream != nullptr) {
+ pscrStream = Resource::getDecompressedStream(pscrStream);
+
loadSurface(*pscrStream);
}
delete pscrStream;
diff --git a/engines/prince/resource.cpp b/engines/prince/resource.cpp
new file mode 100644
index 0000000000..34de29b388
--- /dev/null
+++ b/engines/prince/resource.cpp
@@ -0,0 +1,371 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/fs.h"
+#include "common/config-manager.h"
+
+#include "prince/prince.h"
+#include "prince/graphics.h"
+#include "prince/debugger.h"
+#include "prince/script.h"
+#include "prince/hero.h"
+#include "prince/resource.h"
+#include "prince/archive.h"
+
+namespace Prince {
+
+Common::SeekableReadStream *Resource::getDecompressedStream(Common::SeekableReadStream *stream) {
+ if (!(((PrinceEngine *)g_engine)->getFeatures() & GF_EXTRACTED))
+ return stream;
+
+ byte header[4];
+
+ stream->read(header, 4);
+ stream->seek(0);
+
+ if (READ_BE_UINT32(header) == MKTAG('M', 'A', 'S', 'M')) {
+ byte *buffer = (byte *)malloc(stream->size());
+ stream->read(buffer, stream->size());
+
+ Decompressor dec;
+ uint32 decompLen = READ_BE_UINT32(buffer + 14);
+ byte *decompData = (byte *)malloc(decompLen);
+ dec.decompress(buffer + 18, decompData, decompLen);
+ free(buffer);
+
+ debug(8, "Resource::getDecompressedStream: decompressed %d to %d bytes", stream->size(), decompLen);
+
+ return new Common::MemoryReadStream(decompData, decompLen, DisposeAfterUse::YES);
+ } else {
+ return stream;
+ }
+}
+
+bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) {
+ int32 pos = stream.pos();
+
+ uint16 type = stream.readUint16LE();
+ if (type == 0xFFFF) {
+ return false;
+ }
+ _type = type;
+ _fileNumber = stream.readUint16LE();
+ _startPhase = stream.readUint16LE();
+ _endPhase = stream.readUint16LE();
+ _loopPhase = stream.readUint16LE();
+ _x = stream.readSint16LE();
+ _y = stream.readSint16LE();
+ _loopType = stream.readUint16LE();
+ _nextAnim = stream.readUint16LE();
+ _flags = stream.readUint16LE();
+
+ debug(7, "AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags);
+ debug(7, "startPhase %d, endPhase %d, loopPhase %d", _startPhase, _endPhase, _loopPhase);
+
+ // 32 byte aligment
+ stream.seek(pos + 32);
+
+ return true;
+}
+
+bool PrinceEngine::loadLocation(uint16 locationNr) {
+
+ blackPalette();
+
+ _flicPlayer.close();
+
+ memset(_textSlots, 0, sizeof(_textSlots));
+ freeAllSamples();
+
+ debugEngine("PrinceEngine::loadLocation %d", locationNr);
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.remove(Common::String::format("%02d", _locationNr));
+
+ _locationNr = locationNr;
+ _debugger->_locationNr = locationNr;
+
+ _flags->setFlagValue(Flags::CURRROOM, _locationNr);
+ _interpreter->stopBg();
+
+ changeCursor(0);
+
+ const Common::String locationNrStr = Common::String::format("%02d", _locationNr);
+ debugEngine("loadLocation %s", locationNrStr.c_str());
+
+ if (!(getFeatures() & GF_EXTRACTED)) {
+ PtcArchive *locationArchive = new PtcArchive();
+ if (!locationArchive->open(locationNrStr + "/databank.ptc"))
+ error("Can't open location %s", locationNrStr.c_str());
+
+ SearchMan.add(locationNrStr, locationArchive);
+ } else {
+ SearchMan.addSubDirectoryMatching(gameDataDir, locationNrStr);
+ }
+
+ loadMusic(_locationNr);
+
+ // load location background, replace old one
+ Resource::loadResource(_roomBmp, "room", true);
+ if (_roomBmp->getSurface()) {
+ _sceneWidth = _roomBmp->getSurface()->w;
+ }
+
+ loadZoom(_zoomBitmap, kZoomBitmapLen, "zoom");
+ loadShadow(_shadowBitmap, kShadowBitmapSize, "shadow", "shadow2");
+ loadTrans(_transTable, "trans");
+ loadPath("path");
+
+ for (uint32 i = 0; i < _pscrList.size(); i++) {
+ delete _pscrList[i];
+ }
+ _pscrList.clear();
+ Resource::loadResource(_pscrList, "pscr.lst", false);
+
+ loadMobPriority("mobpri");
+
+ _mobList.clear();
+ if (getGameType() == kPrinceDataDE) {
+ const Common::String mobLstName = Common::String::format("mob%02d.lst", _locationNr);
+ debug(3, "moblist name: %s", mobLstName.c_str());
+ Resource::loadResource(_mobList, mobLstName.c_str(), false);
+ } else if (getGameType() == kPrinceDataPL) {
+ Resource::loadResource(_mobList, "mob.lst", false);
+ }
+ if (getFeatures() & GF_TRANSLATED) {
+ // update Mob texts for translated version
+ setMobTranslationTexts();
+ }
+
+ _animList.clear();
+ Resource::loadResource(_animList, "anim.lst", false);
+
+ for (uint32 i = 0; i < _objList.size(); i++) {
+ delete _objList[i];
+ }
+ _objList.clear();
+ Resource::loadResource(_objList, "obj.lst", false);
+
+ _room->loadRoom(_script->getRoomOffset(_locationNr));
+
+ for (uint i = 0; i < _maskList.size(); i++) {
+ free(_maskList[i]._data);
+ }
+ _maskList.clear();
+ _script->loadAllMasks(_maskList, _room->_nak);
+
+ _picWindowX = 0;
+
+ _lightX = _script->getLightX(_locationNr);
+ _lightY = _script->getLightY(_locationNr);
+ setShadowScale(_script->getShadowScale(_locationNr));
+
+ for (uint i = 0; i < _mobList.size(); i++) {
+ _mobList[i]._visible = _script->getMobVisible(_room->_mobs, i);
+ }
+
+ _script->installObjects(_room->_obj);
+
+ freeAllNormAnims();
+
+ clearBackAnimList();
+ _script->installBackAnims(_backAnimList, _room->_backAnim);
+
+ _graph->makeShadowTable(70, _graph->_shadowTable70);
+ _graph->makeShadowTable(50, _graph->_shadowTable50);
+
+ _mainHero->freeOldMove();
+ _secondHero->freeOldMove();
+
+ _mainHero->scrollHero();
+
+ return true;
+}
+
+bool PrinceEngine::loadAnim(uint16 animNr, bool loop) {
+ Common::String streamName = Common::String::format("AN%02d", animNr);
+ Common::SeekableReadStream *flicStream = SearchMan.createReadStreamForMember(streamName);
+
+ if (!flicStream) {
+ error("Can't open %s", streamName.c_str());
+ return false;
+ }
+
+ flicStream = Resource::getDecompressedStream(flicStream);
+
+ if (!_flicPlayer.loadStream(flicStream)) {
+ error("Can't load flic stream %s", streamName.c_str());
+ }
+
+ debugEngine("%s loaded", streamName.c_str());
+ _flicLooped = loop;
+ _flicPlayer.start();
+ playNextFLCFrame();
+ return true;
+}
+
+bool PrinceEngine::loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+ stream = Resource::getDecompressedStream(stream);
+
+ if (stream->read(zoomBitmap, dataSize) != dataSize) {
+ free(zoomBitmap);
+ delete stream;
+ return false;
+ }
+ delete stream;
+ return true;
+}
+
+bool PrinceEngine::loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName1);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+
+ stream = Resource::getDecompressedStream(stream);
+
+ if (stream->read(shadowBitmap, dataSize) != dataSize) {
+ free(shadowBitmap);
+ delete stream;
+ return false;
+ }
+
+ Common::SeekableReadStream *stream2 = SearchMan.createReadStreamForMember(resourceName2);
+ if (!stream2) {
+ delete stream;
+ delete stream2;
+ return false;
+ }
+
+ stream2 = Resource::getDecompressedStream(stream2);
+
+ byte *shadowBitmap2 = shadowBitmap + dataSize;
+ if (stream2->read(shadowBitmap2, dataSize) != dataSize) {
+ free(shadowBitmap);
+ delete stream;
+ delete stream2;
+ return false;
+ }
+
+ delete stream;
+ delete stream2;
+ return true;
+}
+
+bool PrinceEngine::loadTrans(byte *transTable, const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ for (int i = 0; i < 256; i++) {
+ for (int j = 0; j < 256; j++) {
+ transTable[i * 256 + j] = j;
+ }
+ }
+ return true;
+ }
+
+ stream = Resource::getDecompressedStream(stream);
+
+ if (stream->read(transTable, kTransTableSize) != kTransTableSize) {
+ delete stream;
+ return false;
+ }
+ delete stream;
+ return true;
+}
+
+bool PrinceEngine::loadPath(const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+
+ stream = Resource::getDecompressedStream(stream);
+
+ if (stream->read(_roomPathBitmap, kPathBitmapLen) != kPathBitmapLen) {
+ delete stream;
+ return false;
+ }
+ delete stream;
+ return true;
+}
+
+bool PrinceEngine::loadAllInv() {
+ for (int i = 0; i < kMaxInv; i++) {
+ InvItem tempInvItem;
+
+ const Common::String invStreamName = Common::String::format("INV%02d", i);
+ Common::SeekableReadStream *invStream = SearchMan.createReadStreamForMember(invStreamName);
+ if (!invStream) {
+ delete invStream;
+ return true;
+ }
+
+ invStream = Resource::getDecompressedStream(invStream);
+
+ tempInvItem._x = invStream->readUint16LE();
+ tempInvItem._y = invStream->readUint16LE();
+ int width = invStream->readUint16LE();
+ int height = invStream->readUint16LE();
+ tempInvItem._surface = new Graphics::Surface();
+ tempInvItem._surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int h = 0; h < tempInvItem._surface->h; h++) {
+ invStream->read(tempInvItem._surface->getBasePtr(0, h), tempInvItem._surface->w);
+ }
+
+ _allInvList.push_back(tempInvItem);
+ delete invStream;
+ }
+
+ return true;
+}
+
+bool PrinceEngine::loadMobPriority(const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+
+ stream = Resource::getDecompressedStream(stream);
+
+ _mobPriorityList.clear();
+ uint mobId;
+ while (1) {
+ mobId = stream->readUint32LE();
+ if (mobId == 0xFFFFFFFF) {
+ break;
+ }
+ _mobPriorityList.push_back(mobId);
+ }
+ delete stream;
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/resource.h b/engines/prince/resource.h
index 96bc2ea26d..1746f2bfb5 100644
--- a/engines/prince/resource.h
+++ b/engines/prince/resource.h
@@ -24,74 +24,85 @@
#define PRINCE_RESOURCE_H
#include "common/stream.h"
+#include "common/memstream.h"
#include "common/archive.h"
#include "common/debug-channels.h"
#include "common/ptr.h"
+#include "prince/decompress.h"
+
namespace Prince {
namespace Resource {
- template <typename T>
- bool loadFromStream(T &resource, Common::SeekableReadStream &stream) {
- return resource.loadStream(stream);
- }
+Common::SeekableReadStream *getDecompressedStream(Common::SeekableReadStream *stream);
- template<typename T>
- bool loadResource(T *resource, const char *resourceName, bool required) {
- Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName));
- if (!stream) {
- if (required)
- error("Can't load %s", resourceName);
- return false;
- }
+template <typename T>
+bool loadFromStream(T &resource, Common::SeekableReadStream &stream) {
+ return resource.loadStream(stream);
+}
- return loadFromStream(*resource, *stream);
+template<typename T>
+bool loadResource(T *resource, const char *resourceName, bool required) {
+ Common::SeekableReadStream *stream_(SearchMan.createReadStreamForMember(resourceName));
+ if (!stream_) {
+ if (required)
+ error("Can't load %s", resourceName);
+ return false;
}
- template <typename T>
- bool loadResource(Common::Array<T> &array, Common::SeekableReadStream &stream, bool required = true) {
- T t;
- while (t.loadFromStream(stream))
- array.push_back(t);
+ Common::ScopedPtr<Common::SeekableReadStream> stream(getDecompressedStream(stream_));
- return true;
- }
+ return loadFromStream(*resource, *stream);
+}
+template <typename T>
+bool loadResource(Common::Array<T> &array, Common::SeekableReadStream &stream, bool required = true) {
+ T t;
+ while (t.loadFromStream(stream))
+ array.push_back(t);
- template <typename T>
- bool loadResource(Common::Array<T> &array, const char *resourceName, bool required = true) {
- Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName));
- if (!stream) {
- if (required)
- error("Can't load %s", resourceName);
- return false;
- }
+ return true;
+}
- return loadResource(array, *stream, required);
+
+template <typename T>
+bool loadResource(Common::Array<T> &array, const char *resourceName, bool required = true) {
+ Common::SeekableReadStream *stream_(SearchMan.createReadStreamForMember(resourceName));
+ if (!stream_) {
+ if (required)
+ error("Can't load %s", resourceName);
+ return false;
}
- template <typename T>
- bool loadResource(Common::Array<T *> &array, const char *resourceName, bool required = true) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(getDecompressedStream(stream_));
- Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName));
- if (!stream) {
- if (required)
- error("Can't load %s", resourceName);
- return false;
- }
+ return loadResource(array, *stream, required);
+}
+
+template <typename T>
+bool loadResource(Common::Array<T *> &array, const char *resourceName, bool required = true) {
- // FIXME: This is stupid. Maybe loadFromStream should be helper method that returns initiailzed object
- while (true) {
- T* t = new T();
- if (!t->loadFromStream(*stream)) {
- delete t;
- break;
- }
- array.push_back(t);
+ Common::SeekableReadStream *stream_(SearchMan.createReadStreamForMember(resourceName));
+ if (!stream_) {
+ if (required)
+ error("Can't load %s", resourceName);
+ return false;
+ }
+
+ Common::ScopedPtr<Common::SeekableReadStream> stream(getDecompressedStream(stream_));
+
+ // FIXME: This is stupid. Maybe loadFromStream should be helper method that returns initialized object
+ while (true) {
+ T* t = new T();
+ if (!t->loadFromStream(*stream)) {
+ delete t;
+ break;
}
- return true;
+ array.push_back(t);
}
+ return true;
+}
}
diff --git a/engines/prince/saveload.cpp b/engines/prince/saveload.cpp
index 14f6078910..b1d9fc49fd 100644
--- a/engines/prince/saveload.cpp
+++ b/engines/prince/saveload.cpp
@@ -30,22 +30,63 @@
#include "common/system.h"
#include "common/config-manager.h"
#include "common/memstream.h"
+#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "graphics/surface.h"
#include "graphics/palette.h"
#include "graphics/scaler.h"
+#include "gui/saveload.h"
+
namespace Prince {
-#define kBadSVG 99
#define kSavegameVersion 1
class InterpreterFlags;
class Interpreter;
-bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
- header.thumbnail = nullptr;
+bool PrinceEngine::scummVMSaveLoadDialog(bool isSave) {
+ GUI::SaveLoadChooser *dialog;
+ Common::String desc;
+ int slot;
+
+ if (isSave) {
+ dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+
+ slot = dialog->runModalWithCurrentTarget();
+ desc = dialog->getResultString();
+
+ if (desc.empty()) {
+ desc = dialog->createDefaultSaveDescription(slot);
+ }
+ } else {
+ dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ slot = dialog->runModalWithCurrentTarget();
+ }
+
+ delete dialog;
+
+ if (slot < 0)
+ return false;
+
+ if (isSave) {
+ return saveGameState(slot, desc).getCode() == Common::kNoError;
+ } else {
+ return loadGameState(slot).getCode() == Common::kNoError;
+ }
+}
+
+WARN_UNUSED_RESULT bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) {
+ header.version = 0;
+ header.saveName.clear();
+ header.thumbnail = nullptr;
+ header.saveYear = 0;
+ header.saveMonth = 0;
+ header.saveDay = 0;
+ header.saveHour = 0;
+ header.saveMinutes = 0;
+ header.playTime = 0;
// Get the savegame version
header.version = in->readByte();
@@ -53,22 +94,22 @@ bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &he
return false;
// Read in the string
- header.saveName.clear();
char ch;
while ((ch = (char)in->readByte()) != '\0')
header.saveName += ch;
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
- header.saveYear = in->readSint16LE();
- header.saveMonth = in->readSint16LE();
- header.saveDay = in->readSint16LE();
- header.saveHour = in->readSint16LE();
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
header.saveMinutes = in->readSint16LE();
+ header.playTime = in->readUint32LE();
return true;
}
@@ -157,6 +198,8 @@ void PrinceEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader
out->writeSint16LE(td.tm_mday);
out->writeSint16LE(td.tm_hour);
out->writeSint16LE(td.tm_min);
+
+ out->writeUint32LE(g_engine->getTotalPlayTime() / 1000);
}
void PrinceEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) {
@@ -417,9 +460,7 @@ bool PrinceEngine::loadGame(int slotNumber) {
return false;
}
- // Delete the thumbnail
- saveHeader.thumbnail->free();
- delete saveHeader.thumbnail;
+ g_engine->setTotalPlayTime(saveHeader.playTime * 1000);
}
// Get in the savegame
diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp
index 23ef24a268..2581dde1c1 100644
--- a/engines/prince/script.cpp
+++ b/engines/prince/script.cpp
@@ -222,7 +222,7 @@ void Script::setObjId(int roomObjOffset, int slot, byte objectId) {
}
int Script::scanMobEvents(int mobMask, int dataEventOffset) {
- debug("mobMask: %d", mobMask);
+ debug(3, "scanMobEvents: mobMask: %d", mobMask);
int i = 0;
int16 mob;
int32 code;
@@ -230,7 +230,7 @@ int Script::scanMobEvents(int mobMask, int dataEventOffset) {
mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 6]);
if (mob == mobMask) {
code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 6 + 2]);
- debug("code: %d", code);
+ debug(3, "scanMobEvents: code: %d", code);
return code;
}
i++;
@@ -239,7 +239,7 @@ int Script::scanMobEvents(int mobMask, int dataEventOffset) {
}
int Script::scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask) {
- debug("mobMask: %d", mobMask);
+ debug(3, "scanMobEventsWithItem: mobMask: %d", mobMask);
int i = 0;
int16 mob;
int16 item;
@@ -250,8 +250,8 @@ int Script::scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask
item = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8 + 2]);
if (item == itemMask) {
code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 8 + 4]);
- debug("itemMask: %d", item);
- debug("code: %d", code);
+ debug(3, "scanMobEventsWithItem: itemMask: %d", item);
+ debug(3, "scanMobEventsWithItem: code: %d", code);
return code;
}
}
@@ -388,9 +388,11 @@ bool Script::loadAllMasks(Common::Array<Mask> &maskList, int offset) {
tempMask._width = 0;
tempMask._height = 0;
tempMask._data = nullptr;
- debug("Can't load %s", msStreamName.c_str());
+ warning("loadAllMasks: Can't load %s", msStreamName.c_str());
delete msStream;
} else {
+ msStream = Resource::getDecompressedStream(msStream);
+
int32 dataSize = msStream->size();
if (dataSize != -1) {
tempMask._data = (byte *)malloc(dataSize);
@@ -450,11 +452,9 @@ void Interpreter::debugInterpreter(const char *s, ...) {
Common::String str = Common::String::format("@0x%08X: ", _lastInstruction);
str += Common::String::format("op %04d: ", _lastOpcode);
- //debugC(10, DebugChannel::kScript, "PrinceEngine::Script %s %s", str.c_str(), buf);
if (!strcmp(_mode, "fg")) {
debug(10, "PrinceEngine::Script %s %s", str.c_str(), buf);
}
- //debug("Prince::Script mode %s %s %s", _mode, str.c_str(), buf);
}
void Interpreter::stepBg() {
@@ -916,8 +916,7 @@ void Interpreter::O_ADDFLAG() {
_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) + value);
if (_flags->getFlagValue(flagId)) {
_result = 1;
- }
- else {
+ } else {
_result = 0;
}
debugInterpreter("O_ADDFLAG flagId %04x (%s), value %d", flagId, Flags::getFlagName(flagId), value);
@@ -936,8 +935,7 @@ void Interpreter::O_SUBFLAG() {
_flags->setFlagValue(flagId, _flags->getFlagValue(flagId) - value);
if (_flags->getFlagValue(flagId)) {
_result = 1;
- }
- else {
+ } else {
_result = 0;
}
debugInterpreter("O_SUBFLAG flagId %d, value %d", flagId, value);
@@ -949,8 +947,7 @@ void Interpreter::O_SETSTRING() {
if (offset >= 80000) {
_string = _vm->_variaTxt->getString(offset - 80000);
debugInterpreter("GetVaria %s", _string);
- }
- else if (offset < 2000) {
+ } else if (offset < 2000) {
_vm->_dialogData = &_vm->_dialogDat[offset * 4 - 4];
uint32 of = READ_LE_UINT32(_vm->_talkTxt + offset * 4);
const char *txt = (const char *)&_vm->_talkTxt[of];
@@ -1016,6 +1013,12 @@ void Interpreter::O_XORFLAG() {
void Interpreter::O_GETMOBTEXT() {
int32 mob = readScriptFlagValue();
_currentString = _vm->_locationNr * 100 + mob + 60001;
+ // FIXME: UB?
+ // This casts away the constness of the pointer returned by c_str() which is
+ // stored and potentially modified later (for example in printAt()).
+ // Also, the pointer is only valid as long as _vm->_mobList[mob]
+ // is around and _vm->_mobList[mob]._examText hasn't been modified by any of its
+ // non-const member functions which also might or might not be a problem.
_string = (byte *)_vm->_mobList[mob]._examText.c_str();
debugInterpreter("O_GETMOBTEXT mob %d", mob);
}
@@ -1832,6 +1835,12 @@ void Interpreter::O_DISABLENAK() {
void Interpreter::O_GETMOBNAME() {
int32 modId = readScriptFlagValue();
+ // FIXME: UB?
+ // This casts away the constness of the pointer returned by c_str() which is
+ // stored and potentially modified later (for example in printAt()).
+ // Also, the pointer is only valid as long as _vm->_mobList[mobId]
+ // is around and _vm->_mobList[mobId]._name hasn't been modified by any of its
+ // non-const member functions which also might or might not be a problem.
_string = (byte *)_vm->_mobList[modId]._name.c_str();
debugInterpreter("O_GETMOBNAME modId %d", modId);
}
diff --git a/engines/prince/sound.cpp b/engines/prince/sound.cpp
index 206b131cd2..49983860be 100644
--- a/engines/prince/sound.cpp
+++ b/engines/prince/sound.cpp
@@ -20,191 +20,147 @@
*
*/
-#include "prince/sound.h"
-#include "prince/musNum.h"
-
#include "common/archive.h"
-#include "common/debug.h"
-#include "audio/mididrv.h"
-#include "audio/midiparser.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+
+#include "prince/prince.h"
+#include "prince/hero.h"
+#include "prince/script.h"
namespace Prince {
-const char *MusicPlayer::_musTable[] = {
- "",
- "Battlfld.mid",
- "Cave.mid",
- "Cemetery.mid",
- "Credits.mid",
- "Fjord.mid",
- "Guitar.mid",
- "Hell.mid",
- "Jingle.mid",
- "Main.mid",
- "Night.mid",
- "Reality.mid",
- "Sunlord.mid",
- "Tavern.mid",
- "Temple.mid",
- "Boruta.mid",
- "Intro.mid"
-};
-
-const uint8 MusicPlayer::_musRoomTable[] = {
- 0,
- ROOM01MUS,
- ROOM02MUS,
- ROOM03MUS,
- ROOM04MUS,
- ROOM05MUS,
- ROOM06MUS,
- ROOM07MUS,
- ROOM08MUS,
- ROOM09MUS,
- ROOM10MUS,
- ROOM11MUS,
- ROOM12MUS,
- ROOM13MUS,
- ROOM14MUS,
- ROOM15MUS,
- ROOM16MUS,
- ROOM17MUS,
- ROOM18MUS,
- ROOM19MUS,
- ROOM20MUS,
- ROOM21MUS,
- ROOM22MUS,
- ROOM23MUS,
- ROOM24MUS,
- ROOM25MUS,
- ROOM26MUS,
- ROOM27MUS,
- ROOM28MUS,
- ROOM29MUS,
- ROOM30MUS,
- ROOM31MUS,
- ROOM32MUS,
- ROOM33MUS,
- ROOM34MUS,
- ROOM35MUS,
- ROOM36MUS,
- ROOM37MUS,
- ROOM38MUS,
- ROOM39MUS,
- ROOM40MUS,
- ROOM41MUS,
- ROOM42MUS,
- ROOM43MUS,
- 0,
- 0,
- ROOM46MUS,
- ROOM47MUS,
- ROOM48MUS,
- ROOM49MUS,
- ROOM50MUS,
- ROOM51MUS,
- ROOM52MUS,
- ROOM53MUS,
- ROOM54MUS,
- ROOM55MUS,
- ROOM56MUS,
- ROOM57MUS,
- ROOM58MUS,
- ROOM59MUS,
- ROOM60MUS,
- ROOM61MUS
-};
-
-
-MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) {
- _data = nullptr;
- _dataSize = 0;
- _isGM = false;
-
- MidiPlayer::createDriver();
-
- int ret = _driver->open();
- if (ret == 0) {
- if (_nativeMT32)
- _driver->sendMT32Reset();
- else
- _driver->sendGMReset();
-
- _driver->setTimerCallback(this, &timerCallback);
+void PrinceEngine::playSample(uint16 sampleId, uint16 loopType) {
+ if (_audioStream[sampleId]) {
+ if (_mixer->isSoundIDActive(sampleId)) {
+ return;
+ }
+ _audioStream[sampleId]->rewind();
+ if (sampleId < 28) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ } else {
+ _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ }
}
}
-MusicPlayer::~MusicPlayer() {
- killMidi();
+void PrinceEngine::stopSample(uint16 sampleId) {
+ _mixer->stopID(sampleId);
}
-void MusicPlayer::killMidi() {
- Audio::MidiPlayer::stop();
+void PrinceEngine::stopAllSamples() {
+ _mixer->stopAll();
+}
- free(_data);
- _data = nullptr;
+void PrinceEngine::freeSample(uint16 sampleId) {
+ stopSample(sampleId);
+ if (_audioStream[sampleId] != nullptr) {
+ delete _audioStream[sampleId];
+ _audioStream[sampleId] = nullptr;
+ }
}
-void MusicPlayer::loadMidi(const char *name) {
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name);
- if (!stream) {
- debug("Can't load midi stream %s", name);
- return;
+void PrinceEngine::freeAllSamples() {
+ for (int sampleId = 0; sampleId < kMaxSamples; sampleId++) {
+ freeSample(sampleId);
}
+}
- // Stop any currently playing MIDI file
- killMidi();
+bool PrinceEngine::loadSample(uint32 sampleSlot, const Common::String &streamName) {
+ // FIXME: This is just a workaround streamName is a path
+ // SOUND\\SCIERKA1.WAV for now only last path component is used
+ Common::String normalizedPath = lastPathComponent(streamName, '\\');
- // Read in the data for the file
- _dataSize = stream->size();
- _data = (byte *)malloc(_dataSize);
- stream->read(_data, _dataSize);
+ // WALKAROUND: Wrong name in script, not existing sound in data files
+ if (!normalizedPath.compareTo("9997BEKA.WAV")) {
+ return 0;
+ }
- delete stream;
+ debugEngine("loadSample slot %d, name %s", sampleSlot, normalizedPath.c_str());
- // Start playing the music
- sndMidiStart();
+ freeSample(sampleSlot);
+ Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(normalizedPath);
+ if (sampleStream == nullptr) {
+ delete sampleStream;
+ error("Can't load sample %s to slot %d", normalizedPath.c_str(), sampleSlot);
+ }
+ _audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream, DisposeAfterUse::NO);
+ delete sampleStream;
+ return true;
}
-void MusicPlayer::sndMidiStart() {
- _isGM = true;
+bool PrinceEngine::loadVoice(uint32 slot, uint32 sampleSlot, const Common::String &streamName) {
+ if (getFeatures() & GF_NOVOICES)
+ return false;
- MidiParser *parser = MidiParser::createParser_SMF();
- if (parser->loadMusic(_data, _dataSize)) {
- parser->setTrack(0);
- parser->setMidiDriver(this);
- parser->setTimerRate(_driver->getBaseTempo());
- parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+ debugEngine("Loading wav %s slot %d", streamName.c_str(), slot);
- _parser = parser;
+ if (slot >= kMaxTexts) {
+ error("Text slot bigger than MAXTEXTS %d", kMaxTexts - 1);
+ return false;
+ }
- syncVolume();
+ freeSample(sampleSlot);
+ Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(streamName);
+ if (sampleStream == nullptr) {
+ warning("loadVoice: Can't open %s", streamName.c_str());
+ return false;
+ }
- // Al the tracks are supposed to loop
- _isLooping = true;
- _isPlaying = true;
+ uint32 id = sampleStream->readUint32LE();
+ if (id != MKTAG('F', 'F', 'I', 'R')) {
+ error("It's not RIFF file %s", streamName.c_str());
+ return false;
}
-}
-void MusicPlayer::send(uint32 b) {
- if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
- b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ sampleStream->skip(0x20);
+ id = sampleStream->readUint32LE();
+ if (id != MKTAG('a', 't', 'a', 'd')) {
+ error("No data section in %s id %04x", streamName.c_str(), id);
+ return false;
}
- Audio::MidiPlayer::send(b);
+ id = sampleStream->readUint32LE();
+ debugEngine("SetVoice slot %d time %04x", slot, id);
+ id <<= 3;
+ id /= 22050;
+ id += 2;
+
+ _textSlots[slot]._time = id;
+ if (!slot) {
+ _mainHero->_talkTime = id;
+ } else if (slot == 1) {
+ _secondHero->_talkTime = id;
+ }
+
+ debugEngine("SetVoice slot %d time %04x", slot, id);
+ sampleStream->seek(SEEK_SET);
+ _audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream, DisposeAfterUse::NO);
+ delete sampleStream;
+ return true;
}
-void 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);
+void PrinceEngine::setVoice(uint16 slot, uint32 sampleSlot, uint16 flag) {
+ Common::String sampleName;
+ uint32 currentString = _interpreter->getCurrentString();
+
+ if (currentString >= 80000) {
+ uint32 nr = currentString - 80000;
+ sampleName = Common::String::format("%02d0%02d-%02d.WAV", nr / 100, nr % 100, flag);
+ } else if (currentString >= 70000) {
+ sampleName = Common::String::format("inv%02d-01.WAV", currentString - 70000);
+ } else if (currentString >= 60000) {
+ sampleName = Common::String::format("M%04d-%02d.WAV", currentString - 60000, flag);
+ } else if (currentString >= 2000) {
+ return;
+ } else if (flag >= 100) {
+ sampleName = Common::String::format("%03d-%03d.WAV", currentString, flag);
+ } else {
+ sampleName = Common::String::format("%03d-%02d.WAV", currentString, flag);
}
- if (_channelsTable[channel])
- _channelsTable[channel]->send(b);
+ loadVoice(slot, sampleSlot, sampleName);
}
} // End of namespace Prince
diff --git a/engines/prince/walk.cpp b/engines/prince/walk.cpp
new file mode 100644
index 0000000000..0e81c36f3f
--- /dev/null
+++ b/engines/prince/walk.cpp
@@ -0,0 +1,1610 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/prince.h"
+#include "prince/hero.h"
+#include "prince/script.h"
+
+namespace Prince {
+
+void PrinceEngine::walkTo() {
+ if (_mainHero->_visible) {
+ _mainHero->freeHeroAnim();
+ _mainHero->freeOldMove();
+ _interpreter->storeNewPC(_script->_scriptInfo.usdCode);
+ int destX, destY;
+ if (_optionsMob != -1) {
+ destX = _mobList[_optionsMob]._examPosition.x;
+ destY = _mobList[_optionsMob]._examPosition.y;
+ _mainHero->_destDirection = _mobList[_optionsMob]._examDirection;
+ } else {
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ destX = mousePos.x + _picWindowX;
+ destY = mousePos.y + _picWindowY;
+ _mainHero->_destDirection = 0;
+ }
+ _mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY);
+ if (_mainHero->_coords != nullptr) {
+ _mainHero->_currCoords = _mainHero->_coords;
+ _mainHero->_dirTab = _directionTable;
+ _mainHero->_currDirTab = _directionTable;
+ _directionTable = nullptr;
+ _mainHero->_state = Hero::kHeroStateMove;
+ moveShandria();
+ }
+ }
+}
+
+void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) {
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+
+ if (hero != nullptr) {
+ if (dir) {
+ hero->_destDirection = dir;
+ }
+ if (x || y) {
+ hero->freeOldMove();
+ hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y);
+ if (hero->_coords != nullptr) {
+ hero->_currCoords = hero->_coords;
+ hero->_dirTab = _directionTable;
+ hero->_currDirTab = _directionTable;
+ _directionTable = nullptr;
+ if (runHeroFlag) {
+ hero->_state = Hero::kHeroStateRun;
+ } else {
+ hero->_state = Hero::kHeroStateMove;
+ }
+ if (heroId == kMainHero && _mouseFlag) {
+ moveShandria();
+ }
+ }
+ } else {
+ hero->freeOldMove();
+ hero->_state = Hero::kHeroStateTurn;
+ }
+ hero->freeHeroAnim();
+ hero->_visible = 1;
+ }
+}
+
+// Modified version of Graphics::drawLine() to allow breaking the loop and return value
+int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) {
+ // Bresenham's line algorithm, as described by Wikipedia
+ const bool steep = ABS(y1 - y0) > ABS(x1 - x0);
+
+ if (steep) {
+ SWAP(x0, y0);
+ SWAP(x1, y1);
+ }
+
+ const int delta_x = ABS(x1 - x0);
+ const int delta_y = ABS(y1 - y0);
+ const int delta_err = delta_y;
+ int x = x0;
+ int y = y0;
+ int err = 0;
+
+ const int x_step = (x0 < x1) ? 1 : -1;
+ const int y_step = (y0 < y1) ? 1 : -1;
+
+ int stopFlag = 0;
+ if (steep)
+ stopFlag = (*plotProc)(y, x, data);
+ else
+ stopFlag = (*plotProc)(x, y, data);
+
+ while (x != x1 && !stopFlag) {
+ x += x_step;
+ err += delta_err;
+ if (2 * err > delta_x) {
+ y += y_step;
+ err -= delta_x;
+ }
+ if (steep)
+ stopFlag = (*plotProc)(y, x, data);
+ else
+ stopFlag = (*plotProc)(x, y, data);
+ }
+ return stopFlag;
+}
+
+int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) {
+ int mask = 128 >> (x & 7);
+ byte value = pathBitmap[x / 8 + y * 80];
+ return (mask & value);
+}
+
+void PrinceEngine::findPoint(int x, int y) {
+ _fpX = x;
+ _fpY = y;
+
+ if (getPixelAddr(_roomPathBitmap, x, y)) {
+ return;
+ }
+
+ int fpL = x;
+ int fpU = y;
+ int fpR = x;
+ int fpD = y;
+
+ while (1) {
+ if (fpD != kMaxPicHeight) {
+ if (getPixelAddr(_roomPathBitmap, x, fpD)) {
+ _fpX = x;
+ _fpY = fpD;
+ break;
+ }
+ fpD++;
+ }
+ if (fpU) {
+ if (getPixelAddr(_roomPathBitmap, x, fpU)) {
+ _fpX = x;
+ _fpY = fpU;
+ break;
+ }
+ fpU--;
+ }
+ if (fpL) {
+ if (getPixelAddr(_roomPathBitmap, fpL, y)) {
+ _fpX = fpL;
+ _fpY = y;
+ break;
+ }
+ fpL--;
+ }
+ if (fpR != _sceneWidth) {
+ if (getPixelAddr(_roomPathBitmap, fpR, y)) {
+ _fpX = fpR;
+ _fpY = y;
+ break;
+ }
+ fpR++;
+ }
+ if (!fpU && (fpD == kMaxPicHeight)) {
+ if (!fpL && (fpR == _sceneWidth)) {
+ break;
+ }
+ }
+ }
+}
+
+Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) {
+ if (x1 != x2) {
+ if (y1 != y2) {
+ if (x1 > x2) {
+ if (y1 > y2) {
+ if (x1 - x2 >= y1 - y2) {
+ return kDirLU;
+ } else {
+ return kDirUL;
+ }
+ } else {
+ if (x1 - x2 >= y2 - y1) {
+ return kDirLD;
+ } else {
+ return kDirDL;
+ }
+ }
+ } else {
+ if (y1 > y2) {
+ if (x2 - x1 >= y1 - y2) {
+ return kDirRU;
+ } else {
+ return kDirUR;
+ }
+ } else {
+ if (x2 - x1 >= y2 - y1) {
+ return kDirRD;
+ } else {
+ return kDirDR;
+ }
+ }
+ }
+ } else {
+ if (x1 >= x2) {
+ return kDirL;
+ } else {
+ return kDirR;
+ }
+ }
+ } else {
+ if (y1 >= y2) {
+ return kDirU;
+ } else {
+ return kDirD;
+ }
+ }
+}
+
+void PrinceEngine::specialPlot(int x, int y) {
+ if (_coords < _coordsBufEnd) {
+ WRITE_LE_UINT16(_coords, x);
+ _coords += 2;
+ WRITE_LE_UINT16(_coords, y);
+ _coords += 2;
+ specialPlot2(x, y);
+ }
+}
+
+void PrinceEngine::specialPlot2(int x, int y) {
+ int mask = 128 >> (x & 7);
+ _roomPathBitmapTemp[x / 8 + y * 80] |= mask;
+}
+
+void PrinceEngine::specialPlotInside(int x, int y) {
+ if (_coords < _coordsBufEnd) {
+ WRITE_LE_UINT16(_coords, x);
+ _coords += 2;
+ WRITE_LE_UINT16(_coords, y);
+ _coords += 2;
+ }
+}
+
+int PrinceEngine::plotTraceLine(int x, int y, void *data) {
+ PrinceEngine *traceLine = (PrinceEngine *)data;
+ if (!traceLine->_traceLineFirstPointFlag) {
+ if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) {
+ if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) {
+ traceLine->specialPlotInside(x, y);
+ traceLine->_traceLineLen++;
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return 1;
+ }
+ } else {
+ traceLine->_traceLineFirstPointFlag = false;
+ return 0;
+ }
+}
+
+int PrinceEngine::leftDownDir() {
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::leftDir() {
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::leftUpDir() {
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::rightDownDir() {
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::rightDir() {
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::rightUpDir() {
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::upLeftDir() {
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::upDir() {
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::upRightDir() {
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::downLeftDir() {
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::downDir() {
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::downRightDir() {
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::cpe() {
+ if ((*(_checkBitmap - kPBW) & _checkMask)) {
+ if ((*(_checkBitmap + kPBW) & _checkMask)) {
+ int value;
+ switch (_checkMask) {
+ case 128:
+ value = READ_LE_UINT16(_checkBitmap - 1);
+ value &= 0x4001;
+ if (value != 0x4001) {
+ return 0;
+ }
+ break;
+ case 64:
+ value = *_checkBitmap;
+ value &= 0xA0;
+ if (value != 0xA0) {
+ return 0;
+ }
+ break;
+ case 32:
+ value = *_checkBitmap;
+ value &= 0x50;
+ if (value != 0x50) {
+ return 0;
+ }
+ break;
+ case 16:
+ value = *_checkBitmap;
+ value &= 0x28;
+ if (value != 0x28) {
+ return 0;
+ }
+ break;
+ case 8:
+ value = *_checkBitmap;
+ value &= 0x14;
+ if (value != 0x14) {
+ return 0;
+ }
+ break;
+ case 4:
+ value = *_checkBitmap;
+ value &= 0xA;
+ if (value != 0xA) {
+ return 0;
+ }
+ break;
+ case 2:
+ value = *_checkBitmap;
+ value &= 0x5;
+ if (value != 0x5) {
+ return 0;
+ }
+ break;
+ case 1:
+ value = READ_LE_UINT16(_checkBitmap);
+ value &= 0x8002;
+ if (value != 0x8002) {
+ return 0;
+ }
+ break;
+ default:
+ error("Wrong _checkMask value - cpe()");
+ break;
+ }
+ _checkX = _rembX;
+ _checkY = _rembY;
+ _checkBitmapTemp = _rembBitmapTemp;
+ _checkBitmap = _rembBitmap;
+ _checkMask = _rembMask;
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+int PrinceEngine::checkLeftDownDir() {
+ if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) {
+ int tempMask = _checkMask;
+ if (tempMask != 128) {
+ tempMask <<= 1;
+ if ((*(_checkBitmap + kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
+ _checkBitmap += kPBW;
+ _checkBitmapTemp += kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap + kPBW - 1) & 1)) {
+ if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) {
+ _checkBitmap += (kPBW - 1);
+ _checkBitmapTemp += (kPBW - 1);
+ _checkMask = 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX--;
+ _checkY++;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkLeftDir() {
+ if (_checkX) {
+ int tempMask = _checkMask;
+ if (tempMask != 128) {
+ tempMask <<= 1;
+ if ((*(_checkBitmap) & tempMask)) {
+ if (!(*(_checkBitmapTemp) & tempMask)) {
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap - 1) & 1)) {
+ if (!(*(_checkBitmapTemp - 1) & 1)) {
+ _checkBitmap--;
+ _checkBitmapTemp--;
+ _checkMask = 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX--;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkDownDir() {
+ if (_checkY != (kMaxPicHeight / 2 - 1)) {
+ if ((*(_checkBitmap + kPBW) & _checkMask)) {
+ if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) {
+ _checkBitmap += kPBW;
+ _checkBitmapTemp += kPBW;
+ _checkY++;
+ return cpe();
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkUpDir() {
+ if (_checkY) {
+ if ((*(_checkBitmap - kPBW) & _checkMask)) {
+ if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) {
+ _checkBitmap -= kPBW;
+ _checkBitmapTemp -= kPBW;
+ _checkY--;
+ return cpe();
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkRightDir() {
+ if (_checkX != (kMaxPicWidth / 2 - 1)) {
+ int tempMask = _checkMask;
+ if (tempMask != 1) {
+ tempMask >>= 1;
+ if ((*(_checkBitmap) & tempMask)) {
+ if (!(*(_checkBitmapTemp) & tempMask)) {
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap + 1) & 128)) {
+ if (!(*(_checkBitmapTemp + 1) & 128)) {
+ _checkBitmap++;
+ _checkBitmapTemp++;
+ _checkMask = 128;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX++;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkLeftUpDir() {
+ if (_checkX && _checkY) {
+ int tempMask = _checkMask;
+ if (tempMask != 128) {
+ tempMask <<= 1;
+ if ((*(_checkBitmap - kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
+ _checkBitmap -= kPBW;
+ _checkBitmapTemp -= kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap - (kPBW + 1)) & 1)) {
+ if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) {
+ _checkBitmap -= (kPBW + 1);
+ _checkBitmapTemp -= (kPBW + 1);
+ _checkMask = 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX--;
+ _checkY--;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkRightDownDir() {
+ if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) {
+ int tempMask = _checkMask;
+ if (tempMask != 1) {
+ tempMask >>= 1;
+ if ((*(_checkBitmap + kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
+ _checkBitmap += kPBW;
+ _checkBitmapTemp += kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap + kPBW + 1) & 128)) {
+ if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) {
+ _checkBitmap += kPBW + 1;
+ _checkBitmapTemp += kPBW + 1;
+ _checkMask = 128;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX++;
+ _checkY++;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkRightUpDir() {
+ if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) {
+ int tempMask = _checkMask;
+ if (tempMask != 1) {
+ tempMask >>= 1;
+ if ((*(_checkBitmap - kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
+ _checkBitmap -= kPBW;
+ _checkBitmapTemp -= kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap - kPBW + 1) & 128)) {
+ if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) {
+ _checkBitmap -= (kPBW - 1);
+ _checkBitmapTemp -= (kPBW - 1);
+ _checkMask = 128;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX++;
+ _checkY--;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) {
+ for (uint i = 0; i < kPathBitmapLen; i++) {
+ _roomPathBitmapTemp[i] = 0;
+ }
+ if (x1 != x2 || y1 != y2) {
+ if (getPixelAddr(_roomPathBitmap, x1, y1)) {
+ if (getPixelAddr(_roomPathBitmap, x2, y2)) {
+ _coords = _coordsBuf;
+ specialPlot(x1, y1);
+
+ int x = x1;
+ int y = y1;
+
+ while (1) {
+ int btx = x;
+ int bty = y;
+ byte *bcad = _coords;
+
+ _traceLineLen = 0;
+ _traceLineFirstPointFlag = true;
+ int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this);
+
+ if (!drawLineFlag) {
+ return true;
+ } else if (drawLineFlag == -1 && _traceLineLen >= 2) {
+ byte *tempCorrds = bcad;
+ while (tempCorrds != _coords) {
+ x = READ_LE_UINT16(tempCorrds);
+ y = READ_LE_UINT16(tempCorrds + 2);
+ tempCorrds += 4;
+ specialPlot2(x, y);
+ }
+ } else {
+ _coords = bcad;
+ x = btx;
+ y = bty;
+ }
+
+ Direction dir = makeDirection(x, y, x2, y2);
+
+ _rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80];
+ _rembBitmap = &_roomPathBitmap[x / 8 + y * 80];
+ _rembMask = 128 >> (x & 7);
+ _rembX = x;
+ _rembY = y;
+
+ _checkBitmapTemp = _rembBitmapTemp;
+ _checkBitmap = _rembBitmap;
+ _checkMask = _rembMask;
+ _checkX = _rembX;
+ _checkY = _rembY;
+
+ int result;
+ switch (dir) {
+ case kDirLD:
+ result = leftDownDir();
+ break;
+ case kDirL:
+ result = leftDir();
+ break;
+ case kDirLU:
+ result = leftUpDir();
+ break;
+ case kDirRD:
+ result = rightDownDir();
+ break;
+ case kDirR:
+ result = rightDir();
+ break;
+ case kDirRU:
+ result = rightUpDir();
+ break;
+ case kDirUL:
+ result = upLeftDir();
+ break;
+ case kDirU:
+ result = upDir();
+ break;
+ case kDirUR:
+ result = upRightDir();
+ break;
+ case kDirDL:
+ result = downLeftDir();
+ break;
+ case kDirD:
+ result = downDir();
+ break;
+ case kDirDR:
+ result = downRightDir();
+ break;
+ default:
+ result = -1;
+ error("tracePath: wrong direction %d", dir);
+ break;
+ }
+
+ if (result) {
+ byte *tempCoords = _coords;
+ tempCoords -= 4;
+ if (tempCoords > _coordsBuf) {
+ int tempX = READ_LE_UINT16(tempCoords);
+ int tempY = READ_LE_UINT16(tempCoords + 2);
+ if (_checkX == tempX && _checkY == tempY) {
+ _coords = tempCoords;
+ }
+ x = READ_LE_UINT16(tempCoords);
+ y = READ_LE_UINT16(tempCoords + 2);
+ } else {
+ return false;
+ }
+ } else {
+ x = _checkX;
+ y = _checkY;
+ }
+ }
+ return true;
+ } else {
+ error("tracePath: wrong destination point");
+ }
+ } else {
+ error("tracePath: wrong start point");
+ }
+ } else {
+ error("tracePath: same point");
+ }
+}
+
+void PrinceEngine::specialPlotInside2(int x, int y) {
+ WRITE_LE_UINT16(_coords2, x);
+ _coords2 += 2;
+ WRITE_LE_UINT16(_coords2, y);
+ _coords2 += 2;
+}
+
+int PrinceEngine::plotTracePoint(int x, int y, void *data) {
+ PrinceEngine *tracePoint = (PrinceEngine *)data;
+ if (!tracePoint->_tracePointFirstPointFlag) {
+ if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) {
+ tracePoint->specialPlotInside2(x, y);
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ tracePoint->_tracePointFirstPointFlag = false;
+ return 0;
+ }
+}
+
+void PrinceEngine::approxPath() {
+ byte *oldCoords;
+ _coords2 = _coordsBuf2;
+ byte *tempCoordsBuf = _coordsBuf; // first point on path
+ byte *tempCoords = _coords;
+ if (tempCoordsBuf != tempCoords) {
+ tempCoords -= 4; // last point on path
+ while (tempCoordsBuf != tempCoords) {
+ int x1 = READ_LE_UINT16(tempCoords);
+ int y1 = READ_LE_UINT16(tempCoords + 2);
+ int x2 = READ_LE_UINT16(tempCoordsBuf);
+ int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
+ tempCoordsBuf += 4;
+ //TracePoint
+ oldCoords = _coords2;
+ if (_coords2 == _coordsBuf2) {
+ WRITE_LE_UINT16(_coords2, x1);
+ WRITE_LE_UINT16(_coords2 + 2, y1);
+ _coords2 += 4;
+ } else {
+ int testX = READ_LE_UINT16(_coords2 - 4);
+ int testY = READ_LE_UINT16(_coords2 - 2);
+ if (testX != x1 || testY != y1) {
+ WRITE_LE_UINT16(_coords2, x1);
+ WRITE_LE_UINT16(_coords2 + 2, y1);
+ _coords2 += 4;
+ }
+ }
+ _tracePointFirstPointFlag = true;
+ bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this);
+ if (!drawLineFlag) {
+ tempCoords = tempCoordsBuf - 4;
+ tempCoordsBuf = _coordsBuf;
+ } else {
+ _coords2 = oldCoords;
+ }
+ }
+ }
+}
+
+void PrinceEngine::freeDirectionTable() {
+ if (_directionTable != nullptr) {
+ free(_directionTable);
+ _directionTable = nullptr;
+ }
+}
+
+int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) {
+
+ int tempX, tempY, direction;
+
+ tempX = Hero::kHeroDirLeft;
+ if (xDiff < 0) {
+ tempX = Hero::kHeroDirRight;
+ }
+
+ tempY = Hero::kHeroDirUp;
+ if (yDiff < 0) {
+ tempY = Hero::kHeroDirDown;
+ }
+
+ while (1) {
+ int againPointX1 = READ_LE_UINT16(tempCoordsBuf);
+ int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2);
+ tempCoordsBuf += 4;
+
+ if (tempCoordsBuf == _coords) {
+ direction = tempX;
+ break;
+ }
+
+ int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf);
+ int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2);
+
+ if (dX != xDiff) {
+ direction = tempY;
+ break;
+ }
+
+ if (dY != yDiff) {
+ direction = tempX;
+ break;
+ }
+ }
+ return direction;
+}
+
+void PrinceEngine::scanDirections() {
+ freeDirectionTable();
+ byte *tempCoordsBuf = _coordsBuf;
+ if (tempCoordsBuf != _coords) {
+ int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker
+ _directionTable = (byte *)malloc(size);
+ byte *tempDirTab = _directionTable;
+ int direction = -1;
+ int lastDirection = -1;
+
+ while (1) {
+ int x1 = READ_LE_UINT16(tempCoordsBuf);
+ int y1 = READ_LE_UINT16(tempCoordsBuf + 2);
+ tempCoordsBuf += 4;
+ if (tempCoordsBuf == _coords) {
+ break;
+ }
+ int x2 = READ_LE_UINT16(tempCoordsBuf);
+ int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
+
+ int xDiff = x1 - x2;
+ int yDiff = y1 - y2;
+
+ if (xDiff) {
+ if (yDiff) {
+ if (lastDirection != -1) {
+ direction = lastDirection;
+ if (direction == Hero::kHeroDirLeft) {
+ if (xDiff < 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else if (direction == Hero::kHeroDirRight) {
+ if (xDiff >= 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else if (direction == Hero::kHeroDirUp) {
+ if (yDiff < 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else {
+ if (yDiff >= 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ }
+ } else {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else {
+ direction = Hero::kHeroDirLeft;
+ if (xDiff < 0) {
+ direction = Hero::kHeroDirRight;
+ }
+ }
+ } else {
+ if (yDiff) {
+ direction = Hero::kHeroDirUp;
+ if (yDiff < 0) {
+ direction = Hero::kHeroDirDown;
+ }
+ } else {
+ direction = lastDirection;
+ }
+ }
+ lastDirection = direction;
+ *tempDirTab = direction;
+ tempDirTab++;
+ }
+ *tempDirTab = *(tempDirTab - 1);
+ tempDirTab++;
+ *tempDirTab = 0;
+ }
+}
+
+void PrinceEngine::moveShandria() {
+ int shanLen1 = _shanLen;
+ if (_flags->getFlagValue(Flags::SHANDOG)) {
+ _secondHero->freeHeroAnim();
+ _secondHero->freeOldMove();
+ byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4;
+ int shanX = READ_LE_UINT16(shanCoords - 4);
+ int shanY = READ_LE_UINT16(shanCoords - 2);
+ int xDiff = shanX - _secondHero->_middleX;
+ if (xDiff < 0) {
+ xDiff *= -1;
+ }
+ int yDiff = shanY - _secondHero->_middleY;
+ if (yDiff < 0) {
+ yDiff *= -1;
+ }
+ shanCoords -= 4;
+ if (shanCoords != _mainHero->_currCoords) {
+ yDiff *= 1.5;
+ int shanDis = xDiff * xDiff + yDiff * yDiff;
+ if (shanDis >= kMinDistance) {
+ while (1) {
+ shanCoords -= 4;
+ if (shanCoords == _mainHero->_currCoords) {
+ break;
+ }
+ int x = READ_LE_UINT16(shanCoords);
+ int y = READ_LE_UINT16(shanCoords + 2);
+ int pointDiffX = x - shanX;
+ if (pointDiffX < 0) {
+ pointDiffX *= -1;
+ }
+ int pointDiffY = y - shanY;
+ if (pointDiffY < 0) {
+ pointDiffY *= -1;
+ }
+ pointDiffY *= 1.5;
+ int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY;
+ if (distance >= kMinDistance) {
+ break;
+ }
+ }
+ int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4;
+ int destDir = *(_mainHero->_currDirTab + pathSizeDiff);
+ _secondHero->_destDirection = destDir;
+ int destX = READ_LE_UINT16(shanCoords);
+ int destY = READ_LE_UINT16(shanCoords + 2);
+ _secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY);
+ if (_secondHero->_coords != nullptr) {
+ _secondHero->_currCoords = _secondHero->_coords;
+ int delay = shanLen1 - _shanLen;
+ if (delay < 6) {
+ delay = 6;
+ }
+ _secondHero->_moveDelay = delay / 2;
+ _secondHero->_state = Hero::kHeroStateDelayMove;
+ _secondHero->_dirTab = _directionTable;
+ _secondHero->_currDirTab = _directionTable;
+ _directionTable = nullptr;
+ }
+ }
+ }
+ }
+}
+
+byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) {
+ int realDestX = destX;
+ int realDestY = destY;
+ _flags->setFlagValue(Flags::MOVEDESTX, destX);
+ _flags->setFlagValue(Flags::MOVEDESTY, destY);
+
+ int x1 = currX / 2;
+ int y1 = currY / 2;
+ int x2 = destX / 2;
+ int y2 = destY / 2;
+
+ if ((x1 != x2) || (y1 != y2)) {
+ findPoint(x1, y1);
+ if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
+ return nullptr;
+ }
+ if ((x1 != _fpX) || (y1 != _fpY)) {
+ x1 = _fpX;
+ y1 = _fpY;
+ }
+ findPoint(x2, y2);
+ if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
+ return nullptr;
+ }
+ if ((x2 != _fpX) || (y2 != _fpY)) {
+ x2 = _fpX;
+ y2 = _fpY;
+ if (!_flags->getFlagValue(Flags::EXACTMOVE)) {
+ realDestX = x2 * 2;
+ realDestY = y2 * 2;
+ _flags->setFlagValue(Flags::MOVEDESTX, realDestX);
+ _flags->setFlagValue(Flags::MOVEDESTY, realDestY);
+ } else {
+ return nullptr;
+ }
+ }
+
+ if ((x1 == x2) && (y1 == y2)) {
+ if (!heroId) {
+ _mainHero->freeOldMove();
+ _mainHero->_state = Hero::kHeroStateTurn;
+ } else if (heroId == 1) {
+ _secondHero->freeOldMove();
+ _secondHero->_state = Hero::kHeroStateTurn;
+ }
+ return nullptr;
+ }
+
+ int pathLen1 = 0;
+ int pathLen2 = 0;
+ int stX = x1;
+ int stY = y1;
+ int sizeCoords2 = 0;
+
+ if (tracePath(x1, y1, x2, y2)) {
+ allocCoords2();
+ approxPath();
+ sizeCoords2 = _coords2 - _coordsBuf2;
+ for (int i = 0; i < sizeCoords2; i++) {
+ _coordsBuf[i] = _coordsBuf2[i];
+ }
+ _coords = _coordsBuf + sizeCoords2;
+ approxPath();
+ _coordsBuf3 = _coordsBuf2;
+ _coordsBuf2 = nullptr;
+ _coords3 = _coords2;
+ _coords2 = nullptr;
+ pathLen1 = _coords3 - _coordsBuf3;
+ }
+ if (tracePath(x2, y2, x1, y1)) {
+ allocCoords2();
+ approxPath();
+ sizeCoords2 = _coords2 - _coordsBuf2;
+ for (int i = 0; i < sizeCoords2; i++) {
+ _coordsBuf[i] = _coordsBuf2[i];
+ }
+ _coords = _coordsBuf + sizeCoords2;
+ approxPath();
+ pathLen2 = _coords2 - _coordsBuf2;
+ }
+
+ byte *chosenCoordsBuf = _coordsBuf2;
+ byte *choosenCoords = _coords2;
+ int choosenLength = pathLen1;
+ if (pathLen1 < pathLen2) {
+ chosenCoordsBuf = _coordsBuf3;
+ choosenCoords = _coords3;
+ choosenLength = pathLen2;
+ }
+
+ if (choosenLength) {
+ if (chosenCoordsBuf != nullptr) {
+ int tempXBegin = READ_LE_UINT16(chosenCoordsBuf);
+ int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2);
+ if (stX != tempXBegin || stY != tempYBegin) {
+ SWAP(chosenCoordsBuf, choosenCoords);
+ chosenCoordsBuf -= 4;
+ byte *tempCoordsBuf = _coordsBuf;
+ while (1) {
+ int cord = READ_LE_UINT32(chosenCoordsBuf);
+ WRITE_LE_UINT32(tempCoordsBuf, cord);
+ tempCoordsBuf += 4;
+ if (chosenCoordsBuf == choosenCoords) {
+ break;
+ }
+ chosenCoordsBuf -= 4;
+ }
+ _coords = tempCoordsBuf;
+ } else {
+ int sizeChoosen = choosenCoords - chosenCoordsBuf;
+ for (int i = 0; i < sizeChoosen; i++) {
+ _coordsBuf[i] = chosenCoordsBuf[i];
+ }
+ _coords = _coordsBuf + sizeChoosen;
+ }
+ WRITE_LE_UINT32(_coords, 0xFFFFFFFF);
+ freeCoords2();
+ freeCoords3();
+ scanDirections();
+
+ byte *tempCoordsBuf = _coordsBuf;
+ byte *tempCoords = _coords;
+ byte *newCoords;
+ if (tempCoordsBuf != tempCoords) {
+ int normCoordsSize = _coords - _coordsBuf + 4;
+ newCoords = (byte *)malloc(normCoordsSize);
+ byte *newCoordsBegin = newCoords;
+ while (tempCoordsBuf != tempCoords) {
+ int newValueX = READ_LE_UINT16(tempCoordsBuf);
+ WRITE_LE_UINT16(newCoords, newValueX * 2);
+ newCoords += 2;
+ int newValueY = READ_LE_UINT16(tempCoordsBuf + 2);
+ WRITE_LE_UINT16(newCoords, newValueY * 2);
+ newCoords += 2;
+ tempCoordsBuf += 4;
+ }
+ WRITE_LE_UINT16(newCoords - 4, realDestX);
+ WRITE_LE_UINT16(newCoords - 2, realDestY);
+ WRITE_LE_UINT32(newCoords, 0xFFFFFFFF);
+ newCoords += 4;
+ _shanLen = (newCoords - newCoordsBegin);
+ _shanLen /= 4;
+ return newCoordsBegin;
+ }
+ }
+ }
+ _coords = _coordsBuf;
+ freeCoords2();
+ freeCoords3();
+ return nullptr;
+ } else {
+ if (!heroId) {
+ _mainHero->freeOldMove();
+ _mainHero->_state = Hero::kHeroStateTurn;
+ } else if (heroId == 1) {
+ _secondHero->freeOldMove();
+ _secondHero->_state = Hero::kHeroStateTurn;
+ }
+ return nullptr;
+ }
+}
+
+void PrinceEngine::allocCoords2() {
+ if (_coordsBuf2 == nullptr) {
+ _coordsBuf2 = (byte *)malloc(kTracePts * 4);
+ _coords2 = _coordsBuf2;
+ }
+}
+
+void PrinceEngine::freeCoords2() {
+ if (_coordsBuf2 != nullptr) {
+ free(_coordsBuf2);
+ _coordsBuf2 = nullptr;
+ _coords2 = nullptr;
+ }
+}
+
+void PrinceEngine::freeCoords3() {
+ if (_coordsBuf3 != nullptr) {
+ free(_coordsBuf3);
+ _coordsBuf3 = nullptr;
+ _coords3 = nullptr;
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/queen/detection.cpp b/engines/queen/detection.cpp
index aed8b7dcb1..b9a7c5dff6 100644
--- a/engines/queen/detection.cpp
+++ b/engines/queen/detection.cpp
@@ -422,6 +422,45 @@ static const QueenGameDescription gameDescriptions[] = {
},
#endif
+ // GoG.com Release - German
+ {
+ {
+ "queen",
+ "Talkie",
+ AD_ENTRY1s("queen.1", "28f78dbec7e20f603a10c2f8ea889a5c", 108738717),
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GAMEOPTION_ALT_INTRO)
+ },
+ },
+
+ // GoG.com Release - French
+ {
+ {
+ "queen",
+ "Talkie",
+ AD_ENTRY1s("queen.1", "67e3020f8a35e1df7b1c753b5aaa71e1", 97382620),
+ Common::FR_FRA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GAMEOPTION_ALT_INTRO)
+ },
+ },
+
+ // GoG.com Release - Italian
+ {
+ {
+ "queen",
+ "Talkie",
+ AD_ENTRY1s("queen.1", "2f72b715ed753cf905a37cdcc7ea611e", 98327801),
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GAMEOPTION_ALT_INTRO)
+ },
+ },
+
{ AD_TABLE_END_MARKER }
};
@@ -447,7 +486,7 @@ public:
virtual int getMaximumSaveSlot() const { return 99; }
virtual void removeSaveState(const char *target, int slot) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -457,7 +496,7 @@ bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSupportsDeleteSave);
}
-const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame QueenMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
static ADGameDescription desc;
// Iterate over all files in the given directory
@@ -492,11 +531,13 @@ const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles
desc.extra = "Talkie";
desc.guiOptions = GAMEOPTION_ALT_INTRO;
}
- return (const ADGameDescription *)&desc;
+
+ return ADDetectedGame(&desc);
}
}
}
- return 0;
+
+ return ADDetectedGame();
}
SaveStateList QueenMetaEngine::listSaves(const char *target) const {
diff --git a/engines/queen/music.cpp b/engines/queen/music.cpp
index 9f74aab915..c65f2de5ef 100644
--- a/engines/queen/music.cpp
+++ b/engines/queen/music.cpp
@@ -102,10 +102,7 @@ MidiMusic::~MidiMusic() {
}
void MidiMusic::setVolume(int volume) {
- if (volume < 0)
- volume = 0;
- else if (volume > 255)
- volume = 255;
+ volume = CLIP(volume, 0, 255);
if (_masterVolume == volume)
return;
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index 6fe4277c27..82c29d3389 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -105,7 +105,7 @@ public:
_singleId = "saga";
}
- virtual GameDescriptor findGame(const char *gameId) const {
+ PlainGameDescriptor findGame(const char *gameId) const override {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
@@ -256,7 +256,11 @@ SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int s
}
if (version >= 6) {
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ delete in;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
uint32 saveDate = in->readUint32BE();
diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp
index b7c3fa4d6e..912e62d492 100644
--- a/engines/saga/events.cpp
+++ b/engines/saga/events.cpp
@@ -176,7 +176,7 @@ int Events::handleContinuous(Event *event) {
rect.setWidth(w);
rect.setHeight(h);
- _vm->_render->getBackGroundSurface()->transitionDissolve( maskBuffer, rect, 1, event_pc);
+ _vm->_render->getBackGroundSurface()->transitionDissolve(maskBuffer, rect, 1, event_pc);
_vm->_render->setFullRefresh(true);
break;
default:
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index e6b196c4cd..250d2914b7 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -2804,8 +2804,8 @@ void Interface::mapPanelDrawCrossHair() {
if (screen.contains(mapPosition)) {
_vm->_sprite->draw(_vm->_sprite->_mainSprites,
- _mapPanelCrossHairState? RID_ITE_SPR_CROSSHAIR : RID_ITE_SPR_CROSSHAIR + 1,
- mapPosition, 256);
+ _mapPanelCrossHairState ? RID_ITE_SPR_CROSSHAIR : RID_ITE_SPR_CROSSHAIR + 1,
+ mapPosition, 256);
}
}
diff --git a/engines/saga/isomap.cpp b/engines/saga/isomap.cpp
index cff415868e..ae2b458461 100644
--- a/engines/saga/isomap.cpp
+++ b/engines/saga/isomap.cpp
@@ -304,18 +304,8 @@ void IsoMap::adjustScroll(bool jump) {
maxScrollPos.y = playerPoint.y + SAGA_SCROLL_LIMIT_Y2;
if (jump) {
- if (_viewScroll.y < minScrollPos.y) {
- _viewScroll.y = minScrollPos.y;
- }
- if (_viewScroll.y > maxScrollPos.y) {
- _viewScroll.y = maxScrollPos.y;
- }
- if (_viewScroll.x < minScrollPos.x) {
- _viewScroll.x = minScrollPos.x;
- }
- if (_viewScroll.x > maxScrollPos.x) {
- _viewScroll.x = maxScrollPos.x;
- }
+ _viewScroll.x = CLIP(_viewScroll.x, minScrollPos.x, maxScrollPos.x);
+ _viewScroll.y = CLIP(_viewScroll.y, minScrollPos.y, maxScrollPos.y);
} else {
_viewScroll.y = smoothSlide(_viewScroll.y, minScrollPos.y, maxScrollPos.y);
_viewScroll.x = smoothSlide(_viewScroll.x, minScrollPos.x, maxScrollPos.x);
@@ -453,7 +443,7 @@ void IsoMap::drawTiles(const Location *location) {
if (uc != u2 || vc != v2) {
metaTileIndex = 0;
- switch ( _tileMap.edgeType) {
+ switch (_tileMap.edgeType) {
case kEdgeTypeBlack:
continue;
case kEdgeTypeFill0:
@@ -497,7 +487,7 @@ void IsoMap::drawTiles(const Location *location) {
if (uc != u2 || vc != v2) {
metaTileIndex = 0;
- switch ( _tileMap.edgeType) {
+ switch (_tileMap.edgeType) {
case kEdgeTypeBlack:
continue;
case kEdgeTypeFill0:
@@ -750,7 +740,7 @@ void IsoMap::drawTile(uint16 tileIndex, const Point &point, const Location *loca
if (location->z >= 16) {
return;
} else {
- switch (_tilesTable[tileIndex].GetMaskRule()) {
+ switch (_tilesTable[tileIndex].getMaskRule()) {
case kMaskRuleNever:
return;
case kMaskRuleAlways:
@@ -1015,7 +1005,7 @@ int16 IsoMap::getTileIndex(int16 u, int16 v, int16 z) {
if ((uc != mtileU) || (vc != mtileV)) {
metaTileIndex = 0;
- switch ( _tileMap.edgeType) {
+ switch (_tileMap.edgeType) {
case kEdgeTypeBlack:
return 0;
case kEdgeTypeFill0:
@@ -1088,8 +1078,8 @@ void IsoMap::testPossibleDirections(int16 u, int16 v, uint16 terraComp[8], int s
#define TEST_TILE_PROLOG(offsetU, offsetV) \
tile = getTile(u + offsetU, v + offsetV , _platformHeight); \
if (tile != NULL) { \
- fgdMask = tile->GetFGDMask(); \
- bgdMask = tile->GetBGDMask(); \
+ fgdMask = tile->getFGDMask(); \
+ bgdMask = tile->getBGDMask(); \
mask = tile->terrainMask;
#define TEST_TILE_EPILOG(index) \
@@ -1193,7 +1183,7 @@ void IsoMap::placeOnTileMap(const Location &start, Location &result, int16 dista
_platformHeight = _vm->_actor->_protagonist->_location.z / 8;
- memset( &_searchArray, 0, sizeof(_searchArray));
+ memset(&_searchArray, 0, sizeof(_searchArray));
for (ActorDataArray::const_iterator actor = _vm->_actor->_actors.begin(); actor != _vm->_actor->_actors.end(); ++actor) {
if (!actor->_inScene) continue;
@@ -1248,7 +1238,7 @@ void IsoMap::placeOnTileMap(const Location &start, Location &result, int16 dista
}
}
- pushPoint(tilePoint.u + tdir->u,tilePoint.v + tdir->v, tilePoint.cost + tdir->cost, dir);
+ pushPoint(tilePoint.u + tdir->u, tilePoint.v + tdir->v, tilePoint.cost + tdir->cost, dir);
}
}
@@ -1263,35 +1253,35 @@ bool IsoMap::findNearestChasm(int16 &u0, int16 &v0, uint16 &direction) {
v = v0;
for (i = 1; i < 5; i++) {
- if (getTile( u - i, v, 6) == NULL) {
+ if (getTile(u - i, v, 6) == NULL) {
u0 = u - i - 1;
v0 = v;
direction = kDirDownLeft;
return true;
}
- if (getTile( u, v - i, 6) == NULL) {
+ if (getTile(u, v - i, 6) == NULL) {
u0 = u;
v0 = v - i - 1;
direction = kDirDownRight;
return true;
}
- if (getTile( u - i, v - i, 6) == NULL) {
+ if (getTile(u - i, v - i, 6) == NULL) {
u0 = u - i - 1;
v0 = v - i - 1;
direction = kDirDown;
return true;
}
- if (getTile( u + i, v - i, 6) == NULL) {
+ if (getTile(u + i, v - i, 6) == NULL) {
u0 = u + i + 1;
v0 = v - i - 1;
direction = kDirDownRight;
return true;
}
- if (getTile( u - i, v + i, 6) == NULL) {
+ if (getTile(u - i, v + i, 6) == NULL) {
u0 = u + i + 1;
v0 = v - i - 1;
direction = kDirLeft;
@@ -1300,21 +1290,21 @@ bool IsoMap::findNearestChasm(int16 &u0, int16 &v0, uint16 &direction) {
}
for (i = 1; i < 5; i++) {
- if (getTile( u + i, v, 6) == NULL) {
+ if (getTile(u + i, v, 6) == NULL) {
u0 = u + i + 1;
v0 = v;
direction = kDirUpRight;
return true;
}
- if (getTile( u, v + i, 6) == NULL) {
+ if (getTile(u, v + i, 6) == NULL) {
u0 = u;
v0 = v + i + 1;
direction = kDirUpLeft;
return true;
}
- if (getTile( u + i, v + i, 6) == NULL) {
+ if (getTile(u + i, v + i, 6) == NULL) {
u0 = u + i + 1;
v0 = v + i + 1;
direction = kDirUp;
@@ -1324,7 +1314,7 @@ bool IsoMap::findNearestChasm(int16 &u0, int16 &v0, uint16 &direction) {
return false;
}
-void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Location &end, uint16 initialDirection) {
+void IsoMap::findDragonTilePath(ActorData* actor, const Location &start, const Location &end, uint16 initialDirection) {
byte *res;
int i;
int16 u;
@@ -1360,7 +1350,7 @@ void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Lo
_platformHeight = _vm->_actor->_protagonist->_location.z / 8;
- memset( &_dragonSearchArray, 0, sizeof(_dragonSearchArray));
+ memset(&_dragonSearchArray, 0, sizeof(_dragonSearchArray));
for (u = 0; u < SAGA_DRAGON_SEARCH_DIAMETER; u++) {
for (v = 0; v < SAGA_DRAGON_SEARCH_DIAMETER; v++) {
@@ -1378,8 +1368,8 @@ void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Lo
tile = getTile(u1, v1, _platformHeight);
if (tile != NULL) {
mask = tile->terrainMask;
- if (((mask != 0) && (tile->GetFGDAttr() >= kTerrBlock)) ||
- ((mask != 0xFFFF) && (tile->GetBGDAttr() >= kTerrBlock))) {
+ if (((mask != 0 ) && (tile->getFGDAttr() >= kTerrBlock)) ||
+ ((mask != 0xFFFF) && (tile->getBGDAttr() >= kTerrBlock))) {
pcell->visited = 1;
}
} else {
@@ -1390,7 +1380,7 @@ void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Lo
first = true;
_queueCount = _readCount = 0;
- pushDragonPoint( SAGA_DRAGON_SEARCH_CENTER, SAGA_DRAGON_SEARCH_CENTER, initialDirection);
+ pushDragonPoint(SAGA_DRAGON_SEARCH_CENTER, SAGA_DRAGON_SEARCH_CENTER, initialDirection);
while (_queueCount != _readCount) {
@@ -1414,40 +1404,40 @@ void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Lo
switch (tilePoint->direction) {
case kDirUpRight:
- if (checkDragonPoint( tilePoint->u + 1, tilePoint->v + 0, kDirUpRight)) {
- pushDragonPoint( tilePoint->u + 2, tilePoint->v + 0, kDirUpRight);
- pushDragonPoint( tilePoint->u + 1, tilePoint->v + 1, kDirUpLeft);
- pushDragonPoint( tilePoint->u + 1, tilePoint->v - 1, kDirDownRight);
+ if (checkDragonPoint(tilePoint->u + 1, tilePoint->v + 0, kDirUpRight)) {
+ pushDragonPoint(tilePoint->u + 2, tilePoint->v + 0, kDirUpRight);
+ pushDragonPoint(tilePoint->u + 1, tilePoint->v + 1, kDirUpLeft);
+ pushDragonPoint(tilePoint->u + 1, tilePoint->v - 1, kDirDownRight);
}
break;
case kDirDownRight:
- if (checkDragonPoint( tilePoint->u + 0, tilePoint->v - 1, kDirDownRight)) {
- pushDragonPoint( tilePoint->u + 0, tilePoint->v - 2, kDirDownRight);
- pushDragonPoint( tilePoint->u + 1, tilePoint->v - 1, kDirUpRight);
- pushDragonPoint( tilePoint->u - 1, tilePoint->v - 1, kDirDownLeft);
+ if (checkDragonPoint(tilePoint->u + 0, tilePoint->v - 1, kDirDownRight)) {
+ pushDragonPoint(tilePoint->u + 0, tilePoint->v - 2, kDirDownRight);
+ pushDragonPoint(tilePoint->u + 1, tilePoint->v - 1, kDirUpRight);
+ pushDragonPoint(tilePoint->u - 1, tilePoint->v - 1, kDirDownLeft);
}
break;
case kDirDownLeft:
- if (checkDragonPoint( tilePoint->u - 1, tilePoint->v + 0, kDirDownLeft)) {
- pushDragonPoint( tilePoint->u - 2, tilePoint->v + 0, kDirDownLeft);
- pushDragonPoint( tilePoint->u - 1, tilePoint->v - 1, kDirDownRight);
- pushDragonPoint( tilePoint->u - 1, tilePoint->v + 1, kDirUpLeft);
+ if (checkDragonPoint(tilePoint->u - 1, tilePoint->v + 0, kDirDownLeft)) {
+ pushDragonPoint(tilePoint->u - 2, tilePoint->v + 0, kDirDownLeft);
+ pushDragonPoint(tilePoint->u - 1, tilePoint->v - 1, kDirDownRight);
+ pushDragonPoint(tilePoint->u - 1, tilePoint->v + 1, kDirUpLeft);
}
break;
case kDirUpLeft:
- if (checkDragonPoint( tilePoint->u + 0, tilePoint->v + 1, kDirUpLeft)) {
- pushDragonPoint( tilePoint->u + 0, tilePoint->v + 2, kDirUpLeft);
- pushDragonPoint( tilePoint->u - 1, tilePoint->v + 1, kDirDownLeft);
- pushDragonPoint( tilePoint->u + 1, tilePoint->v + 1, kDirUpRight);
+ if (checkDragonPoint(tilePoint->u + 0, tilePoint->v + 1, kDirUpLeft)) {
+ pushDragonPoint(tilePoint->u + 0, tilePoint->v + 2, kDirUpLeft);
+ pushDragonPoint(tilePoint->u - 1, tilePoint->v + 1, kDirDownLeft);
+ pushDragonPoint(tilePoint->u + 1, tilePoint->v + 1, kDirUpRight);
}
break;
}
if (first && (_queueCount == _readCount)) {
- pushDragonPoint( tilePoint->u + 1, tilePoint->v + 0, kDirUpRight);
- pushDragonPoint( tilePoint->u + 0, tilePoint->v - 1, kDirDownRight);
- pushDragonPoint( tilePoint->u - 1, tilePoint->v + 0, kDirDownLeft);
- pushDragonPoint( tilePoint->u + 0, tilePoint->v + 1, kDirUpLeft);
+ pushDragonPoint(tilePoint->u + 1, tilePoint->v + 0, kDirUpRight);
+ pushDragonPoint(tilePoint->u + 0, tilePoint->v - 1, kDirDownRight);
+ pushDragonPoint(tilePoint->u - 1, tilePoint->v + 0, kDirDownLeft);
+ pushDragonPoint(tilePoint->u + 0, tilePoint->v + 1, kDirUpLeft);
}
first = false;
}
@@ -1517,7 +1507,7 @@ void IsoMap::findTilePath(ActorData* actor, const Location &start, const Locatio
- memset( &_searchArray, 0, sizeof(_searchArray));
+ memset(&_searchArray, 0, sizeof(_searchArray));
if (!(actor->_actorFlags & kActorNoCollide) &&
(_vm->_scene->currentSceneResourceId() != ITE_SCENE_OVERMAP)) {
@@ -1658,7 +1648,7 @@ bool IsoMap::nextTileTarget(ActorData* actor) {
void IsoMap::screenPointToTileCoords(const Point &position, Location &location) {
Point mPos(position);
- int x,y;
+ int x, y;
if (_vm->_scene->currentSceneResourceId() == ITE_SCENE_OVERMAP){
if (mPos.y < 16) {
diff --git a/engines/saga/isomap.h b/engines/saga/isomap.h
index 155d9b8d24..83dfd98b87 100644
--- a/engines/saga/isomap.h
+++ b/engines/saga/isomap.h
@@ -95,20 +95,20 @@ struct IsoTileData {
byte *tilePointer;
uint16 terrainMask;
byte FGDBGDAttr;
- int8 GetMaskRule() const {
+ int8 getMaskRule() const {
return attributes & 0x0F;
}
- byte GetFGDAttr() const {
+ byte getFGDAttr() const {
return FGDBGDAttr >> 4;
}
- byte GetBGDAttr() const {
+ byte getBGDAttr() const {
return FGDBGDAttr & 0x0F;
}
- uint16 GetFGDMask() const {
- return 1 << GetFGDAttr();
+ uint16 getFGDMask() const {
+ return 1 << getFGDAttr();
}
- uint16 GetBGDMask() const {
- return 1 << GetBGDAttr();
+ uint16 getBGDMask() const {
+ return 1 << getBGDAttr();
}
};
diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp
index 1d014052ed..77090860aa 100644
--- a/engines/saga/puzzle.cpp
+++ b/engines/saga/puzzle.cpp
@@ -93,25 +93,25 @@ Puzzle::Puzzle(SagaEngine *vm) : _vm(vm), _solved(false), _active(false) {
_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,
+ 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,
Point(0, 31), Point(0, 47), Point(39, 47), Point(15, 1), Point(0, 0), Point(0, 0));
- initPieceInfo( 2, 19, 51, 0, 0, 0 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 4,
+ initPieceInfo(2, 19, 51, 0, 0, 0 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 4,
Point(0, 0), Point(23, 46), Point(39, 15), Point(31, 0), Point(0, 0), Point(0, 0));
- initPieceInfo( 3, 73, 0, 0, 0, 32 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 6,
+ initPieceInfo(3, 73, 0, 0, 0, 32 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 6,
Point(0, 0), Point(8, 16), Point(0, 31), Point(31, 31), Point(39, 15), Point(31, 0));
- initPieceInfo( 4, 0, 35, 0, 0, 64 + PUZZLE_X_OFFSET, 16 + PUZZLE_Y_OFFSET, 0, 4,
+ initPieceInfo(4, 0, 35, 0, 0, 64 + PUZZLE_X_OFFSET, 16 + PUZZLE_Y_OFFSET, 0, 4,
Point(0, 15), Point(15, 46), Point(23, 32), Point(7, 1), Point(0, 0), Point(0, 0));
- initPieceInfo( 5, 215, 0, 0, 0, 24 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 6,
+ initPieceInfo(5, 215, 0, 0, 0, 24 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 6,
Point(0, 15), Point(8, 31), Point(39, 31), Point(47, 16), Point(39, 0), Point(8, 0));
- initPieceInfo( 6, 159, 0, 0, 0, 32 + PUZZLE_X_OFFSET, 48 + PUZZLE_Y_OFFSET, 0, 5,
+ initPieceInfo(6, 159, 0, 0, 0, 32 + PUZZLE_X_OFFSET, 48 + PUZZLE_Y_OFFSET, 0, 5,
Point(0, 16), Point(8, 31), Point(55, 31), Point(39, 1), Point(32, 15), Point(0, 0));
- initPieceInfo( 7, 9, 70, 0, 0, 80 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 5,
+ initPieceInfo(7, 9, 70, 0, 0, 80 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 5,
Point(0, 31), Point(8, 47), Point(23, 47), Point(31, 31), Point(15, 1), Point(0, 0));
- initPieceInfo( 8, 288, 18, 0, 0, 96 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 4,
+ initPieceInfo(8, 288, 18, 0, 0, 96 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 4,
Point(0, 31), Point(15, 62), Point(31, 32), Point(15, 1), Point(0, 0), Point(0, 0));
- initPieceInfo( 9, 112, 0, 0, 0, 112 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 4,
+ initPieceInfo(9, 112, 0, 0, 0, 112 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 4,
Point(0, 0), Point(16, 31), Point(47, 31), Point(31, 0), Point(0, 0), Point(0, 0));
initPieceInfo(10, 27, 89, 0, 0, 104 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 4,
Point(0, 47), Point(31, 47), Point(31, 0), Point(24, 0), Point(0, 0), Point(0, 0));
diff --git a/engines/saga/resource_hrs.cpp b/engines/saga/resource_hrs.cpp
index ba58830269..9257f65cbc 100644
--- a/engines/saga/resource_hrs.cpp
+++ b/engines/saga/resource_hrs.cpp
@@ -34,7 +34,6 @@
#include "saga/scene.h"
#include "saga/sndres.h"
-#include "engines/advancedDetector.h"
#include "common/endian.h"
namespace Saga {
diff --git a/engines/saga/resource_res.cpp b/engines/saga/resource_res.cpp
index d57238b2eb..a2822f8b33 100644
--- a/engines/saga/resource_res.cpp
+++ b/engines/saga/resource_res.cpp
@@ -32,8 +32,6 @@
#include "saga/scene.h"
#include "saga/sndres.h"
-#include "engines/advancedDetector.h"
-
namespace Saga {
#ifdef ENABLE_IHNM
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 36496e828b..b0d78f753d 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -572,7 +572,7 @@ public:
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
@@ -600,7 +600,7 @@ Common::Language charToScummVMLanguage(const char c) {
}
}
-const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
bool foundResMap = false;
bool foundRes000 = false;
@@ -657,7 +657,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// If these files aren't found, it can't be SCI
if (!foundResMap && !foundRes000)
- return 0;
+ return ADDetectedGame();
ResourceManager resMan(true);
resMan.addAppropriateSourcesForDetection(fslist);
@@ -668,7 +668,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// Is SCI32 compiled in? If not, and this is a SCI32 game,
// stop here
if (getSciVersionForDetection() >= SCI_VERSION_2)
- return 0;
+ return ADDetectedGame();
#endif
ViewType gameViews = resMan.getViewType();
@@ -677,7 +677,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// Can't be SCI (or unsupported SCI views). Pinball Creep by Sierra also uses resource.map/resource.000 files
// but doesn't share SCI format at all
if (gameViews == kViewUnknown)
- return 0;
+ return ADDetectedGame();
// Set the platform to Amiga if the game is using Amiga views
if (gameViews == kViewAmiga)
@@ -688,7 +688,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// If we don't have a game id, the game is not SCI
if (sierraGameId.empty())
- return 0;
+ return ADDetectedGame();
Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
@@ -763,7 +763,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
s_fallbackDesc.extra = "CD";
}
- return &s_fallbackDesc;
+ return ADDetectedGame(&s_fallbackDesc);
}
bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -881,7 +881,14 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl
descriptor.setDescription(meta.name);
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ // invalid
+ delete in;
+
+ descriptor.setDescription("*Invalid*");
+ return descriptor;
+ }
descriptor.setThumbnail(thumbnail);
int day = (meta.saveDate >> 24) & 0xFF;
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 7e63c3576c..3c23cd515f 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1073,6 +1073,7 @@ reg_t kSetPort(EngineState *s, int argc, reg_t *argv) {
case 7:
initPriorityBandsFlag = true;
+ // fall through
case 6:
picRect.top = argv[0].toSint16();
picRect.left = argv[1].toSint16();
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 937b1cfc2f..eb4d5d3748 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -1919,7 +1919,7 @@ static int intersectDir(const Vertex *v1, const Vertex *v2) {
// Direction of edge in degrees from pos. x-axis, between -180 and 180
static int edgeDir(const Vertex *v) {
Common::Point p = v->_next->v - v->v;
- int deg = (int)Common::rad2deg((float)atan2((double)p.y, (double)p.x));
+ int deg = Common::rad2deg<float,int>((float)atan2((double)p.y, (double)p.x));
if (deg < -180) deg += 360;
if (deg > 180) deg -= 360;
return deg;
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index aef84e212d..ab56311cd6 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -418,7 +418,7 @@ SciEvent EventManager::getSciEvent(SciEventType mask) {
void EventManager::flushEvents() {
Common::EventManager *em = g_system->getEventManager();
Common::Event event;
- while (em->pollEvent(event));
+ while (em->pollEvent(event)) {}
_events.clear();
}
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 317e98feab..8875162394 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -650,6 +650,11 @@ void GfxAnimate::animateShowPic() {
}
void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t *argv) {
+ // If necessary, delay this kAnimate for a running PalVary.
+ // See delayForPalVaryWorkaround() for details.
+ if (_screen->_picNotValid)
+ _palette->delayForPalVaryWorkaround();
+
byte old_picNotValid = _screen->_picNotValid;
if (getSciVersion() >= SCI_VERSION_1_1)
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 02b2859f5c..37e9d39bf5 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -132,6 +132,9 @@ struct CelInfo32 {
default:
assert(!"Should never happen");
}
+ // This code should not be reached but the compiler expects to see a legal
+ // return from a non-void function.
+ return Common::String("here be dragons");
}
};
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index e36028d984..bc0b8485d2 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -716,6 +716,7 @@ void GfxPalette::palVaryInit() {
_palVaryStepStop = 0;
_palVaryDirection = 0;
_palVaryTicks = 0;
+ _palVaryZeroTick = false;
}
bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) {
@@ -759,19 +760,13 @@ bool GfxPalette::kernelPalVaryInit(GuiResourceId resourceId, uint16 ticks, uint1
_palVaryStep = 1;
_palVaryStepStop = stepStop;
_palVaryDirection = direction;
+
// if no ticks are given, jump directly to destination
- if (!_palVaryTicks) {
+ if (!_palVaryTicks)
_palVaryDirection = stepStop;
- // sierra sci set the timer to 1 tick instead of calling it directly
- // we have to change this to prevent a race condition to happen in
- // at least freddy pharkas during nighttime. In that case kPalVary is
- // called right before a transition and because we load pictures much
- // faster, the 1 tick won't pass sometimes resulting in the palette
- // being daytime instead of nighttime during the transition.
- palVaryProcess(1, true);
- } else {
- palVaryInstallTimer();
- }
+ _palVaryZeroTick = (_palVaryTicks == 0); //see delayForPalVaryWorkaround()
+
+ palVaryInstallTimer();
return true;
}
return false;
@@ -788,14 +783,13 @@ int16 GfxPalette::kernelPalVaryReverse(int16 ticks, uint16 stepStop, int16 direc
_palVaryStepStop = stepStop;
_palVaryDirection = direction != -1 ? -direction : -_palVaryDirection;
- if (!_palVaryTicks) {
+ // if no ticks are given, jump directly to destination
+ if (!_palVaryTicks)
_palVaryDirection = _palVaryStepStop - _palVaryStep;
- // see palVaryInit above, we fix the code here as well
- // just in case
- palVaryProcess(1, true);
- } else {
- palVaryInstallTimer();
- }
+ _palVaryZeroTick = (_palVaryTicks == 0); // see delayForPalVaryWorkaround()
+
+ palVaryInstallTimer();
+
return kernelPalVaryGetCurrentStep();
}
@@ -855,6 +849,7 @@ void GfxPalette::palVaryIncreaseSignal() {
// FIXME: increments from another thread aren't guaranteed to be atomic
if (!_palVaryPaused)
_palVarySignal++;
+ _palVaryZeroTick = false;
}
// Actually do the pal vary processing
@@ -865,6 +860,34 @@ void GfxPalette::palVaryUpdate() {
}
}
+void GfxPalette::delayForPalVaryWorkaround() {
+ if (_palVaryResourceId == -1)
+ return;
+ if (_palVaryPaused)
+ return;
+
+ // This gets called at the very beginning of kAnimate.
+ // If a zero-tick palVary is running, we delay briefly to give the
+ // palVary time to trigger. In theory there should be no reason for this
+ // to have to wait more than a tick, but we time-out after 4 ticks
+ // to be on the safe side.
+ //
+ // This prevents a race condition in Freddy Pharkas during nighttime,
+ // since we load pictures much faster than on original hardware (bug #5298).
+
+ if (_palVaryZeroTick) {
+ int i;
+ for (i = 0; i < 4; ++i) {
+ g_sci->sleep(17);
+ if (!_palVaryZeroTick)
+ break;
+ }
+ debugC(kDebugLevelGraphics, "Delayed kAnimate for kPalVary, %d times", i+1);
+ if (_palVaryZeroTick)
+ warning("Delayed kAnimate for kPalVary timed out");
+ }
+}
+
void GfxPalette::palVaryPrepareForTransition() {
if (_palVaryResourceId != -1) {
// Before doing transitions, we have to prepare palette
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index af74169976..2923df9220 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -88,6 +88,8 @@ public:
void palVaryPrepareForTransition();
void palVaryProcess(int signal, bool setPalette);
+ void delayForPalVaryWorkaround();
+
Palette _sysPalette;
void saveLoadWithSerializer(Common::Serializer &s);
@@ -122,6 +124,7 @@ protected:
uint16 _palVaryTicks;
int _palVaryPaused;
int _palVarySignal;
+ bool _palVaryZeroTick;
uint16 _totalScreenColors;
void loadMacIconBarPalette();
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 46d08a5997..889a875804 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -143,25 +143,25 @@ public:
MidiPlayer_Midi(SciVersion version);
virtual ~MidiPlayer_Midi();
- int open(ResourceManager *resMan);
- void close();
- void send(uint32 b);
- void sysEx(const byte *msg, uint16 length);
- bool hasRhythmChannel() const { return true; }
- byte getPlayId() const;
- int getPolyphony() const {
+ int open(ResourceManager *resMan) override;
+ void close() override;
+ void send(uint32 b) override;
+ void sysEx(const byte *msg, uint16 length) override;
+ bool hasRhythmChannel() const override { return true; }
+ byte getPlayId() const override;
+ int getPolyphony() const override {
if (g_sci && g_sci->_features->useAltWinGMSound())
return 16;
else
return kVoices;
}
- int getFirstChannel() const;
- int getLastChannel() const;
- void setVolume(byte volume);
+ int getFirstChannel() const override;
+ int getLastChannel() const override;
+ void setVolume(byte volume) override;
virtual void onNewSound() override;
- int getVolume();
- void setReverb(int8 reverb);
- void playSwitch(bool play);
+ int getVolume() override;
+ void setReverb(int8 reverb) override;
+ void playSwitch(bool play) override;
private:
bool isMt32GmPatch(const SciSpan<const byte> &data);
diff --git a/engines/scumm/camera.cpp b/engines/scumm/camera.cpp
index 799fdd7547..5a81057aac 100644
--- a/engines/scumm/camera.cpp
+++ b/engines/scumm/camera.cpp
@@ -25,6 +25,8 @@
#include "scumm/charset.h"
#include "scumm/scumm_v7.h"
+#include "common/util.h"
+
namespace Scumm {
void ScummEngine::setCameraAtEx(int at) {
@@ -85,17 +87,8 @@ void ScummEngine::setCameraFollows(Actor *a, bool setCamera) {
}
void ScummEngine::clampCameraPos(Common::Point *pt) {
- if (pt->x < VAR(VAR_CAMERA_MIN_X))
- pt->x = (short) VAR(VAR_CAMERA_MIN_X);
-
- if (pt->x > VAR(VAR_CAMERA_MAX_X))
- pt->x = (short) VAR(VAR_CAMERA_MAX_X);
-
- if (pt->y < VAR(VAR_CAMERA_MIN_Y))
- pt->y = (short) VAR(VAR_CAMERA_MIN_Y);
-
- if (pt->y > VAR(VAR_CAMERA_MAX_Y))
- pt->y = (short) VAR(VAR_CAMERA_MAX_Y);
+ pt->x = CLIP<short>(pt->x, VAR(VAR_CAMERA_MIN_X), VAR(VAR_CAMERA_MAX_X));
+ pt->y = CLIP<short>(pt->y, VAR(VAR_CAMERA_MIN_Y), VAR(VAR_CAMERA_MAX_Y));
}
void ScummEngine::moveCamera() {
diff --git a/engines/scumm/configure.engine b/engines/scumm/configure.engine
index e8962a371e..42c75226da 100644
--- a/engines/scumm/configure.engine
+++ b/engines/scumm/configure.engine
@@ -2,4 +2,4 @@
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine scumm "SCUMM" yes "scumm_7_8 he" "v0-v6 games"
add_engine scumm_7_8 "v7 & v8 games" yes
-add_engine he "HE71+ games" yes "" "" "highres"
+add_engine he "HE71+ games" yes "" "" "highres bink"
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 0aa993a53a..fccb30b0fa 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -959,9 +959,9 @@ public:
virtual const char *getOriginalCopyright() const;
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist) const;
+ PlainGameList getSupportedGames() const override;
+ PlainGameDescriptor findGame(const char *gameid) const override;
+ virtual DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
@@ -992,11 +992,11 @@ bool ScummEngine::hasFeature(EngineFeature f) const {
(f == kSupportsSubtitleOptions);
}
-GameList ScummMetaEngine::getSupportedGames() const {
- return GameList(gameDescriptions);
+PlainGameList ScummMetaEngine::getSupportedGames() const {
+ return PlainGameList(gameDescriptions);
}
-GameDescriptor ScummMetaEngine::findGame(const char *gameid) const {
+PlainGameDescriptor ScummMetaEngine::findGame(const char *gameid) const {
return Engines::findGameID(gameid, gameDescriptions, obsoleteGameIDsTable);
}
@@ -1026,29 +1026,26 @@ static Common::String generatePreferredTarget(const DetectorResult &x) {
return res;
}
-GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const {
- GameList detectedGames;
+DetectedGames ScummMetaEngine::detectGames(const Common::FSList &fslist) const {
+ DetectedGames detectedGames;
Common::List<DetectorResult> results;
-
::detectGames(fslist, results, 0);
for (Common::List<DetectorResult>::iterator
x = results.begin(); x != results.end(); ++x) {
const PlainGameDescriptor *g = findPlainGameDescriptor(x->game.gameid, gameDescriptions);
assert(g);
- GameDescriptor dg(x->game.gameid, g->description, x->language, x->game.platform);
- // Append additional information, if set, to the description.
- dg.updateDesc(x->extra);
+ DetectedGame game = DetectedGame(x->game.gameid, g->description, x->language, x->game.platform, x->extra);
// Compute and set the preferred target name for this game.
// Based on generateComplexID() in advancedDetector.cpp.
- dg["preferredtarget"] = generatePreferredTarget(*x);
+ game.preferredTarget = generatePreferredTarget(*x);
- dg.setGUIOptions(x->game.guioptions + MidiDriver::musicType2GUIO(x->game.midi));
- dg.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(x->language));
+ game.setGUIOptions(x->game.guioptions + MidiDriver::musicType2GUIO(x->game.midi));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(x->language));
- detectedGames.push_back(dg);
+ detectedGames.push_back(game);
}
return detectedGames;
@@ -1324,6 +1321,14 @@ SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int
}
SaveStateDescriptor desc(slot, saveDesc);
+
+ // Do not allow save slot 0 (used for auto-saving) to be deleted or
+ // overwritten.
+ if (slot == 0) {
+ desc.setWriteProtectedFlag(true);
+ desc.setDeletableFlag(false);
+ }
+
desc.setThumbnail(thumbnail);
if (infoPtr) {
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 9dee4c8a0b..b2cd760ff4 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -127,15 +127,15 @@ class ValueDisplayDialog : public GUI::Dialog {
public:
ValueDisplayDialog(const Common::String& label, int minVal, int maxVal, int val, uint16 incKey, uint16 decKey);
- virtual void open();
+ virtual void open() override;
void drawDialog(GUI::DrawLayer layerToDraw) override;
- virtual void handleTickle();
- virtual void handleMouseDown(int x, int y, int button, int clickCount) {
+ virtual void handleTickle() override;
+ virtual void handleMouseDown(int x, int y, int button, int clickCount) override {
close();
}
- virtual void handleKeyDown(Common::KeyState state);
+ virtual void handleKeyDown(Common::KeyState state) override;
- virtual void reflowLayout();
+ virtual void reflowLayout() override;
protected:
enum {
diff --git a/engines/scumm/he/moonbase/ai_main.cpp b/engines/scumm/he/moonbase/ai_main.cpp
index c391105658..c5c1f6a8e4 100644
--- a/engines/scumm/he/moonbase/ai_main.cpp
+++ b/engines/scumm/he/moonbase/ai_main.cpp
@@ -2811,9 +2811,9 @@ int AI::simulateBuildingLaunch(int x, int y, int power, int angle, int 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 = (static_cast<int>(.70711 * power));
+ sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed));
+ sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed));
sZSpeed *= SCALE_Z;
@@ -2959,9 +2959,9 @@ int AI::simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
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 = (static_cast<int>(.70711 * power));
+ sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed));
+ sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed));
sZSpeed *= SCALE_Z;
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index 5de921bc6b..f5526ab11d 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -1236,11 +1236,8 @@ int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d,
if (trig->id == id && trig->sound == sound && trig->command[0] == a)
break;
- uint16 diff;
- if (trig->expire <= _snm_trigger_index)
- diff = _snm_trigger_index - trig->expire;
- else
- diff = 0x10000 - trig->expire + _snm_trigger_index;
+ // The wraparound if trig->expire > _snm_trigger_index is intentional
+ uint16 diff = _snm_trigger_index - trig->expire;
if (!oldest_ptr || oldest_trigger < diff) {
oldest_ptr = trig;
diff --git a/engines/scumm/imuse_digi/dimuse_track.h b/engines/scumm/imuse_digi/dimuse_track.h
index a007903139..ef0a8adb21 100644
--- a/engines/scumm/imuse_digi/dimuse_track.h
+++ b/engines/scumm/imuse_digi/dimuse_track.h
@@ -66,7 +66,7 @@ struct Track {
int32 curRegion; // id of current used region
int32 curHookId; // id of current used hook id
int32 volGroupId; // id of volume group (IMUSE_VOLGRP_VOICE, IMUSE_VOLGRP_SFX, IMUSE_VOLGRP_MUSIC)
- int32 soundType; // type of sound data (kSpeechSoundType, kSFXSoundType, kMusicSoundType)
+ int32 soundType; // type of sound data (IMUSE_BUNDLE, IMUSE_RESOURCE)
int32 feedSize; // size of sound data needed to be filled at each callback iteration
int32 dataMod12Bit; // value used between all callback to align 12 bit source of data
int32 mixerFlags; // flags for sound mixer's channel (kFlagStereo, kFlag16Bits, kFlagUnsigned)
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 6ef7e4d7f4..9c5271e51c 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -560,7 +560,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
} else if (pauseKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_SPACE && lastKeyHit.hasFlags(0))) {
pauseGame();
- } else if (talkstopKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_PERIOD && lastKeyHit.hasFlags(0))) {
+ } else if (talkstopKeyEnabled && lastKeyHit.ascii == '.') {
_talkDelay = 0;
if (_sound->_sfxMode & 2)
stopTalk();
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index f4aea93b8b..df0b3e1035 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -45,6 +45,7 @@ void ScummEngine::addObjectToInventory(uint obj, uint room) {
idx = getObjectIndex(obj);
assert(idx >= 0);
ptr = getResourceAddress(rtFlObject, _objs[idx].fl_object_index) + 8;
+ assert(ptr);
size = READ_BE_UINT32(ptr + 4);
} else {
findObjectInRoom(&foir, foCodeHeader, obj, room);
@@ -742,6 +743,7 @@ void ScummEngine::resetRoomObjects() {
const CodeHeader *cdhd;
room = getResourceAddress(rtRoom, _roomResource);
+ assert(room);
if (_numObjectsInRoom == 0)
return;
@@ -756,7 +758,7 @@ void ScummEngine::resetRoomObjects() {
assert(searchptr);
// Load in new room objects
- ResourceIterator obcds(searchptr, false);
+ ResourceIterator obcds(searchptr, false);
for (i = 0; i < _numObjectsInRoom; i++) {
od = &_objs[findLocalObjectSlot()];
@@ -784,7 +786,7 @@ void ScummEngine::resetRoomObjects() {
}
searchptr = room;
- ResourceIterator obims(room, false);
+ ResourceIterator obims(room, false);
for (i = 0; i < _numObjectsInRoom; i++) {
ptr = obims.findNext(MKTAG('O','B','I','M'));
if (ptr == NULL)
@@ -810,6 +812,7 @@ void ScummEngine_v3old::resetRoomObjects() {
const byte *room, *ptr;
room = getResourceAddress(rtRoom, _roomResource);
+ assert(room);
if (_numObjectsInRoom == 0)
return;
@@ -854,6 +857,7 @@ void ScummEngine_v4::resetRoomObjects() {
const byte *room;
room = getResourceAddress(rtRoom, _roomResource);
+ assert(room);
if (_numObjectsInRoom == 0)
return;
@@ -861,7 +865,7 @@ void ScummEngine_v4::resetRoomObjects() {
if (_numObjectsInRoom > _numLocalObjects)
error("More than %d objects in room %d", _numLocalObjects, _roomResource);
- ResourceIterator obcds(room, true);
+ ResourceIterator obcds(room, true);
for (i = 0; i < _numObjectsInRoom; i++) {
od = &_objs[findLocalObjectSlot()];
@@ -878,7 +882,7 @@ void ScummEngine_v4::resetRoomObjects() {
}
}
- ResourceIterator obims(room, true);
+ ResourceIterator obims(room, true);
for (i = 0; i < _numObjectsInRoom; i++) {
// In the PC Engine version of Loom, there aren't image blocks
// for all objects.
@@ -979,10 +983,12 @@ void ScummEngine::resetRoomObject(ObjectData *od, const byte *room, const byte *
assert(room);
if (searchptr == NULL) {
- if (_game.version == 8)
+ if (_game.version == 8) {
searchptr = getResourceAddress(rtRoomScripts, _roomResource);
- else
+ assert(searchptr);
+ } else {
searchptr = room;
+ }
}
cdhd = (const CodeHeader *)findResourceData(MKTAG('C','D','H','D'), searchptr + od->OBCDoffset);
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index 7f0f449a92..40f4ec93c9 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -97,6 +97,7 @@ void Player_AD::startSound(int sound) {
// Query the sound resource
const byte *res = _vm->getResourceAddress(rtSound, sound);
+ assert(res);
if (res[2] == 0x80) {
// Stop the current sounds
diff --git a/engines/scumm/players/player_nes.cpp b/engines/scumm/players/player_nes.cpp
index 3b5adc4550..b2f6eb0d40 100644
--- a/engines/scumm/players/player_nes.cpp
+++ b/engines/scumm/players/player_nes.cpp
@@ -1029,11 +1029,7 @@ top:
}
_mchan[x].volume += _mchan[x].voldelta;
-
- if (_mchan[x].volume < 0)
- _mchan[x].volume = 0;
- if (_mchan[x].volume > MAXVOLUME)
- _mchan[x].volume = MAXVOLUME;
+ _mchan[x].volume = CLIP(_mchan[x].volume, 0, MAXVOLUME);
APU_writeChannel(x, 0, (_mchan[x].volume >> 3) | _mchan[x].envflags);
}
diff --git a/engines/scumm/players/player_towns.cpp b/engines/scumm/players/player_towns.cpp
index 16080205c0..a1add906bb 100644
--- a/engines/scumm/players/player_towns.cpp
+++ b/engines/scumm/players/player_towns.cpp
@@ -236,6 +236,8 @@ void Player_Towns_v1::setMusicVolume(int vol) {
void Player_Towns_v1::startSound(int sound) {
uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
+ assert(ptr);
+
if (_vm->_game.version != 3)
ptr += 2;
@@ -620,6 +622,7 @@ int Player_Towns_v2::getSoundStatus(int sound) const {
void Player_Towns_v2::startSound(int sound) {
uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
+ assert(ptr);
if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S')) {
_soundOverride[sound].type = 7;
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index d04b3bb5ad..84dd16efa6 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -706,7 +706,9 @@ bool ScummEngine::querySaveMetaInfos(const char *target, int slot, int heversion
if (hdr.ver > VER(52)) {
if (Graphics::checkThumbnailHeader(*in)) {
- thumbnail = Graphics::loadThumbnail(*in);
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ return false;
+ }
}
if (hdr.ver > VER(57)) {
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp
index 822e32d9c4..208b1f4aef 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -1188,7 +1188,7 @@ void ScummEngine_v2::o2_startScript() {
}
}
- // WORKAROUND bug #4556: Purple Tentacle can appear in the lab, after being
+ // WORKAROUND bug #4556: Purple Tentacle can appear in the lab, after being
// chased out and end up stuck in the room. This bug is triggered if the player
// enters the lab within 45 minutes of first entering the mansion and has chased Purple Tentacle
// out. Eventually the cutscene with Purple Tentacle chasing Sandy in the lab
@@ -1211,10 +1211,9 @@ void ScummEngine_v2::o2_startScript() {
}
void ScummEngine_v2::stopScriptCommon(int script) {
-
// WORKAROUND bug #4112: If you enter the lab while Dr. Fred has the powered turned off
// to repair the Zom-B-Matic, the script will be stopped and the power will never turn
- // back on. This fix forces the power on, when the player enters the lab,
+ // back on. This fix forces the power on, when the player enters the lab,
// if the script which turned it off is running
if (_game.id == GID_MANIAC && _roomResource == 4 && isScriptRunning(MM_SCRIPT(138))) {
@@ -1320,7 +1319,7 @@ void ScummEngine_v2::o2_putActorInRoom() {
// Var[245] is set to have the Disguise on in most situations
//
// We don't touch the variable in the following situations
- // If the Caponian is being put into the space ship room, or the current room is the
+ // If the Caponian is being put into the space ship room, or the current room is the
// space ship and the Caponian is being put into the backroom of the telephone company (you didnt show your fan club card)
if (_game.id == GID_ZAK && _game.version <= 2 && act == 7) {
// Is script-96 cutscene done
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index fc64df4a1a..2f6ea489d5 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2435,6 +2435,9 @@ void ScummEngine::scummLoop_handleSaveLoad() {
if (success && _saveTemporaryState && VAR_GAME_LOADED != 0xFF && _game.version <= 7)
VAR(VAR_GAME_LOADED) = 201;
+
+ if (!_saveTemporaryState)
+ _lastSaveTime = _system->getMillis();
} else {
success = loadState(_saveLoadSlot, _saveTemporaryState, filename);
if (!success)
@@ -2458,7 +2461,6 @@ void ScummEngine::scummLoop_handleSaveLoad() {
clearClickedStatus();
_saveLoadFlag = 0;
- _lastSaveTime = _system->getMillis();
}
}
diff --git a/engines/sherlock/detection.cpp b/engines/sherlock/detection.cpp
index 9184fd8e88..e72700fbf2 100644
--- a/engines/sherlock/detection.cpp
+++ b/engines/sherlock/detection.cpp
@@ -200,6 +200,8 @@ bool SherlockMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime) ||
(f == kSimpleSavesNames);
}
@@ -233,7 +235,10 @@ SaveStateDescriptor SherlockMetaEngine::querySaveMetaInfos(const char *target, i
if (f) {
Sherlock::SherlockSavegameHeader header;
- Sherlock::SaveManager::readSavegameHeader(f, header);
+ if (!Sherlock::SaveManager::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
delete f;
// Create the return descriptor
diff --git a/engines/sherlock/image_file.cpp b/engines/sherlock/image_file.cpp
index c53e537bb8..112655648a 100644
--- a/engines/sherlock/image_file.cpp
+++ b/engines/sherlock/image_file.cpp
@@ -703,7 +703,7 @@ void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
error("load3DOCelRoomData: expected cel data, not enough bytes");
// read data into memory
- byte *celDataPtr = new byte[celDataSize];
+ byte *celDataPtr = new byte[celDataSize];
stream.read(celDataPtr, celDataSize);
streamLeft -= celDataSize;
@@ -936,15 +936,15 @@ void ImageFile3DO::loadFont(Common::SeekableReadStream &stream) {
stream.read(bitsTablePtr, bitsTableSize);
// Now extract all characters
- uint16 curChar = 0;
- const byte *curBitsLinePtr = bitsTablePtr;
- const byte *curBitsPtr = NULL;
- byte curBitsLeft = 0;
- uint32 curCharHeightLeft = 0;
- uint32 curCharWidthLeft = 0;
- byte curBits = 0;
- byte curBitsReversed = 0;
- byte curPosX = 0;
+ uint16 curChar = 0;
+ const byte *curBitsLinePtr = bitsTablePtr;
+ const byte *curBitsPtr = NULL;
+ byte curBitsLeft = 0;
+ uint32 curCharHeightLeft = 0;
+ uint32 curCharWidthLeft = 0;
+ byte curBits = 0;
+ byte curBitsReversed = 0;
+ byte curPosX = 0;
assert(bitsTableSize >= (header_maxChar * header_fontHeight * header_bytesPerLine)); // Security
diff --git a/engines/sherlock/music.cpp b/engines/sherlock/music.cpp
index cef7157034..20b811ea98 100644
--- a/engines/sherlock/music.cpp
+++ b/engines/sherlock/music.cpp
@@ -182,8 +182,8 @@ bool MidiParser_SH::loadMusic(byte *musData, uint32 musDataSize) {
_musData = musData;
_musDataSize = musDataSize;
- byte *headerPtr = _musData + 12; // skip over the already checked SPACE header
- byte *pos = headerPtr;
+ byte *headerPtr = _musData + 12; // skip over the already checked SPACE header
+ byte *pos = headerPtr;
uint16 headerSize = READ_LE_UINT16(headerPtr);
assert(headerSize == 0x7F); // Security check
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 25ccddedbb..6f1148e956 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -470,7 +470,7 @@ struct SceneImage {
int _filesize; // File size
SceneImage();
-} ;
+};
} // End of namespace Sherlock
diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 9ed6951fbe..ec7d60a1a2 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -57,23 +57,24 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream)
int32 signature = stream.readUint32BE();
stream.seek(0);
-
- // Check whether the file is compressed
- if (signature == MKTAG('L', 'Z', 'V', 26)) {
- // Allocate a new cache entry
- _resources[name] = CacheEntry();
- CacheEntry &cacheEntry = _resources[name];
+ // Allocate a new cache entry
+ _resources[name] = CacheEntry();
+ CacheEntry &cacheEntry = _resources[name];
+ // Check whether the file is compressed
+ if (signature == MKTAG('L', 'Z', 'V', 26)) {
// It's compressed, so decompress the file and store its data in the cache entry
Common::SeekableReadStream *decompressed = _vm->_res->decompress(stream);
cacheEntry.resize(decompressed->size());
decompressed->read(&cacheEntry[0], decompressed->size());
delete decompressed;
-
+ } else {
+ // It's not, so read the raw data of the file into the cache entry
+ cacheEntry.resize(stream.size());
+ stream.read(&cacheEntry[0], stream.size());
}
-
}
Common::SeekableReadStream *Cache::get(const Common::String &filename) const {
diff --git a/engines/sherlock/saveload.cpp b/engines/sherlock/saveload.cpp
index 44b5e103d2..ca27f57a97 100644
--- a/engines/sherlock/saveload.cpp
+++ b/engines/sherlock/saveload.cpp
@@ -93,7 +93,6 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) {
SherlockSavegameHeader header;
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
@@ -104,24 +103,20 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- if (!readSavegameHeader(in, header))
- continue;
+ if (readSavegameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
- saveList.push_back(SaveStateDescriptor(slot, header._saveName));
-
- header._thumbnail->free();
- delete header._thumbnail;
delete in;
}
}
}
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
-bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header) {
+WARN_UNUSED_RESULT bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = nullptr;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -138,9 +133,9 @@ bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHea
while ((ch = (char)in->readByte()) != '\0') header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header._year = in->readSint16LE();
@@ -212,11 +207,6 @@ void SaveManager::loadGame(int slot) {
if (!readSavegameHeader(saveFile, header))
error("Invalid savegame");
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
// Synchronize the savegame data
Serializer s(saveFile, nullptr);
s.setVersion(header._version);
diff --git a/engines/sherlock/saveload.h b/engines/sherlock/saveload.h
index 59b0b26d6e..6348b0f668 100644
--- a/engines/sherlock/saveload.h
+++ b/engines/sherlock/saveload.h
@@ -105,7 +105,7 @@ public:
/**
* Read in the header information for a savegame
*/
- static bool readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header, bool skipThumbnail = true);
/**
* Return the index of the button the mouse is over, if any
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 2aa6ae8902..fbe025c0b7 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -258,8 +258,8 @@ void ScalpelEngine::setupGraphics() {
// First try for a 640x400 mode
g_system->beginGFXTransaction();
- initCommonGFX();
- g_system->initSize(640, 400, &pixelFormatRGB565);
+ initCommonGFX();
+ g_system->initSize(640, 400, &pixelFormatRGB565);
OSystem::TransactionError gfxError = g_system->endGFXTransaction();
if (gfxError == OSystem::kTransactionSuccess) {
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index c6b38f78d7..fcc092f017 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -137,9 +137,9 @@ Common::Error SherlockEngine::run() {
_saves->loadGame(_loadGameSlot);
_loadGameSlot = -1;
} else {
- do
+ do {
showOpening();
- while (!shouldQuit() && !_interactiveFl);
+ } while (!shouldQuit() && !_interactiveFl);
}
while (!shouldQuit()) {
diff --git a/engines/sherlock/tattoo/tattoo_people.cpp b/engines/sherlock/tattoo/tattoo_people.cpp
index fc3c2e6574..458cc1a9c2 100644
--- a/engines/sherlock/tattoo/tattoo_people.cpp
+++ b/engines/sherlock/tattoo/tattoo_people.cpp
@@ -39,7 +39,7 @@ struct AdjustWalk {
int _xAdjust;
int _flipXAdjust;
int _yAdjust;
-} ;
+};
static const AdjustWalk ADJUST_WALKS[NUM_ADJUSTED_WALKS] = {
{ "TUPRIGHT", -7, -19, 6 },
diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp
index b5425f9532..642e4d31a7 100644
--- a/engines/sky/detection.cpp
+++ b/engines/sky/detection.cpp
@@ -76,10 +76,10 @@ public:
virtual const char *getOriginalCopyright() const;
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
+ PlainGameList getSupportedGames() const override;
virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist) const;
+ PlainGameDescriptor findGame(const char *gameid) const override;
+ DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
@@ -110,8 +110,8 @@ bool Sky::SkyEngine::hasFeature(EngineFeature f) const {
(f == kSupportsSavingDuringRuntime);
}
-GameList SkyMetaEngine::getSupportedGames() const {
- GameList games;
+PlainGameList SkyMetaEngine::getSupportedGames() const {
+ PlainGameList games;
games.push_back(skySetting);
return games;
}
@@ -135,14 +135,14 @@ const ExtraGuiOptions SkyMetaEngine::getExtraGuiOptions(const Common::String &ta
return options;
}
-GameDescriptor SkyMetaEngine::findGame(const char *gameid) const {
+PlainGameDescriptor SkyMetaEngine::findGame(const char *gameid) const {
if (0 == scumm_stricmp(gameid, skySetting.gameId))
return skySetting;
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
-GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const {
- GameList detectedGames;
+DetectedGames SkyMetaEngine::detectGames(const Common::FSList &fslist) const {
+ DetectedGames detectedGames;
bool hasSkyDsk = false;
bool hasSkyDnr = false;
int dinnerTableEntries = -1;
@@ -173,18 +173,25 @@ GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const {
// Match found, add to list of candidates, then abort inner loop.
// The game detector uses US English by default. We want British
// English to match the recorded voices better.
- GameDescriptor dg(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown);
const SkyVersion *sv = skyVersions;
while (sv->dinnerTableEntries) {
if (dinnerTableEntries == sv->dinnerTableEntries &&
(sv->dataDiskSize == dataDiskSize || sv->dataDiskSize == -1)) {
- dg.updateDesc(Common::String::format("v0.0%d %s", sv->version, sv->extraDesc).c_str());
- dg.setGUIOptions(sv->guioptions);
break;
}
++sv;
}
- detectedGames.push_back(dg);
+
+ if (sv->dinnerTableEntries) {
+ Common::String extra = Common::String::format("v0.0%d %s", sv->version, sv->extraDesc);
+
+ DetectedGame game = DetectedGame(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown, extra);
+ game.setGUIOptions(sv->guioptions);
+
+ detectedGames.push_back(game);
+ } else {
+ detectedGames.push_back(DetectedGame(skySetting.gameId, skySetting.description));
+ }
}
return detectedGames;
diff --git a/engines/sludge/backdrop.cpp b/engines/sludge/backdrop.cpp
index c1042c7f05..0e41230f36 100644
--- a/engines/sludge/backdrop.cpp
+++ b/engines/sludge/backdrop.cpp
@@ -422,6 +422,7 @@ void GraphicsManager::saveLightMap(Common::WriteStream *stream) {
stream->writeByte(0);
}
stream->writeByte(_lightMapMode);
+ stream->writeByte(_fadeMode);
}
bool GraphicsManager::loadLightMap(int ssgVersion, Common::SeekableReadStream *stream) {
@@ -434,6 +435,8 @@ bool GraphicsManager::loadLightMap(int ssgVersion, Common::SeekableReadStream *s
_lightMapMode = stream->readByte() % 3;
}
+ _fadeMode = stream->readByte();
+
return true;
}
@@ -504,6 +507,27 @@ void GraphicsManager::saveHSI(Common::WriteStream *stream) {
Image::writePNG(*stream, _backdropSurface);
}
+void GraphicsManager::saveBackdrop(Common::WriteStream *stream) {
+ stream->writeUint16BE(_cameraX);
+ stream->writeUint16BE(_cameraY);
+ stream->writeFloatLE(_cameraZoom);
+ stream->writeByte(_brightnessLevel);
+ saveHSI(stream);
+}
+
+void GraphicsManager::loadBackdrop(int ssgVersion, Common::SeekableReadStream *stream) {
+ _cameraX = stream->readUint16BE();
+ _cameraY = stream->readUint16BE();
+ if (ssgVersion >= VERSION(2, 0)) {
+ _cameraZoom = stream->readFloatLE();
+ } else {
+ _cameraZoom = 1.0;
+ }
+
+ _brightnessLevel = stream->readByte();
+
+ loadHSI(stream, 0, 0, true);
+}
bool GraphicsManager::getRGBIntoStack(uint x, uint y, StackHandler *sH) {
if (x >= _sceneWidth || y >= _sceneHeight) {
@@ -516,14 +540,14 @@ bool GraphicsManager::getRGBIntoStack(uint x, uint y, StackHandler *sH) {
byte *target = (byte *)_renderSurface.getBasePtr(x, y);
- setVariable(newValue, SVT_INT, target[1]);
+ newValue.setVariable(SVT_INT, target[1]);
if (!addVarToStackQuick(newValue, sH->first)) return false;
sH->last = sH->first;
- setVariable(newValue, SVT_INT, target[2]);
+ newValue.setVariable(SVT_INT, target[2]);
if (!addVarToStackQuick(newValue, sH->first)) return false;
- setVariable(newValue, SVT_INT, target[3]);
+ newValue.setVariable(SVT_INT, target[3]);
if (!addVarToStackQuick(newValue, sH->first)) return false;
return true;
diff --git a/engines/sludge/bg_effects.cpp b/engines/sludge/bg_effects.cpp
index d0c8068a27..3f40fc81e1 100644
--- a/engines/sludge/bg_effects.cpp
+++ b/engines/sludge/bg_effects.cpp
@@ -166,7 +166,7 @@ bool blur_createSettings(int numParams, VariableStack *&stack) {
error = "Third and subsequent parameters in setBackgroundEffect should be arrays";
break;
} else {
- int w = stackSize(justToCheckSizes->thisVar.varData.theStack);
+ int w = justToCheckSizes->thisVar.varData.theStack->getStackSize();
if (a) {
if (w != width) {
error = "Arrays in setBackgroundEffect must be the same size";
@@ -196,7 +196,7 @@ bool blur_createSettings(int numParams, VariableStack *&stack) {
for (int x = 0; x < width; x++) {
int arraySlot = x + (y * width);
// s_matrixEffectData[arraySlot] = (rand() % 4);
- if (!getValueType(s_matrixEffectData[arraySlot], SVT_INT, eachNumber->thisVar)) {
+ if (!eachNumber->thisVar.getValueType(s_matrixEffectData[arraySlot], SVT_INT)) {
error = "";
break;
}
@@ -205,10 +205,10 @@ bool blur_createSettings(int numParams, VariableStack *&stack) {
trimStack(stack);
}
}
- if (error.empty() && !getValueType(s_matrixEffectDivide, SVT_INT, stack->thisVar))
+ if (error.empty() && !stack->thisVar.getValueType(s_matrixEffectDivide, SVT_INT))
error = "";
trimStack(stack);
- if (error.empty() && !getValueType(s_matrixEffectBase, SVT_INT, stack->thisVar))
+ if (error.empty() && !stack->thisVar.getValueType(s_matrixEffectBase, SVT_INT))
error = "";
trimStack(stack);
if (error.empty()) {
diff --git a/engines/sludge/builtin.cpp b/engines/sludge/builtin.cpp
index 7385d4d861..1030643788 100644
--- a/engines/sludge/builtin.cpp
+++ b/engines/sludge/builtin.cpp
@@ -32,6 +32,7 @@
#include "sludge/floor.h"
#include "sludge/fonttext.h"
#include "sludge/freeze.h"
+#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/language.h"
#include "sludge/loadsave.h"
@@ -54,51 +55,16 @@
namespace Sludge {
-int speechMode = 0;
-SpritePalette pastePalette;
-
Variable *launchResult = NULL;
-extern int lastFramesPerSecond, thumbWidth, thumbHeight;
extern bool allowAnyFilename;
-extern bool captureAllKeys;
extern VariableStack *noStack;
extern StatusStuff *nowStatus;
-extern ScreenRegion *overRegion;
extern int numBIFNames, numUserFunc;
extern Common::String *allUserFunc;
extern Common::String *allBIFNames;
-extern byte brightnessLevel;
-extern byte fadeMode;
-extern uint16 saveEncoding;
-
-int paramNum[] = { -1, 0, 1, 1, -1, -1, 1, 3, 4, 1, 0, 0, 8, -1, // SAY->MOVEMOUSE
- -1, 0, 0, -1, -1, 1, 1, 1, 1, 4, 1, 1, 2, 1,// FOCUS->REMOVEREGION
- 2, 2, 0, 0, 2, // ANIMATE->SETSCALE
- -1, 2, 1, 0, 0, 0, 1, 0, 3, // new/push/pop stack, status stuff
- 2, 0, 0, 3, 1, 0, 2, // delFromStack->completeTimers
- -1, -1, -1, 2, 2, 0, 3, 1, // anim, costume, pO, setC, wait, sS, substring, stringLength
- 0, 1, 1, 0, 2, // dark, save, load, quit, rename
- 1, 3, 3, 1, 2, 1, 1, 3, 1, 0, 0, 2, 1, // stackSize, pasteString, startMusic, defvol, vol, stopmus, stopsound, setfont, alignStatus, show x 2, pos'Status, setFloor
- -1, -1, 1, 1, 2, 1, 1, 1, -1, -1, -1, 1, 1, // force, jump, peekstart, peekend, enqueue, getSavedGames, inFont, loopSound, removeChar, stopCharacter
- 1, 0, 3, 3, 1, 2, 1, 2, 2, // launch, howFrozen, pastecol, litcol, checksaved, float, cancelfunc, walkspeed, delAll
- 2, 3, 1, 2, 2, 0, 0, 1, 2, 3, 1, -1, // extras, mixoverlay, pastebloke, getMScreenX/Y, setSound(Default/-)Volume, looppoints, speechMode, setLightMap
- -1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, // think, getCharacterDirection, is(char/region/moving), deleteGame, renameGame, hardScroll, stringWidth, speechSpeed, normalCharacter
- 2, 1, 2, 1, 3, 1, 1, 2, 1, // fetchEvent, setBrightness, spin, fontSpace, burnString, captureAll, cacheSound, setSpinSpeed, transitionMode
- 1, 0, 0, 1, 0, 2, 1, 1, 1, // movie(Start/Abort/Playing), updateDisplay, getSoundCache, savedata, loaddata, savemode, freeSound
- 3, 0, 3, 3, 2, 1, 1, // setParallax, clearParallax, setBlankColour, setBurnColour, getPixelColour, makeFastArray, getCharacterScale
- 0, 2, 0, // getLanguage, launchWith, getFramesPerSecond
- 3, 2, 2, 0, 0, 1, // readThumbnail, setThumbnailSize, hasFlag, snapshot, clearSnapshot, anyFilename
- 2, 1, // regGet, fatal
- 4, 3, -1, 0, // chr AA, max AA, setBackgroundEffect, doBackgroundEffect
- 2, // setCharacterAngleOffset
- 2, 5, // setCharacterTransparency, setCharacterColourise
- 1, // zoomCamera
- 1, 0, 0 // playMovie, stopMovie, pauseMovie
- };
-
bool failSecurityCheck(const Common::String &fn) {
if (fn.empty())
return true;
@@ -121,11 +87,12 @@ bool failSecurityCheck(const Common::String &fn) {
return false;
}
-LoadedFunction *saverFunc;
+extern LoadedFunction *saverFunc;
typedef BuiltReturn (*builtInSludgeFunc)(int numParams, LoadedFunction *fun);
struct builtInFunctionData {
builtInSludgeFunc func;
+ int paramNum;
};
#define builtIn(a) static BuiltReturn builtIn_ ## a (int numParams, LoadedFunction *fun)
@@ -140,15 +107,15 @@ static BuiltReturn sayCore(int numParams, LoadedFunction *fun, bool sayIt) {
switch (numParams) {
case 3:
- if (!getValueType(fileNum, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNum, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
// fall through
case 2:
- newText = getTextFromAnyVar(fun->stack->thisVar);
+ newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
- if (!getValueType(objT, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objT, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
p = g_sludge->_speechMan->wrapSpeech(newText, objT, fileNum, sayIt);
@@ -192,13 +159,13 @@ builtIn(unfreeze) {
builtIn(howFrozen) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, g_sludge->_gfxMan->howFrozen());
+ fun->reg.setVariable(SVT_INT, g_sludge->_gfxMan->howFrozen());
return BR_CONTINUE;
}
builtIn(setCursor) {
UNUSEDALL
- PersonaAnimation *aa = getAnimationFromVar(fun->stack->thisVar);
+ PersonaAnimation *aa = fun->stack->thisVar.getAnimationFromVar();
g_sludge->_cursorMan->pickAnimCursor(aa);
trimStack(fun->stack);
return BR_CONTINUE;
@@ -206,39 +173,39 @@ builtIn(setCursor) {
builtIn(getMouseX) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, g_sludge->_evtMan->mouseX() + g_sludge->_gfxMan->getCamX());
+ fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseX() + g_sludge->_gfxMan->getCamX());
return BR_CONTINUE;
}
builtIn(getMouseY) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, g_sludge->_evtMan->mouseY() + g_sludge->_gfxMan->getCamY());
+ fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseY() + g_sludge->_gfxMan->getCamY());
return BR_CONTINUE;
}
builtIn(getMouseScreenX) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, g_sludge->_evtMan->mouseX() * g_sludge->_gfxMan->getCamZoom());
+ fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseX() * g_sludge->_gfxMan->getCamZoom());
return BR_CONTINUE;
}
builtIn(getMouseScreenY) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, g_sludge->_evtMan->mouseY() * g_sludge->_gfxMan->getCamZoom());
+ fun->reg.setVariable(SVT_INT, g_sludge->_evtMan->mouseY() * g_sludge->_gfxMan->getCamZoom());
return BR_CONTINUE;
}
builtIn(getStatusText) {
UNUSEDALL
- makeTextVar(fun->reg, statusBarText());
+ fun->reg.makeTextVar(statusBarText());
return BR_CONTINUE;
}
builtIn(getMatchingFiles) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
- unlinkVar(fun->reg);
+ fun->reg.unlinkVar();
// Return value
fun->reg.varType = SVT_STACK;
@@ -248,7 +215,7 @@ builtIn(getMatchingFiles) {
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
- if (!getSavedGamesStack(fun->reg.varData.theStack, newText))
+ if (!fun->reg.varData.theStack->getSavedGamesStack(newText))
return BR_ERROR;
return BR_CONTINUE;
}
@@ -260,7 +227,7 @@ builtIn(saveGame) {
fatal("Can't save game state while the engine is frozen");
}
- g_sludge->loadNow = getTextFromAnyVar(fun->stack->thisVar);
+ g_sludge->loadNow = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String aaaaa = encodeFilename(g_sludge->loadNow);
@@ -270,14 +237,14 @@ builtIn(saveGame) {
g_sludge->loadNow = ":" + aaaaa;
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
saverFunc = fun;
return BR_KEEP_AND_PAUSE;
}
builtIn(fileExists) {
UNUSEDALL
- g_sludge->loadNow = getTextFromAnyVar(fun->stack->thisVar);
+ g_sludge->loadNow = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String aaaaa = encodeFilename(g_sludge->loadNow);
g_sludge->loadNow.clear();
@@ -300,13 +267,13 @@ builtIn(fileExists) {
}
// Return value
- setVariable(fun->reg, SVT_INT, exist);
+ fun->reg.setVariable(SVT_INT, exist);
return BR_CONTINUE;
}
builtIn(loadGame) {
UNUSEDALL
- Common::String aaaaa = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
g_sludge->loadNow.clear();
g_sludge->loadNow = encodeFilename(aaaaa);
@@ -340,16 +307,16 @@ builtIn(blankScreen) {
builtIn(blankArea) {
UNUSEDALL
int x1, y1, x2, y2;
- if (!getValueType(y2, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x2, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(y1, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x1, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->blankScreen(x1, y1, x2, y2);
@@ -365,13 +332,13 @@ builtIn(darkBackground) {
builtIn(addOverlay) {
UNUSEDALL
int fileNumber, xPos, yPos;
- if (!getValueType(yPos, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(yPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(xPos, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(xPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->loadBackDrop(fileNumber, xPos, yPos);
@@ -381,13 +348,13 @@ builtIn(addOverlay) {
builtIn(mixOverlay) {
UNUSEDALL
int fileNumber, xPos, yPos;
- if (!getValueType(yPos, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(yPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(xPos, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(xPos, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->mixBackDrop(fileNumber, xPos, yPos);
@@ -397,13 +364,13 @@ builtIn(mixOverlay) {
builtIn(pasteImage) {
UNUSEDALL
int x, y;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- PersonaAnimation *pp = getAnimationFromVar(fun->stack->thisVar);
+ PersonaAnimation *pp = fun->stack->thisVar.getAnimationFromVar();
trimStack(fun->stack);
if (pp == NULL)
return BR_CONTINUE;
@@ -418,10 +385,10 @@ builtIn(pasteImage) {
builtIn(setSceneDimensions) {
UNUSEDALL
int x, y;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (g_sludge->_gfxMan->killResizeBackdrop(x, y)) {
@@ -435,10 +402,10 @@ builtIn(setSceneDimensions) {
builtIn(aimCamera) {
UNUSEDALL
int cameraX, cameraY;
- if (!getValueType(cameraY, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(cameraY, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(cameraX, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(cameraX, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
@@ -450,7 +417,7 @@ builtIn(aimCamera) {
builtIn(zoomCamera) {
UNUSEDALL
int z;
- if (!getValueType(z, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(z, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
@@ -476,7 +443,7 @@ builtIn(pickOne) {
// Return value
while (numParams--) {
if (i == numParams)
- copyVariable(fun->stack->thisVar, fun->reg);
+ fun->reg.copyFrom(fun->stack->thisVar);
trimStack(fun->stack);
}
return BR_CONTINUE;
@@ -489,13 +456,13 @@ builtIn(substring) {
//debugOut ("BUILTIN: substring\n");
- if (!getValueType(length, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(length, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(start, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(start, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- wholeString = getTextFromAnyVar(fun->stack->thisVar);
+ wholeString = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
UTF8Converter convert;
@@ -517,21 +484,21 @@ builtIn(substring) {
Common::String newString(wholeString.begin() + startoffset, wholeString.begin() + endoffset);
- makeTextVar(fun->reg, newString);
+ fun->reg.makeTextVar(newString);
return BR_CONTINUE;
}
builtIn(stringLength) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, g_sludge->_txtMan->stringLength(newText));
+ fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->stringLength(newText));
return BR_CONTINUE;
}
builtIn(newStack) {
UNUSEDALL
- unlinkVar(fun->reg);
+ fun->reg.unlinkVar();
// Return value
fun->reg.varType = SVT_STACK;
@@ -560,13 +527,13 @@ builtIn(stackSize) {
switch (fun->stack->thisVar.varType) {
case SVT_STACK:
// Return value
- setVariable(fun->reg, SVT_INT, stackSize(fun->stack->thisVar.varData.theStack));
+ fun->reg.setVariable(SVT_INT, fun->stack->thisVar.varData.theStack->getStackSize());
trimStack(fun->stack);
return BR_CONTINUE;
case SVT_FASTARRAY:
// Return value
- setVariable(fun->reg, SVT_INT, fun->stack->thisVar.varData.fastArray->size);
+ fun->reg.setVariable(SVT_INT, fun->stack->thisVar.varData.fastArray->size);
trimStack(fun->stack);
return BR_CONTINUE;
@@ -584,7 +551,7 @@ builtIn(copyStack) {
return BR_ERROR;
}
// Return value
- if (!copyStack(fun->stack->thisVar, fun->reg))
+ if (!fun->reg.copyStack(fun->stack->thisVar))
return BR_ERROR;
trimStack(fun->stack);
return BR_CONTINUE;
@@ -639,10 +606,11 @@ builtIn(deleteFromStack) {
}
// Return value
- setVariable(fun->reg, SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, false));
+ fun->reg.setVariable(SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, false));
// Horrible hacking because 'last' value might now be wrong!
- fun->stack->next->thisVar.varData.theStack->last = stackFindLast(fun->stack->next->thisVar.varData.theStack->first);
+ VariableStack *nextFirstStack = fun->stack->next->thisVar.varData.theStack->first;
+ fun->stack->next->thisVar.varData.theStack->last = (nextFirstStack == NULL) ? NULL : nextFirstStack->stackFindLast();
trimStack(fun->stack);
trimStack(fun->stack);
@@ -657,10 +625,11 @@ builtIn(deleteAllFromStack) {
}
// Return value
- setVariable(fun->reg, SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, true));
+ fun->reg.setVariable(SVT_INT, deleteVarFromStack(fun->stack->thisVar, fun->stack->next->thisVar.varData.theStack->first, true));
// Horrible hacking because 'last' value might now be wrong!
- fun->stack->next->thisVar.varData.theStack->last = stackFindLast(fun->stack->next->thisVar.varData.theStack->first);
+ VariableStack *nextFirstStack = fun->stack->next->thisVar.varData.theStack->first;
+ fun->stack->next->thisVar.varData.theStack->last = (nextFirstStack == NULL) ? NULL : nextFirstStack->stackFindLast();
trimStack(fun->stack);
trimStack(fun->stack);
@@ -679,7 +648,7 @@ builtIn(popFromStack) {
}
// Return value
- copyVariable(fun->stack->thisVar.varData.theStack->first->thisVar, fun->reg);
+ fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->first->thisVar);
trimStack(fun->stack->thisVar.varData.theStack->first);
trimStack(fun->stack);
return BR_CONTINUE;
@@ -697,7 +666,7 @@ builtIn(peekStart) {
}
// Return value
- copyVariable(fun->stack->thisVar.varData.theStack->first->thisVar, fun->reg);
+ fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->first->thisVar);
trimStack(fun->stack);
return BR_CONTINUE;
}
@@ -714,7 +683,7 @@ builtIn(peekEnd) {
}
// Return value
- copyVariable(fun->stack->thisVar.varData.theStack->last->thisVar, fun->reg);
+ fun->reg.copyFrom(fun->stack->thisVar.varData.theStack->last->thisVar);
trimStack(fun->stack);
return BR_CONTINUE;
}
@@ -723,24 +692,24 @@ builtIn(random) {
UNUSEDALL
int num;
- if (!getValueType(num, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(num, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (num <= 0)
num = 1;
- setVariable(fun->reg, SVT_INT, 0 /*rand() % num*/); //TODO:false value
+ fun->reg.setVariable(SVT_INT, 0 /*rand() % num*/); //TODO:false value
return BR_CONTINUE;
}
static bool getRGBParams(int &red, int &green, int &blue, LoadedFunction *fun) {
- if (!getValueType(blue, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(blue, SVT_INT))
return false;
trimStack(fun->stack);
- if (!getValueType(green, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(green, SVT_INT))
return false;
trimStack(fun->stack);
- if (!getValueType(red, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(red, SVT_INT))
return false;
trimStack(fun->stack);
return true;
@@ -775,7 +744,7 @@ builtIn(setPasteColour) {
if (!getRGBParams(red, green, blue, fun))
return BR_ERROR;
- setFontColour(pastePalette, (byte)red, (byte)green, (byte)blue);
+ g_sludge->_txtMan->setPasterColor((byte)red, (byte)green, (byte)blue);
return BR_CONTINUE;
}
@@ -787,7 +756,7 @@ builtIn(setBlankColour) {
return BR_ERROR;
g_sludge->_gfxMan->setBlankColor(red, green, blue);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
@@ -799,21 +768,21 @@ builtIn(setBurnColour) {
return BR_ERROR;
g_sludge->_gfxMan->setBurnColor(red, green, blue);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(setFont) {
UNUSEDALL
int fileNumber, newHeight;
- if (!getValueType(newHeight, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(newHeight, SVT_INT))
return BR_ERROR;
// newDebug (" Height:", newHeight);
trimStack(fun->stack);
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
// newDebug (" Character supported:", newText);
trimStack(fun->stack);
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
// newDebug (" File:", fileNumber);
trimStack(fun->stack);
@@ -825,28 +794,28 @@ builtIn(setFont) {
builtIn(inFont) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
// Return value
- setVariable(fun->reg, SVT_INT, g_sludge->_txtMan->isInFont(newText));
+ fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->isInFont(newText));
return BR_CONTINUE;
}
builtIn(pasteString) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
int y, x;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (x == IN_THE_CENTRE)
x = g_sludge->_gfxMan->getCenterX(g_sludge->_txtMan->stringWidth(newText));
- g_sludge->_txtMan->pasteStringToBackdrop(newText, x, y, pastePalette);
+ g_sludge->_txtMan->pasteStringToBackdrop(newText, x, y);
return BR_CONTINUE;
}
@@ -858,11 +827,11 @@ builtIn(anim) {
}
// First store the frame numbers and take 'em off the stack
- PersonaAnimation *ba = createPersonaAnim(numParams - 1, fun->stack);
+ PersonaAnimation *ba = new PersonaAnimation(numParams - 1, fun->stack);
// Only remaining paramter is the file number
int fileNumber;
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
@@ -870,10 +839,10 @@ builtIn(anim) {
LoadedSpriteBank *sprBanky = g_sludge->_gfxMan->loadBankForAnim(fileNumber);
if (!sprBanky)
return BR_ERROR; // File not found, fatal done already
- setBankFile(ba, sprBanky);
+ ba->theSprites = sprBanky;
// Return value
- newAnimationVariable(fun->reg, ba);
+ fun->reg.makeAnimationVariable(ba);
return BR_CONTINUE;
}
@@ -893,18 +862,18 @@ builtIn(costume) {
if (!checkNew(newPersona->animation))
return BR_ERROR;
for (iii = numParams - 1; iii >= 0; iii--) {
- newPersona->animation[iii] = getAnimationFromVar(fun->stack->thisVar);
+ newPersona->animation[iii] = fun->stack->thisVar.getAnimationFromVar();
trimStack(fun->stack);
}
// Return value
- newCostumeVariable(fun->reg, newPersona);
+ fun->reg.makeCostumeVariable(newPersona);
return BR_CONTINUE;
}
builtIn(launch) {
UNUSEDALL
- Common::String newTextA = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newTextA = fun->stack->thisVar.getTextFromAnyVar();
Common::String newText = encodeFilename(newTextA);
@@ -922,7 +891,7 @@ builtIn(launch) {
if (g_sludge->launchMe.empty())
return BR_ERROR;
}
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
launchResult = &fun->reg;
return BR_KEEP_AND_PAUSE;
@@ -931,7 +900,7 @@ builtIn(launch) {
builtIn(pause) {
UNUSEDALL
int theTime;
- if (!getValueType(theTime, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(theTime, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (theTime > 0) {
@@ -951,10 +920,10 @@ builtIn(completeTimers) {
builtIn(callEvent) {
UNUSEDALL
int obj1, obj2;
- if (!getValueType(obj2, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj2, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj1, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj1, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
@@ -962,10 +931,10 @@ builtIn(callEvent) {
// Return value
if (fNum) {
- setVariable(fun->reg, SVT_FUNC, fNum);
+ fun->reg.setVariable(SVT_FUNC, fNum);
return BR_CALLAFUNC;
}
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
@@ -987,13 +956,13 @@ builtIn(_rem_movieStart) {
builtIn(_rem_movieAbort) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(_rem_moviePlaying) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
@@ -1004,13 +973,13 @@ builtIn(playMovie) {
if (movieIsPlaying)
return BR_PAUSE;
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
r = playMovie(fileNumber);
- setVariable(fun->reg, SVT_INT, r);
+ fun->reg.setVariable(SVT_INT, r);
if (r && (!fun->next)) {
restartFunction(fun);
@@ -1024,7 +993,7 @@ builtIn(stopMovie) {
stopMovie();
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
@@ -1033,7 +1002,7 @@ builtIn(pauseMovie) {
pauseMovie();
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
@@ -1043,13 +1012,13 @@ builtIn(pauseMovie) {
builtIn(startMusic) {
UNUSEDALL
int fromTrack, musChan, fileNumber;
- if (!getValueType(fromTrack, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fromTrack, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(musChan, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(musChan, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_soundMan->playMOD(fileNumber, musChan, fromTrack))
@@ -1060,7 +1029,7 @@ builtIn(startMusic) {
builtIn(stopMusic) {
UNUSEDALL
int v;
- if (!getValueType(v, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->stopMOD(v);
@@ -1070,10 +1039,10 @@ builtIn(stopMusic) {
builtIn(setMusicVolume) {
UNUSEDALL
int musChan, v;
- if (!getValueType(v, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(musChan, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(musChan, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setMusicVolume(musChan, v);
@@ -1083,7 +1052,7 @@ builtIn(setMusicVolume) {
builtIn(setDefaultMusicVolume) {
UNUSEDALL
int v;
- if (!getValueType(v, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setDefaultMusicVolume(v);
@@ -1093,7 +1062,7 @@ builtIn(setDefaultMusicVolume) {
builtIn(playSound) {
UNUSEDALL
int fileNumber;
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_soundMan->startSound(fileNumber, false))
@@ -1109,7 +1078,7 @@ builtIn(loopSound) {
return BR_ERROR;
} else if (numParams < 2) {
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_soundMan->startSound(fileNumber, true))
@@ -1124,12 +1093,12 @@ builtIn(loopSound) {
// Should we loop?
if (fun->stack->thisVar.varType != SVT_FILE) {
- getValueType(doLoop, SVT_INT, fun->stack->thisVar);
+ fun->stack->thisVar.getValueType(doLoop, SVT_INT);
trimStack(fun->stack);
numParams--;
}
while (numParams) {
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar)) {
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE)) {
fatal("Illegal parameter given built-in function loopSound().");
return BR_ERROR;
}
@@ -1162,7 +1131,7 @@ builtIn(loopSound) {
builtIn(stopSound) {
UNUSEDALL
int v;
- if (!getValueType(v, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->huntKillSound(v);
@@ -1172,7 +1141,7 @@ builtIn(stopSound) {
builtIn(setDefaultSoundVolume) {
UNUSEDALL
int v;
- if (!getValueType(v, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setDefaultSoundVolume(v);
@@ -1182,10 +1151,10 @@ builtIn(setDefaultSoundVolume) {
builtIn(setSoundVolume) {
UNUSEDALL
int musChan, v;
- if (!getValueType(v, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(musChan, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(musChan, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setSoundVolume(musChan, v);
@@ -1195,13 +1164,13 @@ builtIn(setSoundVolume) {
builtIn(setSoundLoopPoints) {
UNUSEDALL
int musChan, theEnd, theStart;
- if (!getValueType(theEnd, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(theEnd, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(theStart, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(theStart, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(musChan, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(musChan, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->setSoundLoop(musChan, theStart, theEnd);
@@ -1215,20 +1184,20 @@ builtIn(setFloor) {
UNUSEDALL
if (fun->stack->thisVar.varType == SVT_FILE) {
int v;
- getValueType(v, SVT_FILE, fun->stack->thisVar);
+ fun->stack->thisVar.getValueType(v, SVT_FILE);
trimStack(fun->stack);
- if (!setFloor(v))
+ if (!g_sludge->_floorMan->setFloor(v))
return BR_ERROR;
} else {
trimStack(fun->stack);
- setFloorNull();
+ g_sludge->_floorMan->setFloorNull();
}
return BR_CONTINUE;
}
builtIn(showFloor) {
UNUSEDALL
- drawFloor();
+ g_sludge->_floorMan->drawFloor();
return BR_CONTINUE;
}
@@ -1236,7 +1205,7 @@ builtIn(setZBuffer) {
UNUSEDALL
if (fun->stack->thisVar.varType == SVT_FILE) {
int v;
- getValueType(v, SVT_FILE, fun->stack->thisVar);
+ fun->stack->thisVar.getValueType(v, SVT_FILE);
trimStack(fun->stack);
if (!g_sludge->_gfxMan->setZBuffer(v))
return BR_ERROR;
@@ -1251,7 +1220,7 @@ builtIn(setLightMap) {
UNUSEDALL
switch (numParams) {
case 2:
- if (!getValueType(g_sludge->_gfxMan->_lightMapMode, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(g_sludge->_gfxMan->_lightMapMode, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->_lightMapMode %= LIGHTMAPMODE_NUM;
@@ -1260,15 +1229,15 @@ builtIn(setLightMap) {
case 1:
if (fun->stack->thisVar.varType == SVT_FILE) {
int v;
- getValueType(v, SVT_FILE, fun->stack->thisVar);
+ fun->stack->thisVar.getValueType(v, SVT_FILE);
trimStack(fun->stack);
if (!g_sludge->_gfxMan->loadLightMap(v))
return BR_ERROR;
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
} else {
trimStack(fun->stack);
g_sludge->_gfxMan->killLightMap();
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
break;
@@ -1284,13 +1253,15 @@ builtIn(setLightMap) {
builtIn(setSpeechMode) {
UNUSEDALL
- if (!getValueType(speechMode, SVT_INT, fun->stack->thisVar))
+ int speechMode;
+ if (!fun->stack->thisVar.getValueType(speechMode, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (speechMode < 0 || speechMode > 2) {
fatal("Valid parameters are be SPEECHANDTEXT, SPEECHONLY or TEXTONLY");
return BR_ERROR;
}
+ g_sludge->_speechMan->setSpeechMode(speechMode);
return BR_CONTINUE;
}
@@ -1298,9 +1269,9 @@ builtIn(somethingSpeaking) {
UNUSEDALL
int i = g_sludge->_speechMan->isThereAnySpeechGoingOn();
if (i == -1) {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
} else {
- setVariable(fun->reg, SVT_OBJTYPE, i);
+ fun->reg.setVariable(SVT_OBJTYPE, i);
}
return BR_CONTINUE;
}
@@ -1313,21 +1284,21 @@ builtIn(skipSpeech) {
builtIn(getOverObject) {
UNUSEDALL
- if (overRegion)
+ if (g_sludge->_regionMan->getOverRegion())
// Return value
- setVariable(fun->reg, SVT_OBJTYPE, overRegion->thisType->objectNum);
+ fun->reg.setVariable(SVT_OBJTYPE, g_sludge->_regionMan->getOverRegion()->thisType->objectNum);
else
// Return value
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(rename) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
int objT;
trimStack(fun->stack);
- if (!getValueType(objT, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objT, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
ObjectType *o = g_sludge->_objMan->findObjectType(objT);
@@ -1339,19 +1310,19 @@ builtIn(rename) {
builtIn(getObjectX) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *pers = findPerson(objectNumber);
+ OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
if (pers) {
- setVariable(fun->reg, SVT_INT, pers->x);
+ fun->reg.setVariable(SVT_INT, pers->x);
} else {
- ScreenRegion *la = getRegionForObject(objectNumber);
+ ScreenRegion *la = g_sludge->_regionMan->getRegionForObject(objectNumber);
if (la) {
- setVariable(fun->reg, SVT_INT, la->sX);
+ fun->reg.setVariable(SVT_INT, la->sX);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
}
return BR_CONTINUE;
@@ -1360,19 +1331,19 @@ builtIn(getObjectX) {
builtIn(getObjectY) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *pers = findPerson(objectNumber);
+ OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
if (pers) {
- setVariable(fun->reg, SVT_INT, pers->y);
+ fun->reg.setVariable(SVT_INT, pers->y);
} else {
- ScreenRegion *la = getRegionForObject(objectNumber);
+ ScreenRegion *la = g_sludge->_regionMan->getRegionForObject(objectNumber);
if (la) {
- setVariable(fun->reg, SVT_INT, la->sY);
+ fun->reg.setVariable(SVT_INT, la->sY);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
}
return BR_CONTINUE;
@@ -1381,31 +1352,31 @@ builtIn(getObjectY) {
builtIn(addScreenRegion) {
UNUSEDALL
int sX, sY, x1, y1, x2, y2, di, objectNumber;
- if (!getValueType(di, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(sY, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(sY, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(sX, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(sX, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(y2, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x2, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(y1, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x1, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- if (addScreenRegion(x1, y1, x2, y2, sX, sY, di, objectNumber))
+ if (g_sludge->_regionMan->addScreenRegion(x1, y1, x2, y2, sX, sY, di, objectNumber))
return BR_CONTINUE;
return BR_ERROR;
@@ -1414,22 +1385,22 @@ builtIn(addScreenRegion) {
builtIn(removeScreenRegion) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- removeScreenRegion(objectNumber);
+ g_sludge->_regionMan->removeScreenRegion(objectNumber);
return BR_CONTINUE;
}
builtIn(showBoxes) {
UNUSEDALL
- showBoxes();
+ g_sludge->_regionMan->showBoxes();
return BR_CONTINUE;
}
builtIn(removeAllScreenRegions) {
UNUSEDALL
- killAllRegions();
+ g_sludge->_regionMan->kill();
return BR_CONTINUE;
}
@@ -1438,21 +1409,21 @@ builtIn(addCharacter) {
Persona *p;
int x, y, objectNumber;
- p = getCostumeFromVar(fun->stack->thisVar);
+ p = fun->stack->thisVar.getCostumeFromVar();
if (p == NULL)
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- if (addPerson(x, y, objectNumber, p))
+ if (g_sludge->_peopleMan->addPerson(x, y, objectNumber, p))
return BR_CONTINUE;
return BR_ERROR;
}
@@ -1460,109 +1431,109 @@ builtIn(addCharacter) {
builtIn(hideCharacter) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setShown(false, objectNumber);
+ g_sludge->_peopleMan->setShown(false, objectNumber);
return BR_CONTINUE;
}
builtIn(showCharacter) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setShown(true, objectNumber);
+ g_sludge->_peopleMan->setShown(true, objectNumber);
return BR_CONTINUE;
}
builtIn(removeAllCharacters) {
UNUSEDALL
killSpeechTimers();
- killMostPeople();
+ g_sludge->_peopleMan->killMostPeople();
return BR_CONTINUE;
}
builtIn(setCharacterDrawMode) {
UNUSEDALL
int obj, di;
- if (!getValueType(di, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setDrawMode(di, obj);
+ g_sludge->_peopleMan->setDrawMode(di, obj);
return BR_CONTINUE;
}
builtIn(setCharacterTransparency) {
UNUSEDALL
int obj, x;
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setPersonTransparency(obj, x);
+ g_sludge->_peopleMan->setPersonTransparency(obj, x);
return BR_CONTINUE;
}
builtIn(setCharacterColourise) {
UNUSEDALL
int obj, r, g, b, mix;
- if (!getValueType(mix, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(mix, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(b, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(b, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(g, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(g, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(r, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(r, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setPersonColourise(obj, r, g, b, mix);
+ g_sludge->_peopleMan->setPersonColourise(obj, r, g, b, mix);
return BR_CONTINUE;
}
builtIn(setScale) {
UNUSEDALL
int val1, val2;
- if (!getValueType(val2, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(val2, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(val1, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(val1, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- setScale((int16)val1, (int16)val2);
+ g_sludge->_peopleMan->setScale((int16)val1, (int16)val2);
return BR_CONTINUE;
}
builtIn(stopCharacter) {
UNUSEDALL
int obj;
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
// Return value
- setVariable(fun->reg, SVT_INT, stopPerson(obj));
+ fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->stopPerson(obj));
return BR_CONTINUE;
}
builtIn(pasteCharacter) {
UNUSEDALL
int obj;
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(obj);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(obj);
if (thisPerson) {
PersonaAnimation *myAnim;
myAnim = thisPerson->myAnim;
@@ -1574,9 +1545,9 @@ builtIn(pasteCharacter) {
int fNum = myAnim->frames[thisPerson->frameNum].frameNum;
g_sludge->_gfxMan->fixScaleSprite(thisPerson->x, thisPerson->y, myAnim->theSprites->bank.sprites[ABS(fNum)], myAnim->theSprites->bank.myPalette, thisPerson, 0, 0, fNum < 0);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -1584,91 +1555,91 @@ builtIn(pasteCharacter) {
builtIn(animate) {
UNUSEDALL
int obj;
- PersonaAnimation *pp = getAnimationFromVar(fun->stack->thisVar);
+ PersonaAnimation *pp = fun->stack->thisVar.getAnimationFromVar();
if (pp == NULL)
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- animatePerson(obj, pp);
- setVariable(fun->reg, SVT_INT, timeForAnim(pp));
+ g_sludge->_peopleMan->animatePerson(obj, pp);
+ fun->reg.setVariable(SVT_INT, pp->getTotalTime());
return BR_CONTINUE;
}
builtIn(setCostume) {
UNUSEDALL
int obj;
- Persona *pp = getCostumeFromVar(fun->stack->thisVar);
+ Persona *pp = fun->stack->thisVar.getCostumeFromVar();
if (pp == NULL)
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- animatePerson(obj, pp);
+ g_sludge->_peopleMan->animatePerson(obj, pp);
return BR_CONTINUE;
}
builtIn(floatCharacter) {
UNUSEDALL
int obj, di;
- if (!getValueType(di, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, floatCharacter(di, obj));
+ fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->floatCharacter(di, obj));
return BR_CONTINUE;
}
builtIn(setCharacterWalkSpeed) {
UNUSEDALL
int obj, di;
- if (!getValueType(di, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, setCharacterWalkSpeed(di, obj));
+ fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->setCharacterWalkSpeed(di, obj));
return BR_CONTINUE;
}
builtIn(turnCharacter) {
UNUSEDALL
int obj, di;
- if (!getValueType(di, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, turnPersonToFace(obj, di));
+ fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->turnPersonToFace(obj, di));
return BR_CONTINUE;
}
builtIn(setCharacterExtra) {
UNUSEDALL
int obj, di;
- if (!getValueType(di, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(di, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, setPersonExtra(obj, di));
+ fun->reg.setVariable(SVT_INT, g_sludge->_peopleMan->setPersonExtra(obj, di));
return BR_CONTINUE;
}
builtIn(removeCharacter) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- removeOneCharacter(objectNumber);
+ g_sludge->_peopleMan->removeOneCharacter(objectNumber);
return BR_CONTINUE;
}
@@ -1677,23 +1648,23 @@ static BuiltReturn moveChr(int numParams, LoadedFunction *fun, bool force, bool
case 3: {
int x, y, objectNumber;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
if (force) {
- if (forceWalkingPerson(x, y, objectNumber, fun, -1))
+ if (g_sludge->_peopleMan->forceWalkingPerson(x, y, objectNumber, fun, -1))
return BR_PAUSE;
} else if (immediate) {
- jumpPerson(x, y, objectNumber);
+ g_sludge->_peopleMan->jumpPerson(x, y, objectNumber);
} else {
- if (makeWalkingPerson(x, y, objectNumber, fun, -1))
+ if (g_sludge->_peopleMan->makeWalkingPerson(x, y, objectNumber, fun, -1))
return BR_PAUSE;
}
return BR_CONTINUE;
@@ -1703,23 +1674,23 @@ static BuiltReturn moveChr(int numParams, LoadedFunction *fun, bool force, bool
int toObj, objectNumber;
ScreenRegion*reggie;
- if (!getValueType(toObj, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(toObj, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- reggie = getRegionForObject(toObj);
+ reggie = g_sludge->_regionMan->getRegionForObject(toObj);
if (reggie == NULL)
return BR_CONTINUE;
if (force) {
- if (forceWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
+ if (g_sludge->_peopleMan->forceWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
return BR_PAUSE;
} else if (immediate) {
- jumpPerson(reggie->sX, reggie->sY, objectNumber);
+ g_sludge->_peopleMan->jumpPerson(reggie->sX, reggie->sY, objectNumber);
} else {
- if (makeWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
+ if (g_sludge->_peopleMan->makeWalkingPerson(reggie->sX, reggie->sY, objectNumber, fun, reggie->di))
return BR_PAUSE;
}
return BR_CONTINUE;
@@ -1766,7 +1737,7 @@ builtIn(addStatus) {
builtIn(statusText) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
setStatusBar(newText);
return BR_CONTINUE;
@@ -1775,7 +1746,7 @@ builtIn(statusText) {
builtIn(lightStatus) {
UNUSEDALL
int val;
- if (!getValueType(val, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(val, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
setLitStatus(val);
@@ -1785,10 +1756,10 @@ builtIn(lightStatus) {
builtIn(positionStatus) {
UNUSEDALL
int x, y;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
positionStatus(x, y);
@@ -1798,7 +1769,7 @@ builtIn(positionStatus) {
builtIn(alignStatus) {
UNUSEDALL
int val;
- if (!getValueType(val, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(val, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
nowStatus->alignStatus = (int16)val;
@@ -1812,7 +1783,7 @@ static bool getFuncNumForCallback(int numParams, LoadedFunction *fun, int &funct
break;
case 1:
- if (!getValueType(functionNum, SVT_FUNC, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(functionNum, SVT_FUNC))
return false;
trimStack(fun->stack);
break;
@@ -1922,18 +1893,18 @@ builtIn(cancelSub) {
builtIn(stringWidth) {
UNUSEDALL
- Common::String theText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String theText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
// Return value
- setVariable(fun->reg, SVT_INT, g_sludge->_txtMan->stringWidth(theText));
+ fun->reg.setVariable(SVT_INT, g_sludge->_txtMan->stringWidth(theText));
return BR_CONTINUE;
}
builtIn(hardScroll) {
UNUSEDALL
int v;
- if (!getValueType(v, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_gfxMan->hardScroll(v);
@@ -1943,80 +1914,76 @@ builtIn(hardScroll) {
builtIn(isScreenRegion) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, getRegionForObject(objectNumber) != NULL);
+ fun->reg.setVariable(SVT_INT, g_sludge->_regionMan->getRegionForObject(objectNumber) != NULL);
return BR_CONTINUE;
}
builtIn(setSpeechSpeed) {
UNUSEDALL
int number;
- if (!getValueType(number, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(number, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_speechMan->setSpeechSpeed(number * 0.01);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(setFontSpacing) {
UNUSEDALL
int fontSpaceI;
- if (!getValueType(fontSpaceI, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fontSpaceI, SVT_INT))
return BR_ERROR;
g_sludge->_txtMan->setFontSpace(fontSpaceI);
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(transitionLevel) {
UNUSEDALL
- int number;
- if (!getValueType(number, SVT_INT, fun->stack->thisVar))
+ int brightnessLevel;
+ if (!fun->stack->thisVar.getValueType(brightnessLevel, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (number < 0)
- brightnessLevel = 0;
- else if (number > 255)
- brightnessLevel = 255;
- else
- brightnessLevel = number;
+ g_sludge->_gfxMan->setBrightnessLevel(brightnessLevel);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(captureAllKeys) {
UNUSEDALL
- captureAllKeys = getBoolean(fun->stack->thisVar);
+ // This built-in function doesn't have any effect any more, we capture all keys by default
+ bool captureAllKeysDeprecated = fun->stack->thisVar.getBoolean();
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, captureAllKeys);
+ fun->reg.setVariable(SVT_INT, captureAllKeysDeprecated);
return BR_CONTINUE;
}
builtIn(spinCharacter) {
UNUSEDALL
int number, objectNumber;
- if (!getValueType(number, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(number, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(objectNumber);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
thisPerson->wantAngle = number;
thisPerson->spinning = true;
thisPerson->continueAfterWalking = fun;
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_PAUSE;
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
}
@@ -2024,14 +1991,14 @@ builtIn(spinCharacter) {
builtIn(getCharacterDirection) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(objectNumber);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
- setVariable(fun->reg, SVT_INT, thisPerson->direction);
+ fun->reg.setVariable(SVT_INT, thisPerson->direction);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -2039,26 +2006,26 @@ builtIn(getCharacterDirection) {
builtIn(isCharacter) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(objectNumber);
- setVariable(fun->reg, SVT_INT, thisPerson != NULL);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
+ fun->reg.setVariable(SVT_INT, thisPerson != NULL);
return BR_CONTINUE;
}
builtIn(normalCharacter) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(objectNumber);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
thisPerson->myAnim = thisPerson->myPersona->animation[thisPerson->direction];
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -2066,14 +2033,14 @@ builtIn(normalCharacter) {
builtIn(isMoving) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(objectNumber);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objectNumber);
if (thisPerson) {
- setVariable(fun->reg, SVT_INT, thisPerson->walking);
+ fun->reg.setVariable(SVT_INT, thisPerson->walking);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -2081,10 +2048,10 @@ builtIn(isMoving) {
builtIn(fetchEvent) {
UNUSEDALL
int obj1, obj2;
- if (!getValueType(obj2, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj2, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(obj1, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(obj1, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
@@ -2092,9 +2059,9 @@ builtIn(fetchEvent) {
// Return value
if (fNum) {
- setVariable(fun->reg, SVT_FUNC, fNum);
+ fun->reg.setVariable(SVT_FUNC, fNum);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -2102,13 +2069,13 @@ builtIn(fetchEvent) {
builtIn(deleteFile) {
UNUSEDALL
- Common::String namNormal = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String namNormal = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String nam = encodeFilename(namNormal);
namNormal.clear();
if (failSecurityCheck(nam))
return BR_ERROR;
- setVariable(fun->reg, SVT_INT, remove(nam.c_str()));
+ fun->reg.setVariable(SVT_INT, remove(nam.c_str()));
return BR_CONTINUE;
}
@@ -2118,20 +2085,20 @@ builtIn(renameFile) {
Common::String temp;
temp.clear();
- temp = getTextFromAnyVar(fun->stack->thisVar);
+ temp = fun->stack->thisVar.getTextFromAnyVar();
Common::String newnam = encodeFilename(temp);
trimStack(fun->stack);
if (failSecurityCheck(newnam))
return BR_ERROR;
temp.clear();
- temp = getTextFromAnyVar(fun->stack->thisVar);
+ temp = fun->stack->thisVar.getTextFromAnyVar();
Common::String nam = encodeFilename(temp);
trimStack(fun->stack);
if (failSecurityCheck(nam))
return BR_ERROR;
- setVariable(fun->reg, SVT_INT, rename(nam.c_str(), newnam.c_str()));
+ fun->reg.setVariable(SVT_INT, rename(nam.c_str(), newnam.c_str()));
return BR_CONTINUE;
}
@@ -2139,7 +2106,7 @@ builtIn(renameFile) {
builtIn(cacheSound) {
UNUSEDALL
int fileNumber;
- if (!getValueType(fileNumber, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(fileNumber, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (g_sludge->_soundMan->cacheSound(fileNumber) == -1)
@@ -2149,38 +2116,38 @@ builtIn(cacheSound) {
builtIn(burnString) {
UNUSEDALL
- Common::String newText = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newText = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
int y, x;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
if (x == IN_THE_CENTRE)
x = g_sludge->_gfxMan->getCenterX(g_sludge->_txtMan->stringWidth(newText));
- g_sludge->_txtMan->burnStringToBackdrop(newText, x, y, pastePalette);
+ g_sludge->_txtMan->burnStringToBackdrop(newText, x, y);
return BR_CONTINUE;
}
builtIn(setCharacterSpinSpeed) {
UNUSEDALL
int speed, who;
- if (!getValueType(speed, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(speed, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(who, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(who, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(who);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(who);
if (thisPerson) {
thisPerson->spinSpeed = speed;
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -2188,20 +2155,20 @@ builtIn(setCharacterSpinSpeed) {
builtIn(setCharacterAngleOffset) {
UNUSEDALL
int angle, who;
- if (!getValueType(angle, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(angle, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(who, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(who, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *thisPerson = findPerson(who);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(who);
if (thisPerson) {
thisPerson->angleOffset = angle;
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
@@ -2209,11 +2176,11 @@ builtIn(setCharacterAngleOffset) {
builtIn(transitionMode) {
UNUSEDALL
int n;
- if (!getValueType(n, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(n, SVT_INT))
return BR_ERROR;
- fadeMode = n;
+ g_sludge->_gfxMan->setFadeMode(n);
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
@@ -2221,7 +2188,7 @@ builtIn(transitionMode) {
builtIn(_rem_updateDisplay) {
UNUSEDALL
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, true);
+ fun->reg.setVariable(SVT_INT, true);
return BR_CONTINUE;
}
@@ -2242,7 +2209,7 @@ builtIn(getSoundCache) {
builtIn(saveCustomData) {
UNUSEDALL
// saveCustomData (thisStack, fileName);
- Common::String fileNameB = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String fileNameB = fun->stack->thisVar.getTextFromAnyVar();
Common::String fileName = encodeFilename(fileNameB);
@@ -2254,7 +2221,7 @@ builtIn(saveCustomData) {
fatal("First parameter isn't a stack");
return BR_ERROR;
}
- if (!stackToFile(fileName, fun->stack->thisVar))
+ if (!CustomSaveHelper::stackToFile(fileName, fun->stack->thisVar))
return BR_ERROR;
trimStack(fun->stack);
return BR_CONTINUE;
@@ -2263,7 +2230,7 @@ builtIn(saveCustomData) {
builtIn(loadCustomData) {
UNUSEDALL
- Common::String newTextA = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String newTextA = fun->stack->thisVar.getTextFromAnyVar();
Common::String newText = encodeFilename(newTextA);
@@ -2271,7 +2238,7 @@ builtIn(loadCustomData) {
return BR_ERROR;
trimStack(fun->stack);
- unlinkVar(fun->reg);
+ fun->reg.unlinkVar();
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
@@ -2279,7 +2246,7 @@ builtIn(loadCustomData) {
fun->reg.varData.theStack->first = NULL;
fun->reg.varData.theStack->last = NULL;
fun->reg.varData.theStack->timesUsed = 1;
- if (!fileToStack(newText, fun->reg.varData.theStack))
+ if (!CustomSaveHelper::fileToStack(newText, fun->reg.varData.theStack))
return BR_ERROR;
return BR_CONTINUE;
}
@@ -2287,18 +2254,18 @@ builtIn(loadCustomData) {
builtIn(setCustomEncoding) {
UNUSEDALL
int n;
- if (!getValueType(n, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(n, SVT_INT))
return BR_ERROR;
- saveEncoding = n;
+ CustomSaveHelper::_saveEncoding = n;
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(freeSound) {
UNUSEDALL
int v;
- if (!getValueType(v, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
g_sludge->_soundMan->huntKillFreeSound(v);
@@ -2312,19 +2279,19 @@ builtIn(parallaxAdd) {
return BR_ERROR;
} else {
int wrapX, wrapY, v;
- if (!getValueType(wrapY, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(wrapY, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(wrapX, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(wrapX, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(v, SVT_FILE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(v, SVT_FILE))
return BR_ERROR;
trimStack(fun->stack);
if (!g_sludge->_gfxMan->loadParallax(v, wrapX, wrapY))
return BR_ERROR;
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
}
return BR_CONTINUE;
}
@@ -2332,21 +2299,21 @@ builtIn(parallaxAdd) {
builtIn(parallaxClear) {
UNUSEDALL
g_sludge->_gfxMan->killParallax();
- setVariable(fun->reg, SVT_INT, 1);
+ fun->reg.setVariable(SVT_INT, 1);
return BR_CONTINUE;
}
builtIn(getPixelColour) {
UNUSEDALL
int x, y;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- unlinkVar(fun->reg);
+ fun->reg.unlinkVar();
fun->reg.varType = SVT_STACK;
fun->reg.varData.theStack = new StackHandler;
if (!checkNew(fun->reg.varData.theStack))
@@ -2364,7 +2331,7 @@ builtIn(makeFastArray) {
UNUSEDALL
switch (fun->stack->thisVar.varType) {
case SVT_STACK: {
- bool success = makeFastArrayFromStack(fun->reg, fun->stack->thisVar.varData.theStack);
+ bool success = fun->reg.makeFastArrayFromStack(fun->stack->thisVar.varData.theStack);
trimStack(fun->stack);
return success ? BR_CONTINUE : BR_ERROR;
}
@@ -2373,7 +2340,7 @@ builtIn(makeFastArray) {
case SVT_INT: {
int i = fun->stack->thisVar.varData.intValue;
trimStack(fun->stack);
- return makeFastArraySize(fun->reg, i) ? BR_CONTINUE : BR_ERROR;
+ return fun->reg.makeFastArraySize(i) ? BR_CONTINUE : BR_ERROR;
}
break;
@@ -2387,22 +2354,22 @@ builtIn(makeFastArray) {
builtIn(getCharacterScale) {
UNUSEDALL
int objectNumber;
- if (!getValueType(objectNumber, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objectNumber, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
- OnScreenPerson *pers = findPerson(objectNumber);
+ OnScreenPerson *pers = g_sludge->_peopleMan->findPerson(objectNumber);
if (pers) {
- setVariable(fun->reg, SVT_INT, pers->scale * 100);
+ fun->reg.setVariable(SVT_INT, pers->scale * 100);
} else {
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
}
return BR_CONTINUE;
}
builtIn(getLanguageID) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, g_sludge->getLanguageID());
+ fun->reg.setVariable(SVT_INT, g_sludge->getLanguageID());
return BR_CONTINUE;
}
@@ -2413,7 +2380,7 @@ builtIn(_rem_launchWith) {
trimStack(fun->stack);
// To support some windows only games
- Common::String filename = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String filename = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
if (filename.hasSuffix(".exe")) {
@@ -2432,28 +2399,28 @@ builtIn(_rem_launchWith) {
}
g_sludge->launchNext.clear();
- setVariable(fun->reg, SVT_INT, false);
+ fun->reg.setVariable(SVT_INT, false);
return BR_CONTINUE;
}
builtIn(getFramesPerSecond) {
UNUSEDALL
- setVariable(fun->reg, SVT_INT, lastFramesPerSecond);
+ fun->reg.setVariable(SVT_INT, g_sludge->_timer.getLastFps());
return BR_CONTINUE;
}
builtIn(showThumbnail) {
UNUSEDALL
int x, y;
- if (!getValueType(y, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(y, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(x, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(x, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
// Encode the name!Encode the name!
- Common::String aaaaa = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
Common::String file = encodeFilename(aaaaa);
g_sludge->_gfxMan->showThumbnail(file, x, y);
@@ -2462,13 +2429,14 @@ builtIn(showThumbnail) {
builtIn(setThumbnailSize) {
UNUSEDALL
- if (!getValueType(thumbHeight, SVT_INT, fun->stack->thisVar))
+ int thumbHeight, thumbWidth;
+ if (!fun->stack->thisVar.getValueType(thumbHeight, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(thumbWidth, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(thumbWidth, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!g_sludge->_gfxMan->checkSizeValide(thumbWidth, thumbHeight)) {
+ if (!g_sludge->_gfxMan->setThumbnailSize(thumbWidth, thumbHeight)) {
Common::String buff = Common::String::format("%i x %i", thumbWidth, thumbWidth);
fatal("Invalid thumbnail size", buff);
return BR_ERROR;
@@ -2479,16 +2447,16 @@ builtIn(setThumbnailSize) {
builtIn(hasFlag) {
UNUSEDALL
int objNum, flagIndex;
- if (!getValueType(flagIndex, SVT_INT, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(flagIndex, SVT_INT))
return BR_ERROR;
trimStack(fun->stack);
- if (!getValueType(objNum, SVT_OBJTYPE, fun->stack->thisVar))
+ if (!fun->stack->thisVar.getValueType(objNum, SVT_OBJTYPE))
return BR_ERROR;
trimStack(fun->stack);
ObjectType *objT = g_sludge->_objMan->findObjectType(objNum);
if (!objT)
return BR_ERROR;
- setVariable(fun->reg, SVT_INT, objT->flags & (1 << flagIndex));
+ fun->reg.setVariable(SVT_INT, objT->flags & (1 << flagIndex));
return BR_CONTINUE;
}
@@ -2506,9 +2474,9 @@ builtIn(snapshotClear) {
builtIn(bodgeFilenames) {
UNUSEDALL
bool lastValue = allowAnyFilename;
- allowAnyFilename = getBoolean(fun->stack->thisVar);
+ allowAnyFilename = fun->stack->thisVar.getBoolean();
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, lastValue);
+ fun->reg.setVariable(SVT_INT, lastValue);
return BR_CONTINUE;
}
@@ -2517,14 +2485,14 @@ builtIn(_rem_registryGetString) {
UNUSEDALL
trimStack(fun->stack);
trimStack(fun->stack);
- setVariable(fun->reg, SVT_INT, 0);
+ fun->reg.setVariable(SVT_INT, 0);
return BR_CONTINUE;
}
builtIn(quitWithFatalError) {
UNUSEDALL
- Common::String mess = getTextFromAnyVar(fun->stack->thisVar);
+ Common::String mess = fun->stack->thisVar.getTextFromAnyVar();
trimStack(fun->stack);
fatal(mess);
return BR_ERROR;
@@ -2555,14 +2523,14 @@ builtIn(_rem_setMaximumAA) {
builtIn(setBackgroundEffect) {
UNUSEDALL
bool done = blur_createSettings(numParams, fun->stack);
- setVariable(fun->reg, SVT_INT, done ? 1 : 0);
+ fun->reg.setVariable(SVT_INT, done ? 1 : 0);
return BR_CONTINUE;
}
builtIn(doBackgroundEffect) {
UNUSEDALL
bool done = blurScreen();
- setVariable(fun->reg, SVT_INT, done ? 1 : 0);
+ fun->reg.setVariable(SVT_INT, done ? 1 : 0);
return BR_CONTINUE;
}
@@ -2584,9 +2552,9 @@ BuiltReturn callBuiltIn(int whichFunc, int numParams, LoadedFunction *fun) {
}
if (whichFunc < NUM_FUNCS) {
- if (paramNum[whichFunc] != -1) {
- if (paramNum[whichFunc] != numParams) {
- Common::String buff = Common::String::format("Built in function must have %i parameter%s", paramNum[whichFunc], (paramNum[whichFunc] == 1) ? "" : "s");
+ if (builtInFunctionArray[whichFunc].paramNum != -1) {
+ if (builtInFunctionArray[whichFunc].paramNum != numParams) {
+ Common::String buff = Common::String::format("Built in function must have %i parameter%s", builtInFunctionArray[whichFunc].paramNum, (builtInFunctionArray[whichFunc].paramNum == 1) ? "" : "s");
Common::String msg = buff;
fatal(msg);
return BR_ERROR;
diff --git a/engines/sludge/builtin.h b/engines/sludge/builtin.h
index b2274c22e9..b7fa8b86ef 100644
--- a/engines/sludge/builtin.h
+++ b/engines/sludge/builtin.h
@@ -23,6 +23,8 @@
#ifndef SLUDGE_BUILTIN_H
#define SLUDGE_BUILTIN_H
+#include "sludge/allfiles.h"
+
namespace Sludge {
struct LoadedFunction;
diff --git a/engines/sludge/csludge.h b/engines/sludge/csludge.h
index 435a220a2d..cf0d6aaf43 100644
--- a/engines/sludge/csludge.h
+++ b/engines/sludge/csludge.h
@@ -25,7 +25,7 @@
namespace Sludge {
-enum sludgeCommand {
+enum SludgeCommand {
SLU_UNKNOWN,
SLU_RETURN,
SLU_BRANCH,
diff --git a/engines/sludge/cursors.cpp b/engines/sludge/cursors.cpp
index 0c7745e9ff..0ec46e2f17 100644
--- a/engines/sludge/cursors.cpp
+++ b/engines/sludge/cursors.cpp
@@ -44,18 +44,24 @@ CursorManager::~CursorManager() {
}
void CursorManager::init() {
- _mouseCursorAnim = makeNullAnim();
+ _mouseCursorAnim = new PersonaAnimation();
_mouseCursorFrameNum = 0;
_mouseCursorCountUp = 0;
}
void CursorManager::kill() {
- deleteAnim(_mouseCursorAnim);
+ if (_mouseCursorAnim) {
+ delete _mouseCursorAnim;
+ _mouseCursorAnim = nullptr;
+ }
_mouseCursorAnim = nullptr;
}
void CursorManager::pickAnimCursor(PersonaAnimation *pp) {
- deleteAnim(_mouseCursorAnim);
+ if (_mouseCursorAnim) {
+ delete _mouseCursorAnim;
+ _mouseCursorAnim = nullptr;
+ }
_mouseCursorAnim = pp;
_mouseCursorFrameNum = 0;
_mouseCursorCountUp = 0;
@@ -107,18 +113,21 @@ void CursorManager::pasteCursor(int x, int y, PersonaAnimation *c) {
void CursorManager::freeze(FrozenStuffStruct *frozenStuff) {
frozenStuff->mouseCursorAnim = _mouseCursorAnim;
frozenStuff->mouseCursorFrameNum = _mouseCursorFrameNum;
- _mouseCursorAnim = makeNullAnim();
+ _mouseCursorAnim = new PersonaAnimation();
_mouseCursorFrameNum = 0;
}
void CursorManager::resotre(FrozenStuffStruct *frozenStuff) {
- deleteAnim(_mouseCursorAnim);
+ if (_mouseCursorAnim) {
+ delete _mouseCursorAnim;
+ _mouseCursorAnim = nullptr;
+ }
_mouseCursorAnim = frozenStuff->mouseCursorAnim;
_mouseCursorFrameNum = frozenStuff->mouseCursorFrameNum;
}
void CursorManager::saveCursor(Common::WriteStream *stream) {
- saveAnim(_mouseCursorAnim, stream);
+ _mouseCursorAnim->save(stream);
stream->writeUint16BE(_mouseCursorFrameNum);
}
@@ -126,7 +135,7 @@ bool CursorManager::loadCursor(Common::SeekableReadStream *stream) {
_mouseCursorAnim = new PersonaAnimation;
if (!checkNew(_mouseCursorAnim))
return false;
- if (!loadAnim(_mouseCursorAnim, stream))
+ if (!_mouseCursorAnim->load(stream))
return false;
_mouseCursorFrameNum = stream->readUint16BE();
return true;
diff --git a/engines/sludge/cursors.h b/engines/sludge/cursors.h
index 4229900a94..f3c71c2560 100644
--- a/engines/sludge/cursors.h
+++ b/engines/sludge/cursors.h
@@ -53,7 +53,7 @@ public:
private:
SludgeEngine *_vm;
- PersonaAnimation *_mouseCursorAnim;
+ PersonaAnimation *_mouseCursorAnim;
int _mouseCursorFrameNum;
int _mouseCursorCountUp;
};
diff --git a/engines/sludge/detection.cpp b/engines/sludge/detection.cpp
index a530a5c796..8c5c0ac13d 100644
--- a/engines/sludge/detection.cpp
+++ b/engines/sludge/detection.cpp
@@ -86,11 +86,11 @@ public:
virtual const char *getName() const {
return "Sludge Engine";
}
-
+
virtual const char *getOriginalCopyright() const {
return "Copyright (C) 2000-2014 Hungry Software and contributors";
}
-
+
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
const Sludge::SludgeGameDescription *gd = (const Sludge::SludgeGameDescription *)desc;
if (gd) {
@@ -100,10 +100,10 @@ public:
}
// for fall back detection
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
-const ADGameDescription *SludgeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame SludgeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// reset fallback description
s_fallbackDesc.desc.gameId = "sludge";
s_fallbackDesc.desc.extra = "";
@@ -147,9 +147,19 @@ const ADGameDescription *SludgeMetaEngine::fallbackDetect(const FileMap &allFile
s_fallbackFileNameBuffer[50] = '\0';
s_fallbackDesc.desc.filesDescriptions[0].fileName = s_fallbackFileNameBuffer;
- return (const ADGameDescription *)&s_fallbackDesc;
+ ADDetectedGame game;
+ game.desc = &s_fallbackDesc.desc;
+
+ FileProperties tmp;
+ if (getFileProperties(file->getParent(), allFiles, s_fallbackDesc.desc, fileName, tmp)) {
+ game.hasUnknownFiles = true;
+ game.matchedFiles[fileName] = tmp;
+ }
+
+ return game;
}
- return 0;
+
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(SLUDGE)
diff --git a/engines/sludge/event.cpp b/engines/sludge/event.cpp
index d5c453bdc1..098720b4c6 100644
--- a/engines/sludge/event.cpp
+++ b/engines/sludge/event.cpp
@@ -25,6 +25,7 @@
#include "sludge/event.h"
#include "sludge/freeze.h"
+#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/newfatal.h"
#include "sludge/region.h"
@@ -36,8 +37,6 @@ namespace Sludge {
extern Variable *launchResult;
extern VariableStack *noStack;
-extern ScreenRegion *overRegion;
-extern ScreenRegion *lastRegion;
EventManager::EventManager(SludgeEngine *vm) {
_vm = vm;
@@ -152,14 +151,14 @@ void EventManager::checkInput() {
bool EventManager::handleInput() {
static int l = 0;
- if (!g_sludge->launchMe.empty()) {
+ if (!_vm->launchMe.empty()) {
if (l) {
// Still paused because of spawned thingy...
} else {
l = 1;
- setVariable(*launchResult, SVT_INT, 0/*launch(launchMe) > 31*/); //TODO:false value
- g_sludge->launchMe.clear();
+ launchResult->setVariable(SVT_INT, 0/*launch(launchMe) > 31*/); //TODO:false value
+ _vm->launchMe.clear();
launchResult = nullptr;
}
return true;
@@ -167,8 +166,8 @@ bool EventManager::handleInput() {
l = 0;
}
- if (!overRegion)
- getOverRegion();
+ if (!_vm->_regionMan->getOverRegion())
+ _vm->_regionMan->updateOverRegion();
if (_input.justMoved) {
if (_currentEvents->func[kMoveMouse]) {
@@ -178,16 +177,16 @@ bool EventManager::handleInput() {
}
_input.justMoved = false;
- if (lastRegion != overRegion && _currentEvents->func[kFocus]) {
+ if (_vm-> _regionMan->isRegionChanged()&& _currentEvents->func[kFocus]) {
VariableStack *tempStack = new VariableStack;
if (!checkNew(tempStack))
return false;
- initVarNew(tempStack->thisVar);
+ ScreenRegion *overRegion = _vm->_regionMan->getOverRegion();
if (overRegion) {
- setVariable(tempStack->thisVar, SVT_OBJTYPE, overRegion->thisType->objectNum);
+ tempStack->thisVar.setVariable(SVT_OBJTYPE, overRegion->thisType->objectNum);
} else {
- setVariable(tempStack->thisVar, SVT_INT, 0);
+ tempStack->thisVar.setVariable(SVT_INT, 0);
}
tempStack->next = nullptr;
if (!startNewFunctionNum(_currentEvents->func[kFocus], 1, nullptr, tempStack))
@@ -321,8 +320,7 @@ bool EventManager::handleInput() {
VariableStack *tempStack = new VariableStack;
if (!checkNew(tempStack))
return false;
- initVarNew(tempStack->thisVar);
- makeTextVar(tempStack->thisVar, tempString);
+ tempStack->thisVar.makeTextVar(tempString);
tempStack->next = nullptr;
if (!startNewFunctionNum(_currentEvents->func[kSpace], 1, nullptr, tempStack))
return false;
@@ -333,7 +331,7 @@ bool EventManager::handleInput() {
_input.rightRelease = false;
_input.leftRelease = false;
_input.keyPressed = 0;
- lastRegion = overRegion;
+ _vm->_regionMan->updateLastRegion();
return true;
}
diff --git a/engines/sludge/event.h b/engines/sludge/event.h
index 015e9ea1cb..c07f7b87ad 100644
--- a/engines/sludge/event.h
+++ b/engines/sludge/event.h
@@ -69,7 +69,7 @@ public:
int &mouseY() { return _input.mouseY; }
// Events
- void setEventFunction(EventFunctions event, int funcNum) { _currentEvents->func[event] = funcNum; } ;
+ void setEventFunction(EventFunctions event, int funcNum) { _currentEvents->func[event] = funcNum; };
void loadHandlers(Common::SeekableReadStream *stream);
void saveHandlers(Common::WriteStream *stream);
bool freeze(FrozenStuffStruct *frozenStuff);
diff --git a/engines/sludge/fileset.cpp b/engines/sludge/fileset.cpp
index fcdec32335..c9c3e7a43b 100644
--- a/engines/sludge/fileset.cpp
+++ b/engines/sludge/fileset.cpp
@@ -48,12 +48,14 @@ void ResourceManager::init() {
_startOfSubIndex = 0;
_startOfObjectIndex = 0;
_startIndex = 0;
+ _allResourceNames.clear();
}
void ResourceManager::kill() {
if (_bigDataFile) {
delete _bigDataFile;
_bigDataFile = nullptr;
}
+ _allResourceNames.clear();
}
bool ResourceManager::openSubSlice(int num) {
@@ -216,6 +218,31 @@ void ResourceManager::finishAccess() {
_sliceBusy = false;
}
+void ResourceManager::readResourceNames(Common::SeekableReadStream *readStream) {
+ int numResourceNames = readStream->readUint16BE();
+ debugC(2, kSludgeDebugDataLoad, "numResourceNames %i", numResourceNames);
+ _allResourceNames.reserve(numResourceNames);
+
+ for (int fn = 0; fn < numResourceNames; fn++) {
+ _allResourceNames[fn].clear();
+ _allResourceNames[fn] = readString(readStream);
+ debugC(2, kSludgeDebugDataLoad, "Resource %i: %s", fn, _allResourceNames[fn].c_str());
+ }
+}
+
+const Common::String ResourceManager::resourceNameFromNum(int i) {
+ if (i == -1)
+ return "";
+
+ if (_allResourceNames.empty())
+ return "RESOURCE";
+
+ if (i < (int)_allResourceNames.size())
+ return _allResourceNames[i];
+
+ return "Unknown resource";
+}
+
void ResourceManager::setData(Common::File *fp) {
_bigDataFile = fp;
_startIndex = fp->pos();
diff --git a/engines/sludge/fileset.h b/engines/sludge/fileset.h
index 83200ceeb8..fb6a696f47 100644
--- a/engines/sludge/fileset.h
+++ b/engines/sludge/fileset.h
@@ -44,15 +44,23 @@ public:
bool openObjectSlice(int num);
Common::String getNumberedString(int value);
+ // Access control flag
bool startAccess();
void finishAccess();
+ // Resource names
+ void readResourceNames(Common::SeekableReadStream *readStream);
+ const Common::String resourceNameFromNum(int i);
+ bool hasResourceNames() { return !_allResourceNames.empty(); }
+
private:
bool _sliceBusy;
Common::File *_bigDataFile;
uint32 _startOfDataIndex, _startOfTextIndex, _startOfSubIndex, _startOfObjectIndex;
int32 _startIndex;
+ Common::Array<Common::String> _allResourceNames;
+
private:
static uint32 _cp1250ToUTF32[128];
Common::String convertString(const Common::String &s);
diff --git a/engines/sludge/floor.cpp b/engines/sludge/floor.cpp
index 71aa75cbe7..c51fcc4309 100644
--- a/engines/sludge/floor.cpp
+++ b/engines/sludge/floor.cpp
@@ -28,23 +28,33 @@
#include "sludge/graphics.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
+#include "sludge/people.h"
#include "sludge/sludge.h"
+#define ANGLEFIX (180.0 / 3.14157)
+
namespace Sludge {
-Floor *currentFloor = NULL;
+FloorManager::FloorManager(SludgeEngine *vm) {
+ _vm = vm;
+ _currentFloor = nullptr;
+}
-bool pointInFloorPolygon(FloorPolygon &floorPoly, int x, int y) {
+FloorManager::~FloorManager() {
+ kill();
+}
+
+bool FloorManager::pointInFloorPolygon(FloorPolygon &floorPoly, int x, int y) {
int i = 0, j, c = 0;
float xp_i, yp_i;
float xp_j, yp_j;
for (j = floorPoly.numVertices - 1; i < floorPoly.numVertices; j = i++) {
- xp_i = currentFloor->vertex[floorPoly.vertexID[i]].x;
- yp_i = currentFloor->vertex[floorPoly.vertexID[i]].y;
- xp_j = currentFloor->vertex[floorPoly.vertexID[j]].x;
- yp_j = currentFloor->vertex[floorPoly.vertexID[j]].y;
+ xp_i = _currentFloor->vertex[floorPoly.vertexID[i]].x;
+ yp_i = _currentFloor->vertex[floorPoly.vertexID[i]].y;
+ xp_j = _currentFloor->vertex[floorPoly.vertexID[j]].x;
+ yp_j = _currentFloor->vertex[floorPoly.vertexID[j]].y;
if ((((yp_i <= y) && (y < yp_j)) || ((yp_j <= y) && (y < yp_i))) && (x < (xp_j - xp_i) * (y - yp_i) / (yp_j - yp_i) + xp_i)) {
c = !c;
@@ -53,7 +63,7 @@ bool pointInFloorPolygon(FloorPolygon &floorPoly, int x, int y) {
return c;
}
-bool getMatchingCorners(FloorPolygon &a, FloorPolygon &b, int &cornerA, int &cornerB) {
+bool FloorManager::getMatchingCorners(FloorPolygon &a, FloorPolygon &b, int &cornerA, int &cornerB) {
int sharedVertices = 0;
int i, j;
@@ -73,7 +83,7 @@ bool getMatchingCorners(FloorPolygon &a, FloorPolygon &b, int &cornerA, int &cor
return false;
}
-bool polysShareSide(FloorPolygon &a, FloorPolygon &b) {
+bool FloorManager::polysShareSide(FloorPolygon &a, FloorPolygon &b) {
int sharedVertices = 0;
int i, j;
@@ -89,46 +99,45 @@ bool polysShareSide(FloorPolygon &a, FloorPolygon &b) {
return false;
}
-void noFloor() {
- currentFloor->numPolygons = 0;
- currentFloor->polygon = NULL;
- currentFloor->vertex = NULL;
- currentFloor->matrix = NULL;
-}
-
-bool initFloor() {
- currentFloor = new Floor;
- if (!checkNew(currentFloor))
+bool FloorManager::init() {
+ _currentFloor = new Floor;
+ if (!checkNew(_currentFloor))
return false;
- noFloor();
+ _currentFloor->numPolygons = 0;
+ _currentFloor->polygon = nullptr;
+ _currentFloor->vertex = nullptr;
+ _currentFloor->matrix = nullptr;
return true;
}
-void killFloor() {
- if (currentFloor) {
- for (int i = 0; i < currentFloor->numPolygons; i++) {
- delete []currentFloor->polygon[i].vertexID;
- delete []currentFloor->matrix[i];
+void FloorManager::setFloorNull() {
+ if (_currentFloor) {
+ for (int i = 0; i < _currentFloor->numPolygons; i++) {
+ delete[] _currentFloor->polygon[i].vertexID;
+ delete[] _currentFloor->matrix[i];
}
- delete []currentFloor->polygon;
- currentFloor->polygon = NULL;
- delete []currentFloor->vertex;
- currentFloor->vertex = NULL;
- delete []currentFloor->matrix;
- currentFloor->matrix = NULL;
+ delete[] _currentFloor->polygon;
+ _currentFloor->polygon = nullptr;
+ delete[] _currentFloor->vertex;
+ _currentFloor->vertex = nullptr;
+ delete[] _currentFloor->matrix;
+ _currentFloor->matrix = nullptr;
}
}
-void setFloorNull() {
- killFloor();
- noFloor();
+void FloorManager::kill() {
+ setFloorNull();
+ if (_currentFloor) {
+ delete _currentFloor;
+ _currentFloor = nullptr;
+ }
}
-bool setFloor(int fileNum) {
+bool FloorManager::setFloor(int fileNum) {
int i, j;
- killFloor();
+ setFloorNull();
setResourceForFatal(fileNum);
@@ -137,73 +146,73 @@ bool setFloor(int fileNum) {
// Find out how many polygons there are and reserve memory
- currentFloor->originalNum = fileNum;
- currentFloor->numPolygons = g_sludge->_resMan->getData()->readByte();
- currentFloor->polygon = new FloorPolygon[currentFloor->numPolygons];
- if (!checkNew(currentFloor->polygon))
+ _currentFloor->originalNum = fileNum;
+ _currentFloor->numPolygons = g_sludge->_resMan->getData()->readByte();
+ _currentFloor->polygon = new FloorPolygon[_currentFloor->numPolygons];
+ if (!checkNew(_currentFloor->polygon))
return false;
// Read in each polygon
- for (i = 0; i < currentFloor->numPolygons; i++) {
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
// Find out how many vertex IDs there are and reserve memory
- currentFloor->polygon[i].numVertices = g_sludge->_resMan->getData()->readByte();
- currentFloor->polygon[i].vertexID = new int[currentFloor->polygon[i].numVertices];
- if (!checkNew(currentFloor->polygon[i].vertexID))
+ _currentFloor->polygon[i].numVertices = g_sludge->_resMan->getData()->readByte();
+ _currentFloor->polygon[i].vertexID = new int[_currentFloor->polygon[i].numVertices];
+ if (!checkNew(_currentFloor->polygon[i].vertexID))
return false;
// Read in each vertex ID
- for (j = 0; j < currentFloor->polygon[i].numVertices; j++) {
- currentFloor->polygon[i].vertexID[j] = g_sludge->_resMan->getData()->readUint16BE();
+ for (j = 0; j < _currentFloor->polygon[i].numVertices; j++) {
+ _currentFloor->polygon[i].vertexID[j] = g_sludge->_resMan->getData()->readUint16BE();
}
}
// Find out how many vertices there are and reserve memory
i = g_sludge->_resMan->getData()->readUint16BE();
- currentFloor->vertex = new Common::Point[i];
- if (!checkNew(currentFloor->vertex))
+ _currentFloor->vertex = new Common::Point[i];
+ if (!checkNew(_currentFloor->vertex))
return false;
for (j = 0; j < i; j++) {
- currentFloor->vertex[j].x = g_sludge->_resMan->getData()->readUint16BE();
- currentFloor->vertex[j].y = g_sludge->_resMan->getData()->readUint16BE();
+ _currentFloor->vertex[j].x = g_sludge->_resMan->getData()->readUint16BE();
+ _currentFloor->vertex[j].y = g_sludge->_resMan->getData()->readUint16BE();
}
g_sludge->_resMan->finishAccess();
// Now build the movement martix
- currentFloor->matrix = new int *[currentFloor->numPolygons];
- int **distanceMatrix = new int *[currentFloor->numPolygons];
+ _currentFloor->matrix = new int *[_currentFloor->numPolygons];
+ int **distanceMatrix = new int *[_currentFloor->numPolygons];
- if (!checkNew(currentFloor->matrix))
+ if (!checkNew(_currentFloor->matrix))
return false;
- for (i = 0; i < currentFloor->numPolygons; i++) {
- currentFloor->matrix[i] = new int[currentFloor->numPolygons];
- distanceMatrix[i] = new int[currentFloor->numPolygons];
- if (!checkNew(currentFloor->matrix[i]))
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
+ _currentFloor->matrix[i] = new int[_currentFloor->numPolygons];
+ distanceMatrix[i] = new int[_currentFloor->numPolygons];
+ if (!checkNew(_currentFloor->matrix[i]))
return false;
- for (j = 0; j < currentFloor->numPolygons; j++) {
- currentFloor->matrix[i][j] = -1;
+ for (j = 0; j < _currentFloor->numPolygons; j++) {
+ _currentFloor->matrix[i][j] = -1;
distanceMatrix[i][j] = 10000;
}
}
- for (i = 0; i < currentFloor->numPolygons; i++) {
- for (j = 0; j < currentFloor->numPolygons; j++) {
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
+ for (j = 0; j < _currentFloor->numPolygons; j++) {
if (i != j) {
- if (polysShareSide(currentFloor->polygon[i], currentFloor->polygon[j])) {
- currentFloor->matrix[i][j] = j;
+ if (polysShareSide(_currentFloor->polygon[i], _currentFloor->polygon[j])) {
+ _currentFloor->matrix[i][j] = j;
distanceMatrix[i][j] = 1;
}
} else {
- currentFloor->matrix[i][j] = -2;
+ _currentFloor->matrix[i][j] = -2;
distanceMatrix[i][j] = 0;
}
}
@@ -214,17 +223,16 @@ bool setFloor(int fileNum) {
do {
lookForDistance++;
-// debugMatrix ();
madeChange = false;
- for (i = 0; i < currentFloor->numPolygons; i++) {
- for (j = 0; j < currentFloor->numPolygons; j++) {
- if (currentFloor->matrix[i][j] == -1) {
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
+ for (j = 0; j < _currentFloor->numPolygons; j++) {
+ if (_currentFloor->matrix[i][j] == -1) {
// OK, so we don't know how to get from i to j...
- for (int d = 0; d < currentFloor->numPolygons; d++) {
+ for (int d = 0; d < _currentFloor->numPolygons; d++) {
if (d != i && d != j) {
- if (currentFloor->matrix[i][d] == d && currentFloor->matrix[d][j] >= 0 && distanceMatrix[d][j] <= lookForDistance) {
- currentFloor->matrix[i][j] = d;
+ if (_currentFloor->matrix[i][d] == d && _currentFloor->matrix[d][j] >= 0 && distanceMatrix[d][j] <= lookForDistance) {
+ _currentFloor->matrix[i][j] = d;
distanceMatrix[i][j] = lookForDistance + 1;
madeChange = true;
}
@@ -235,44 +243,44 @@ bool setFloor(int fileNum) {
}
} while (madeChange);
- for (i = 0; i < currentFloor->numPolygons; i++) {
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
delete[] distanceMatrix[i];
}
delete []distanceMatrix;
- distanceMatrix = NULL;
+ distanceMatrix = nullptr;
setResourceForFatal(-1);
return true;
}
-void drawFloor() {
+void FloorManager::drawFloor() {
int i, j, nV;
- for (i = 0; i < currentFloor->numPolygons; i++) {
- nV = currentFloor->polygon[i].numVertices;
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
+ nV = _currentFloor->polygon[i].numVertices;
if (nV > 1) {
for (j = 1; j < nV; j++) {
- g_sludge->_gfxMan->drawLine(currentFloor->vertex[currentFloor->polygon[i].vertexID[j - 1]].x, currentFloor->vertex[currentFloor->polygon[i].vertexID[j - 1]].y,
- currentFloor->vertex[currentFloor->polygon[i].vertexID[j]].x, currentFloor->vertex[currentFloor->polygon[i].vertexID[j]].y);
+ g_sludge->_gfxMan->drawLine(_currentFloor->vertex[_currentFloor->polygon[i].vertexID[j - 1]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j - 1]].y,
+ _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].y);
}
- g_sludge->_gfxMan->drawLine(currentFloor->vertex[currentFloor->polygon[i].vertexID[0]].x, currentFloor->vertex[currentFloor->polygon[i].vertexID[0]].y,
- currentFloor->vertex[currentFloor->polygon[i].vertexID[nV - 1]].x, currentFloor->vertex[currentFloor->polygon[i].vertexID[nV - 1]].y);
+ g_sludge->_gfxMan->drawLine(_currentFloor->vertex[_currentFloor->polygon[i].vertexID[0]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[0]].y,
+ _currentFloor->vertex[_currentFloor->polygon[i].vertexID[nV - 1]].x, _currentFloor->vertex[_currentFloor->polygon[i].vertexID[nV - 1]].y);
}
}
}
-int inFloor(int x, int y) {
+int FloorManager::inFloor(int x, int y) {
int i, r = -1;
- for (i = 0; i < currentFloor->numPolygons; i++)
- if (pointInFloorPolygon(currentFloor->polygon[i], x, y))
+ for (i = 0; i < _currentFloor->numPolygons; i++)
+ if (pointInFloorPolygon(_currentFloor->polygon[i], x, y))
r = i;
return r;
}
-bool closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, int y2, int xP, int yP) {
+bool FloorManager::closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, int y2, int xP, int yP) {
int xDiff = x2 - x1;
int yDiff = y2 - y1;
@@ -293,4 +301,126 @@ bool closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, in
return false;
}
+bool FloorManager::handleClosestPoint(int &setX, int &setY, int &setPoly) {
+ int gotX = 320, gotY = 200, gotPoly = -1, i, j, xTest1, yTest1, xTest2, yTest2, closestX, closestY, oldJ, currentDistance = 0xFFFFF, thisDistance;
+
+ for (i = 0; i < _currentFloor->numPolygons; i++) {
+ oldJ = _currentFloor->polygon[i].numVertices - 1;
+ for (j = 0; j < _currentFloor->polygon[i].numVertices; j++) {
+ xTest1 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].x;
+ yTest1 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[j]].y;
+ xTest2 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[oldJ]].x;
+ yTest2 = _currentFloor->vertex[_currentFloor->polygon[i].vertexID[oldJ]].y;
+ closestPointOnLine(closestX, closestY, xTest1, yTest1, xTest2, yTest2, setX, setY);
+ xTest1 = setX - closestX;
+ yTest1 = setY - closestY;
+ thisDistance = xTest1 * xTest1 + yTest1 * yTest1;
+
+ if (thisDistance < currentDistance) {
+ currentDistance = thisDistance;
+ gotX = closestX;
+ gotY = closestY;
+ gotPoly = i;
+ }
+ oldJ = j;
+ }
+ }
+
+ if (gotPoly == -1)
+ return false;
+ setX = gotX;
+ setY = gotY;
+ setPoly = gotPoly;
+ return true;
+}
+
+bool FloorManager::doBorderStuff(OnScreenPerson *moveMe) {
+ if (moveMe->inPoly == moveMe->walkToPoly) {
+ moveMe->inPoly = -1;
+ moveMe->thisStepX = moveMe->walkToX;
+ moveMe->thisStepY = moveMe->walkToY;
+ } else {
+ // The section in which we need to be next...
+ int newPoly = _currentFloor->matrix[moveMe->inPoly][moveMe->walkToPoly];
+ if (newPoly == -1)
+ return false;
+
+ // Grab the index of the second matching corner...
+ int ID, ID2;
+ if (!getMatchingCorners(_currentFloor->polygon[moveMe->inPoly], _currentFloor->polygon[newPoly], ID, ID2))
+ return fatal("Not a valid floor plan!");
+
+ // Remember that we're walking to the new polygon...
+ moveMe->inPoly = newPoly;
+
+ // Calculate the destination position on the coincidantal line...
+ int x1 = moveMe->x, y1 = moveMe->y;
+ int x2 = moveMe->walkToX, y2 = moveMe->walkToY;
+ int x3 = _currentFloor->vertex[ID].x, y3 = _currentFloor->vertex[ID].y;
+ int x4 = _currentFloor->vertex[ID2].x, y4 = _currentFloor->vertex[ID2].y;
+
+ int xAB = x1 - x2;
+ int yAB = y1 - y2;
+ int xCD = x4 - x3;
+ int yCD = y4 - y3;
+
+ double m = (yAB * (x3 - x1) - xAB * (y3 - y1));
+ m /= ((xAB * yCD) - (yAB * xCD));
+
+ if (m > 0 && m < 1) {
+ moveMe->thisStepX = x3 + m * xCD;
+ moveMe->thisStepY = y3 + m * yCD;
+ } else {
+ int dx13 = x1 - x3, dx14 = x1 - x4, dx23 = x2 - x3, dx24 = x2 - x4;
+ int dy13 = y1 - y3, dy14 = y1 - y4, dy23 = y2 - y3, dy24 = y2 - y4;
+
+ dx13 *= dx13;
+ dx14 *= dx14;
+ dx23 *= dx23;
+ dx24 *= dx24;
+ dy13 *= dy13;
+ dy14 *= dy14;
+ dy23 *= dy23;
+ dy24 *= dy24;
+
+ if (sqrt((double)dx13 + dy13) + sqrt((double)dx23 + dy23) < sqrt((double)dx14 + dy14) + sqrt((double)dx24 + dy24)) {
+ moveMe->thisStepX = x3;
+ moveMe->thisStepY = y3;
+ } else {
+ moveMe->thisStepX = x4;
+ moveMe->thisStepY = y4;
+ }
+ }
+ }
+
+ float yDiff = moveMe->thisStepY - moveMe->y;
+ float xDiff = moveMe->x - moveMe->thisStepX;
+ if (xDiff || yDiff) {
+ moveMe->wantAngle = 180 + ANGLEFIX * atan2(xDiff, yDiff * 2);
+ moveMe->spinning = true;
+ }
+
+ moveMe->makeTalker();
+ return true;
+}
+
+void FloorManager::save(Common::WriteStream *stream) {
+ if (_currentFloor->numPolygons) {
+ stream->writeByte(1);
+ stream->writeUint16BE(_currentFloor->originalNum);
+ } else {
+ stream->writeByte(0);
+ }
+}
+
+bool FloorManager::load(Common::SeekableReadStream *stream) {
+ if (stream->readByte()) {
+ if (!setFloor(stream->readUint16BE()))
+ return false;
+ } else {
+ setFloorNull();
+ }
+ return true;
+}
+
} // End of namespace Sludge
diff --git a/engines/sludge/floor.h b/engines/sludge/floor.h
index 4db7e22deb..22c8b12f30 100644
--- a/engines/sludge/floor.h
+++ b/engines/sludge/floor.h
@@ -26,6 +26,9 @@
namespace Sludge {
+class SludgeEngine;
+struct OnScreenPerson;
+
struct FloorPolygon {
int numVertices;
int *vertexID;
@@ -39,13 +42,37 @@ struct Floor {
int **matrix;
};
-bool initFloor();
-void setFloorNull();
-bool setFloor(int fileNum);
-void drawFloor();
-int inFloor(int x, int y);
-bool getMatchingCorners(FloorPolygon &, FloorPolygon &, int &, int &);
-bool closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, int y2, int xP, int yP);
+class FloorManager {
+public:
+ FloorManager(SludgeEngine *vm);
+ ~FloorManager();
+
+ bool init();
+ void kill();
+
+ void setFloorNull();
+ bool setFloor(int fileNum);
+ void drawFloor();
+ int inFloor(int x, int y);
+ bool isFloorNoPolygon() { return !_currentFloor || _currentFloor->numPolygons == 0; }
+
+ // For Person collision detection
+ bool handleClosestPoint(int &setX, int &setY, int &setPoly);
+ bool doBorderStuff(OnScreenPerson *moveMe);
+
+ // Save & load
+ void save(Common::WriteStream *stream);
+ bool load(Common::SeekableReadStream *stream);
+
+private:
+ Floor *_currentFloor;
+ SludgeEngine *_vm;
+
+ bool getMatchingCorners(FloorPolygon &, FloorPolygon &, int &, int &);
+ bool closestPointOnLine(int &closestX, int &closestY, int x1, int y1, int x2, int y2, int xP, int yP);
+ bool pointInFloorPolygon(FloorPolygon &floorPoly, int x, int y);
+ bool polysShareSide(FloorPolygon &a, FloorPolygon &b);
+};
} // End of namespace Sludge
diff --git a/engines/sludge/fonttext.cpp b/engines/sludge/fonttext.cpp
index 0f63c6e24f..da380f4f0b 100644
--- a/engines/sludge/fonttext.cpp
+++ b/engines/sludge/fonttext.cpp
@@ -48,11 +48,13 @@ void TextManager::init() {
_loadedFontNum = 0;
_fontSpace = -1;
+ _pastePalette.init();
_fontTable.clear();
}
void TextManager::kill() {
GraphicsManager::forgetSpriteBank(_theFont);
+ _pastePalette.kill();
}
bool TextManager::isInFont(const Common::String &theText) {
@@ -110,7 +112,7 @@ void TextManager::pasteString(const Common::String &theText, int xOff, int y, Sp
}
}
-void TextManager::pasteStringToBackdrop(const Common::String &theText, int xOff, int y, SpritePalette &thePal) {
+void TextManager::pasteStringToBackdrop(const Common::String &theText, int xOff, int y) {
if (_fontTable.empty())
return;
@@ -120,12 +122,12 @@ void TextManager::pasteStringToBackdrop(const Common::String &theText, int xOff,
for (uint32 i = 0; i < str32.size(); ++i) {
uint32 c = str32[i];
Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
- g_sludge->_gfxMan->pasteSpriteToBackDrop(xOff, y, *mySprite, thePal);
+ g_sludge->_gfxMan->pasteSpriteToBackDrop(xOff, y, *mySprite, _pastePalette);
xOff += mySprite->surface.w + _fontSpace;
}
}
-void TextManager::burnStringToBackdrop(const Common::String &theText, int xOff, int y, SpritePalette &thePal) {
+void TextManager::burnStringToBackdrop(const Common::String &theText, int xOff, int y) {
if (_fontTable.empty())
return;
@@ -135,17 +137,11 @@ void TextManager::burnStringToBackdrop(const Common::String &theText, int xOff,
for (uint i = 0; i < str32.size(); ++i) {
uint32 c = str32[i];
Sprite *mySprite = &_theFont.sprites[fontInTable(c)];
- g_sludge->_gfxMan->burnSpriteToBackDrop(xOff, y, *mySprite, thePal);
+ g_sludge->_gfxMan->burnSpriteToBackDrop(xOff, y, *mySprite, _pastePalette);
xOff += mySprite->surface.w + _fontSpace;
}
}
-void setFontColour(SpritePalette &sP, byte r, byte g, byte b) {
- sP.originalRed = r;
- sP.originalGreen = g;
- sP.originalBlue = b;
-}
-
bool TextManager::loadFont(int filenum, const Common::String &charOrder, int h) {
_fontOrder.setUTF8String(charOrder);
diff --git a/engines/sludge/fonttext.h b/engines/sludge/fonttext.h
index 26b12d9f11..7018c75213 100644
--- a/engines/sludge/fonttext.h
+++ b/engines/sludge/fonttext.h
@@ -46,12 +46,14 @@ public:
bool loadFont(int filenum, const Common::String &charOrder, int);
void pasteString(const Common::String &theText, int, int, SpritePalette &);
- void pasteStringToBackdrop(const Common::String &theText, int xOff, int y, SpritePalette &thePal);
- void burnStringToBackdrop(const Common::String &theText, int xOff, int y, SpritePalette &thePal);
+ void pasteStringToBackdrop(const Common::String &theText, int xOff, int y);
+ void burnStringToBackdrop(const Common::String &theText, int xOff, int y);
bool isInFont(const Common::String &theText);
+ // setter & getter
void setFontSpace(int fontSpace) { _fontSpace = fontSpace; }
int getFontHeight() const { return _fontHeight; }
+ void setPasterColor(byte r, byte g, byte b) { _pastePalette.setColor(r, g, b); }
// load & save
void saveFont(Common::WriteStream *stream);
@@ -62,6 +64,7 @@ private:
int _fontHeight, _numFontColours, _loadedFontNum;
UTF8Converter _fontOrder;
int16 _fontSpace;
+ SpritePalette _pastePalette;
Common::HashMap<uint32, uint32> _fontTable;
@@ -69,8 +72,6 @@ private:
};
-void setFontColour(SpritePalette &sP, byte r, byte g, byte b);
-
} // End of namespace Sludge
#endif
diff --git a/engines/sludge/freeze.cpp b/engines/sludge/freeze.cpp
index e90f2700d8..9f8c85e828 100644
--- a/engines/sludge/freeze.cpp
+++ b/engines/sludge/freeze.cpp
@@ -41,10 +41,6 @@
namespace Sludge {
-extern OnScreenPerson *allPeople;
-extern ScreenRegion *allScreenRegions;
-extern ScreenRegion *overRegion;
-
void GraphicsManager::freezeGraphics() {
int w = _winWidth;
@@ -87,18 +83,14 @@ bool GraphicsManager::freeze() {
_backdropSurface.copyFrom(_freezeSurface);
_backdropExists = true;
- newFreezer->allPeople = allPeople;
- allPeople = NULL;
+ _vm->_peopleMan->freeze(newFreezer);
- StatusStuff *newStatusStuff = new StatusStuff ;
+ StatusStuff *newStatusStuff = new StatusStuff;
if (!checkNew(newStatusStuff))
return false;
newFreezer->frozenStatus = copyStatusBarStuff(newStatusStuff);
- newFreezer->allScreenRegions = allScreenRegions;
- allScreenRegions = NULL;
- overRegion = NULL;
-
+ _vm->_regionMan->freeze(newFreezer);
_vm->_cursorMan->freeze(newFreezer);
_vm->_speechMan->freeze(newFreezer);
_vm->_evtMan->freeze(newFreezer);
@@ -136,11 +128,8 @@ void GraphicsManager::unfreeze(bool killImage) {
_vm->_evtMan->mouseX() = (int)(_vm->_evtMan->mouseX() / _cameraZoom);
_vm->_evtMan->mouseY() = (int)(_vm->_evtMan->mouseY() / _cameraZoom);
- killAllPeople();
- allPeople = _frozenStuff->allPeople;
-
- killAllRegions();
- allScreenRegions = _frozenStuff->allScreenRegions;
+ g_sludge->_peopleMan->resotre(_frozenStuff);
+ g_sludge->_regionMan->resotre(_frozenStuff);
killLightMap();
@@ -171,7 +160,6 @@ void GraphicsManager::unfreeze(bool killImage) {
_vm->_speechMan->restore(_frozenStuff);
_frozenStuff = _frozenStuff->next;
- overRegion = NULL;
// free current frozen screen struct
if (killMe->backdropSurface.getPixels())
diff --git a/engines/sludge/freeze.h b/engines/sludge/freeze.h
index 830c2d8a72..4a7740887f 100644
--- a/engines/sludge/freeze.h
+++ b/engines/sludge/freeze.h
@@ -30,14 +30,18 @@ struct OnScreenPerson;
struct PersonaAnimation;
struct ScreenRegion;
struct SpeechStruct;
-struct StatusStuff ;
+struct StatusStuff;
struct EventHandlers;
+struct ScreenRegion;
+
+typedef Common::List<ScreenRegion *> ScreenRegionList;
+typedef Common::List<OnScreenPerson *> OnScreenPersonList;
class Parallax;
struct FrozenStuffStruct {
- OnScreenPerson *allPeople;
- ScreenRegion *allScreenRegions;
+ OnScreenPersonList *allPeople;
+ ScreenRegionList *allScreenRegions;
Graphics::Surface backdropSurface;
Graphics::Surface lightMapSurface;
Graphics::Surface *zBufferSprites;
diff --git a/engines/sludge/function.cpp b/engines/sludge/function.cpp
new file mode 100644
index 0000000000..553e59d76c
--- /dev/null
+++ b/engines/sludge/function.cpp
@@ -0,0 +1,788 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "sludge/builtin.h"
+#include "sludge/function.h"
+#include "sludge/loadsave.h"
+#include "sludge/newfatal.h"
+#include "sludge/people.h"
+#include "sludge/sludge.h"
+#include "sludge/sound.h"
+#include "sludge/speech.h"
+
+namespace Sludge {
+
+int numBIFNames = 0;
+Common::String *allBIFNames = NULL;
+int numUserFunc = 0;
+Common::String *allUserFunc = NULL;
+
+LoadedFunction *saverFunc;
+LoadedFunction *allRunningFunctions = NULL;
+VariableStack *noStack = NULL;
+Variable *globalVars = NULL;
+
+const char *sludgeText[] = { "?????", "RETURN", "BRANCH", "BR_ZERO",
+ "SET_GLOBAL", "SET_LOCAL", "LOAD_GLOBAL", "LOAD_LOCAL", "PLUS", "MINUS",
+ "MULT", "DIVIDE", "AND", "OR", "EQUALS", "NOT_EQ", "MODULUS",
+ "LOAD_VALUE", "LOAD_BUILT", "LOAD_FUNC", "CALLIT", "LOAD_STRING",
+ "LOAD_FILE", "LOAD_OBJTYPE", "NOT", "LOAD_NULL", "STACK_PUSH",
+ "LESSTHAN", "MORETHAN", "NEGATIVE", "U", "LESS_EQUAL", "MORE_EQUAL",
+ "INC_LOCAL", "DEC_LOCAL", "INC_GLOBAL", "DEC_GLOBAL", "INDEXSET",
+ "INDEXGET", "INC_INDEX", "DEC_INDEX", "QUICK_PUSH" };
+
+void pauseFunction(LoadedFunction *fun) {
+ LoadedFunction **huntAndDestroy = &allRunningFunctions;
+ while (*huntAndDestroy) {
+ if (fun == *huntAndDestroy) {
+ (*huntAndDestroy) = (*huntAndDestroy)->next;
+ fun->next = NULL;
+ } else {
+ huntAndDestroy = &(*huntAndDestroy)->next;
+ }
+ }
+}
+
+void restartFunction(LoadedFunction *fun) {
+ fun->next = allRunningFunctions;
+ allRunningFunctions = fun;
+}
+
+void killSpeechTimers() {
+ LoadedFunction *thisFunction = allRunningFunctions;
+
+ while (thisFunction) {
+ if (thisFunction->freezerLevel == 0 && thisFunction->isSpeech
+ && thisFunction->timeLeft) {
+ thisFunction->timeLeft = 0;
+ thisFunction->isSpeech = false;
+ }
+ thisFunction = thisFunction->next;
+ }
+
+ g_sludge->_speechMan->kill();
+}
+
+void completeTimers() {
+ LoadedFunction *thisFunction = allRunningFunctions;
+
+ while (thisFunction) {
+ if (thisFunction->freezerLevel == 0)
+ thisFunction->timeLeft = 0;
+ thisFunction = thisFunction->next;
+ }
+}
+
+void finishFunction(LoadedFunction *fun) {
+ int a;
+
+ pauseFunction(fun);
+ if (fun->stack)
+ fatal(ERROR_NON_EMPTY_STACK);
+ delete[] fun->compiledLines;
+ for (a = 0; a < fun->numLocals; a++)
+ fun->localVars[a].unlinkVar();
+ delete[] fun->localVars;
+ fun->reg.unlinkVar();
+ delete fun;
+ fun = NULL;
+}
+
+void abortFunction(LoadedFunction *fun) {
+ int a;
+
+ pauseFunction(fun);
+ while (fun->stack)
+ trimStack(fun->stack);
+ delete []fun->compiledLines;
+ for (a = 0; a < fun->numLocals; a++)
+ fun->localVars[a].unlinkVar();
+ delete []fun->localVars;
+ fun->reg.unlinkVar();
+ if (fun->calledBy)
+ abortFunction(fun->calledBy);
+ delete fun;
+ fun = NULL;
+}
+
+int cancelAFunction(int funcNum, LoadedFunction *myself, bool &killedMyself) {
+ int n = 0;
+ killedMyself = false;
+
+ LoadedFunction *fun = allRunningFunctions;
+ while (fun) {
+ if (fun->originalNumber == funcNum) {
+ fun->cancelMe = true;
+ n++;
+ if (fun == myself)
+ killedMyself = true;
+ }
+ fun = fun->next;
+ }
+ return n;
+}
+
+void freezeSubs() {
+ LoadedFunction *thisFunction = allRunningFunctions;
+
+ while (thisFunction) {
+ if (thisFunction->unfreezable) {
+ //msgBox ("SLUDGE debugging bollocks!", "Trying to freeze an unfreezable function!");
+ } else {
+ thisFunction->freezerLevel++;
+ }
+ thisFunction = thisFunction->next;
+ }
+}
+
+void unfreezeSubs() {
+ LoadedFunction *thisFunction = allRunningFunctions;
+
+ while (thisFunction) {
+ if (thisFunction->freezerLevel)
+ thisFunction->freezerLevel--;
+ thisFunction = thisFunction->next;
+ }
+}
+
+bool continueFunction(LoadedFunction *fun) {
+ bool keepLooping = true;
+ bool advanceNow;
+ uint param;
+ SludgeCommand com;
+
+ if (fun->cancelMe) {
+ abortFunction(fun);
+ return true;
+ }
+
+ while (keepLooping) {
+ advanceNow = true;
+ debugC(1, kSludgeDebugStackMachine, "Executing command line %i : ", fun->runThisLine);
+ param = fun->compiledLines[fun->runThisLine].param;
+ com = fun->compiledLines[fun->runThisLine].theCommand;
+
+ if (numBIFNames) {
+ setFatalInfo((fun->originalNumber < numUserFunc) ? allUserFunc[fun->originalNumber] : "Unknown user function", (com < numSludgeCommands) ? sludgeText[com] : ERROR_UNKNOWN_MCODE);
+ }
+
+ switch (com) {
+ case SLU_RETURN:
+ if (fun->calledBy) {
+ LoadedFunction *returnTo = fun->calledBy;
+ if (fun->returnSomething)
+ returnTo->reg.copyFrom(fun->reg);
+ finishFunction(fun);
+ fun = returnTo;
+ restartFunction(fun);
+ } else {
+ finishFunction(fun);
+ advanceNow = false; // So we don't do anything else with "fun"
+ keepLooping = false; // So we drop out of the loop
+ }
+ break;
+
+ case SLU_CALLIT:
+ switch (fun->reg.varType) {
+ case SVT_FUNC:
+ pauseFunction(fun);
+ if (numBIFNames)
+ setFatalInfo(
+ (fun->originalNumber < numUserFunc) ?
+ allUserFunc[fun->originalNumber] :
+ "Unknown user function",
+ (fun->reg.varData.intValue < numUserFunc) ?
+ allUserFunc[fun->reg.varData.intValue] :
+ "Unknown user function");
+
+ if (!startNewFunctionNum(fun->reg.varData.intValue, param, fun,
+ fun->stack))
+ return false;
+ fun = allRunningFunctions;
+ advanceNow = false; // So we don't do anything else with "fun"
+ break;
+
+ case SVT_BUILT: {
+ debugC(1, kSludgeDebugStackMachine, "Built-in init value: %i",
+ fun->reg.varData.intValue);
+ BuiltReturn br = callBuiltIn(fun->reg.varData.intValue, param,
+ fun);
+
+ switch (br) {
+ case BR_ERROR:
+ return fatal(
+ "Unknown error. This shouldn't happen. Please notify the SLUDGE developers.");
+
+ case BR_PAUSE:
+ pauseFunction(fun);
+ // fall through
+
+ case BR_KEEP_AND_PAUSE:
+ keepLooping = false;
+ break;
+
+ case BR_ALREADY_GONE:
+ keepLooping = false;
+ advanceNow = false;
+ break;
+
+ case BR_CALLAFUNC: {
+ int i = fun->reg.varData.intValue;
+ fun->reg.setVariable(SVT_INT, 1);
+ pauseFunction(fun);
+ if (numBIFNames)
+ setFatalInfo(
+ (fun->originalNumber < numUserFunc) ?
+ allUserFunc[fun->originalNumber] :
+ "Unknown user function",
+ (i < numUserFunc) ?
+ allUserFunc[i] :
+ "Unknown user function");
+ if (!startNewFunctionNum(i, 0, fun, noStack, false))
+ return false;
+ fun = allRunningFunctions;
+ advanceNow = false; // So we don't do anything else with "fun"
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ return fatal(ERROR_CALL_NONFUNCTION);
+ }
+ break;
+
+ // These all grab things and shove 'em into the register
+
+ case SLU_LOAD_NULL:
+ fun->reg.setVariable(SVT_NULL, 0);
+ break;
+
+ case SLU_LOAD_FILE:
+ fun->reg.setVariable(SVT_FILE, param);
+ break;
+
+ case SLU_LOAD_VALUE:
+ fun->reg.setVariable(SVT_INT, param);
+ break;
+
+ case SLU_LOAD_LOCAL:
+ if (!fun->reg.copyFrom(fun->localVars[param]))
+ return false;
+ break;
+
+ case SLU_AND:
+ fun->reg.setVariable(SVT_INT,
+ fun->reg.getBoolean() && fun->stack->thisVar.getBoolean());
+ trimStack(fun->stack);
+ break;
+
+ case SLU_OR:
+ fun->reg.setVariable(SVT_INT,
+ fun->reg.getBoolean() || fun->stack->thisVar.getBoolean());
+ trimStack(fun->stack);
+ break;
+
+ case SLU_LOAD_FUNC:
+ fun->reg.setVariable(SVT_FUNC, param);
+ break;
+
+ case SLU_LOAD_BUILT:
+ fun->reg.setVariable(SVT_BUILT, param);
+ break;
+
+ case SLU_LOAD_OBJTYPE:
+ fun->reg.setVariable(SVT_OBJTYPE, param);
+ break;
+
+ case SLU_UNREG:
+ break;
+
+ case SLU_LOAD_STRING:
+ if (!fun->reg.loadStringToVar(param)) {
+ return false;
+ }
+ break;
+
+ case SLU_INDEXGET:
+ case SLU_INCREMENT_INDEX:
+ case SLU_DECREMENT_INDEX:
+ switch (fun->stack->thisVar.varType) {
+ case SVT_NULL:
+ if (com == SLU_INDEXGET) {
+ fun->reg.setVariable(SVT_NULL, 0);
+ trimStack(fun->stack);
+ } else {
+ return fatal(ERROR_INCDEC_UNKNOWN);
+ }
+ break;
+
+ case SVT_FASTARRAY:
+ case SVT_STACK:
+ if (fun->stack->thisVar.varData.theStack->first == NULL) {
+ return fatal(ERROR_INDEX_EMPTY);
+ } else {
+ int ii;
+ if (!fun->reg.getValueType(ii, SVT_INT))
+ return false;
+ Variable *grab =
+ (fun->stack->thisVar.varType == SVT_FASTARRAY) ?
+ fun->stack->thisVar.varData.fastArray->fastArrayGetByIndex(ii) :
+ fun->stack->thisVar.varData.theStack->first->stackGetByIndex(ii);
+
+ trimStack(fun->stack);
+
+ if (!grab) {
+ fun->reg.setVariable(SVT_NULL, 0);
+ } else {
+ int kk;
+ switch (com) {
+ case SLU_INCREMENT_INDEX:
+ if (!grab->getValueType(kk, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, kk);
+ grab->varData.intValue = kk + 1;
+ break;
+
+ case SLU_DECREMENT_INDEX:
+ if (!grab->getValueType(kk, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, kk);
+ grab->varData.intValue = kk - 1;
+ break;
+
+ default:
+ if (!fun->reg.copyFrom(*grab))
+ return false;
+ }
+ }
+ }
+ break;
+
+ default:
+ return fatal(ERROR_INDEX_NONSTACK);
+ }
+ break;
+
+ case SLU_INDEXSET:
+ switch (fun->stack->thisVar.varType) {
+ case SVT_STACK:
+ if (fun->stack->thisVar.varData.theStack->first == NULL) {
+ return fatal(ERROR_INDEX_EMPTY);
+ } else {
+ int ii;
+ if (!fun->reg.getValueType(ii, SVT_INT))
+ return false;
+ if (!fun->stack->thisVar.varData.theStack->first->stackSetByIndex(ii, fun->stack->next->thisVar)) {
+ return false;
+ }
+ trimStack(fun->stack);
+ trimStack(fun->stack);
+ }
+ break;
+
+ case SVT_FASTARRAY: {
+ int ii;
+ if (!fun->reg.getValueType(ii, SVT_INT))
+ return false;
+ Variable *v = fun->stack->thisVar.varData.fastArray->fastArrayGetByIndex(ii);
+ if (v == NULL)
+ return fatal("Not within bounds of fast array.");
+ if (!v->copyFrom(fun->stack->next->thisVar))
+ return false;
+ trimStack(fun->stack);
+ trimStack(fun->stack);
+ }
+ break;
+
+ default:
+ return fatal(ERROR_INDEX_NONSTACK);
+ }
+ break;
+
+ // What can we do with the register? Well, we can copy it into a local
+ // variable, a global or onto the stack...
+
+ case SLU_INCREMENT_LOCAL: {
+ int ii;
+ if (!fun->localVars[param].getValueType(ii, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, ii);
+ fun->localVars[param].setVariable(SVT_INT, ii + 1);
+ }
+ break;
+
+ case SLU_INCREMENT_GLOBAL: {
+ int ii;
+ if (!globalVars[param].getValueType(ii, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, ii);
+ globalVars[param].setVariable(SVT_INT, ii + 1);
+ }
+ break;
+
+ case SLU_DECREMENT_LOCAL: {
+ int ii;
+ if (!fun->localVars[param].getValueType(ii, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, ii);
+ fun->localVars[param].setVariable(SVT_INT, ii - 1);
+ }
+ break;
+
+ case SLU_DECREMENT_GLOBAL: {
+ int ii;
+ if (!globalVars[param].getValueType(ii, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, ii);
+ globalVars[param].setVariable(SVT_INT, ii - 1);
+ }
+ break;
+
+ case SLU_SET_LOCAL:
+ if (!fun->localVars[param].copyFrom(fun->reg))
+ return false;
+ break;
+
+ case SLU_SET_GLOBAL:
+ if (!globalVars[param].copyFrom(fun->reg))
+ return false;
+ break;
+
+ case SLU_LOAD_GLOBAL:
+ if (!fun->reg.copyFrom(globalVars[param]))
+ return false;
+ break;
+
+ case SLU_STACK_PUSH:
+ if (!addVarToStack(fun->reg, fun->stack))
+ return false;
+ break;
+
+ case SLU_QUICK_PUSH:
+ if (!addVarToStackQuick(fun->reg, fun->stack))
+ return false;
+ break;
+
+ case SLU_NOT:
+ fun->reg.setVariable(SVT_INT, !fun->reg.getBoolean());
+ break;
+
+ case SLU_BR_ZERO:
+ if (!fun->reg.getBoolean()) {
+ advanceNow = false;
+ fun->runThisLine = param;
+ }
+ break;
+
+ case SLU_BRANCH:
+ advanceNow = false;
+ fun->runThisLine = param;
+ break;
+
+ case SLU_NEGATIVE: {
+ int i;
+ if (!fun->reg.getValueType(i, SVT_INT))
+ return false;
+ fun->reg.setVariable(SVT_INT, -i);
+ }
+ break;
+
+ // All these things rely on there being somet' on the stack
+
+ case SLU_MULT:
+ case SLU_PLUS:
+ case SLU_MINUS:
+ case SLU_MODULUS:
+ case SLU_DIVIDE:
+ case SLU_EQUALS:
+ case SLU_NOT_EQ:
+ case SLU_LESSTHAN:
+ case SLU_MORETHAN:
+ case SLU_LESS_EQUAL:
+ case SLU_MORE_EQUAL:
+ if (fun->stack) {
+ int firstValue, secondValue;
+
+ switch (com) {
+ case SLU_PLUS:
+ fun->reg.addVariablesInSecond(fun->stack->thisVar);
+ trimStack(fun->stack);
+ break;
+
+ case SLU_EQUALS:
+ fun->reg.compareVariablesInSecond(fun->stack->thisVar);
+ trimStack(fun->stack);
+ break;
+
+ case SLU_NOT_EQ:
+ fun->reg.compareVariablesInSecond(fun->stack->thisVar);
+ trimStack(fun->stack);
+ fun->reg.varData.intValue = !fun->reg.varData.intValue;
+ break;
+
+ default:
+ if (!fun->stack->thisVar.getValueType(firstValue, SVT_INT))
+ return false;
+ if (!fun->reg.getValueType(secondValue, SVT_INT))
+ return false;
+ trimStack(fun->stack);
+
+ switch (com) {
+ case SLU_MULT:
+ fun->reg.setVariable(SVT_INT,
+ firstValue * secondValue);
+ break;
+
+ case SLU_MINUS:
+ fun->reg.setVariable(SVT_INT,
+ firstValue - secondValue);
+ break;
+
+ case SLU_MODULUS:
+ fun->reg.setVariable(SVT_INT,
+ firstValue % secondValue);
+ break;
+
+ case SLU_DIVIDE:
+ fun->reg.setVariable(SVT_INT,
+ firstValue / secondValue);
+ break;
+
+ case SLU_LESSTHAN:
+ fun->reg.setVariable(SVT_INT,
+ firstValue < secondValue);
+ break;
+
+ case SLU_MORETHAN:
+ fun->reg.setVariable(SVT_INT,
+ firstValue > secondValue);
+ break;
+
+ case SLU_LESS_EQUAL:
+ fun->reg.setVariable(SVT_INT,
+ firstValue <= secondValue);
+ break;
+
+ case SLU_MORE_EQUAL:
+ fun->reg.setVariable(SVT_INT,
+ firstValue >= secondValue);
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else {
+ return fatal(ERROR_NOSTACK);
+ }
+ break;
+
+ default:
+ return fatal(ERROR_UNKNOWN_CODE);
+ }
+
+ if (advanceNow)
+ fun->runThisLine++;
+
+ }
+ return true;
+}
+
+void killAllFunctions() {
+ while (allRunningFunctions)
+ finishFunction(allRunningFunctions);
+}
+
+bool loadFunctionCode(LoadedFunction *newFunc) {
+ uint numLines, numLinesRead;
+
+ if (!g_sludge->_resMan->openSubSlice(newFunc->originalNumber))
+ return false;
+
+ debugC(3, kSludgeDebugDataLoad, "Load function code");
+
+ Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
+ newFunc->unfreezable = readStream->readByte();
+ numLines = readStream->readUint16BE();
+ debugC(3, kSludgeDebugDataLoad, "numLines: %i", numLines);
+ newFunc->numArgs = readStream->readUint16BE();
+ debugC(3, kSludgeDebugDataLoad, "numArgs: %i", newFunc->numArgs);
+ newFunc->numLocals = readStream->readUint16BE();
+ debugC(3, kSludgeDebugDataLoad, "numLocals: %i", newFunc->numLocals);
+ newFunc->compiledLines = new LineOfCode[numLines];
+ if (!checkNew(newFunc->compiledLines))
+ return false;
+
+ for (numLinesRead = 0; numLinesRead < numLines; numLinesRead++) {
+ newFunc->compiledLines[numLinesRead].theCommand = (SludgeCommand)readStream->readByte();
+ newFunc->compiledLines[numLinesRead].param = readStream->readUint16BE();
+ debugC(3, kSludgeDebugDataLoad, "command line %i: %i", numLinesRead,
+ newFunc->compiledLines[numLinesRead].theCommand);
+ }
+ g_sludge->_resMan->finishAccess();
+
+ // Now we need to reserve memory for the local variables
+ newFunc->localVars = new Variable[newFunc->numLocals];
+ if (!checkNew(newFunc->localVars))
+ return false;
+
+ return true;
+}
+
+int startNewFunctionNum(uint funcNum, uint numParamsExpected,
+ LoadedFunction *calledBy, VariableStack *&vStack, bool returnSommet) {
+ LoadedFunction *newFunc = new LoadedFunction;
+ checkNew(newFunc);
+ newFunc->originalNumber = funcNum;
+
+ loadFunctionCode(newFunc);
+
+ if (newFunc->numArgs != (int) numParamsExpected)
+ return fatal("Wrong number of parameters!");
+ if (newFunc->numArgs > newFunc->numLocals)
+ return fatal("More arguments than local Variable space!");
+
+ // Now, lets copy the parameters from the calling function's stack...
+
+ while (numParamsExpected) {
+ numParamsExpected--;
+ if (vStack == NULL)
+ return fatal(
+ "Corrupted file!The stack's empty and there were still parameters expected");
+ newFunc->localVars[numParamsExpected].copyFrom(vStack->thisVar);
+ trimStack(vStack);
+ }
+
+ newFunc->cancelMe = false;
+ newFunc->timeLeft = 0;
+ newFunc->returnSomething = returnSommet;
+ newFunc->calledBy = calledBy;
+ newFunc->stack = NULL;
+ newFunc->freezerLevel = 0;
+ newFunc->runThisLine = 0;
+ newFunc->isSpeech = 0;
+
+ restartFunction(newFunc);
+ return 1;
+}
+
+bool runAllFunctions() {
+
+ LoadedFunction *thisFunction = allRunningFunctions;
+ LoadedFunction *nextFunction;
+
+ while (thisFunction) {
+ nextFunction = thisFunction->next;
+
+ if (!thisFunction->freezerLevel) {
+ if (thisFunction->timeLeft) {
+ if (thisFunction->timeLeft < 0) {
+ if (!g_sludge->_soundMan->stillPlayingSound(
+ g_sludge->_speechMan->getLastSpeechSound())) {
+ thisFunction->timeLeft = 0;
+ }
+ } else if (!--(thisFunction->timeLeft)) {
+ }
+ } else {
+ if (thisFunction->isSpeech) {
+ thisFunction->isSpeech = false;
+ g_sludge->_speechMan->kill();
+ }
+ if (!continueFunction(thisFunction))
+ return false;
+ }
+ }
+
+ thisFunction = nextFunction;
+ }
+
+ return true;
+}
+
+void saveFunction(LoadedFunction *fun, Common::WriteStream *stream) {
+ int a;
+ stream->writeUint16BE(fun->originalNumber);
+ if (fun->calledBy) {
+ stream->writeByte(1);
+ saveFunction(fun->calledBy, stream);
+ } else {
+ stream->writeByte(0);
+ }
+ stream->writeUint32LE(fun->timeLeft);
+ stream->writeUint16BE(fun->runThisLine);
+ stream->writeByte(fun->cancelMe);
+ stream->writeByte(fun->returnSomething);
+ stream->writeByte(fun->isSpeech);
+ fun->reg.save(stream);
+
+ if (fun->freezerLevel) {
+ fatal(ERROR_GAME_SAVE_FROZEN);
+ }
+ saveStack(fun->stack, stream);
+ for (a = 0; a < fun->numLocals; a++) {
+ fun->localVars[a].save(stream);
+ }
+}
+
+LoadedFunction *loadFunction(Common::SeekableReadStream *stream) {
+ int a;
+
+ // Reserve memory...
+
+ LoadedFunction *buildFunc = new LoadedFunction;
+ if (!checkNew(buildFunc))
+ return NULL;
+
+ // See what it was called by and load if we need to...
+
+ buildFunc->originalNumber = stream->readUint16BE();
+ buildFunc->calledBy = NULL;
+ if (stream->readByte()) {
+ buildFunc->calledBy = loadFunction(stream);
+ if (!buildFunc->calledBy)
+ return NULL;
+ }
+
+ buildFunc->timeLeft = stream->readUint32LE();
+ buildFunc->runThisLine = stream->readUint16BE();
+ buildFunc->freezerLevel = 0;
+ buildFunc->cancelMe = stream->readByte();
+ buildFunc->returnSomething = stream->readByte();
+ buildFunc->isSpeech = stream->readByte();
+ buildFunc->reg.load(stream);
+ loadFunctionCode(buildFunc);
+
+ buildFunc->stack = loadStack(stream, NULL);
+
+ for (a = 0; a < buildFunc->numLocals; a++) {
+ buildFunc->localVars[a].load(stream);
+ }
+
+ return buildFunc;
+}
+
+} // End of namespace Sludge
diff --git a/engines/sludge/function.h b/engines/sludge/function.h
new file mode 100644
index 0000000000..005760a960
--- /dev/null
+++ b/engines/sludge/function.h
@@ -0,0 +1,73 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef SLUDGE_FUNCTION_H
+#define SLUDGE_FUNCTION_H
+
+#include "sludge/allfiles.h"
+#include "sludge/csludge.h"
+#include "sludge/variable.h"
+
+namespace Sludge {
+
+struct Variable;
+struct VariableStack;
+
+struct LineOfCode {
+ SludgeCommand theCommand;
+ int32 param;
+};
+
+struct LoadedFunction {
+ int originalNumber;
+ LineOfCode *compiledLines;
+ int numLocals, timeLeft, numArgs;
+ Variable *localVars;
+ VariableStack *stack;
+ Variable reg;
+ uint runThisLine;
+ LoadedFunction *calledBy;
+ LoadedFunction *next;
+ bool returnSomething, isSpeech, unfreezable, cancelMe;
+ byte freezerLevel;
+};
+
+bool runAllFunctions();
+int startNewFunctionNum(uint, uint, LoadedFunction *, VariableStack*&, bool = true);
+void restartFunction(LoadedFunction *fun);
+bool loadFunctionCode(LoadedFunction *newFunc);
+void killAllFunctions();
+
+void finishFunction(LoadedFunction *fun);
+void abortFunction(LoadedFunction *fun);
+
+void freezeSubs();
+void unfreezeSubs();
+void completeTimers();
+void killSpeechTimers();
+int cancelAFunction(int funcNum, LoadedFunction *myself, bool &killedMyself);
+
+LoadedFunction *loadFunction(Common::SeekableReadStream *stream);
+void saveFunction(LoadedFunction *fun, Common::WriteStream *stream);
+
+} // End of namespace Sludge
+
+#endif
diff --git a/engines/sludge/functionlist.h b/engines/sludge/functionlist.h
index 025f80a844..c7858a2d03 100644
--- a/engines/sludge/functionlist.h
+++ b/engines/sludge/functionlist.h
@@ -29,178 +29,178 @@
namespace Sludge {
-#define FUNC(special,name) {builtIn_ ## name},
+#define FUNC(special,name,paramNum) {builtIn_ ## name, paramNum},
static builtInFunctionData builtInFunctionArray[] = {
- FUNC(true, say)
- FUNC(true, skipSpeech)
- FUNC(true, statusText)
- FUNC(true, pause)
- FUNC(true, onLeftMouse)
- FUNC(true, onRightMouse)
- FUNC(true, setCursor)
- FUNC(true, addOverlay)
- FUNC(true, addCharacter)
- FUNC(true, playSound)
- FUNC(true, getMouseX)
- FUNC(true, getMouseY)
- FUNC(true, addScreenRegion)
- FUNC(true, onMoveMouse)
- FUNC(true, onFocusChange)
- FUNC(true, getOverObject)
- FUNC(true, blankScreen)
- FUNC(true, moveCharacter)
- FUNC(true, onKeyboard)
- FUNC(true, getObjectX)
- FUNC(true, getObjectY)
- FUNC(true, random)
- FUNC(true, spawnSub)
- FUNC(true, blankArea)
- FUNC(true, hideCharacter)
- FUNC(true, showCharacter)
- FUNC(true, callEvent)
- FUNC(true, removeScreenRegion)
- FUNC(true, animate)
- FUNC(true, turnCharacter)
- FUNC(true, removeAllCharacters)
- FUNC(true, removeAllScreenRegions)
- FUNC(true, setScale)
- FUNC(true, newStack)
- FUNC(true, pushToStack)
- FUNC(true, popFromStack)
- FUNC(true, clearStatus)
- FUNC(true, addStatus)
- FUNC(true, removeLastStatus)
- FUNC(true, lightStatus)
- FUNC(true, getStatusText)
- FUNC(true, setStatusColour)
- FUNC(true, deleteFromStack)
- FUNC(true, freeze)
- FUNC(true, unfreeze)
- FUNC(true, pasteImage)
- FUNC(true, copyStack)
- FUNC(true, completeTimers)
- FUNC(true, setCharacterDrawMode)
- FUNC(true, anim)
- FUNC(true, costume)
- FUNC(true, pickOne)
- FUNC(true, setCostume)
- FUNC(true, wait)
- FUNC(true, somethingSpeaking)
- FUNC(true, substring)
- FUNC(true, stringLength)
- FUNC(true, darkBackground)
- FUNC(true, saveGame)
- FUNC(true, loadGame)
- FUNC(true, quitGame)
- FUNC(true, rename)
- FUNC(true, stackSize)
- FUNC(true, pasteString)
- FUNC(true, startMusic)
- FUNC(true, setDefaultMusicVolume)
- FUNC(true, setMusicVolume)
- FUNC(true, stopMusic)
- FUNC(true, stopSound)
- FUNC(true, setFont)
- FUNC(true, alignStatus)
- FUNC(true, showFloor)
- FUNC(true, showBoxes)
- FUNC(true, positionStatus)
- FUNC(true, setFloor)
- FUNC(true, forceCharacter)
- FUNC(true, jumpCharacter)
- FUNC(true, peekStart)
- FUNC(true, peekEnd)
- FUNC(true, enqueue)
- FUNC(true, setZBuffer)
- FUNC(true, getMatchingFiles)
- FUNC(true, inFont)
- FUNC(true, onLeftMouseUp)
- FUNC(true, onRightMouseUp)
- FUNC(true, loopSound)
- FUNC(true, removeCharacter)
- FUNC(true, stopCharacter)
- FUNC(true, launch)
- FUNC(true, howFrozen)
- FUNC(true, setPasteColour)
- FUNC(true, setLitStatusColour)
- FUNC(true, fileExists)
- FUNC(true, floatCharacter)
- FUNC(true, cancelSub)
- FUNC(true, setCharacterWalkSpeed)
- FUNC(true, deleteAllFromStack)
- FUNC(true, setCharacterExtra)
- FUNC(true, mixOverlay)
- FUNC(true, pasteCharacter)
- FUNC(true, setSceneDimensions)
- FUNC(true, aimCamera)
- FUNC(true, getMouseScreenX)
- FUNC(true, getMouseScreenY)
- FUNC(true, setDefaultSoundVolume)
- FUNC(true, setSoundVolume)
- FUNC(true, setSoundLoopPoints)
- FUNC(true, setSpeechMode)
- FUNC(true, setLightMap)
- FUNC(true, think)
- FUNC(true, getCharacterDirection)
- FUNC(true, isCharacter)
- FUNC(true, isScreenRegion)
- FUNC(true, isMoving)
- FUNC(true, deleteFile)
- FUNC(true, renameFile)
- FUNC(true, hardScroll)
- FUNC(true, stringWidth)
- FUNC(true, setSpeechSpeed)
- FUNC(true, normalCharacter)
- FUNC(true, fetchEvent)
- FUNC(true, transitionLevel)
- FUNC(true, spinCharacter)
- FUNC(true, setFontSpacing)
- FUNC(true, burnString)
- FUNC(true, captureAllKeys)
- FUNC(true, cacheSound)
- FUNC(true, setCharacterSpinSpeed)
- FUNC(true, transitionMode)
- FUNC(false, _rem_movieStart)
- FUNC(false, _rem_movieAbort)
- FUNC(false, _rem_moviePlaying)
- FUNC(false, _rem_updateDisplay)
- FUNC(true, getSoundCache)
- FUNC(true, saveCustomData)
- FUNC(true, loadCustomData)
- FUNC(true, setCustomEncoding)
- FUNC(true, freeSound)
- FUNC(true, parallaxAdd)
- FUNC(true, parallaxClear)
- FUNC(true, setBlankColour)
- FUNC(true, setBurnColour)
- FUNC(true, getPixelColour)
- FUNC(true, makeFastArray)
- FUNC(true, getCharacterScale)
- FUNC(true, getLanguageID)
- FUNC(false, _rem_launchWith)
- FUNC(true, getFramesPerSecond)
- FUNC(true, showThumbnail)
- FUNC(true, setThumbnailSize)
- FUNC(true, hasFlag)
- FUNC(true, snapshotGrab)
- FUNC(true, snapshotClear)
- FUNC(true, bodgeFilenames)
- FUNC(false, _rem_registryGetString)
- FUNC(true, quitWithFatalError)
- FUNC(true, _rem_setCharacterAA)
- FUNC(true, _rem_setMaximumAA)
- FUNC(true, setBackgroundEffect)
- FUNC(true, doBackgroundEffect)
- FUNC(true, setCharacterAngleOffset)
- FUNC(true, setCharacterTransparency)
- FUNC(true, setCharacterColourise)
- FUNC(true, zoomCamera)
- FUNC(true, playMovie)
- FUNC(true, stopMovie)
- FUNC(true, pauseMovie)
+ FUNC(true, say, -1)
+ FUNC(true, skipSpeech, 0)
+ FUNC(true, statusText, 1)
+ FUNC(true, pause, 1)
+ FUNC(true, onLeftMouse, -1)
+ FUNC(true, onRightMouse, -1)
+ FUNC(true, setCursor, 1)
+ FUNC(true, addOverlay, 3)
+ FUNC(true, addCharacter, 4)
+ FUNC(true, playSound, 1)
+ FUNC(true, getMouseX, 0)
+ FUNC(true, getMouseY, 0)
+ FUNC(true, addScreenRegion, 8)
+ FUNC(true, onMoveMouse, -1)
+ FUNC(true, onFocusChange, -1)
+ FUNC(true, getOverObject, 0)
+ FUNC(true, blankScreen, 0)
+ FUNC(true, moveCharacter, -1)
+ FUNC(true, onKeyboard, -1)
+ FUNC(true, getObjectX, 1)
+ FUNC(true, getObjectY, 1)
+ FUNC(true, random, 1)
+ FUNC(true, spawnSub, 1)
+ FUNC(true, blankArea, 4)
+ FUNC(true, hideCharacter, 1)
+ FUNC(true, showCharacter, 1)
+ FUNC(true, callEvent, 2)
+ FUNC(true, removeScreenRegion, 1)
+ FUNC(true, animate, 2)
+ FUNC(true, turnCharacter, 2)
+ FUNC(true, removeAllCharacters, 0)
+ FUNC(true, removeAllScreenRegions, 0)
+ FUNC(true, setScale, 2)
+ FUNC(true, newStack, -1)
+ FUNC(true, pushToStack, 2)
+ FUNC(true, popFromStack, 1)
+ FUNC(true, clearStatus, 0)
+ FUNC(true, addStatus, 0)
+ FUNC(true, removeLastStatus, 0)
+ FUNC(true, lightStatus, 1)
+ FUNC(true, getStatusText, 0)
+ FUNC(true, setStatusColour, 3)
+ FUNC(true, deleteFromStack, 2)
+ FUNC(true, freeze, 0)
+ FUNC(true, unfreeze, 0)
+ FUNC(true, pasteImage, 3)
+ FUNC(true, copyStack, 1)
+ FUNC(true, completeTimers, 0)
+ FUNC(true, setCharacterDrawMode, 2)
+ FUNC(true, anim, -1)
+ FUNC(true, costume, -1)
+ FUNC(true, pickOne, -1)
+ FUNC(true, setCostume, 2)
+ FUNC(true, wait, 2)
+ FUNC(true, somethingSpeaking, 0)
+ FUNC(true, substring, 3)
+ FUNC(true, stringLength, 1)
+ FUNC(true, darkBackground, 0)
+ FUNC(true, saveGame, 1)
+ FUNC(true, loadGame, 1)
+ FUNC(true, quitGame, 0)
+ FUNC(true, rename, 2)
+ FUNC(true, stackSize, 1)
+ FUNC(true, pasteString, 3)
+ FUNC(true, startMusic, 3)
+ FUNC(true, setDefaultMusicVolume, 1)
+ FUNC(true, setMusicVolume, 2)
+ FUNC(true, stopMusic, 1)
+ FUNC(true, stopSound, 1)
+ FUNC(true, setFont, 3)
+ FUNC(true, alignStatus, 1)
+ FUNC(true, showFloor, 0)
+ FUNC(true, showBoxes, 0)
+ FUNC(true, positionStatus, 2)
+ FUNC(true, setFloor, 1)
+ FUNC(true, forceCharacter, -1)
+ FUNC(true, jumpCharacter, -1)
+ FUNC(true, peekStart, 1)
+ FUNC(true, peekEnd, 1)
+ FUNC(true, enqueue, 2)
+ FUNC(true, setZBuffer, 1)
+ FUNC(true, getMatchingFiles, 1)
+ FUNC(true, inFont, 1)
+ FUNC(true, onLeftMouseUp, -1)
+ FUNC(true, onRightMouseUp, -1)
+ FUNC(true, loopSound, -1)
+ FUNC(true, removeCharacter, 1)
+ FUNC(true, stopCharacter, 1)
+ FUNC(true, launch, 1)
+ FUNC(true, howFrozen, 0)
+ FUNC(true, setPasteColour, 3)
+ FUNC(true, setLitStatusColour, 3)
+ FUNC(true, fileExists, 1)
+ FUNC(true, floatCharacter, 2)
+ FUNC(true, cancelSub, 1)
+ FUNC(true, setCharacterWalkSpeed, 2)
+ FUNC(true, deleteAllFromStack, 2)
+ FUNC(true, setCharacterExtra, 2)
+ FUNC(true, mixOverlay, 3)
+ FUNC(true, pasteCharacter, 1)
+ FUNC(true, setSceneDimensions, 2)
+ FUNC(true, aimCamera, 2)
+ FUNC(true, getMouseScreenX, 0)
+ FUNC(true, getMouseScreenY, 0)
+ FUNC(true, setDefaultSoundVolume, 1)
+ FUNC(true, setSoundVolume, 2)
+ FUNC(true, setSoundLoopPoints, 3)
+ FUNC(true, setSpeechMode, 1)
+ FUNC(true, setLightMap, -1)
+ FUNC(true, think, -1)
+ FUNC(true, getCharacterDirection, 1)
+ FUNC(true, isCharacter, 1)
+ FUNC(true, isScreenRegion, 1)
+ FUNC(true, isMoving, 1)
+ FUNC(true, deleteFile, 1)
+ FUNC(true, renameFile, 2)
+ FUNC(true, hardScroll, 1)
+ FUNC(true, stringWidth, 1)
+ FUNC(true, setSpeechSpeed, 1)
+ FUNC(true, normalCharacter, 1)
+ FUNC(true, fetchEvent, 2)
+ FUNC(true, transitionLevel, 1)
+ FUNC(true, spinCharacter, 2)
+ FUNC(true, setFontSpacing, 1)
+ FUNC(true, burnString, 3)
+ FUNC(true, captureAllKeys, 1)
+ FUNC(true, cacheSound, 1)
+ FUNC(true, setCharacterSpinSpeed, 2)
+ FUNC(true, transitionMode, 1)
+ FUNC(false, _rem_movieStart, 1)
+ FUNC(false, _rem_movieAbort, 0)
+ FUNC(false, _rem_moviePlaying, 0)
+ FUNC(false, _rem_updateDisplay, 1)
+ FUNC(true, getSoundCache, 0)
+ FUNC(true, saveCustomData, 2)
+ FUNC(true, loadCustomData, 1)
+ FUNC(true, setCustomEncoding, 1)
+ FUNC(true, freeSound, 1)
+ FUNC(true, parallaxAdd, 3)
+ FUNC(true, parallaxClear, 0)
+ FUNC(true, setBlankColour, 3)
+ FUNC(true, setBurnColour, 3)
+ FUNC(true, getPixelColour, 2)
+ FUNC(true, makeFastArray, 1)
+ FUNC(true, getCharacterScale, 1)
+ FUNC(true, getLanguageID, 0)
+ FUNC(false, _rem_launchWith, 2)
+ FUNC(true, getFramesPerSecond, 0)
+ FUNC(true, showThumbnail, 3)
+ FUNC(true, setThumbnailSize, 2)
+ FUNC(true, hasFlag, 2)
+ FUNC(true, snapshotGrab, 0)
+ FUNC(true, snapshotClear, 0)
+ FUNC(true, bodgeFilenames, 1)
+ FUNC(false, _rem_registryGetString, 2)
+ FUNC(true, quitWithFatalError, 1)
+ FUNC(true, _rem_setCharacterAA, 4)
+ FUNC(true, _rem_setMaximumAA, 3)
+ FUNC(true, setBackgroundEffect, -1)
+ FUNC(true, doBackgroundEffect, 0)
+ FUNC(true, setCharacterAngleOffset, 2)
+ FUNC(true, setCharacterTransparency, 2)
+ FUNC(true, setCharacterColourise, 5)
+ FUNC(true, zoomCamera, 1)
+ FUNC(true, playMovie, 1)
+ FUNC(true, stopMovie, 0)
+ FUNC(true, pauseMovie, 0)
};
#undef FUNC
-int NUM_FUNCS = (sizeof (builtInFunctionArray) / sizeof (builtInFunctionArray[0]));
+const static int NUM_FUNCS = (sizeof (builtInFunctionArray) / sizeof (builtInFunctionArray[0]));
} // End of namespace Sludge
diff --git a/engines/sludge/graphics.cpp b/engines/sludge/graphics.cpp
index 578e6f65fe..72301b3475 100644
--- a/engines/sludge/graphics.cpp
+++ b/engines/sludge/graphics.cpp
@@ -83,6 +83,15 @@ void GraphicsManager::init() {
_currentBurnR = 0;
_currentBurnG = 0;
_currentBurnB = 0;
+
+ // Thumbnail
+ _thumbWidth = 0;
+ _thumbHeight = 0;
+
+ // Transition
+ resetRandW();
+ _brightnessLevel = 255;
+ _fadeMode = 2;
}
void GraphicsManager::kill() {
@@ -157,6 +166,8 @@ bool GraphicsManager::initGfx() {
void GraphicsManager::display() {
g_system->copyRectToScreen((byte *)_renderSurface.getPixels(), _renderSurface.pitch, 0, 0, _renderSurface.w, _renderSurface.h);
g_system->updateScreen();
+ if (_brightnessLevel < 255)
+ fixBrightness();
}
void GraphicsManager::clear() {
diff --git a/engines/sludge/graphics.h b/engines/sludge/graphics.h
index 16973a1658..8bc47cdab4 100644
--- a/engines/sludge/graphics.h
+++ b/engines/sludge/graphics.h
@@ -91,6 +91,8 @@ public:
void drawVerticalLine(uint, uint, uint);
void hardScroll(int distance);
bool getRGBIntoStack(uint x, uint y, StackHandler *sH);
+ void saveBackdrop(Common::WriteStream *stream); // To game save
+ void loadBackdrop(int ssgVersion, Common::SeekableReadStream *streamn); // From game save
// Lightmap
int _lightMapMode;
@@ -109,11 +111,6 @@ public:
int getCamX() { return _cameraX; }
int getCamY() { return _cameraY; }
float getCamZoom() { return _cameraZoom; }
- void setCamera(int camerX, int camerY, float camerZ) {
- _cameraX = camerX;
- _cameraY = camerY;
- _cameraZoom = camerZ;
- }
void aimCamera(int cameraX, int cameraY);
void zoomCamera(int z);
@@ -167,11 +164,18 @@ public:
void saveColors(Common::WriteStream *stream);
void loadColors(Common::SeekableReadStream *stream);
- // Thumb nail
+ // Thumbnail
+ bool setThumbnailSize(int thumbWidth, int thumbHeight);
bool saveThumbnail(Common::WriteStream *stream);
bool skipThumbnail(Common::SeekableReadStream *stream);
void showThumbnail(const Common::String &filename, int x, int y);
+ // Transition
+ void setBrightnessLevel(int brightnessLevel);
+ void setFadeMode(int fadeMode) { _fadeMode = fadeMode; };
+ void fixBrightness();
+ void resetRandW();
+
private:
SludgeEngine *_vm;
@@ -222,6 +226,14 @@ private:
// Colors
uint _currentBlankColour;
byte _currentBurnR, _currentBurnG, _currentBurnB;
+
+ // Thumbnail
+ int _thumbWidth;
+ int _thumbHeight;
+
+ // Transition
+ byte _brightnessLevel;
+ byte _fadeMode;
};
} // End of namespace Sludge
diff --git a/engines/sludge/loadsave.cpp b/engines/sludge/loadsave.cpp
index 4cabbc79da..453e78f3e5 100644
--- a/engines/sludge/loadsave.cpp
+++ b/engines/sludge/loadsave.cpp
@@ -29,6 +29,7 @@
#include "sludge/event.h"
#include "sludge/floor.h"
#include "sludge/fonttext.h"
+#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/language.h"
#include "sludge/loadsave.h"
@@ -37,6 +38,7 @@
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/region.h"
+#include "sludge/savedata.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/sound.h"
@@ -54,291 +56,31 @@ namespace Sludge {
// From elsewhere
//----------------------------------------------------------------------
+extern LoadedFunction *saverFunc; // In function.cpp
extern LoadedFunction *allRunningFunctions; // In sludger.cpp
-extern const char *typeName[]; // In variable.cpp
extern int numGlobals; // In sludger.cpp
extern Variable *globalVars; // In sludger.cpp
-extern Floor *currentFloor; // In floor.cpp
extern FILETIME fileTime; // In sludger.cpp
-extern byte brightnessLevel; // " " "
-extern byte fadeMode; // In transition.cpp
-extern bool captureAllKeys;
extern bool allowAnyFilename;
-extern uint16 saveEncoding; // in savedata.cpp
//----------------------------------------------------------------------
-// Globals (so we know what's saved already and what's a reference
-//----------------------------------------------------------------------
-
-struct stackLibrary {
- StackHandler *stack;
- stackLibrary *next;
-};
-
-int stackLibTotal = 0;
-stackLibrary *stackLib = NULL;
-
-//----------------------------------------------------------------------
-// For saving and loading stacks...
-//----------------------------------------------------------------------
-void saveStack(VariableStack *vs, Common::WriteStream *stream) {
- int elements = 0;
- int a;
-
- VariableStack *search = vs;
- while (search) {
- elements++;
- search = search->next;
- }
-
- stream->writeUint16BE(elements);
- search = vs;
- for (a = 0; a < elements; a++) {
- saveVariable(&search->thisVar, stream);
- search = search->next;
- }
-}
-
-VariableStack *loadStack(Common::SeekableReadStream *stream, VariableStack **last) {
- int elements = stream->readUint16BE();
- int a;
- VariableStack *first = NULL;
- VariableStack **changeMe = &first;
-
- for (a = 0; a < elements; a++) {
- VariableStack *nS = new VariableStack;
- if (!checkNew(nS))
- return NULL;
- loadVariable(&(nS->thisVar), stream);
- if (last && a == elements - 1) {
- *last = nS;
- }
- nS->next = NULL;
- (*changeMe) = nS;
- changeMe = &(nS->next);
- }
-
- return first;
-}
-
-bool saveStackRef(StackHandler *vs, Common::WriteStream *stream) {
- stackLibrary *s = stackLib;
- int a = 0;
- while (s) {
- if (s->stack == vs) {
- stream->writeByte(1);
- stream->writeUint16BE(stackLibTotal - a);
- return true;
- }
- s = s->next;
- a++;
- }
- stream->writeByte(0);
- saveStack(vs->first, stream);
- s = new stackLibrary;
- stackLibTotal++;
- if (!checkNew(s))
- return false;
- s->next = stackLib;
- s->stack = vs;
- stackLib = s;
- return true;
-}
-
-void clearStackLib() {
- stackLibrary *k;
- while (stackLib) {
- k = stackLib;
- stackLib = stackLib->next;
- delete k;
- }
- stackLibTotal = 0;
-}
-
-StackHandler *getStackFromLibrary(int n) {
- n = stackLibTotal - n;
- while (n) {
- stackLib = stackLib->next;
- n--;
- }
- return stackLib->stack;
-}
-
-StackHandler *loadStackRef(Common::SeekableReadStream *stream) {
- StackHandler *nsh;
-
- if (stream->readByte()) { // It's one we've loaded already...
- nsh = getStackFromLibrary(stream->readUint16BE());
- nsh->timesUsed++;
- } else {
- // Load the new stack
-
- nsh = new StackHandler;
- if (!checkNew(nsh))
- return NULL;
- nsh->last = NULL;
- nsh->first = loadStack(stream, &nsh->last);
- nsh->timesUsed = 1;
-
- // Add it to the library of loaded stacks
-
- stackLibrary *s = new stackLibrary;
- if (!checkNew(s))
- return NULL;
- s->stack = nsh;
- s->next = stackLib;
- stackLib = s;
- stackLibTotal++;
- }
- return nsh;
-}
-
-//----------------------------------------------------------------------
-// For saving and loading variables...
+// Save everything
//----------------------------------------------------------------------
-bool saveVariable(Variable *from, Common::WriteStream *stream) {
- stream->writeByte(from->varType);
- switch (from->varType) {
- case SVT_INT:
- case SVT_FUNC:
- case SVT_BUILT:
- case SVT_FILE:
- case SVT_OBJTYPE:
- stream->writeUint32LE(from->varData.intValue);
- return true;
-
- case SVT_STRING:
- writeString(from->varData.theString, stream);
- return true;
-
- case SVT_STACK:
- return saveStackRef(from->varData.theStack, stream);
-
- case SVT_COSTUME:
- saveCostume(from->varData.costumeHandler, stream);
- return false;
-
- case SVT_ANIM:
- saveAnim(from->varData.animHandler, stream);
- return false;
-
- case SVT_NULL:
- return false;
-
- default:
- fatal("Can't save variables of this type:", (from->varType < SVT_NUM_TYPES) ? typeName[from->varType] : "bad ID");
- }
- return true;
-}
-bool loadVariable(Variable *to, Common::SeekableReadStream *stream) {
- to->varType = (VariableType)stream->readByte();
- switch (to->varType) {
- case SVT_INT:
- case SVT_FUNC:
- case SVT_BUILT:
- case SVT_FILE:
- case SVT_OBJTYPE:
- to->varData.intValue = stream->readUint32LE();
- return true;
-
- case SVT_STRING:
- to->varData.theString = createCString(readString(stream));
- return true;
-
- case SVT_STACK:
- to->varData.theStack = loadStackRef(stream);
- return true;
-
- case SVT_COSTUME:
- to->varData.costumeHandler = new Persona;
- if (!checkNew(to->varData.costumeHandler))
+bool handleSaveLoad() {
+ if (!g_sludge->loadNow.empty()) {
+ if (g_sludge->loadNow[0] == ':') {
+ saveGame(g_sludge->loadNow.c_str() + 1);
+ saverFunc->reg.setVariable(SVT_INT, 1);
+ } else {
+ if (!loadGame(g_sludge->loadNow))
return false;
- loadCostume(to->varData.costumeHandler, stream);
- return true;
-
- case SVT_ANIM:
- to->varData.animHandler = new PersonaAnimation ;
- if (!checkNew(to->varData.animHandler))
- return false;
- loadAnim(to->varData.animHandler, stream);
- return true;
-
- default:
- break;
+ }
+ g_sludge->loadNow.clear();
}
return true;
}
-//----------------------------------------------------------------------
-// For saving and loading functions
-//----------------------------------------------------------------------
-void saveFunction(LoadedFunction *fun, Common::WriteStream *stream) {
- int a;
- stream->writeUint16BE(fun->originalNumber);
- if (fun->calledBy) {
- stream->writeByte(1);
- saveFunction(fun->calledBy, stream);
- } else {
- stream->writeByte(0);
- }
- stream->writeUint32LE(fun->timeLeft);
- stream->writeUint16BE(fun->runThisLine);
- stream->writeByte(fun->cancelMe);
- stream->writeByte(fun->returnSomething);
- stream->writeByte(fun->isSpeech);
- saveVariable(&(fun->reg), stream);
-
- if (fun->freezerLevel) {
- fatal(ERROR_GAME_SAVE_FROZEN);
- }
- saveStack(fun->stack, stream);
- for (a = 0; a < fun->numLocals; a++) {
- saveVariable(&(fun->localVars[a]), stream);
- }
-}
-
-LoadedFunction *loadFunction(Common::SeekableReadStream *stream) {
- int a;
-
- // Reserve memory...
-
- LoadedFunction *buildFunc = new LoadedFunction;
- if (!checkNew(buildFunc))
- return NULL;
-
- // See what it was called by and load if we need to...
-
- buildFunc->originalNumber = stream->readUint16BE();
- buildFunc->calledBy = NULL;
- if (stream->readByte()) {
- buildFunc->calledBy = loadFunction(stream);
- if (!buildFunc->calledBy)
- return NULL;
- }
-
- buildFunc->timeLeft = stream->readUint32LE();
- buildFunc->runThisLine = stream->readUint16BE();
- buildFunc->freezerLevel = 0;
- buildFunc->cancelMe = stream->readByte();
- buildFunc->returnSomething = stream->readByte();
- buildFunc->isSpeech = stream->readByte();
- loadVariable(&(buildFunc->reg), stream);
- loadFunctionCode(buildFunc);
-
- buildFunc->stack = loadStack(stream, NULL);
-
- for (a = 0; a < buildFunc->numLocals; a++) {
- loadVariable(&(buildFunc->localVars[a]), stream);
- }
-
- return buildFunc;
-}
-
-//----------------------------------------------------------------------
-// Save everything
-//----------------------------------------------------------------------
-
bool saveGame(const Common::String &fname) {
Common::OutSaveFile *fp = g_system->getSavefileManager()->openForSaving(fname);
@@ -359,23 +101,18 @@ bool saveGame(const Common::String &fname) {
// DON'T ADD ANYTHING NEW BEFORE THIS POINT!
fp->writeByte(allowAnyFilename);
- fp->writeByte(captureAllKeys);
+ fp->writeByte(false); // deprecated captureAllKeys
fp->writeByte(true);
g_sludge->_txtMan->saveFont(fp);
// Save backdrop
- fp->writeUint16BE(g_sludge->_gfxMan->getCamX());
- fp->writeUint16BE(g_sludge->_gfxMan->getCamY());
- fp->writeFloatLE(g_sludge->_gfxMan->getCamZoom());
-
- fp->writeByte(brightnessLevel);
- g_sludge->_gfxMan->saveHSI(fp);
+ g_sludge->_gfxMan->saveBackdrop(fp);
// Save event handlers
g_sludge->_evtMan->saveHandlers(fp);
// Save regions
- saveRegions(fp);
+ g_sludge->_regionMan->saveRegions(fp);
g_sludge->_cursorMan->saveCursor(fp);
@@ -395,28 +132,21 @@ bool saveGame(const Common::String &fname) {
}
for (int a = 0; a < numGlobals; a++) {
- saveVariable(&globalVars[a], fp);
+ globalVars[a].save(fp);
}
- savePeople(fp);
+ g_sludge->_peopleMan->savePeople(fp);
- if (currentFloor->numPolygons) {
- fp->writeByte(1);
- fp->writeUint16BE(currentFloor->originalNum);
- } else {
- fp->writeByte(0);
- }
+ g_sludge->_floorMan->save(fp);
g_sludge->_gfxMan->saveZBuffer(fp);
g_sludge->_gfxMan->saveLightMap(fp);
- fp->writeByte(fadeMode);
-
g_sludge->_speechMan->save(fp);
saveStatusBars(fp);
g_sludge->_soundMan->saveSounds(fp);
- fp->writeUint16BE(saveEncoding);
+ fp->writeUint16BE(CustomSaveHelper::_saveEncoding);
blur_saveSettings(fp);
@@ -498,28 +228,18 @@ bool loadGame(const Common::String &fname) {
if (ssgVersion >= VERSION(1, 4)) {
allowAnyFilename = fp->readByte();
}
- captureAllKeys = fp->readByte();
- fp->readByte(); // updateDisplay (part of movie playing)
+ fp->readByte(); // deprecated captureAllKeys
+ fp->readByte(); // updateDisplay (part of movie playing)
g_sludge->_txtMan->loadFont(ssgVersion, fp);
- killAllPeople();
- killAllRegions();
-
- int camerX = fp->readUint16BE();
- int camerY = fp->readUint16BE();
- float camerZ;
- if (ssgVersion >= VERSION(2, 0)) {
- camerZ = fp->readFloatLE();
- } else {
- camerZ = 1.0;
- }
+ g_sludge->_regionMan->kill();
- brightnessLevel = fp->readByte();
+ g_sludge->_gfxMan->loadBackdrop(ssgVersion, fp);
- g_sludge->_gfxMan->loadHSI(fp, 0, 0, true);
g_sludge->_evtMan->loadHandlers(fp);
- loadRegions(fp);
+
+ g_sludge->_regionMan->loadRegions(fp);
if (!g_sludge->_cursorMan->loadCursor(fp)) {
return false;
@@ -537,17 +257,15 @@ bool loadGame(const Common::String &fname) {
}
for (int a = 0; a < numGlobals; a++) {
- unlinkVar(globalVars[a]);
- loadVariable(&globalVars[a], fp);
+ globalVars[a].unlinkVar();
+ globalVars[a].load(fp);
}
- loadPeople(fp);
+ g_sludge->_peopleMan->loadPeople(fp);
- if (fp->readByte()) {
- if (!setFloor(fp->readUint16BE()))
- return false;
- } else
- setFloorNull();
+ if (!g_sludge->_floorMan->load(fp)) {
+ return false;
+ }
if (!g_sludge->_gfxMan->loadZBuffer(fp))
return false;
@@ -556,12 +274,11 @@ bool loadGame(const Common::String &fname) {
return false;
}
- fadeMode = fp->readByte();
g_sludge->_speechMan->load(fp);
loadStatusBars(fp);
g_sludge->_soundMan->loadSounds(fp);
- saveEncoding = fp->readUint16BE();
+ CustomSaveHelper::_saveEncoding = fp->readUint16BE();
if (ssgVersion >= VERSION(1, 6)) {
if (ssgVersion < VERSION(2, 0)) {
@@ -600,8 +317,6 @@ bool loadGame(const Common::String &fname) {
delete fp;
- g_sludge->_gfxMan->setCamera(camerX, camerY, camerZ);
-
clearStackLib();
return true;
}
diff --git a/engines/sludge/loadsave.h b/engines/sludge/loadsave.h
index 269fadb507..4077950cfb 100644
--- a/engines/sludge/loadsave.h
+++ b/engines/sludge/loadsave.h
@@ -24,23 +24,10 @@
namespace Sludge {
-struct LoadedFunction;
-struct Variable;
-struct VariableStack;
-
+bool handleSaveLoad();
bool saveGame(const Common::String &fname);
bool loadGame(const Common::String &fname);
-bool saveVariable(Variable *from, Common::WriteStream *stream);
-bool loadVariable(Variable *to, Common::SeekableReadStream *stream);
-
-VariableStack *loadStack(Common::SeekableReadStream *stream, VariableStack **last);
-bool saveStackRef(StackHandler *vs, Common::WriteStream *stream);
-StackHandler *loadStackRef(Common::SeekableReadStream *stream);
-
-LoadedFunction *loadFunction(Common::SeekableReadStream *stream);
-void saveFunction(LoadedFunction *fun, Common::WriteStream *stream);
-
} // End of namespace Sludge
#endif
diff --git a/engines/sludge/main_loop.cpp b/engines/sludge/main_loop.cpp
index 905d91d9c2..8f6e1f9cfb 100644
--- a/engines/sludge/main_loop.cpp
+++ b/engines/sludge/main_loop.cpp
@@ -28,8 +28,10 @@
#include "sludge/backdrop.h"
#include "sludge/event.h"
#include "sludge/floor.h"
+#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/language.h"
+#include "sludge/loadsave.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
@@ -39,15 +41,12 @@
#include "sludge/sludge.h"
#include "sludge/sludger.h"
#include "sludge/speech.h"
-#include "sludge/transition.h"
#include "sludge/timing.h"
namespace Sludge {
extern VariableStack *noStack;
-int dialogValue = 0;
-
int main_loop(Common::String filename) {
if (!initSludge(filename)) {
@@ -63,9 +62,10 @@ int main_loop(Common::String filename) {
while (!g_sludge->_evtMan->quit()) {
g_sludge->_evtMan->checkInput();
- walkAllPeople();
+ g_sludge->_peopleMan->walkAllPeople();
if (g_sludge->_evtMan->handleInput()) {
- runSludge();
+ runAllFunctions();
+ handleSaveLoad();
}
sludgeDisplay();
g_sludge->_soundMan->handleSoundLists();
diff --git a/engines/sludge/module.mk b/engines/sludge/module.mk
index a083ec4a95..d904e6c4c3 100644
--- a/engines/sludge/module.mk
+++ b/engines/sludge/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS := \
floor.o \
freeze.o \
fonttext.o \
+ function.o \
graphics.o \
hsi.o \
imgloader.o \
diff --git a/engines/sludge/moreio.cpp b/engines/sludge/moreio.cpp
index 1512574207..ee9ab8e0f0 100644
--- a/engines/sludge/moreio.cpp
+++ b/engines/sludge/moreio.cpp
@@ -167,4 +167,15 @@ Common::String decodeFilename(const Common::String &nameIn) {
return newName;
}
+char *createCString(const Common::String &s) {
+ uint n = s.size() + 1;
+ char *res = new char[n];
+ if (!checkNew(res)) {
+ fatal("createCString : Unable to copy String");
+ return NULL;
+ }
+ memcpy(res, s.c_str(), n);
+ return res;
+}
+
} // End of namespace Sludge
diff --git a/engines/sludge/moreio.h b/engines/sludge/moreio.h
index 09235ae8a6..237a918626 100644
--- a/engines/sludge/moreio.h
+++ b/engines/sludge/moreio.h
@@ -31,6 +31,8 @@ void writeString(Common::String s, Common::WriteStream *stream);
Common::String encodeFilename(const Common::String &nameIn);
Common::String decodeFilename(const Common::String &nameIn);
+char *createCString(const Common::String &s);
+
} // End of namespace Sludge
#endif
diff --git a/engines/sludge/movie.cpp b/engines/sludge/movie.cpp
index 271728da75..2c43c3cceb 100644
--- a/engines/sludge/movie.cpp
+++ b/engines/sludge/movie.cpp
@@ -911,7 +911,8 @@ int playMovie(int fileNumber) {
glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
movieIsPlaying = nothing;
- for (int i = 0; i < 10; i++) Wait_Frame();
+ for (int i = 0; i < 10; i++)
+ Wait_Frame();
huntKillFreeSound(fileNumber);
if (vpx_codec_destroy(&codec))
diff --git a/engines/sludge/newfatal.cpp b/engines/sludge/newfatal.cpp
index edd4a88073..a5069ae306 100644
--- a/engines/sludge/newfatal.cpp
+++ b/engines/sludge/newfatal.cpp
@@ -24,34 +24,17 @@
#include "sludge/allfiles.h"
#include "sludge/errors.h"
+#include "sludge/fileset.h"
+#include "sludge/newfatal.h"
#include "sludge/sludge.h"
#include "sludge/sound.h"
#include "sludge/version.h"
-namespace Sludge {
-
-const char emergencyMemoryMessage[] = "Out of memory displaying error message!";
-
-extern int numResourceNames /* = 0*/;
-extern Common::String *allResourceNames /*= ""*/;
-
-int resourceForFatal = -1;
-
-const Common::String resourceNameFromNum(int i) {
- if (i == -1)
- return NULL;
- if (numResourceNames == 0)
- return "RESOURCE";
- if (i < numResourceNames)
- return allResourceNames[i];
- return "Unknown resource";
+namespace Common {
+DECLARE_SINGLETON(Sludge::FatalMsgManager);
}
-bool hasFatal() {
- if (!g_sludge->fatalMessage.empty())
- return true;
- return false;
-}
+namespace Sludge {
int inFatal(const Common::String &str) {
g_sludge->_soundMan->killSoundStuff();
@@ -59,35 +42,55 @@ int inFatal(const Common::String &str) {
return true;
}
-int checkNew(const void *mem) {
- if (mem == NULL) {
- inFatal(ERROR_OUT_OF_MEMORY);
- return 0;
- }
- return 1;
+FatalMsgManager::FatalMsgManager() {
+ reset();
}
-void setFatalInfo(const Common::String &userFunc, const Common::String &BIF) {
- g_sludge->fatalInfo = "Currently in this sub: " + userFunc + "\nCalling: " + BIF;
- debugC(0, kSludgeDebugFatal, "%s", g_sludge->fatalInfo.c_str());
+FatalMsgManager::~FatalMsgManager() {
}
-void setResourceForFatal(int n) {
- resourceForFatal = n;
+void FatalMsgManager::reset() {
+ _fatalMessage = "";
+ _fatalInfo = "Initialisation error! Something went wrong before we even got started!";
+ _resourceForFatal = -1;
}
-int fatal(const Common::String &str1) {
- if (numResourceNames && resourceForFatal != -1) {
- Common::String r = resourceNameFromNum(resourceForFatal);
- Common::String newStr = g_sludge->fatalInfo + "\nResource: " + r + "\n\n" + str1;
+bool FatalMsgManager::hasFatal() {
+ if (!_fatalMessage.empty())
+ return true;
+ return false;
+}
+
+void FatalMsgManager::setFatalInfo(const Common::String &userFunc, const Common::String &BIF) {
+ _fatalInfo = "Currently in this sub: " + userFunc + "\nCalling: " + BIF;
+ debugC(0, kSludgeDebugFatal, "%s", _fatalInfo.c_str());
+}
+
+void FatalMsgManager::setResourceForFatal(int n) {
+ _resourceForFatal = n;
+}
+
+int FatalMsgManager::fatal(const Common::String &str1) {
+ ResourceManager *resMan = g_sludge->_resMan;
+ if (resMan->hasResourceNames() && _resourceForFatal != -1) {
+ Common::String r = resMan->resourceNameFromNum(_resourceForFatal);
+ Common::String newStr = _fatalInfo + "\nResource: " + r + "\n\n" + str1;
inFatal(newStr);
} else {
- Common::String newStr = g_sludge->fatalInfo + "\n\n" + str1;
+ Common::String newStr = _fatalInfo + "\n\n" + str1;
inFatal(newStr);
}
return 0;
}
+int checkNew(const void *mem) {
+ if (mem == NULL) {
+ inFatal(ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+ return 1;
+}
+
int fatal(const Common::String &str1, const Common::String &str2) {
Common::String newStr = str1 + " " + str2;
fatal(newStr);
diff --git a/engines/sludge/newfatal.h b/engines/sludge/newfatal.h
index fc91110758..81ca4b7616 100644
--- a/engines/sludge/newfatal.h
+++ b/engines/sludge/newfatal.h
@@ -23,19 +23,49 @@
#define SLUDGE_NEWFATAL_H
#include "common/str.h"
+#include "common/singleton.h"
#include "sludge/errors.h"
namespace Sludge {
-bool hasFatal();
+class FatalMsgManager : public Common::Singleton<Sludge::FatalMsgManager>{
+public:
+ FatalMsgManager();
+ ~FatalMsgManager();
+
+ void reset();
+
+ bool hasFatal();
+ int fatal(const Common::String &str);
+ void setFatalInfo(const Common::String &userFunc, const Common::String &BIF);
+ void setResourceForFatal(int n);
+
+private:
+ Common::String _fatalMessage;
+ Common::String _fatalInfo;
+
+ int _resourceForFatal;
+};
+
+inline bool hasFatal() {
+ return FatalMsgManager::instance().hasFatal();
+}
+
+inline int fatal(const Common::String &str) {
+ return FatalMsgManager::instance().fatal(str);
+}
+
+inline void setFatalInfo(const Common::String &userFunc, const Common::String &BIF) {
+ FatalMsgManager::instance().setFatalInfo(userFunc, BIF);
+}
+
+inline void setResourceForFatal(int n) {
+ FatalMsgManager::instance().setResourceForFatal(n);
+}
-int fatal(const Common::String &str);
-int fatal(const Common::String &str1, const Common::String &str2);
int checkNew(const void *mem);
-void setFatalInfo(const Common::String &userFunc, const Common::String &BIF);
-void setResourceForFatal(int n);
-const Common::String resourceNameFromNum(int i);
+int fatal(const Common::String &str1, const Common::String &str2);
} // End of namespace Sludge
diff --git a/engines/sludge/people.cpp b/engines/sludge/people.cpp
index 4aec5fa8b7..433ab2d895 100644
--- a/engines/sludge/people.cpp
+++ b/engines/sludge/people.cpp
@@ -22,6 +22,7 @@
#include "sludge/allfiles.h"
#include "sludge/floor.h"
+#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/loadsave.h"
#include "sludge/moreio.h"
@@ -39,7 +40,6 @@
#include "sludge/version.h"
#include "sludge/zbuffer.h"
-#define ANGLEFIX (180.0 / 3.14157)
#define ANI_STAND 0
#define ANI_WALK 1
#define ANI_TALK 2
@@ -47,108 +47,174 @@
namespace Sludge {
extern VariableStack *noStack;
-
extern int ssgVersion;
-ScreenRegion personRegion;
-extern ScreenRegion *lastRegion;
-extern Floor *currentFloor;
-
-OnScreenPerson *allPeople = NULL;
-int16 scaleHorizon = 75;
-int16 scaleDivide = 150;
-extern ScreenRegion *allScreenRegions;
-
-void setFrames(OnScreenPerson &m, int a) {
- m.myAnim = m.myPersona->animation[(a * m.myPersona->numDirections) + m.direction];
+PersonaAnimation::PersonaAnimation() {
+ theSprites = nullptr;
+ numFrames = 0;
+ frames = nullptr;
}
-PersonaAnimation *createPersonaAnim(int num, VariableStack *&stacky) {
- PersonaAnimation *newP = new PersonaAnimation ;
- checkNew(newP);
-
- newP->numFrames = num;
- newP->frames = new AnimFrame [num];
- checkNew(newP->frames);
+PersonaAnimation::~PersonaAnimation() {
+ if (numFrames) {
+ delete[] frames;
+ frames = nullptr;
+ }
+}
+PersonaAnimation::PersonaAnimation(int num, VariableStack *&stacky) {
+ theSprites = nullptr;
+ numFrames = num;
+ frames = new AnimFrame[num];
int a = num, frameNum, howMany;
while (a) {
a--;
- newP->frames[a].noise = 0;
+ frames[a].noise = 0;
if (stacky->thisVar.varType == SVT_FILE) {
- newP->frames[a].noise = stacky->thisVar.varData.intValue;
+ frames[a].noise = stacky->thisVar.varData.intValue;
} else if (stacky->thisVar.varType == SVT_FUNC) {
- newP->frames[a].noise = -stacky->thisVar.varData.intValue;
+ frames[a].noise = -stacky->thisVar.varData.intValue;
} else if (stacky->thisVar.varType == SVT_STACK) {
- getValueType(frameNum, SVT_INT, stacky->thisVar.varData.theStack->first->thisVar);
- getValueType(howMany, SVT_INT, stacky->thisVar.varData.theStack->first->next->thisVar);
+ stacky->thisVar.varData.theStack->first->thisVar.getValueType(frameNum, SVT_INT);
+ stacky->thisVar.varData.theStack->first->next->thisVar.getValueType(howMany, SVT_INT);
} else {
- getValueType(frameNum, SVT_INT, stacky->thisVar);
+ stacky->thisVar.getValueType(frameNum, SVT_INT);
howMany = 1;
}
trimStack(stacky);
- newP->frames[a].frameNum = frameNum;
- newP->frames[a].howMany = howMany;
+ frames[a].frameNum = frameNum;
+ frames[a].howMany = howMany;
}
-
- return newP;
}
-PersonaAnimation *makeNullAnim() {
- PersonaAnimation *newAnim = new PersonaAnimation ;
- if (!checkNew(newAnim))
- return NULL;
-
- newAnim->theSprites = NULL;
- newAnim->numFrames = 0;
- newAnim->frames = NULL;
- return newAnim;
-}
-
-PersonaAnimation *copyAnim(PersonaAnimation *orig) {
+PersonaAnimation::PersonaAnimation(PersonaAnimation *orig) {
int num = orig->numFrames;
- PersonaAnimation *newAnim = new PersonaAnimation ;
- if (!checkNew(newAnim))
- return NULL;
-
// Copy the easy bits...
- newAnim->theSprites = orig->theSprites;
- newAnim->numFrames = num;
+ theSprites = orig->theSprites;
+ numFrames = num;
if (num) {
-
- // Argh!Frames!We need a whole NEW array of AnimFrame structures...
-
- newAnim->frames = new AnimFrame [num];
- if (!checkNew(newAnim->frames))
- return NULL;
+ // Argh! Frames! We need a whole NEW array of AnimFrame structures...
+ frames = new AnimFrame[num];
for (int a = 0; a < num; a++) {
- newAnim->frames[a].frameNum = orig->frames[a].frameNum;
- newAnim->frames[a].howMany = orig->frames[a].howMany;
- newAnim->frames[a].noise = orig->frames[a].noise;
+ frames[a].frameNum = orig->frames[a].frameNum;
+ frames[a].howMany = orig->frames[a].howMany;
+ frames[a].noise = orig->frames[a].noise;
}
} else {
- newAnim->frames = NULL;
+ frames = nullptr;
}
+}
- return newAnim;
+int PersonaAnimation::getTotalTime() {
+ int total = 0;
+ for (int a = 0; a < numFrames; a++) {
+ total += frames[a].howMany;
+ }
+ return total;
}
-void deleteAnim(PersonaAnimation *orig) {
+bool PersonaAnimation::save(Common::WriteStream *stream) {
+ stream->writeUint16BE(numFrames);
+ if (numFrames) {
+ stream->writeUint32LE(theSprites->ID);
- if (orig) {
- if (orig->numFrames) {
- delete[] orig->frames;
+ for (int a = 0; a < numFrames; a++) {
+ stream->writeUint32LE(frames[a].frameNum);
+ stream->writeUint32LE(frames[a].howMany);
+ stream->writeUint32LE(frames[a].noise);
}
- delete orig;
- orig = NULL;
}
+ return true;
+}
+
+bool PersonaAnimation::load(Common::SeekableReadStream *stream) {
+ numFrames = stream->readUint16BE();
+
+ if (numFrames) {
+ int a = stream->readUint32LE();
+ frames = new AnimFrame [numFrames];
+ if (!checkNew(frames))
+ return false;
+ theSprites = g_sludge->_gfxMan->loadBankForAnim(a);
+
+ for (a = 0; a < numFrames; a++) {
+ frames[a].frameNum = stream->readUint32LE();
+ frames[a].howMany = stream->readUint32LE();
+ if (ssgVersion >= VERSION(2, 0)) {
+ frames[a].noise = stream->readUint32LE();
+ } else {
+ frames[a].noise = 0;
+ }
+ }
+ } else {
+ theSprites = NULL;
+ frames = NULL;
+ }
+ return true;
+}
+
+bool Persona::save(Common::WriteStream *stream) {
+ int a;
+ stream->writeUint16BE(numDirections);
+ for (a = 0; a < numDirections * 3; a++) {
+ if (!animation[a]->save(stream))
+ return false;
+ }
+ return true;
+}
+
+bool Persona::load(Common::SeekableReadStream *stream) {
+ int a;
+ numDirections = stream->readUint16BE();
+ animation = new PersonaAnimation *[numDirections * 3];
+ if (!checkNew(animation))
+ return false;
+ for (a = 0; a < numDirections * 3; a++) {
+ animation[a] = new PersonaAnimation;
+ if (!checkNew(animation[a]))
+ return false;
+
+ if (!animation[a]->load(stream))
+ return false;
+ }
+ return true;
+}
+
+void OnScreenPerson::setFrames(int a) {
+ myAnim = myPersona->animation[(a * myPersona->numDirections) + direction];
+}
+
+void OnScreenPerson::makeTalker() {
+ setFrames(ANI_TALK);
+}
+
+void OnScreenPerson::makeSilent() {
+ setFrames(ANI_STAND);
}
-void turnMeAngle(OnScreenPerson *thisPerson, int direc) {
+PeopleManager::PeopleManager(SludgeEngine *vm) {
+ _vm = vm;
+ _allPeople = new OnScreenPersonList;
+ _scaleHorizon = 75;
+ _scaleDivide = 150;
+ _personRegion = new ScreenRegion;
+}
+
+PeopleManager::~PeopleManager() {
+ kill();
+
+ delete _personRegion;
+ _personRegion = nullptr;
+
+ delete _allPeople;
+ _allPeople = nullptr;
+}
+
+void PeopleManager::turnMeAngle(OnScreenPerson *thisPerson, int direc) {
int d = thisPerson->myPersona->numDirections;
thisPerson->angle = direc;
direc += (180 / d) + 180 + thisPerson->angleOffset;
@@ -157,16 +223,14 @@ void turnMeAngle(OnScreenPerson *thisPerson, int direc) {
thisPerson->direction = (direc * d) / 360;
}
-bool initPeople() {
- personRegion.sX = 0;
- personRegion.sY = 0;
- personRegion.di = -1;
- allScreenRegions = NULL;
-
+bool PeopleManager::init() {
+ _personRegion->sX = 0;
+ _personRegion->sY = 0;
+ _personRegion->di = -1;
return true;
}
-void spinStep(OnScreenPerson *thisPerson) {
+void PeopleManager::spinStep(OnScreenPerson *thisPerson) {
int diff = (thisPerson->angle + 360) - thisPerson->wantAngle;
int eachSlice = thisPerson->spinSpeed ? thisPerson->spinSpeed : (360 / thisPerson->myPersona->numDirections);
while (diff > 180) {
@@ -183,7 +247,7 @@ void spinStep(OnScreenPerson *thisPerson) {
}
}
-void rethinkAngle(OnScreenPerson *thisPerson) {
+void PeopleManager::rethinkAngle(OnScreenPerson *thisPerson) {
int d = thisPerson->myPersona->numDirections;
int direc = thisPerson->angle + (180 / d) + 180 + thisPerson->angleOffset;
while (direc >= 360)
@@ -191,7 +255,7 @@ void rethinkAngle(OnScreenPerson *thisPerson) {
thisPerson->direction = (direc * d) / 360;
}
-bool turnPersonToFace(int thisNum, int direc) {
+bool PeopleManager::turnPersonToFace(int thisNum, int direc) {
OnScreenPerson *thisPerson = findPerson(thisNum);
if (thisPerson) {
if (thisPerson->continueAfterWalking)
@@ -200,13 +264,14 @@ bool turnPersonToFace(int thisNum, int direc) {
thisPerson->walking = false;
thisPerson->spinning = false;
turnMeAngle(thisPerson, direc);
- setFrames(*thisPerson, g_sludge->_speechMan->isCurrentTalker(thisPerson) ? ANI_TALK : ANI_STAND);
+ _vm->_speechMan->isCurrentTalker(thisPerson) ?
+ thisPerson->makeTalker() : thisPerson->makeSilent();
return true;
}
return false;
}
-bool setPersonExtra(int thisNum, int extra) {
+bool PeopleManager::setPersonExtra(int thisNum, int extra) {
OnScreenPerson *thisPerson = findPerson(thisNum);
if (thisPerson) {
thisPerson->extra = extra;
@@ -217,35 +282,34 @@ bool setPersonExtra(int thisNum, int extra) {
return false;
}
-void setScale(int16 h, int16 d) {
- scaleHorizon = h;
- scaleDivide = d;
+void PeopleManager::setScale(int16 h, int16 d) {
+ _scaleHorizon = h;
+ _scaleDivide = d;
}
-void moveAndScale(OnScreenPerson &me, float x, float y) {
+void PeopleManager::moveAndScale(OnScreenPerson &me, float x, float y) {
me.x = x;
me.y = y;
- if (!(me.extra & EXTRA_NOSCALE) && scaleDivide)
- me.scale = (me.y - scaleHorizon) / scaleDivide;
+ if (!(me.extra & EXTRA_NOSCALE) && _scaleDivide)
+ me.scale = (me.y - _scaleHorizon) / _scaleDivide;
}
-OnScreenPerson *findPerson(int v) {
- OnScreenPerson *thisPerson = allPeople;
- while (thisPerson) {
- if (v == thisPerson->thisType->objectNum)
- break;
- thisPerson = thisPerson->next;
+OnScreenPerson *PeopleManager::findPerson(int v) {
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ if (v == (*it)->thisType->objectNum) {
+ return (*it);
+ }
}
- return thisPerson;
+ return nullptr;
}
-void movePerson(int x, int y, int objNum) {
+void PeopleManager::movePerson(int x, int y, int objNum) {
OnScreenPerson *moveMe = findPerson(objNum);
if (moveMe)
moveAndScale(*moveMe, x, y);
}
-void setShown(bool h, int ob) {
+void PeopleManager::setShown(bool h, int ob) {
OnScreenPerson *moveMe = findPerson(ob);
if (moveMe)
moveMe->show = h;
@@ -275,7 +339,7 @@ enum drawModes {
numDrawModes
};
-void setMyDrawMode(OnScreenPerson *moveMe, int h) {
+void PeopleManager::setMyDrawMode(OnScreenPerson *moveMe, int h) {
switch (h) {
case drawModeTransparent3:
moveMe->r = moveMe->g = moveMe->b = 0;
@@ -381,7 +445,7 @@ void setMyDrawMode(OnScreenPerson *moveMe, int h) {
}
-void setDrawMode(int h, int ob) {
+void PeopleManager::setDrawMode(int h, int ob) {
OnScreenPerson *moveMe = findPerson(ob);
if (!moveMe)
return;
@@ -389,7 +453,7 @@ void setDrawMode(int h, int ob) {
setMyDrawMode(moveMe, h);
}
-void setPersonTransparency(int ob, byte x) {
+void PeopleManager::setPersonTransparency(int ob, byte x) {
OnScreenPerson *moveMe = findPerson(ob);
if (!moveMe)
return;
@@ -399,7 +463,7 @@ void setPersonTransparency(int ob, byte x) {
moveMe->transparency = x;
}
-void setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix) {
+void PeopleManager::setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix) {
OnScreenPerson *moveMe = findPerson(ob);
if (!moveMe)
return;
@@ -410,44 +474,29 @@ void setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix) {
moveMe->colourmix = colourmix;
}
-extern ScreenRegion *overRegion;
-
-void shufflePeople() {
- OnScreenPerson **thisReference = &allPeople;
- OnScreenPerson *A, *B;
+struct PeopleYComperator {
+ bool operator()(const OnScreenPerson *p1, const OnScreenPerson *p2) {
+ float y1 = p1->extra & EXTRA_FRONT ? p1->y + 1000 : p1->y;
+ float y2 = p2->extra & EXTRA_FRONT ? p2->y + 1000 : p2->y;
+ return y1 < y2;
+ }
+};
- if (!allPeople)
+void PeopleManager::shufflePeople() {
+ if (_allPeople->empty())
return;
- while ((*thisReference)->next) {
- float y1 = (*thisReference)->y;
- if ((*thisReference)->extra & EXTRA_FRONT)
- y1 += 1000;
-
- float y2 = (*thisReference)->next->y;
- if ((*thisReference)->next->extra & EXTRA_FRONT)
- y2 += 1000;
-
- if (y1 > y2) {
- A = (*thisReference);
- B = (*thisReference)->next;
- A->next = B->next;
- B->next = A;
- (*thisReference) = B;
- } else {
- thisReference = &((*thisReference)->next);
- }
- }
+ Common::sort(_allPeople->begin(), _allPeople->end(), PeopleYComperator());
}
-void drawPeople() {
+void PeopleManager::drawPeople() {
shufflePeople();
- OnScreenPerson *thisPerson = allPeople;
- PersonaAnimation *myAnim = NULL;
- overRegion = NULL;
+ PersonaAnimation *myAnim = NULL;
+ _vm->_regionMan->resetOverRegion();
- while (thisPerson) {
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ OnScreenPerson * thisPerson = (*it);
if (thisPerson->show) {
myAnim = thisPerson->myAnim;
if (myAnim != thisPerson->lastUsedAnim) {
@@ -455,7 +504,7 @@ void drawPeople() {
thisPerson->frameNum = 0;
thisPerson->frameTick = myAnim->frames[0].howMany;
if (myAnim->frames[thisPerson->frameNum].noise > 0) {
- g_sludge->_soundMan->startSound(myAnim->frames[thisPerson->frameNum].noise, false);
+ _vm->_soundMan->startSound(myAnim->frames[thisPerson->frameNum].noise, false);
thisPerson->frameNum++;
thisPerson->frameNum %= thisPerson->myAnim->numFrames;
thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
@@ -476,13 +525,13 @@ void drawPeople() {
}
if (m != 2) {
bool r = false;
- r = g_sludge->_gfxMan->scaleSprite(myAnim->theSprites->bank.sprites[fNum], myAnim->theSprites->bank.myPalette, thisPerson, m);
+ r = _vm->_gfxMan->scaleSprite(myAnim->theSprites->bank.sprites[fNum], myAnim->theSprites->bank.myPalette, thisPerson, m);
if (r) {
if (!thisPerson->thisType->screenName.empty()) {
- if (personRegion.thisType != thisPerson->thisType)
- lastRegion = NULL;
- personRegion.thisType = thisPerson->thisType;
- overRegion = &personRegion;
+ if (_personRegion->thisType != thisPerson->thisType)
+ _vm->_regionMan->resetLastRegion();
+ _personRegion->thisType = thisPerson->thisType;
+ _vm->_regionMan->setOverRegion(_personRegion);
}
}
}
@@ -493,7 +542,7 @@ void drawPeople() {
thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
if (thisPerson->show && myAnim && myAnim->frames) {
if (myAnim->frames[thisPerson->frameNum].noise > 0) {
- g_sludge->_soundMan->startSound(myAnim->frames[thisPerson->frameNum].noise, false);
+ _vm->_soundMan->startSound(myAnim->frames[thisPerson->frameNum].noise, false);
thisPerson->frameNum++;
thisPerson->frameNum %= thisPerson->myAnim->numFrames;
thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
@@ -506,132 +555,10 @@ void drawPeople() {
}
}
}
- thisPerson = thisPerson->next;
- }
-}
-
-void makeTalker(OnScreenPerson &me) {
- setFrames(me, ANI_TALK);
-}
-
-void makeSilent(OnScreenPerson &me) {
- setFrames(me, ANI_STAND);
-}
-
-bool handleClosestPoint(int &setX, int &setY, int &setPoly) {
- int gotX = 320, gotY = 200, gotPoly = -1, i, j, xTest1, yTest1, xTest2, yTest2, closestX, closestY, oldJ, currentDistance = 0xFFFFF, thisDistance;
-
-// FILE * dbug = fopen ("debug_closest.txt", "at");
-// fprintf (dbug, "\nGetting closest point to %i, %i\n", setX, setY);
-
- for (i = 0; i < currentFloor->numPolygons; i++) {
- oldJ = currentFloor->polygon[i].numVertices - 1;
- for (j = 0; j < currentFloor->polygon[i].numVertices; j++) {
-// fprintf (dbug, "Polygon %i, line %i... ", i, j);
- xTest1 = currentFloor->vertex[currentFloor->polygon[i].vertexID[j]].x;
- yTest1 = currentFloor->vertex[currentFloor->polygon[i].vertexID[j]].y;
- xTest2 = currentFloor->vertex[currentFloor->polygon[i].vertexID[oldJ]].x;
- yTest2 = currentFloor->vertex[currentFloor->polygon[i].vertexID[oldJ]].y;
- closestPointOnLine(closestX, closestY, xTest1, yTest1, xTest2, yTest2, setX, setY);
-// fprintf (dbug, "closest point is %i, %i... ", closestX, closestY);
- xTest1 = setX - closestX;
- yTest1 = setY - closestY;
- thisDistance = xTest1 * xTest1 + yTest1 * yTest1;
-// fprintf (dbug, "Distance squared %i\n", thisDistance);
-
- if (thisDistance < currentDistance) {
-// fprintf (dbug, "** We have a new winner!**\n");
-
- currentDistance = thisDistance;
- gotX = closestX;
- gotY = closestY;
- gotPoly = i;
- }
- oldJ = j;
- }
}
-// fclose (dbug);
-
- if (gotPoly == -1)
- return false;
- setX = gotX;
- setY = gotY;
- setPoly = gotPoly;
-
- return true;
}
-bool doBorderStuff(OnScreenPerson *moveMe) {
- if (moveMe->inPoly == moveMe->walkToPoly) {
- moveMe->inPoly = -1;
- moveMe->thisStepX = moveMe->walkToX;
- moveMe->thisStepY = moveMe->walkToY;
- } else {
- // The section in which we need to be next...
- int newPoly = currentFloor->matrix[moveMe->inPoly][moveMe->walkToPoly];
- if (newPoly == -1)
- return false;
-
- // Grab the index of the second matching corner...
- int ID, ID2;
- if (!getMatchingCorners(currentFloor->polygon[moveMe->inPoly], currentFloor->polygon[newPoly], ID, ID2))
- return fatal("Not a valid floor plan!");
-
- // Remember that we're walking to the new polygon...
- moveMe->inPoly = newPoly;
-
- // Calculate the destination position on the coincidantal line...
- int x1 = moveMe->x, y1 = moveMe->y;
- int x2 = moveMe->walkToX, y2 = moveMe->walkToY;
- int x3 = currentFloor->vertex[ID].x, y3 = currentFloor->vertex[ID].y;
- int x4 = currentFloor->vertex[ID2].x, y4 = currentFloor->vertex[ID2].y;
-
- int xAB = x1 - x2;
- int yAB = y1 - y2;
- int xCD = x4 - x3;
- int yCD = y4 - y3;
-
- double m = (yAB * (x3 - x1) - xAB * (y3 - y1));
- m /= ((xAB * yCD) - (yAB * xCD));
-
- if (m > 0 && m < 1) {
- moveMe->thisStepX = x3 + m * xCD;
- moveMe->thisStepY = y3 + m * yCD;
- } else {
- int dx13 = x1 - x3, dx14 = x1 - x4, dx23 = x2 - x3, dx24 = x2 - x4;
- int dy13 = y1 - y3, dy14 = y1 - y4, dy23 = y2 - y3, dy24 = y2 - y4;
-
- dx13 *= dx13;
- dx14 *= dx14;
- dx23 *= dx23;
- dx24 *= dx24;
- dy13 *= dy13;
- dy14 *= dy14;
- dy23 *= dy23;
- dy24 *= dy24;
-
- if (sqrt((double)dx13 + dy13) + sqrt((double)dx23 + dy23) < sqrt((double)dx14 + dy14) + sqrt((double)dx24 + dy24)) {
- moveMe->thisStepX = x3;
- moveMe->thisStepY = y3;
- } else {
- moveMe->thisStepX = x4;
- moveMe->thisStepY = y4;
- }
- }
- }
-
- float yDiff = moveMe->thisStepY - moveMe->y;
- float xDiff = moveMe->x - moveMe->thisStepX;
- if (xDiff || yDiff) {
- moveMe->wantAngle = 180 + ANGLEFIX * atan2(xDiff, yDiff * 2);
- moveMe->spinning = true;
- }
-
- setFrames(*moveMe, ANI_WALK);
- return true;
-}
-
-bool walkMe(OnScreenPerson *thisPerson, bool move = true) {
+bool PeopleManager::walkMe(OnScreenPerson *thisPerson, bool move) {
float xDiff, yDiff, maxDiff, s;
for (;;) {
@@ -646,7 +573,7 @@ bool walkMe(OnScreenPerson *thisPerson, bool move = true) {
if (ABS(maxDiff) > s) {
if (thisPerson->spinning) {
spinStep(thisPerson);
- setFrames(*thisPerson, ANI_WALK);
+ thisPerson->setFrames(ANI_WALK);
}
s = maxDiff / s;
if (move)
@@ -662,20 +589,20 @@ bool walkMe(OnScreenPerson *thisPerson, bool move = true) {
}
break;
}
- if (!doBorderStuff(thisPerson))
+ if (!_vm->_floorMan->doBorderStuff(thisPerson))
break;
}
thisPerson->walking = false;
- setFrames(*thisPerson, ANI_STAND);
+ thisPerson->setFrames(ANI_STAND);
moveAndScale(*thisPerson, thisPerson->walkToX, thisPerson->walkToY);
return false;
}
-bool makeWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
+bool PeopleManager::makeWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
if (x == 0 && y == 0)
return false;
- if (currentFloor->numPolygons == 0)
+ if (_vm->_floorMan->isFloorNoPolygon())
return false;
OnScreenPerson *moveMe = findPerson(objNum);
if (!moveMe)
@@ -689,20 +616,20 @@ bool makeWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
moveMe->walkToX = x;
moveMe->walkToY = y;
- moveMe->walkToPoly = inFloor(x, y);
+ moveMe->walkToPoly = _vm->_floorMan->inFloor(x, y);
if (moveMe->walkToPoly == -1) {
- if (!handleClosestPoint(moveMe->walkToX, moveMe->walkToY, moveMe->walkToPoly))
+ if (!_vm->_floorMan->handleClosestPoint(moveMe->walkToX, moveMe->walkToY, moveMe->walkToPoly))
return false;
}
- moveMe->inPoly = inFloor(moveMe->x, moveMe->y);
+ moveMe->inPoly = _vm->_floorMan->inFloor(moveMe->x, moveMe->y);
if (moveMe->inPoly == -1) {
int xxx = moveMe->x, yyy = moveMe->y;
- if (!handleClosestPoint(xxx, yyy, moveMe->inPoly))
+ if (!_vm->_floorMan->handleClosestPoint(xxx, yyy, moveMe->inPoly))
return false;
}
- doBorderStuff(moveMe);
+ _vm->_floorMan->doBorderStuff(moveMe);
if (walkMe(moveMe, false) || moveMe->spinning) {
moveMe->continueAfterWalking = func;
return true;
@@ -711,7 +638,7 @@ bool makeWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
}
}
-bool stopPerson(int o) {
+bool PeopleManager::stopPerson(int o) {
OnScreenPerson *moveMe = findPerson(o);
if (moveMe)
if (moveMe->continueAfterWalking) {
@@ -719,13 +646,13 @@ bool stopPerson(int o) {
moveMe->continueAfterWalking = NULL;
moveMe->walking = false;
moveMe->spinning = false;
- setFrames(*moveMe, ANI_STAND);
+ moveMe->setFrames(ANI_STAND);
return true;
}
return false;
}
-bool forceWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
+bool PeopleManager::forceWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
if (x == 0 && y == 0)
return false;
OnScreenPerson *moveMe = findPerson(objNum);
@@ -746,7 +673,7 @@ bool forceWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di)
moveMe->inPoly = 0;
moveMe->walkToPoly = 0;
- doBorderStuff(moveMe);
+ _vm->_floorMan->doBorderStuff(moveMe);
if (walkMe(moveMe) || moveMe->spinning) {
moveMe->continueAfterWalking = func;
return true;
@@ -755,7 +682,7 @@ bool forceWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di)
}
}
-void jumpPerson(int x, int y, int objNum) {
+void PeopleManager::jumpPerson(int x, int y, int objNum) {
if (x == 0 && y == 0)
return;
OnScreenPerson *moveMe = findPerson(objNum);
@@ -769,7 +696,7 @@ void jumpPerson(int x, int y, int objNum) {
moveAndScale(*moveMe, x, y);
}
-bool floatCharacter(int f, int objNum) {
+bool PeopleManager::floatCharacter(int f, int objNum) {
OnScreenPerson *moveMe = findPerson(objNum);
if (!moveMe)
return false;
@@ -777,7 +704,7 @@ bool floatCharacter(int f, int objNum) {
return true;
}
-bool setCharacterWalkSpeed(int f, int objNum) {
+bool PeopleManager::setCharacterWalkSpeed(int f, int objNum) {
if (f <= 0)
return false;
OnScreenPerson *moveMe = findPerson(objNum);
@@ -787,31 +714,29 @@ bool setCharacterWalkSpeed(int f, int objNum) {
return true;
}
-void walkAllPeople() {
- OnScreenPerson *thisPerson = allPeople;
-
- while (thisPerson) {
+void PeopleManager::walkAllPeople() {
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ OnScreenPerson *thisPerson = (*it);
if (thisPerson->walking) {
walkMe(thisPerson);
} else if (thisPerson->spinning) {
spinStep(thisPerson);
- setFrames(*thisPerson, ANI_STAND);
+ thisPerson->setFrames(ANI_STAND);
}
if ((!thisPerson->walking) && (!thisPerson->spinning) && thisPerson->continueAfterWalking) {
restartFunction(thisPerson->continueAfterWalking);
thisPerson->continueAfterWalking = NULL;
}
- thisPerson = thisPerson->next;
}
}
-bool addPerson(int x, int y, int objNum, Persona *p) {
+bool PeopleManager::addPerson(int x, int y, int objNum, Persona *p) {
OnScreenPerson *newPerson = new OnScreenPerson;
if (!checkNew(newPerson))
return false;
- // EASY STUFF
- newPerson->thisType = g_sludge->_objMan->loadObjectType(objNum);
+ // Init newPerson
+ newPerson->thisType = _vm->_objMan->loadObjectType(objNum);
newPerson->scale = 1;
newPerson->extra = 0;
newPerson->continueAfterWalking = NULL;
@@ -839,7 +764,7 @@ bool addPerson(int x, int y, int objNum, Persona *p) {
newPerson->lastUsedAnim = 0;
newPerson->frameTick = 0;
- setFrames(*newPerson, ANI_STAND);
+ newPerson->setFrames(ANI_STAND);
// HEIGHT (BASED ON 1st FRAME OF 1st ANIMATION... INC. SPECIAL CASES)
int fNumSigned = p->animation[0]->frames[0].frameNum;
@@ -854,27 +779,23 @@ bool addPerson(int x, int y, int objNum, Persona *p) {
newPerson->height = p->animation[0]->theSprites->bank.sprites[fNum].yhot + 5;
}
- // NOW ADD IT IN THE RIGHT PLACE
- OnScreenPerson **changethat = &allPeople;
-
- while (((*changethat) != NULL) && ((*changethat)->y < y))
- changethat = &((*changethat)->next);
-
- newPerson->next = (*changethat);
- (*changethat) = newPerson;
+ // NOW INSERT IT IN THE RIGHT PLACE
+ bool inserted = false;
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ if ((*it)->y >= y) {
+ _allPeople->insert(it, newPerson);
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted) {
+ _allPeople->push_back(newPerson);
+ }
return (bool)(newPerson->thisType != NULL);
}
-int timeForAnim(PersonaAnimation *fram) {
- int total = 0;
- for (int a = 0; a < fram->numFrames; a++) {
- total += fram->frames[a].howMany;
- }
- return total;
-}
-
-void animatePerson(int obj, PersonaAnimation *fram) { // Set a new SINGLE animation
+void PeopleManager::animatePerson(int obj, PersonaAnimation *fram) { // Set a new SINGLE animation
OnScreenPerson *moveMe = findPerson(obj);
if (moveMe) {
if (moveMe->continueAfterWalking)
@@ -886,231 +807,127 @@ void animatePerson(int obj, PersonaAnimation *fram) { // Set a new SINGLE anima
}
}
-void animatePerson(int obj, Persona *per) { // Set a new costume
+void PeopleManager::animatePerson(int obj, Persona *per) { // Set a new costume
OnScreenPerson *moveMe = findPerson(obj);
if (moveMe) {
- // if (moveMe->continueAfterWalking) abortFunction (moveMe->continueAfterWalking);
- // moveMe->continueAfterWalking = NULL;
- // moveMe->walking = false;
moveMe->spinning = false;
moveMe->myPersona = per;
rethinkAngle(moveMe);
if (moveMe->walking) {
- setFrames(*moveMe, ANI_WALK);
+ moveMe->setFrames(ANI_WALK);
} else {
- setFrames(*moveMe, ANI_STAND);
+ moveMe->setFrames(ANI_STAND);
}
}
}
-void killAllPeople() {
- OnScreenPerson *killPeople;
- while (allPeople) {
- if (allPeople->continueAfterWalking)
- abortFunction(allPeople->continueAfterWalking);
- allPeople->continueAfterWalking = NULL;
- killPeople = allPeople;
- allPeople = allPeople->next;
- g_sludge->_objMan->removeObjectType(killPeople->thisType);
- delete killPeople;
+void PeopleManager::kill() {
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ if ((*it)->continueAfterWalking)
+ abortFunction((*it)->continueAfterWalking);
+ (*it)->continueAfterWalking = NULL;
+ _vm->_objMan->removeObjectType((*it)->thisType);
+ delete (*it);
+ (*it) = nullptr;
}
+ _allPeople->clear();
}
-void killMostPeople() {
- OnScreenPerson *killPeople;
- OnScreenPerson **lookyHere = &allPeople;
-
- while (*lookyHere) {
- if ((*lookyHere)->extra & EXTRA_NOREMOVE) {
- lookyHere = &(*lookyHere)->next;
- } else {
- killPeople = (*lookyHere);
-
- // Change last pointer to NEXT in the list instead
- (*lookyHere) = killPeople->next;
+void PeopleManager::killMostPeople() {
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ if (!((*it)->extra & EXTRA_NOREMOVE)) {
+ OnScreenPerson *killPeople = (*it);
+ _allPeople->reverse_erase(it);
// Gone from the list... now free some memory
if (killPeople->continueAfterWalking)
abortFunction(killPeople->continueAfterWalking);
killPeople->continueAfterWalking = NULL;
- g_sludge->_objMan->removeObjectType(killPeople->thisType);
+ _vm->_objMan->removeObjectType(killPeople->thisType);
delete killPeople;
}
}
}
-void removeOneCharacter(int i) {
- OnScreenPerson *p = findPerson(i);
-
- if (p) {
- if (overRegion == &personRegion && overRegion->thisType == p->thisType) {
- overRegion = NULL;
- }
-
- if (p->continueAfterWalking)
- abortFunction(p->continueAfterWalking);
- p->continueAfterWalking = NULL;
- OnScreenPerson **killPeople;
-
- for (killPeople = &allPeople; *killPeople != p; killPeople = &((*killPeople)->next)) {
- ;
+void PeopleManager::removeOneCharacter(int i) {
+ OnScreenPerson *removePerson = findPerson(i);
+ if (removePerson) {
+ ScreenRegion *overRegion = _vm->_regionMan->getOverRegion();
+ if (overRegion == _personRegion && overRegion->thisType == removePerson->thisType) {
+ overRegion = nullptr;
}
- *killPeople = p->next;
- g_sludge->_objMan->removeObjectType(p->thisType);
- delete p;
- }
-}
-
-bool saveAnim(PersonaAnimation *p, Common::WriteStream *stream) {
- stream->writeUint16BE(p->numFrames);
- if (p->numFrames) {
- stream->writeUint32LE(p->theSprites->ID);
+ if (removePerson->continueAfterWalking)
+ abortFunction(removePerson->continueAfterWalking);
+ removePerson->continueAfterWalking = NULL;
- for (int a = 0; a < p->numFrames; a++) {
- stream->writeUint32LE(p->frames[a].frameNum);
- stream->writeUint32LE(p->frames[a].howMany);
- stream->writeUint32LE(p->frames[a].noise);
- }
+ _allPeople->remove(removePerson);
+ _vm->_objMan->removeObjectType(removePerson->thisType);
+ delete removePerson;
+ removePerson = nullptr;
}
- return true;
}
-bool loadAnim(PersonaAnimation *p, Common::SeekableReadStream *stream) {
- p->numFrames = stream->readUint16BE();
-
- if (p->numFrames) {
- int a = stream->readUint32LE();
- p->frames = new AnimFrame [p->numFrames];
- if (!checkNew(p->frames))
- return false;
- p->theSprites = g_sludge->_gfxMan->loadBankForAnim(a);
-
- for (a = 0; a < p->numFrames; a++) {
- p->frames[a].frameNum = stream->readUint32LE();
- p->frames[a].howMany = stream->readUint32LE();
- if (ssgVersion >= VERSION(2, 0)) {
- p->frames[a].noise = stream->readUint32LE();
- } else {
- p->frames[a].noise = 0;
- }
- }
- } else {
- p->theSprites = NULL;
- p->frames = NULL;
- }
- return true;
-}
-
-bool saveCostume(Persona *cossy, Common::WriteStream *stream) {
- int a;
- stream->writeUint16BE(cossy->numDirections);
- for (a = 0; a < cossy->numDirections * 3; a++) {
- if (!saveAnim(cossy->animation[a], stream))
- return false;
- }
-// debugCostume ("Saved", cossy);
- return true;
-}
-
-bool loadCostume(Persona *cossy, Common::SeekableReadStream *stream) {
- int a;
- cossy->numDirections = stream->readUint16BE();
- cossy->animation = new PersonaAnimation *[cossy->numDirections * 3];
- if (!checkNew(cossy->animation))
- return false;
- for (a = 0; a < cossy->numDirections * 3; a++) {
- cossy->animation[a] = new PersonaAnimation ;
- if (!checkNew(cossy->animation[a]))
- return false;
-
- if (!loadAnim(cossy->animation[a], stream))
- return false;
- }
-// debugCostume ("Loaded", cossy);
- return true;
-}
-
-bool savePeople(Common::WriteStream *stream) {
- OnScreenPerson *me = allPeople;
- int countPeople = 0, a;
-
- stream->writeSint16LE(scaleHorizon);
- stream->writeSint16LE(scaleDivide);
-
- while (me) {
- countPeople++;
- me = me->next;
- }
-
+bool PeopleManager::savePeople(Common::WriteStream* stream) {
+ stream->writeSint16LE(_scaleHorizon);
+ stream->writeSint16LE(_scaleDivide);
+ int countPeople = _allPeople->size();
stream->writeUint16BE(countPeople);
-
- me = allPeople;
- for (a = 0; a < countPeople; a++) {
-
- stream->writeFloatLE(me->x);
- stream->writeFloatLE(me->y);
-
- saveCostume(me->myPersona, stream);
- saveAnim(me->myAnim, stream);
- stream->writeByte(me->myAnim == me->lastUsedAnim);
-
- stream->writeFloatLE(me->scale);
-
- stream->writeUint16BE(me->extra);
- stream->writeUint16BE(me->height);
- stream->writeUint16BE(me->walkToX);
- stream->writeUint16BE(me->walkToY);
- stream->writeUint16BE(me->thisStepX);
- stream->writeUint16BE(me->thisStepY);
- stream->writeUint16BE(me->frameNum);
- stream->writeUint16BE(me->frameTick);
- stream->writeUint16BE(me->walkSpeed);
- stream->writeUint16BE(me->spinSpeed);
- stream->writeSint16LE(me->floaty);
- stream->writeByte(me->show);
- stream->writeByte(me->walking);
- stream->writeByte(me->spinning);
- if (me->continueAfterWalking) {
+ for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
+ stream->writeFloatLE((*it)->x);
+ stream->writeFloatLE((*it)->y);
+ (*it)->myPersona->save(stream);
+ (*it)->myAnim->save(stream);
+ stream->writeByte((*it)->myAnim == (*it)->lastUsedAnim);
+ stream->writeFloatLE((*it)->scale);
+ stream->writeUint16BE((*it)->extra);
+ stream->writeUint16BE((*it)->height);
+ stream->writeUint16BE((*it)->walkToX);
+ stream->writeUint16BE((*it)->walkToY);
+ stream->writeUint16BE((*it)->thisStepX);
+ stream->writeUint16BE((*it)->thisStepY);
+ stream->writeUint16BE((*it)->frameNum);
+ stream->writeUint16BE((*it)->frameTick);
+ stream->writeUint16BE((*it)->walkSpeed);
+ stream->writeUint16BE((*it)->spinSpeed);
+ stream->writeSint16LE((*it)->floaty);
+ stream->writeByte((*it)->show);
+ stream->writeByte((*it)->walking);
+ stream->writeByte((*it)->spinning);
+ if ((*it)->continueAfterWalking) {
stream->writeByte(1);
- saveFunction(me->continueAfterWalking, stream);
+ saveFunction((*it)->continueAfterWalking, stream);
} else {
stream->writeByte(0);
}
- stream->writeUint16BE(me->direction);
- stream->writeUint16BE(me->angle);
- stream->writeUint16BE(me->angleOffset);
- stream->writeUint16BE(me->wantAngle);
- stream->writeSint16LE(me->directionWhenDoneWalking);
- stream->writeSint16LE(me->inPoly);
- stream->writeSint16LE(me->walkToPoly);
-
- stream->writeByte(me->r);
- stream->writeByte(me->g);
- stream->writeByte(me->b);
- stream->writeByte(me->colourmix);
- stream->writeByte(me->transparency);
-
- g_sludge->_objMan->saveObjectRef(me->thisType, stream);
-
- me = me->next;
+ stream->writeUint16BE((*it)->direction);
+ stream->writeUint16BE((*it)->angle);
+ stream->writeUint16BE((*it)->angleOffset);
+ stream->writeUint16BE((*it)->wantAngle);
+ stream->writeSint16LE((*it)->directionWhenDoneWalking);
+ stream->writeSint16LE((*it)->inPoly);
+ stream->writeSint16LE((*it)->walkToPoly);
+ stream->writeByte((*it)->r);
+ stream->writeByte((*it)->g);
+ stream->writeByte((*it)->b);
+ stream->writeByte((*it)->colourmix);
+ stream->writeByte((*it)->transparency);
+ _vm->_objMan->saveObjectRef((*it)->thisType, stream);
}
return true;
}
-bool loadPeople(Common::SeekableReadStream *stream) {
- OnScreenPerson **pointy = &allPeople;
- OnScreenPerson *me;
+bool PeopleManager::loadPeople(Common::SeekableReadStream *stream) {
+ kill();
- scaleHorizon = stream->readSint16LE();
- scaleDivide = stream->readSint16LE();
+ _scaleHorizon = stream->readSint16LE();
+ _scaleDivide = stream->readSint16LE();
int countPeople = stream->readUint16BE();
int a;
- allPeople = NULL;
for (a = 0; a < countPeople; a++) {
- me = new OnScreenPerson;
+ OnScreenPerson *me = new OnScreenPerson;
if (!checkNew(me))
return false;
@@ -1118,15 +935,15 @@ bool loadPeople(Common::SeekableReadStream *stream) {
if (!checkNew(me->myPersona))
return false;
- me->myAnim = new PersonaAnimation ;
+ me->myAnim = new PersonaAnimation;
if (!checkNew(me->myAnim))
return false;
me->x = stream->readFloatLE();
me->y = stream->readFloatLE();
- loadCostume(me->myPersona, stream);
- loadAnim(me->myAnim, stream);
+ me->myPersona->load(stream);
+ me->myAnim->load(stream);
me->lastUsedAnim = stream->readByte() ? me->myAnim : NULL;
@@ -1173,7 +990,7 @@ bool loadPeople(Common::SeekableReadStream *stream) {
} else {
setMyDrawMode(me, stream->readUint16BE());
}
- me->thisType = g_sludge->_objMan->loadObjectRef(stream);
+ me->thisType = _vm->_objMan->loadObjectRef(stream);
// Anti-aliasing settings
if (ssgVersion >= VERSION(1, 6)) {
@@ -1184,13 +1001,22 @@ bool loadPeople(Common::SeekableReadStream *stream) {
stream->readFloatLE();
}
}
-
- me->next = NULL;
- *pointy = me;
- pointy = &(me->next);
+ _allPeople->push_back(me);
}
-// db ("End of loadPeople");
return true;
}
+void PeopleManager::freeze(FrozenStuffStruct *frozenStuff) {
+ frozenStuff->allPeople = _allPeople;
+ _allPeople = nullptr;
+ _allPeople = new OnScreenPersonList;
+}
+
+void PeopleManager::resotre(FrozenStuffStruct *frozenStuff) {
+ kill();
+ delete _allPeople;
+ _allPeople = nullptr;
+ _allPeople = frozenStuff->allPeople;
+}
+
} // End of namespace Sludge
diff --git a/engines/sludge/people.h b/engines/sludge/people.h
index 95b8e923b6..db22d19ad1 100644
--- a/engines/sludge/people.h
+++ b/engines/sludge/people.h
@@ -26,6 +26,12 @@
namespace Sludge {
+struct FrozenStuffStruct;
+struct LoadedSpriteBank;
+struct ScreenRegion;
+
+class SludgeEngine;
+
struct AnimFrame {
int frameNum, howMany;
int noise;
@@ -41,26 +47,41 @@ struct AnimFrame {
#define EXTRA_RECTANGULAR 64
struct PersonaAnimation {
- struct LoadedSpriteBank *theSprites;
- AnimFrame *frames;
+ LoadedSpriteBank *theSprites;
+ AnimFrame *frames;
int numFrames;
+
+ PersonaAnimation();
+ PersonaAnimation(int num, struct VariableStack *&stacky);
+ PersonaAnimation(PersonaAnimation *orig);
+ ~PersonaAnimation();
+
+ // Setter & getter
+ int getTotalTime();
+
+ // Save & load
+ bool save(Common::WriteStream *stream);
+ bool load(Common::SeekableReadStream *stream);
};
struct Persona {
- PersonaAnimation **animation;
+ PersonaAnimation **animation;
int numDirections;
+
+ // Save & load
+ bool save(Common::WriteStream *stream);
+ bool load(Common::SeekableReadStream *stream);
};
struct OnScreenPerson {
float x, y;
int height, floaty, walkSpeed;
float scale;
- OnScreenPerson *next;
int walkToX, walkToY, thisStepX, thisStepY, inPoly, walkToPoly;
bool walking, spinning;
struct LoadedFunction *continueAfterWalking;
- PersonaAnimation *myAnim;
- PersonaAnimation *lastUsedAnim;
+ PersonaAnimation *myAnim;
+ PersonaAnimation *lastUsedAnim;
Persona *myPersona;
int frameNum, frameTick, angle, wantAngle, angleOffset;
bool show;
@@ -68,64 +89,84 @@ struct OnScreenPerson {
struct ObjectType *thisType;
int extra, spinSpeed;
byte r, g, b, colourmix, transparency;
+
+ void makeTalker();
+ void makeSilent();
+ void setFrames(int a);
};
-// Initialisation and creation
-bool initPeople();
-bool addPerson(int x, int y, int objNum, Persona *p);
-
-// Draw to screen and to backdrop
-void drawPeople();
-void freezePeople(int, int);
-
-// Removalisationisms
-void killAllPeople();
-void killMostPeople();
-void removeOneCharacter(int i);
-
-// Things which affect or use all characters
-OnScreenPerson *findPerson(int v);
-void setScale(int16 h, int16 d);
-
-// Things which affect one character
-void makeTalker(OnScreenPerson &me);
-void makeSilent(OnScreenPerson &me);
-void setShown(bool h, int ob);
-void setDrawMode(int h, int ob);
-void setPersonTransparency(int ob, byte x);
-void setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix);
-
-// Moving 'em
-void movePerson(int x, int y, int objNum);
-bool makeWalkingPerson(int x, int y, int objNum, struct LoadedFunction *func, int di);
-bool forceWalkingPerson(int x, int y, int objNum, struct LoadedFunction *func, int di);
-void jumpPerson(int x, int y, int objNum);
-void walkAllPeople();
-bool turnPersonToFace(int thisNum, int direc);
-bool stopPerson(int o);
-bool floatCharacter(int f, int objNum);
-bool setCharacterWalkSpeed(int f, int objNum);
-
-// Animating 'em
-void animatePerson(int obj, PersonaAnimation *);
-void animatePerson(int obj, Persona *per);
-PersonaAnimation *createPersonaAnim(int num, struct VariableStack *&stacky);
-inline void setBankFile(PersonaAnimation *newP, LoadedSpriteBank *sB) {
- newP->theSprites = sB;
-}
-bool setPersonExtra(int f, int newSetting);
-int timeForAnim(PersonaAnimation *fram);
-PersonaAnimation *copyAnim(PersonaAnimation *orig);
-PersonaAnimation *makeNullAnim();
-void deleteAnim(PersonaAnimation *orig);
-
-// Loading and saving
-bool saveAnim(PersonaAnimation *p, Common::WriteStream *stream);
-bool loadAnim(PersonaAnimation *p, Common::SeekableReadStream *stream);
-bool savePeople(Common::WriteStream *stream);
-bool loadPeople(Common::SeekableReadStream *stream);
-bool saveCostume(Persona *cossy, Common::WriteStream *stream);
-bool loadCostume(Persona *cossy, Common::SeekableReadStream *stream);
+typedef Common::List<OnScreenPerson *> OnScreenPersonList;
+
+class PeopleManager {
+public:
+ PeopleManager(SludgeEngine *vm);
+ ~PeopleManager();
+
+ // Initialisation and creation
+ bool init();
+ bool addPerson(int x, int y, int objNum, Persona *p);
+
+ // Draw to screen and to backdrop
+ void drawPeople();
+ void freezePeople(int, int);
+
+ // Removalisationisms
+ void kill();
+ void killMostPeople();
+ void removeOneCharacter(int i);
+
+ // Things which affect or use all characters
+ OnScreenPerson *findPerson(int v);
+ void setScale(int16 h, int16 d);
+
+ // Things which affect one character
+ void setShown(bool h, int ob);
+ void setDrawMode(int h, int ob);
+ void setPersonTransparency(int ob, byte x);
+ void setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix);
+
+ // Moving 'em
+ void movePerson(int x, int y, int objNum);
+ bool makeWalkingPerson(int x, int y, int objNum, struct LoadedFunction *func, int di);
+ bool forceWalkingPerson(int x, int y, int objNum, struct LoadedFunction *func, int di);
+ void jumpPerson(int x, int y, int objNum);
+ void walkAllPeople();
+ bool turnPersonToFace(int thisNum, int direc);
+ bool stopPerson(int o);
+ bool floatCharacter(int f, int objNum);
+ bool setCharacterWalkSpeed(int f, int objNum);
+
+ // Animating 'em
+ void animatePerson(int obj, PersonaAnimation *);
+ void animatePerson(int obj, Persona *per);
+ bool setPersonExtra(int f, int newSetting);
+
+ // Loading and saving
+ bool savePeople(Common::WriteStream *stream);
+ bool loadPeople(Common::SeekableReadStream *stream);
+
+ // Freeze
+ void freeze(FrozenStuffStruct *frozenStuff);
+ void resotre(FrozenStuffStruct *frozenStuff);
+
+private:
+ ScreenRegion *_personRegion;
+ OnScreenPersonList *_allPeople;
+ int16 _scaleHorizon;
+ int16 _scaleDivide;
+
+ SludgeEngine *_vm;
+
+ void shufflePeople();
+
+ // OnScreenPerson manipulation
+ void turnMeAngle(OnScreenPerson *thisPerson, int direc);
+ void spinStep(OnScreenPerson *thisPerson);
+ void rethinkAngle(OnScreenPerson *thisPerson);
+ void moveAndScale(OnScreenPerson &me, float x, float y);
+ void setMyDrawMode(OnScreenPerson *moveMe, int h);
+ bool walkMe(OnScreenPerson *thisPerson, bool move = true);
+};
} // End of namespace Sludge
diff --git a/engines/sludge/region.cpp b/engines/sludge/region.cpp
index 7593fe4aee..4410951057 100644
--- a/engines/sludge/region.cpp
+++ b/engines/sludge/region.cpp
@@ -33,75 +33,65 @@
namespace Sludge {
-ScreenRegion *allScreenRegions = nullptr;
-ScreenRegion *overRegion = nullptr;
-ScreenRegion *lastRegion = nullptr;
-
-void showBoxes() {
- ScreenRegion*huntRegion = allScreenRegions;
-
- while (huntRegion) {
- g_sludge->_gfxMan->drawVerticalLine(huntRegion->x1, huntRegion->y1, huntRegion->y2);
- g_sludge->_gfxMan->drawVerticalLine(huntRegion->x2, huntRegion->y1, huntRegion->y2);
- g_sludge->_gfxMan->drawHorizontalLine(huntRegion->x1, huntRegion->y1, huntRegion->x2);
- g_sludge->_gfxMan->drawHorizontalLine(huntRegion->x1, huntRegion->y2, huntRegion->x2);
- huntRegion = huntRegion->next;
- }
+RegionManager::RegionManager(SludgeEngine *vm)
+{
+ _vm = vm;
+ _allScreenRegions = new ScreenRegionList;
+ _allScreenRegions->clear();
+ _lastRegion = nullptr;
+ _overRegion = nullptr;
+}
+
+RegionManager::~RegionManager() {
+ kill();
+
+ delete _allScreenRegions;
+ _allScreenRegions = nullptr;
}
-void removeScreenRegion(int objectNum) {
- ScreenRegion **huntRegion = &allScreenRegions;
- ScreenRegion *killMe;
+void RegionManager::showBoxes() {
+ for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
+ g_sludge->_gfxMan->drawVerticalLine((*it)->x1, (*it)->y1, (*it)->y2);
+ g_sludge->_gfxMan->drawVerticalLine((*it)->x2, (*it)->y1, (*it)->y2);
+ g_sludge->_gfxMan->drawHorizontalLine((*it)->x1, (*it)->y1, (*it)->x2);
+ g_sludge->_gfxMan->drawHorizontalLine((*it)->x1, (*it)->y2, (*it)->x2);
+ }
+}
- while (*huntRegion) {
- if ((*huntRegion)->thisType->objectNum == objectNum) {
- killMe = *huntRegion;
- *huntRegion = killMe->next;
+void RegionManager::removeScreenRegion(int objectNum) {
+ for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
+ if ((*it)->thisType->objectNum == objectNum) {
+ ScreenRegion *killMe = *it;
g_sludge->_objMan->removeObjectType(killMe->thisType);
- if (killMe == overRegion)
- overRegion = NULL;
+ if (killMe == _overRegion)
+ _overRegion = nullptr;
delete killMe;
- killMe = NULL;
- } else {
- huntRegion = &((*huntRegion)->next);
+ killMe = nullptr;
+ _allScreenRegions->reverse_erase(it);
}
}
}
-void saveRegions(Common::WriteStream *stream) {
- int numRegions = 0;
- ScreenRegion *thisRegion = allScreenRegions;
- while (thisRegion) {
- thisRegion = thisRegion->next;
- numRegions++;
- }
+void RegionManager::saveRegions(Common::WriteStream *stream) {
+ uint numRegions = _allScreenRegions->size();
stream->writeUint16BE(numRegions);
- thisRegion = allScreenRegions;
- while (thisRegion) {
- stream->writeUint16BE(thisRegion->x1);
- stream->writeUint16BE(thisRegion->y1);
- stream->writeUint16BE(thisRegion->x2);
- stream->writeUint16BE(thisRegion->y2);
- stream->writeUint16BE(thisRegion->sX);
- stream->writeUint16BE(thisRegion->sY);
- stream->writeUint16BE(thisRegion->di);
- g_sludge->_objMan->saveObjectRef(thisRegion->thisType, stream);
-
- thisRegion = thisRegion->next;
+ for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
+ stream->writeUint16BE((*it)->x1);
+ stream->writeUint16BE((*it)->y1);
+ stream->writeUint16BE((*it)->x2);
+ stream->writeUint16BE((*it)->y2);
+ stream->writeUint16BE((*it)->sX);
+ stream->writeUint16BE((*it)->sY);
+ stream->writeUint16BE((*it)->di);
+ g_sludge->_objMan->saveObjectRef((*it)->thisType, stream);
}
}
-void loadRegions(Common::SeekableReadStream *stream) {
+void RegionManager::loadRegions(Common::SeekableReadStream *stream) {
int numRegions = stream->readUint16BE();
-
- ScreenRegion *newRegion;
- ScreenRegion **pointy = &allScreenRegions;
-
while (numRegions--) {
- newRegion = new ScreenRegion;
- *pointy = newRegion;
- pointy = &(newRegion->next);
-
+ ScreenRegion *newRegion = new ScreenRegion;
+ _allScreenRegions->push_back(newRegion);
newRegion->x1 = stream->readUint16BE();
newRegion->y1 = stream->readUint16BE();
newRegion->x2 = stream->readUint16BE();
@@ -111,22 +101,20 @@ void loadRegions(Common::SeekableReadStream *stream) {
newRegion->di = stream->readUint16BE();
newRegion->thisType = g_sludge->_objMan->loadObjectRef(stream);
}
- *pointy = NULL;
}
-void killAllRegions() {
- ScreenRegion *killRegion;
- while (allScreenRegions) {
- killRegion = allScreenRegions;
- allScreenRegions = allScreenRegions->next;
+void RegionManager::kill() {
+ for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
+ ScreenRegion *killRegion = (*it);
g_sludge->_objMan->removeObjectType(killRegion->thisType);
delete killRegion;
}
- overRegion = nullptr;
- lastRegion = nullptr;
+ _allScreenRegions->clear();
+ _overRegion = nullptr;
+ _lastRegion = nullptr;
}
-bool addScreenRegion(int x1, int y1, int x2, int y2, int sX, int sY, int di,
+bool RegionManager::addScreenRegion(int x1, int y1, int x2, int y2, int sX, int sY, int di,
int objectNum) {
ScreenRegion *newRegion = new ScreenRegion;
if (!checkNew(newRegion))
@@ -139,40 +127,51 @@ bool addScreenRegion(int x1, int y1, int x2, int y2, int sX, int sY, int di,
newRegion->sX = sX;
newRegion->sY = sY;
newRegion->thisType = g_sludge->_objMan->loadObjectType(objectNum);
- newRegion->next = allScreenRegions;
- allScreenRegions = newRegion;
- return (bool) (newRegion->thisType != NULL);
+ _allScreenRegions->push_front(newRegion);
+ return (bool) (newRegion->thisType != nullptr);
}
-void getOverRegion() {
+void RegionManager::updateOverRegion() {
int cameraX = g_sludge->_gfxMan->getCamX();
int cameraY = g_sludge->_gfxMan->getCamY();
- ScreenRegion *thisRegion = allScreenRegions;
- while (thisRegion) {
- if ((g_sludge->_evtMan->mouseX() >= thisRegion->x1 - cameraX)
- && (g_sludge->_evtMan->mouseY() >= thisRegion->y1 - cameraY)
- && (g_sludge->_evtMan->mouseX() <= thisRegion->x2 - cameraX)
- && (g_sludge->_evtMan->mouseY() <= thisRegion->y2 - cameraY)) {
- overRegion = thisRegion;
+ for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
+ if ((g_sludge->_evtMan->mouseX() >= (*it)->x1 - cameraX)
+ && (g_sludge->_evtMan->mouseY() >= (*it)->y1 - cameraY)
+ && (g_sludge->_evtMan->mouseX() <= (*it)->x2 - cameraX)
+ && (g_sludge->_evtMan->mouseY() <= (*it)->y2 - cameraY)) {
+ _overRegion = (*it);
return;
}
- thisRegion = thisRegion->next;
}
- overRegion = NULL;
+ _overRegion = nullptr;
return;
}
-ScreenRegion *getRegionForObject(int obj) {
- ScreenRegion *thisRegion = allScreenRegions;
-
- while (thisRegion) {
- if (obj == thisRegion->thisType->objectNum) {
- return thisRegion;
+ScreenRegion *RegionManager::getRegionForObject(int obj) {
+ for (ScreenRegionList::iterator it = _allScreenRegions->begin(); it != _allScreenRegions->end(); ++it) {
+ if (obj == (*it)->thisType->objectNum) {
+ return (*it);
}
- thisRegion = thisRegion->next;
}
- return NULL;
+ return nullptr;
+}
+
+void RegionManager::freeze(FrozenStuffStruct *frozenStuff) {
+ frozenStuff->allScreenRegions = _allScreenRegions;
+ _allScreenRegions = new ScreenRegionList;
+ _overRegion = nullptr;
+}
+
+void RegionManager::resotre(FrozenStuffStruct *frozenStuff) {
+ // kill
+ kill();
+ delete _allScreenRegions;
+ _allScreenRegions = nullptr;
+
+ // restore
+ _allScreenRegions = frozenStuff->allScreenRegions;
+ _overRegion = nullptr;
}
} // End of namespace Sludge
diff --git a/engines/sludge/region.h b/engines/sludge/region.h
index 74294814f6..5f307cc9d0 100644
--- a/engines/sludge/region.h
+++ b/engines/sludge/region.h
@@ -23,24 +23,56 @@
#define SLUDGE_REGION_H
#include "sludge/objtypes.h"
+#include "sludge/freeze.h"
namespace Sludge {
struct ScreenRegion {
int x1, y1, x2, y2, sX, sY, di;
ObjectType *thisType;
- ScreenRegion *next;
};
+typedef Common::List<ScreenRegion *> ScreenRegionList;
-bool addScreenRegion(int x1, int y1, int x2, int y2, int, int, int, int objectNum);
-void getOverRegion();
-ScreenRegion *getRegionForObject(int obj);
-void removeScreenRegion(int objectNum);
-void loadRegions(Common::SeekableReadStream *stream);
-void saveRegions(Common::WriteStream *stream);
-void killAllRegions();
+class RegionManager {
+public:
+ RegionManager(SludgeEngine *vm);
+ ~RegionManager();
-void showBoxes();
+ // Kill
+ void kill();
+
+ // Add & remove region
+ bool addScreenRegion(int x1, int y1, int x2, int y2, int, int, int, int objectNum);
+ void removeScreenRegion(int objectNum);
+
+ // Save & load
+ void loadRegions(Common::SeekableReadStream *stream);
+ void saveRegions(Common::WriteStream *stream);
+
+ // Draw
+ void showBoxes();
+
+ // Setter & getter
+ ScreenRegion *getRegionForObject(int obj);
+ ScreenRegion *getOverRegion() const { return _overRegion; }
+ void setOverRegion(ScreenRegion *newRegion) { _overRegion = newRegion; }
+ void updateOverRegion();
+ bool isRegionChanged() const { return _lastRegion != _overRegion; }
+ void updateLastRegion() { _lastRegion = _overRegion; }
+ void resetOverRegion() { _overRegion = nullptr; }
+ void resetLastRegion() { _lastRegion = nullptr; }
+
+ // Freeze
+ void freeze(FrozenStuffStruct *frozenStuff);
+ void resotre(FrozenStuffStruct *frozenStuff);
+
+private:
+ SludgeEngine *_vm;
+
+ ScreenRegionList *_allScreenRegions;
+ ScreenRegion *_overRegion;
+ ScreenRegion *_lastRegion;
+};
} // End of namespace Sludge
diff --git a/engines/sludge/savedata.cpp b/engines/sludge/savedata.cpp
index 9e2c92395d..b103523f8c 100644
--- a/engines/sludge/savedata.cpp
+++ b/engines/sludge/savedata.cpp
@@ -20,44 +20,45 @@
*
*/
-#include "common/file.h"
+#include "common/savefile.h"
#include "sludge/allfiles.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
+#include "sludge/savedata.h"
#include "sludge/variable.h"
#define LOAD_ERROR "Can't load custom data...\n\n"
namespace Sludge {
-const char UTF8_CHECKER[] = {'U', 'N', '\xef', '\xbf', '\xbd', 'L', 'O', '\xef', '\xbf', '\xbd', 'C', 'K', 'E', 'D', '\0'};
-uint16 saveEncoding = false;
-char encode1 = 0;
-char encode2 = 0;
+const char CustomSaveHelper::UTF8_CHECKER[] = {'U', 'N', '\xef', '\xbf', '\xbd', 'L', 'O', '\xef', '\xbf', '\xbd', 'C', 'K', 'E', 'D', '\0'};
+uint16 CustomSaveHelper::_saveEncoding = false;
+char CustomSaveHelper::_encode1 = 0;
+char CustomSaveHelper::_encode2 = 0;
-void writeStringEncoded(const Common::String &s, Common::WriteStream *stream) {
- int len = s.size();
+void CustomSaveHelper::writeStringEncoded(const Common::String checker, Common::WriteStream *stream) {
+ int len = checker.size();
stream->writeUint16BE(len);
for (int a = 0; a < len; a++) {
- stream->writeByte(s[a] ^ encode1);
- encode1 += encode2;
+ stream->writeByte(checker[a] ^ _encode1);
+ _encode1 += _encode2;
}
}
-Common::String readStringEncoded(Common::File *fp) {
+Common::String CustomSaveHelper::readStringEncoded(Common::SeekableReadStream *fp) {
int len = fp->readUint16BE();
Common::String res = "";
for (int a = 0; a < len; a++) {
- res += (char)(fp->readByte() ^ encode1);
- encode1 += encode2;
+ res += (char)(fp->readByte() ^ _encode1);
+ _encode1 += _encode2;
}
return res;
}
-char *readTextPlain(Common::File *fp) {
+char *CustomSaveHelper::readTextPlain(Common::SeekableReadStream *fp) {
int32 startPos;
uint32 stringSize = 0;
@@ -94,86 +95,66 @@ char *readTextPlain(Common::File *fp) {
return reply;
}
-bool fileToStack(const Common::String &filename, StackHandler *sH) {
-
+bool CustomSaveHelper::fileToStack(const Common::String &filename, StackHandler *sH) {
Variable stringVar;
stringVar.varType = SVT_NULL;
- Common::String checker = saveEncoding ? "[Custom data (encoded)]\r\n" : "[Custom data (ASCII)]\n";
-
- Common::File fd;
-
- if (!fd.open(filename)) {
-#if 0
- char currentDir[1000];
- if (!getcwd(currentDir, 998)) {
- debugOut("Can't get current directory.\n");
- }
-
- if (chdir(gamePath)) {
- debugOut("Error: Failed changing to directory %s\n", gamePath);
- }
+ Common::String checker = _saveEncoding ? "[Custom data (encoded)]\r\n" : "[Custom data (ASCII)]\n";
- if (chdir(currentDir)) {
- debugOut("Error: Failed changing to directory %s\n", currentDir);
- }
+ Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(filename);
- if (!fd.open(filename)) {
- return fatal("No such file", filename);
- }
-#endif
+ if (fp == NULL) {
return fatal("No such file", filename); //TODO: false value
}
- encode1 = (byte)saveEncoding & 255;
- encode2 = (byte)(saveEncoding >> 8);
+ _encode1 = (byte)_saveEncoding & 255;
+ _encode2 = (byte)(_saveEncoding >> 8);
for (uint i = 0; i < checker.size(); ++i) {
- if (fd.readByte() != checker[i]) {
- fd.close();
+ if (fp->readByte() != checker[i]) {
+ delete fp;
return fatal(LOAD_ERROR "This isn't a SLUDGE custom data file:", filename);
}
}
- if (saveEncoding) {
- checker = readStringEncoded(&fd);
+ if (_saveEncoding) {
+ checker = readStringEncoded(fp);
if (checker == UTF8_CHECKER) {
- fd.close();
- return fatal(
- LOAD_ERROR "The current file encoding setting does not match the encoding setting used when this file was created:", filename);
+ delete fp;
+ return fatal(LOAD_ERROR "The current file encoding setting does not match the encoding setting used when this file was created:", filename);
}
}
for (;;) {
- if (saveEncoding) {
- char i = fd.readByte() ^ encode1;
+ if (_saveEncoding) {
+ char i = fp->readByte() ^ _encode1;
- if (fd.eos())
+ if (fp->eos())
break;
switch (i) {
case 0: {
- Common::String g = readStringEncoded(&fd);
- makeTextVar(stringVar, g);
+ Common::String g = readStringEncoded(fp);
+ stringVar.makeTextVar(g);
}
break;
case 1:
- setVariable(stringVar, SVT_INT, fd.readUint32LE());
+ stringVar.setVariable(SVT_INT, fp->readUint32LE());
break;
case 2:
- setVariable(stringVar, SVT_INT, fd.readByte());
+ stringVar.setVariable(SVT_INT, fp->readByte());
break;
default:
fatal(LOAD_ERROR "Corrupt custom data file:", filename);
- fd.close();
+ delete fp;
return false;
}
} else {
- char *line = readTextPlain(&fd);
+ char *line = readTextPlain(fp);
if (!line)
break;
- makeTextVar(stringVar, line);
+ stringVar.makeTextVar(line);
}
if (sH->first == NULL) {
@@ -188,63 +169,66 @@ bool fileToStack(const Common::String &filename, StackHandler *sH) {
sH->last = sH->last->next;
}
}
- fd.close();
+
+ delete fp;
return true;
}
-bool stackToFile(const Common::String &filename, const Variable &from) {
-#if 0
- FILE *fp = fopen(filename, saveEncoding ? "wb" : "wt");
- if (!fp) return fatal("Can't create file", filename);
+bool CustomSaveHelper::stackToFile(const Common::String &filename, const Variable &from) {
+ Common::OutSaveFile *fp = g_system->getSavefileManager()->openForSaving(filename);
+ if (fp == NULL) {
+ return fatal("Can't create file", filename);
+ }
VariableStack *hereWeAre = from.varData.theStack -> first;
- encode1 = (byte)saveEncoding & 255;
- encode2 = (byte)(saveEncoding >> 8);
+ _encode1 = (byte)_saveEncoding & 255;
+ _encode2 = (byte)(_saveEncoding >> 8);
- if (saveEncoding) {
- fprintf(fp, "[Custom data (encoded)]\r\n");
+ if (_saveEncoding) {
+ fp->writeString("[Custom data (encoded)]\r\n");
writeStringEncoded(UTF8_CHECKER, fp);
} else {
- fprintf(fp, "[Custom data (ASCII)]\n");
+ fp->writeString("[Custom data (ASCII)]\n");
}
while (hereWeAre) {
- if (saveEncoding) {
+ if (_saveEncoding) {
switch (hereWeAre -> thisVar.varType) {
case SVT_STRING:
- fputc(encode1, fp);
- writeStringEncoded(hereWeAre -> thisVar.varData.theString, fp);
- break;
+ fp->writeByte(_encode1);
+ writeStringEncoded(hereWeAre -> thisVar.varData.theString, fp);
+ break;
case SVT_INT:
- // Small enough to be stored as a char
- if (hereWeAre -> thisVar.varData.intValue >= 0 && hereWeAre -> thisVar.varData.intValue < 256) {
- fputc(2 ^ encode1, fp);
- fputc(hereWeAre -> thisVar.varData.intValue, fp);
- } else {
- fputc(1 ^ encode1, fp);
- fp->writeUint32LE(hereWeAre -> thisVar.varData.intValue);
- }
- break;
+ // Small enough to be stored as a char
+ if (hereWeAre -> thisVar.varData.intValue >= 0 && hereWeAre -> thisVar.varData.intValue < 256) {
+ fp->writeByte(2 ^ _encode1);
+ fp->writeByte(hereWeAre -> thisVar.varData.intValue);
+ } else {
+ fp->writeByte(1 ^ _encode1);
+ fp->writeUint32LE(hereWeAre -> thisVar.varData.intValue);
+ }
+ break;
default:
- fatal("Can't create an encoded custom data file containing anything other than numbers and strings", filename);
- fclose(fp);
- return false;
+ fatal("Can't create an encoded custom data file containing anything other than numbers and strings", filename);
+ delete fp;
+ return false;
}
} else {
- char *makeSureItsText = getTextFromAnyVar(hereWeAre -> thisVar);
- if (makeSureItsText == NULL) break;
- fprintf(fp, "%s\n", makeSureItsText);
- delete makeSureItsText;
+ Common::String makeSureItsText = hereWeAre->thisVar.getTextFromAnyVar();
+ if (makeSureItsText.empty())
+ break;
+ fp->writeString((makeSureItsText + "\n").c_str());
}
hereWeAre = hereWeAre -> next;
}
- fclose(fp);
-#endif
+
+ delete fp;
+
return true;
}
diff --git a/engines/sludge/savedata.h b/engines/sludge/savedata.h
index 956df93f35..90b093f4ff 100644
--- a/engines/sludge/savedata.h
+++ b/engines/sludge/savedata.h
@@ -24,8 +24,26 @@
namespace Sludge {
-bool fileToStack(const Common::String &filename, StackHandler *sH);
-bool stackToFile(const Common::String &filename, const Variable &from);
+struct StackHandler;
+struct Variable;
+
+class CustomSaveHelper {
+public:
+ static bool fileToStack(const Common::String &filename, StackHandler *sH);
+ static bool stackToFile(const Common::String &filename, const Variable &from);
+
+ static uint16 _saveEncoding;
+
+private:
+ static const char UTF8_CHECKER[];
+ static char _encode1;
+ static char _encode2;
+
+ static void writeStringEncoded(const Common::String checker, Common::WriteStream *stream);
+ static Common::String readStringEncoded(Common::SeekableReadStream *fp);
+ static char *readTextPlain(Common::SeekableReadStream *fp);
+
+};
} // End of namespace Sludge
diff --git a/engines/sludge/sludge.cpp b/engines/sludge/sludge.cpp
index d14f92202f..821539d877 100644
--- a/engines/sludge/sludge.cpp
+++ b/engines/sludge/sludge.cpp
@@ -28,11 +28,15 @@
#include "sludge/cursors.h"
#include "sludge/event.h"
#include "sludge/fonttext.h"
+#include "sludge/floor.h"
#include "sludge/graphics.h"
+#include "sludge/main_loop.h"
+#include "sludge/newfatal.h"
+#include "sludge/people.h"
+#include "sludge/region.h"
#include "sludge/sludge.h"
#include "sludge/sound.h"
#include "sludge/speech.h"
-#include "sludge/main_loop.h"
namespace Sludge {
@@ -68,11 +72,10 @@ SludgeEngine::SludgeEngine(OSystem *syst, const SludgeGameDescription *gameDesc)
launchNext = "";
loadNow = "";
gamePath = "";
- bundleFolder = "";
- fatalMessage = "";
- fatalInfo = "Initialisation error! Something went wrong before we even got started!";
// Init managers
+ _fatalMan = new FatalMsgManager();
+ _peopleMan = new PeopleManager(this);
_resMan = new ResourceManager();
_languageMan = new LanguageManager();
_objMan = new ObjectManager(this);
@@ -82,6 +85,8 @@ SludgeEngine::SludgeEngine(OSystem *syst, const SludgeGameDescription *gameDesc)
_txtMan = new TextManager();
_cursorMan = new CursorManager(this);
_speechMan = new SpeechManager(this);
+ _regionMan = new RegionManager(this);
+ _floorMan = new FloorManager(this);
}
SludgeEngine::~SludgeEngine() {
@@ -122,6 +127,14 @@ SludgeEngine::~SludgeEngine() {
_resMan = nullptr;
delete _speechMan;
_speechMan = nullptr;
+ delete _regionMan;
+ _regionMan = nullptr;
+ delete _peopleMan;
+ _peopleMan = nullptr;
+ delete _floorMan;
+ _floorMan = nullptr;
+ delete _fatalMan;
+ _fatalMan = nullptr;
}
Common::Error SludgeEngine::run() {
diff --git a/engines/sludge/sludge.h b/engines/sludge/sludge.h
index 83c6359f52..692af64071 100644
--- a/engines/sludge/sludge.h
+++ b/engines/sludge/sludge.h
@@ -40,7 +40,11 @@ extern SludgeEngine *g_sludge;
class CursorManager;
class EventManager;
+class FatalMsgManager;
+class FloorManager;
class GraphicsManager;
+class PeopleManager;
+class RegionManager;
class SoundManager;
class SpeechManager;
class TextManager;
@@ -71,9 +75,6 @@ public:
Common::String launchNext;
Common::String loadNow;
Common::String gamePath;
- Common::String bundleFolder;
- Common::String fatalMessage;
- Common::String fatalInfo;
// timer
Timer _timer;
@@ -88,6 +89,10 @@ public:
TextManager *_txtMan;
CursorManager *_cursorMan;
SpeechManager *_speechMan;
+ RegionManager *_regionMan;
+ PeopleManager *_peopleMan;
+ FloorManager *_floorMan;
+ FatalMsgManager *_fatalMan;
SludgeEngine(OSystem *syst, const SludgeGameDescription *gameDesc);
virtual ~SludgeEngine();
diff --git a/engines/sludge/sludger.cpp b/engines/sludge/sludger.cpp
index 812f42fb5d..f9dedf22fc 100644
--- a/engines/sludge/sludger.cpp
+++ b/engines/sludge/sludger.cpp
@@ -32,69 +32,46 @@
#include "sludge/freeze.h"
#include "sludge/floor.h"
#include "sludge/fileset.h"
+#include "sludge/function.h"
#include "sludge/graphics.h"
#include "sludge/imgloader.h"
-#include "sludge/loadsave.h"
#include "sludge/language.h"
#include "sludge/moreio.h"
#include "sludge/newfatal.h"
#include "sludge/objtypes.h"
#include "sludge/people.h"
#include "sludge/region.h"
-#include "sludge/statusba.h"
-#include "sludge/sprites.h"
-#include "sludge/sprbanks.h"
-#include "sludge/sound.h"
+#include "sludge/savedata.h"
#include "sludge/sludge.h"
#include "sludge/sludger.h"
+#include "sludge/sound.h"
#include "sludge/speech.h"
-#include "sludge/transition.h"
+#include "sludge/sprites.h"
+#include "sludge/sprbanks.h"
+#include "sludge/statusba.h"
#include "sludge/variable.h"
#include "sludge/version.h"
#include "sludge/zbuffer.h"
namespace Sludge {
-extern int dialogValue;
+extern int numBIFNames;
+extern Common::String *allBIFNames;
+extern int numUserFunc;
+extern Common::String *allUserFunc;
-int numBIFNames = 0;
-Common::String *allBIFNames;
-int numUserFunc = 0;
-Common::String *allUserFunc = NULL;
-int numResourceNames = 0;
-Common::String *allResourceNames = NULL;
int selectedLanguage = 0;
int gameVersion;
FILETIME fileTime;
-bool captureAllKeys = false;
-
-byte brightnessLevel = 255;
-
-extern LoadedFunction *saverFunc;
-
-LoadedFunction *allRunningFunctions = NULL;
-VariableStack *noStack = NULL;
-Variable *globalVars;
int numGlobals = 0;
-extern SpritePalette pastePalette;
extern Variable *launchResult;
-extern int lastFramesPerSecond, thumbWidth, thumbHeight;
+extern Variable *globalVars;
+extern VariableStack *noStack;
extern bool allowAnyFilename;
-extern byte fadeMode;
-extern uint16 saveEncoding;
-
-const char *sludgeText[] = { "?????", "RETURN", "BRANCH", "BR_ZERO",
- "SET_GLOBAL", "SET_LOCAL", "LOAD_GLOBAL", "LOAD_LOCAL", "PLUS", "MINUS",
- "MULT", "DIVIDE", "AND", "OR", "EQUALS", "NOT_EQ", "MODULUS",
- "LOAD_VALUE", "LOAD_BUILT", "LOAD_FUNC", "CALLIT", "LOAD_STRING",
- "LOAD_FILE", "LOAD_OBJTYPE", "NOT", "LOAD_NULL", "STACK_PUSH",
- "LESSTHAN", "MORETHAN", "NEGATIVE", "U", "LESS_EQUAL", "MORE_EQUAL",
- "INC_LOCAL", "DEC_LOCAL", "INC_GLOBAL", "DEC_GLOBAL", "INDEXSET",
- "INDEXGET", "INC_INDEX", "DEC_INDEX", "QUICK_PUSH" };
Common::File *openAndVerify(const Common::String &filename, char extra1, char extra2,
const char *er, int &fileVersion) {
@@ -146,15 +123,15 @@ Common::File *openAndVerify(const Common::String &filename, char extra1, char ex
}
void initSludge() {
+ g_sludge->_timer.reset();
g_sludge->_languageMan->init();
g_sludge->_gfxMan->init();
g_sludge->_resMan->init();
- initPeople();
- initFloor();
+ g_sludge->_peopleMan->init();
+ g_sludge->_floorMan->init();
g_sludge->_objMan->init();
g_sludge->_speechMan->init();
initStatusBar();
- resetRandW();
g_sludge->_evtMan->init();
g_sludge->_txtMan->init();
g_sludge->_cursorMan->init();
@@ -164,27 +141,23 @@ void initSludge() {
g_sludge->_soundMan->initSoundStuff();
}
+ CustomSaveHelper::_saveEncoding = false;
+
// global variables
numGlobals = 0;
launchResult = nullptr;
- lastFramesPerSecond = -1;
- thumbWidth = thumbHeight = 0;
allowAnyFilename = true;
- captureAllKeys = false;
noStack = nullptr;
numBIFNames = numUserFunc = 0;
allUserFunc = allBIFNames = nullptr;
- brightnessLevel = 255;
- fadeMode = 2;
- saveEncoding = false;
}
void killSludge() {
killAllFunctions();
- killAllPeople();
- killAllRegions();
- setFloorNull();
+ g_sludge->_peopleMan->kill();
+ g_sludge->_regionMan->kill();
+ g_sludge->_floorMan->kill();
g_sludge->_speechMan->kill();
g_sludge->_languageMan->kill();
g_sludge->_gfxMan->kill();
@@ -196,7 +169,6 @@ void killSludge() {
g_sludge->_cursorMan->kill();
// global variables
- pastePalette.reset();
numBIFNames = numUserFunc = 0;
delete []allUserFunc;
delete []allBIFNames;
@@ -205,7 +177,6 @@ void killSludge() {
bool initSludge(const Common::String &filename) {
initSludge();
- int a = 0;
Common::File *fp = openAndVerify(filename, 'G', 'E', ERROR_BAD_HEADER, gameVersion);
if (!fp)
return false;
@@ -232,19 +203,9 @@ bool initSludge(const Common::String &filename) {
allUserFunc[fn].clear();
allUserFunc[fn] = readString(fp);
}
- if (gameVersion >= VERSION(1, 3)) {
- numResourceNames = fp->readUint16BE();
- debugC(2, kSludgeDebugDataLoad, "numResourceNames %i",
- numResourceNames);
- allResourceNames = new Common::String[numResourceNames];
- if (!checkNew(allResourceNames))
- return false;
- for (int fn = 0; fn < numResourceNames; fn++) {
- allResourceNames[fn].clear();
- allResourceNames[fn] = readString(fp);
- debugC(2, kSludgeDebugDataLoad, "Resource %i: %s", fn, allResourceNames[fn].c_str());
- }
+ if (gameVersion >= VERSION(1, 3)) {
+ g_sludge->_resMan->readResourceNames(fp);
}
}
@@ -256,7 +217,7 @@ bool initSludge(const Common::String &filename) {
int specialSettings = fp->readByte();
debugC(2, kSludgeDebugDataLoad, "specialSettings : %i", specialSettings);
- g_sludge->_timer.setDesiredfps(1000 / fp->readByte());
+ g_sludge->_timer.setDesiredFPS(1000 / fp->readByte());
readString(fp); // Unused - was used for registration purposes.
@@ -314,8 +275,6 @@ bool initSludge(const Common::String &filename) {
globalVars = new Variable[numGlobals];
if (!checkNew(globalVars))
return false;
- for (a = 0; a < numGlobals; a++)
- initVarNew(globalVars[a]);
// Get language selected by user
g_sludge->_resMan->setData(fp);
@@ -334,7 +293,7 @@ void displayBase() {
g_sludge->_gfxMan->clear(); // Clear screen
g_sludge->_gfxMan->drawBackDrop();// Draw Backdrop
g_sludge->_gfxMan->drawZBuffer(g_sludge->_gfxMan->getCamX(), g_sludge->_gfxMan->getCamY(), false);
- drawPeople();// Then add any moving characters...
+ g_sludge->_peopleMan->drawPeople();// Then add any moving characters...
g_sludge->_gfxMan->displaySpriteLayers();
}
@@ -344,712 +303,6 @@ void sludgeDisplay() {
drawStatusBar();
g_sludge->_cursorMan->displayCursor();
g_sludge->_gfxMan->display();
- if (brightnessLevel < 255) fixBrightness();// This is for transitionLevel special effects
-}
-
-void pauseFunction(LoadedFunction *fun) {
- LoadedFunction **huntAndDestroy = &allRunningFunctions;
- while (*huntAndDestroy) {
- if (fun == *huntAndDestroy) {
- (*huntAndDestroy) = (*huntAndDestroy)->next;
- fun->next = NULL;
- } else {
- huntAndDestroy = &(*huntAndDestroy)->next;
- }
- }
-}
-
-void restartFunction(LoadedFunction *fun) {
- fun->next = allRunningFunctions;
- allRunningFunctions = fun;
-}
-
-void killSpeechTimers() {
- LoadedFunction *thisFunction = allRunningFunctions;
-
- while (thisFunction) {
- if (thisFunction->freezerLevel == 0 && thisFunction->isSpeech
- && thisFunction->timeLeft) {
- thisFunction->timeLeft = 0;
- thisFunction->isSpeech = false;
- }
- thisFunction = thisFunction->next;
- }
-
- g_sludge->_speechMan->kill();
-}
-
-void completeTimers() {
- LoadedFunction *thisFunction = allRunningFunctions;
-
- while (thisFunction) {
- if (thisFunction->freezerLevel == 0)
- thisFunction->timeLeft = 0;
- thisFunction = thisFunction->next;
- }
-}
-
-void finishFunction(LoadedFunction *fun) {
- int a;
-
- pauseFunction(fun);
- if (fun->stack)
- fatal(ERROR_NON_EMPTY_STACK);
- delete[] fun->compiledLines;
- for (a = 0; a < fun->numLocals; a++)
- unlinkVar(fun->localVars[a]);
- delete[] fun->localVars;
- unlinkVar(fun->reg);
- delete fun;
- fun = NULL;
-}
-
-void abortFunction(LoadedFunction *fun) {
- int a;
-
- pauseFunction(fun);
- while (fun->stack)
- trimStack(fun->stack);
- delete []fun->compiledLines;
- for (a = 0; a < fun->numLocals; a++)
- unlinkVar(fun->localVars[a]);
- delete []fun->localVars;
- unlinkVar(fun->reg);
- if (fun->calledBy)
- abortFunction(fun->calledBy);
- delete fun;
- fun = NULL;
-}
-
-int cancelAFunction(int funcNum, LoadedFunction *myself, bool &killedMyself) {
- int n = 0;
- killedMyself = false;
-
- LoadedFunction *fun = allRunningFunctions;
- while (fun) {
- if (fun->originalNumber == funcNum) {
- fun->cancelMe = true;
- n++;
- if (fun == myself)
- killedMyself = true;
- }
- fun = fun->next;
- }
- return n;
}
-void freezeSubs() {
- LoadedFunction *thisFunction = allRunningFunctions;
-
- while (thisFunction) {
- if (thisFunction->unfreezable) {
- //msgBox ("SLUDGE debugging bollocks!", "Trying to freeze an unfreezable function!");
- } else {
- thisFunction->freezerLevel++;
- }
- thisFunction = thisFunction->next;
- }
-}
-
-void unfreezeSubs() {
- LoadedFunction *thisFunction = allRunningFunctions;
-
- while (thisFunction) {
- if (thisFunction->freezerLevel)
- thisFunction->freezerLevel--;
- thisFunction = thisFunction->next;
- }
-}
-
-bool continueFunction(LoadedFunction *fun) {
- bool keepLooping = true;
- bool advanceNow;
- uint param;
- sludgeCommand com;
-
- if (fun->cancelMe) {
- abortFunction(fun);
- return true;
- }
-
- while (keepLooping) {
- advanceNow = true;
- debugC(1, kSludgeDebugStackMachine, "Executing command line %i : ", fun->runThisLine);
- param = fun->compiledLines[fun->runThisLine].param;
- com = fun->compiledLines[fun->runThisLine].theCommand;
-
- if (numBIFNames) {
- setFatalInfo((fun->originalNumber < numUserFunc) ? allUserFunc[fun->originalNumber] : "Unknown user function", (com < numSludgeCommands) ? sludgeText[com] : ERROR_UNKNOWN_MCODE);
- }
-
- switch (com) {
- case SLU_RETURN:
- if (fun->calledBy) {
- LoadedFunction *returnTo = fun->calledBy;
- if (fun->returnSomething)
- copyVariable(fun->reg, returnTo->reg);
- finishFunction(fun);
- fun = returnTo;
- restartFunction(fun);
- } else {
- finishFunction(fun);
- advanceNow = false; // So we don't do anything else with "fun"
- keepLooping = false; // So we drop out of the loop
- }
- break;
-
- case SLU_CALLIT:
- switch (fun->reg.varType) {
- case SVT_FUNC:
- pauseFunction(fun);
- if (numBIFNames)
- setFatalInfo(
- (fun->originalNumber < numUserFunc) ?
- allUserFunc[fun->originalNumber] :
- "Unknown user function",
- (fun->reg.varData.intValue < numUserFunc) ?
- allUserFunc[fun->reg.varData.intValue] :
- "Unknown user function");
-
- if (!startNewFunctionNum(fun->reg.varData.intValue, param, fun,
- fun->stack))
- return false;
- fun = allRunningFunctions;
- advanceNow = false; // So we don't do anything else with "fun"
- break;
-
- case SVT_BUILT: {
- debugC(1, kSludgeDebugStackMachine, "Built-in init value: %i",
- fun->reg.varData.intValue);
- BuiltReturn br = callBuiltIn(fun->reg.varData.intValue, param,
- fun);
-
- switch (br) {
- case BR_ERROR:
- return fatal(
- "Unknown error. This shouldn't happen. Please notify the SLUDGE developers.");
-
- case BR_PAUSE:
- pauseFunction(fun);
- // fall through
-
- case BR_KEEP_AND_PAUSE:
- keepLooping = false;
- break;
-
- case BR_ALREADY_GONE:
- keepLooping = false;
- advanceNow = false;
- break;
-
- case BR_CALLAFUNC: {
- int i = fun->reg.varData.intValue;
- setVariable(fun->reg, SVT_INT, 1);
- pauseFunction(fun);
- if (numBIFNames)
- setFatalInfo(
- (fun->originalNumber < numUserFunc) ?
- allUserFunc[fun->originalNumber] :
- "Unknown user function",
- (i < numUserFunc) ?
- allUserFunc[i] :
- "Unknown user function");
- if (!startNewFunctionNum(i, 0, fun, noStack, false))
- return false;
- fun = allRunningFunctions;
- advanceNow = false; // So we don't do anything else with "fun"
- }
- break;
-
- default:
- break;
- }
- }
- break;
-
- default:
- return fatal(ERROR_CALL_NONFUNCTION);
- }
- break;
-
- // These all grab things and shove 'em into the register
-
- case SLU_LOAD_NULL:
- setVariable(fun->reg, SVT_NULL, 0);
- break;
-
- case SLU_LOAD_FILE:
- setVariable(fun->reg, SVT_FILE, param);
- break;
-
- case SLU_LOAD_VALUE:
- setVariable(fun->reg, SVT_INT, param);
- break;
-
- case SLU_LOAD_LOCAL:
- if (!copyVariable(fun->localVars[param], fun->reg))
- return false;
- break;
-
- case SLU_AND:
- setVariable(fun->reg, SVT_INT,
- getBoolean(fun->reg) && getBoolean(fun->stack->thisVar));
- trimStack(fun->stack);
- break;
-
- case SLU_OR:
- setVariable(fun->reg, SVT_INT,
- getBoolean(fun->reg) || getBoolean(fun->stack->thisVar));
- trimStack(fun->stack);
- break;
-
- case SLU_LOAD_FUNC:
- setVariable(fun->reg, SVT_FUNC, param);
- break;
-
- case SLU_LOAD_BUILT:
- setVariable(fun->reg, SVT_BUILT, param);
- break;
-
- case SLU_LOAD_OBJTYPE:
- setVariable(fun->reg, SVT_OBJTYPE, param);
- break;
-
- case SLU_UNREG:
- if (dialogValue != 1)
- fatal(ERROR_HACKER);
- break;
-
- case SLU_LOAD_STRING:
- if (!loadStringToVar(fun->reg, param)) {
- return false;
- }
- break;
-
- case SLU_INDEXGET:
- case SLU_INCREMENT_INDEX:
- case SLU_DECREMENT_INDEX:
- switch (fun->stack->thisVar.varType) {
- case SVT_NULL:
- if (com == SLU_INDEXGET) {
- setVariable(fun->reg, SVT_NULL, 0);
- trimStack(fun->stack);
- } else {
- return fatal(ERROR_INCDEC_UNKNOWN);
- }
- break;
-
- case SVT_FASTARRAY:
- case SVT_STACK:
- if (fun->stack->thisVar.varData.theStack->first == NULL) {
- return fatal(ERROR_INDEX_EMPTY);
- } else {
- int ii;
- if (!getValueType(ii, SVT_INT, fun->reg))
- return false;
- Variable *grab =
- (fun->stack->thisVar.varType == SVT_FASTARRAY) ?
- fastArrayGetByIndex(
- fun->stack->thisVar.varData.fastArray,
- ii) :
- stackGetByIndex(
- fun->stack->thisVar.varData.theStack->first,
- ii);
-
- trimStack(fun->stack);
-
- if (!grab) {
- setVariable(fun->reg, SVT_NULL, 0);
- } else {
- int kk;
- switch (com) {
- case SLU_INCREMENT_INDEX:
- if (!getValueType(kk, SVT_INT, *grab))
- return false;
- setVariable(fun->reg, SVT_INT, kk);
- grab->varData.intValue = kk + 1;
- break;
-
- case SLU_DECREMENT_INDEX:
- if (!getValueType(kk, SVT_INT, *grab))
- return false;
- setVariable(fun->reg, SVT_INT, kk);
- grab->varData.intValue = kk - 1;
- break;
-
- default:
- if (!copyVariable(*grab, fun->reg))
- return false;
- }
- }
- }
- break;
-
- default:
- return fatal(ERROR_INDEX_NONSTACK);
- }
- break;
-
- case SLU_INDEXSET:
- switch (fun->stack->thisVar.varType) {
- case SVT_STACK:
- if (fun->stack->thisVar.varData.theStack->first == NULL) {
- return fatal(ERROR_INDEX_EMPTY);
- } else {
- int ii;
- if (!getValueType(ii, SVT_INT, fun->reg))
- return false;
- if (!stackSetByIndex(
- fun->stack->thisVar.varData.theStack->first, ii,
- fun->stack->next->thisVar)) {
- return false;
- }
- trimStack(fun->stack);
- trimStack(fun->stack);
- }
- break;
-
- case SVT_FASTARRAY: {
- int ii;
- if (!getValueType(ii, SVT_INT, fun->reg))
- return false;
- Variable *v = fastArrayGetByIndex(
- fun->stack->thisVar.varData.fastArray, ii);
- if (v == NULL)
- return fatal("Not within bounds of fast array.");
- if (!copyVariable(fun->stack->next->thisVar, *v))
- return false;
- trimStack(fun->stack);
- trimStack(fun->stack);
- }
- break;
-
- default:
- return fatal(ERROR_INDEX_NONSTACK);
- }
- break;
-
- // What can we do with the register? Well, we can copy it into a local
- // variable, a global or onto the stack...
-
- case SLU_INCREMENT_LOCAL: {
- int ii;
- if (!getValueType(ii, SVT_INT, fun->localVars[param]))
- return false;
- setVariable(fun->reg, SVT_INT, ii);
- setVariable(fun->localVars[param], SVT_INT, ii + 1);
- }
- break;
-
- case SLU_INCREMENT_GLOBAL: {
- int ii;
- if (!getValueType(ii, SVT_INT, globalVars[param]))
- return false;
- setVariable(fun->reg, SVT_INT, ii);
- setVariable(globalVars[param], SVT_INT, ii + 1);
- }
- break;
-
- case SLU_DECREMENT_LOCAL: {
- int ii;
- if (!getValueType(ii, SVT_INT, fun->localVars[param]))
- return false;
- setVariable(fun->reg, SVT_INT, ii);
- setVariable(fun->localVars[param], SVT_INT, ii - 1);
- }
- break;
-
- case SLU_DECREMENT_GLOBAL: {
- int ii;
- if (!getValueType(ii, SVT_INT, globalVars[param]))
- return false;
- setVariable(fun->reg, SVT_INT, ii);
- setVariable(globalVars[param], SVT_INT, ii - 1);
- }
- break;
-
- case SLU_SET_LOCAL:
- if (!copyVariable(fun->reg, fun->localVars[param]))
- return false;
- break;
-
- case SLU_SET_GLOBAL:
-// newDebug (" Copying TO global variable", param);
-// newDebug (" Global type at the moment", globalVars[param].varType);
- if (!copyVariable(fun->reg, globalVars[param]))
- return false;
-// newDebug (" New type", globalVars[param].varType);
- break;
-
- case SLU_LOAD_GLOBAL:
-// newDebug (" Copying FROM global variable", param);
-// newDebug (" Global type at the moment", globalVars[param].varType);
- if (!copyVariable(globalVars[param], fun->reg))
- return false;
- break;
-
- case SLU_STACK_PUSH:
- if (!addVarToStack(fun->reg, fun->stack))
- return false;
- break;
-
- case SLU_QUICK_PUSH:
- if (!addVarToStackQuick(fun->reg, fun->stack))
- return false;
- break;
-
- case SLU_NOT:
- setVariable(fun->reg, SVT_INT, !getBoolean(fun->reg));
- break;
-
- case SLU_BR_ZERO:
- if (!getBoolean(fun->reg)) {
- advanceNow = false;
- fun->runThisLine = param;
- }
- break;
-
- case SLU_BRANCH:
- advanceNow = false;
- fun->runThisLine = param;
- break;
-
- case SLU_NEGATIVE: {
- int i;
- if (!getValueType(i, SVT_INT, fun->reg))
- return false;
- setVariable(fun->reg, SVT_INT, -i);
- }
- break;
-
- // All these things rely on there being somet' on the stack
-
- case SLU_MULT:
- case SLU_PLUS:
- case SLU_MINUS:
- case SLU_MODULUS:
- case SLU_DIVIDE:
- case SLU_EQUALS:
- case SLU_NOT_EQ:
- case SLU_LESSTHAN:
- case SLU_MORETHAN:
- case SLU_LESS_EQUAL:
- case SLU_MORE_EQUAL:
- if (fun->stack) {
- int firstValue, secondValue;
-
- switch (com) {
- case SLU_PLUS:
- addVariablesInSecond(fun->stack->thisVar, fun->reg);
- trimStack(fun->stack);
- break;
-
- case SLU_EQUALS:
- compareVariablesInSecond(fun->stack->thisVar, fun->reg);
- trimStack(fun->stack);
- break;
-
- case SLU_NOT_EQ:
- compareVariablesInSecond(fun->stack->thisVar, fun->reg);
- trimStack(fun->stack);
- fun->reg.varData.intValue = !fun->reg.varData.intValue;
- break;
-
- default:
- if (!getValueType(firstValue, SVT_INT, fun->stack->thisVar))
- return false;
- if (!getValueType(secondValue, SVT_INT, fun->reg))
- return false;
- trimStack(fun->stack);
-
- switch (com) {
- case SLU_MULT:
- setVariable(fun->reg, SVT_INT,
- firstValue * secondValue);
- break;
-
- case SLU_MINUS:
- setVariable(fun->reg, SVT_INT,
- firstValue - secondValue);
- break;
-
- case SLU_MODULUS:
- setVariable(fun->reg, SVT_INT,
- firstValue % secondValue);
- break;
-
- case SLU_DIVIDE:
- setVariable(fun->reg, SVT_INT,
- firstValue / secondValue);
- break;
-
- case SLU_LESSTHAN:
- setVariable(fun->reg, SVT_INT,
- firstValue < secondValue);
- break;
-
- case SLU_MORETHAN:
- setVariable(fun->reg, SVT_INT,
- firstValue > secondValue);
- break;
-
- case SLU_LESS_EQUAL:
- setVariable(fun->reg, SVT_INT,
- firstValue <= secondValue);
- break;
-
- case SLU_MORE_EQUAL:
- setVariable(fun->reg, SVT_INT,
- firstValue >= secondValue);
- break;
-
- default:
- break;
- }
- }
- } else {
- return fatal(ERROR_NOSTACK);
- }
- break;
-
- default:
- return fatal(ERROR_UNKNOWN_CODE);
- }
-
- if (advanceNow)
- fun->runThisLine++;
-
- }
- return true;
-}
-
-bool runSludge() {
-
- LoadedFunction *thisFunction = allRunningFunctions;
- LoadedFunction *nextFunction;
-
- while (thisFunction) {
- nextFunction = thisFunction->next;
-
- if (!thisFunction->freezerLevel) {
- if (thisFunction->timeLeft) {
- if (thisFunction->timeLeft < 0) {
- if (!g_sludge->_soundMan->stillPlayingSound(
- g_sludge->_speechMan->getLastSpeechSound())) {
- thisFunction->timeLeft = 0;
- }
- } else if (!--(thisFunction->timeLeft)) {
- }
- } else {
- if (thisFunction->isSpeech) {
- thisFunction->isSpeech = false;
- g_sludge->_speechMan->kill();
- }
- if (!continueFunction(thisFunction))
- return false;
- }
- }
-
- thisFunction = nextFunction;
- }
-
- if (!g_sludge->loadNow.empty()) {
- if (g_sludge->loadNow[0] == ':') {
- saveGame(g_sludge->loadNow.c_str() + 1);
- setVariable(saverFunc->reg, SVT_INT, 1);
- } else {
- if (!loadGame(g_sludge->loadNow))
- return false;
- }
- g_sludge->loadNow.clear();
- }
-
- return true;
-}
-
-void killAllFunctions() {
- while (allRunningFunctions)
- finishFunction(allRunningFunctions);
-}
-
-bool loadFunctionCode(LoadedFunction *newFunc) {
- uint numLines, numLinesRead;
-
- if (!g_sludge->_resMan->openSubSlice(newFunc->originalNumber))
- return false;
-
- debugC(3, kSludgeDebugDataLoad, "Load function code");
-
- Common::SeekableReadStream *readStream = g_sludge->_resMan->getData();
- newFunc->unfreezable = readStream->readByte();
- numLines = readStream->readUint16BE();
- debugC(3, kSludgeDebugDataLoad, "numLines: %i", numLines);
- newFunc->numArgs = readStream->readUint16BE();
- debugC(3, kSludgeDebugDataLoad, "numArgs: %i", newFunc->numArgs);
- newFunc->numLocals = readStream->readUint16BE();
- debugC(3, kSludgeDebugDataLoad, "numLocals: %i", newFunc->numLocals);
- newFunc->compiledLines = new LineOfCode[numLines];
- if (!checkNew(newFunc->compiledLines))
- return false;
-
- for (numLinesRead = 0; numLinesRead < numLines; numLinesRead++) {
- newFunc->compiledLines[numLinesRead].theCommand = (sludgeCommand)readStream->readByte();
- newFunc->compiledLines[numLinesRead].param = readStream->readUint16BE();
- debugC(3, kSludgeDebugDataLoad, "command line %i: %i", numLinesRead,
- newFunc->compiledLines[numLinesRead].theCommand);
- }
- g_sludge->_resMan->finishAccess();
-
- // Now we need to reserve memory for the local variables
- newFunc->localVars = new Variable[newFunc->numLocals];
- if (!checkNew(newFunc->localVars))
- return false;
- for (int a = 0; a < newFunc->numLocals; a++) {
- initVarNew(newFunc->localVars[a]);
- }
-
- return true;
-}
-
-int startNewFunctionNum(uint funcNum, uint numParamsExpected,
- LoadedFunction *calledBy, VariableStack *&vStack, bool returnSommet) {
- LoadedFunction *newFunc = new LoadedFunction;
- checkNew(newFunc);
- newFunc->originalNumber = funcNum;
-
- loadFunctionCode(newFunc);
-
- if (newFunc->numArgs != (int) numParamsExpected)
- return fatal("Wrong number of parameters!");
- if (newFunc->numArgs > newFunc->numLocals)
- return fatal("More arguments than local Variable space!");
-
- // Now, lets copy the parameters from the calling function's stack...
-
- while (numParamsExpected) {
- numParamsExpected--;
- if (vStack == NULL)
- return fatal(
- "Corrupted file!The stack's empty and there were still parameters expected");
- copyVariable(vStack->thisVar, newFunc->localVars[numParamsExpected]);
- trimStack(vStack);
- }
-
- newFunc->cancelMe = false;
- newFunc->timeLeft = 0;
- newFunc->returnSomething = returnSommet;
- newFunc->calledBy = calledBy;
- newFunc->stack = NULL;
- newFunc->freezerLevel = 0;
- newFunc->runThisLine = 0;
- newFunc->isSpeech = 0;
- initVarNew(newFunc->reg);
-
- restartFunction(newFunc);
- return 1;
-}
-
-int lastFramesPerSecond = -1;
-int thisFramesPerSecond = -1;
-
} // End of namespace Sludge
diff --git a/engines/sludge/sludger.h b/engines/sludge/sludger.h
index 8f554f83cb..8efdfa62f2 100644
--- a/engines/sludge/sludger.h
+++ b/engines/sludge/sludger.h
@@ -22,12 +22,7 @@
#ifndef SLUDGER_H
#define SLUDGER_H
-#include "common/file.h"
-
#include "sludge/allfiles.h"
-#include "sludge/variable.h"
-#include "sludge/csludge.h"
-#include "sludge/language.h"
namespace Sludge {
@@ -36,52 +31,15 @@ typedef struct _FILETIME {
uint32 dwHighDateTime;
} FILETIME;
-struct Variable;
-struct VariableStack;
-
-struct LineOfCode {
- sludgeCommand theCommand;
- int32 param;
-};
-
-struct LoadedFunction {
- int originalNumber;
- LineOfCode *compiledLines;
- int numLocals, timeLeft, numArgs;
- Variable *localVars;
- VariableStack *stack;
- Variable reg;
- uint runThisLine;
- LoadedFunction *calledBy;
- LoadedFunction *next;
- bool returnSomething, isSpeech, unfreezable, cancelMe;
- byte freezerLevel;
-};
-
bool initSludge(const Common::String &);
-bool runSludge();
-
void initSludge();
void killSludge();
void displayBase();
void sludgeDisplay();
-int startNewFunctionNum(uint, uint, LoadedFunction *, VariableStack*&, bool = true);
-bool handleInput();
-void restartFunction(LoadedFunction *fun);
-bool loadFunctionCode(LoadedFunction *newFunc);
-void killAllFunctions();
-void finishFunction(LoadedFunction *fun);
-void abortFunction(LoadedFunction *fun);
Common::File *openAndVerify(const Common::String &filename, char extra1, char extra2, const char *er, int &fileVersion);
-void freezeSubs();
-void unfreezeSubs();
-void completeTimers();
-void killSpeechTimers();
-int cancelAFunction(int funcNum, LoadedFunction *myself, bool &killedMyself);
-
} // End of namespace Sludge
#endif
diff --git a/engines/sludge/sound.cpp b/engines/sludge/sound.cpp
index 306fd49b4e..25b239c191 100644
--- a/engines/sludge/sound.cpp
+++ b/engines/sludge/sound.cpp
@@ -402,7 +402,7 @@ bool SoundManager::getSoundCacheStack(StackHandler *sH) {
for (int a = 0; a < MAX_SAMPLES; a++) {
if (_soundCache[a].fileLoaded != -1) {
- setVariable(newFileHandle, SVT_FILE, _soundCache[a].fileLoaded);
+ newFileHandle.setVariable(SVT_FILE, _soundCache[a].fileLoaded);
if (!addVarToStackQuick(newFileHandle, sH->first))
return false;
if (sH->last == NULL)
diff --git a/engines/sludge/speech.cpp b/engines/sludge/speech.cpp
index 1d342a1b65..9c02eda5a6 100644
--- a/engines/sludge/speech.cpp
+++ b/engines/sludge/speech.cpp
@@ -45,7 +45,7 @@ void SpeechManager::init() {
_speech = new SpeechStruct;
if (checkNew(_speech)) {
_speech->currentTalker = NULL;
- _speech->allSpeech = NULL;
+ _speech->allSpeech.clear();
_speech->speechY = 0;
_speech->lastFile = -1;
}
@@ -61,20 +61,20 @@ void SpeechManager::kill() {
}
if (_speech->currentTalker) {
- makeSilent(*(_speech->currentTalker));
- _speech->currentTalker = NULL;
+ _speech->currentTalker->makeSilent();
+ _speech->currentTalker = nullptr;
}
- SpeechLine *killMe;
- while (_speech->allSpeech) {
- killMe = _speech->allSpeech;
- _speech->allSpeech = _speech->allSpeech->next;
+ for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
+ SpeechLine *killMe = *it;
delete killMe;
+ killMe = nullptr;
}
+ _speech->allSpeech.clear();
}
void SpeechManager::setObjFontColour(ObjectType *t) {
- setFontColour(_speech->talkCol, t->r, t->g, t->b);
+ _speech->talkCol.setColor(t->r, t->g, t->b);
}
void SpeechManager::addSpeechLine(const Common::String &theLine, int x, int &offset) {
@@ -82,14 +82,16 @@ void SpeechManager::addSpeechLine(const Common::String &theLine, int x, int &off
int halfWidth = (g_sludge->_txtMan->stringWidth(theLine) >> 1) / cameraZoom;
int xx1 = x - (halfWidth);
int xx2 = x + (halfWidth);
+
+ // Create new speech line
SpeechLine *newLine = new SpeechLine;
checkNew(newLine);
-
- newLine->next = _speech->allSpeech;
newLine->textLine.clear();
newLine->textLine = theLine;
newLine->x = xx1;
- _speech->allSpeech = newLine;
+ _speech->allSpeech.push_front(newLine);
+
+ // Calculate offset
if ((xx1 < 5) && (offset < (5 - xx1))) {
offset = 5 - xx1;
} else if ((xx2 >= ((float) g_system->getWidth() / cameraZoom) - 5)
@@ -99,7 +101,7 @@ void SpeechManager::addSpeechLine(const Common::String &theLine, int x, int &off
}
int SpeechManager::isThereAnySpeechGoingOn() {
- return _speech->allSpeech ? _speech->lookWhosTalking : -1;
+ return _speech->allSpeech.empty() ? -1 : _speech->lookWhosTalking;
}
int SpeechManager::getLastSpeechSound() {
@@ -158,10 +160,8 @@ int SpeechManager::wrapSpeechXY(const Common::String &theText, int x, int y, int
+ (float) (g_system->getHeight() - fontHeight / 3) / cameraZoom;
if (offset) {
- SpeechLine *viewLine = _speech->allSpeech;
- while (viewLine) {
- viewLine->x += offset;
- viewLine = viewLine->next;
+ for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
+ (*it)->x += offset;
}
}
return speechTime;
@@ -176,7 +176,7 @@ int SpeechManager::wrapSpeechPerson(const Common::String &theText, OnScreenPerso
- thePerson.thisType->speechGap,
thePerson.thisType->wrapSpeech, sampleFile);
if (animPerson) {
- makeTalker(thePerson);
+ thePerson.makeTalker();
_speech->currentTalker = &thePerson;
}
return i;
@@ -188,12 +188,12 @@ int SpeechManager::wrapSpeech(const Common::String &theText, int objT, int sampl
int cameraY = g_sludge->_gfxMan->getCamY();
_speech->lookWhosTalking = objT;
- OnScreenPerson *thisPerson = findPerson(objT);
+ OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objT);
if (thisPerson) {
setObjFontColour(thisPerson->thisType);
i = wrapSpeechPerson(theText, *thisPerson, sampleFile, animPerson);
} else {
- ScreenRegion *thisRegion = getRegionForObject(objT);
+ ScreenRegion *thisRegion = g_sludge->_regionMan->getRegionForObject(objT);
if (thisRegion) {
setObjFontColour(thisRegion->thisType);
i = wrapSpeechXY(theText,
@@ -214,19 +214,14 @@ void SpeechManager::display() {
float cameraZoom = g_sludge->_gfxMan->getCamZoom();
int fontHeight = g_sludge->_txtMan->getFontHeight();
int viewY = _speech->speechY;
- SpeechLine *viewLine = _speech->allSpeech;
- while (viewLine) {
- g_sludge->_txtMan->pasteString(viewLine->textLine, viewLine->x, viewY, _speech->talkCol);
+ for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
+ g_sludge->_txtMan->pasteString((*it)->textLine, (*it)->x, viewY, _speech->talkCol);
viewY -= fontHeight / cameraZoom;
- viewLine = viewLine->next;
}
}
void SpeechManager::save(Common::WriteStream *stream) {
stream->writeByte(_speechMode);
-
- SpeechLine *viewLine = _speech->allSpeech;
-
stream->writeByte(_speech->talkCol.originalRed);
stream->writeByte(_speech->talkCol.originalGreen);
stream->writeByte(_speech->talkCol.originalBlue);
@@ -246,11 +241,10 @@ void SpeechManager::save(Common::WriteStream *stream) {
}
// Write what's being said
- while (viewLine) {
+ for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
stream->writeByte(1);
- writeString(viewLine->textLine, stream);
- stream->writeUint16BE(viewLine->x);
- viewLine = viewLine->next;
+ writeString((*it)->textLine, stream);
+ stream->writeUint16BE((*it)->x);
}
stream->writeByte(0);
}
@@ -264,8 +258,7 @@ bool SpeechManager::load(Common::SeekableReadStream *stream) {
byte r = stream->readByte();
byte g = stream->readByte();
byte b = stream->readByte();
- setFontColour(_speech->talkCol, r, g, b);
-
+ _speech->talkCol.setColor(r, g, b);
_speechSpeed = stream->readFloatLE();
// Read y co-ordinate
@@ -275,24 +268,20 @@ bool SpeechManager::load(Common::SeekableReadStream *stream) {
_speech->lookWhosTalking = stream->readUint16BE();
if (stream->readByte()) {
- _speech->currentTalker = findPerson(stream->readUint16BE());
+ _speech->currentTalker = g_sludge->_peopleMan->findPerson(stream->readUint16BE());
} else {
_speech->currentTalker = NULL;
}
// Read what's being said
- SpeechLine **viewLine = &_speech->allSpeech;
- SpeechLine *newOne;
_speech->lastFile = -1;
while (stream->readByte()) {
- newOne = new SpeechLine;
+ SpeechLine *newOne = new SpeechLine;
if (!checkNew(newOne))
return false;
newOne->textLine = readString(stream);
newOne->x = stream->readUint16BE();
- newOne->next = NULL;
- (*viewLine) = newOne;
- viewLine = &(newOne->next);
+ _speech->allSpeech.push_back(newOne);
}
return true;
}
diff --git a/engines/sludge/speech.h b/engines/sludge/speech.h
index 98b6035cb0..776a9f5dea 100644
--- a/engines/sludge/speech.h
+++ b/engines/sludge/speech.h
@@ -30,13 +30,14 @@ struct ObjectType;
struct SpeechLine {
Common::String textLine;
- SpeechLine *next;
int x;
};
+typedef Common::List<SpeechLine *> SpeechLineList;
+
struct SpeechStruct {
OnScreenPerson *currentTalker;
- SpeechLine *allSpeech;
+ SpeechLineList allSpeech;
int speechY, lastFile, lookWhosTalking;
SpritePalette talkCol;
};
@@ -60,6 +61,7 @@ public:
void setObjFontColour(ObjectType *t);
void setSpeechSpeed(float speed) { _speechSpeed = speed; }
float getSpeechSpeed() { return _speechSpeed; }
+ void setSpeechMode(int speechMode) { _speechMode = speechMode; }
// load & save
void save(Common::WriteStream *stream);
diff --git a/engines/sludge/sprites.h b/engines/sludge/sprites.h
index e138c6f14f..e18d16e5df 100644
--- a/engines/sludge/sprites.h
+++ b/engines/sludge/sprites.h
@@ -42,15 +42,8 @@ public:
byte originalRed, originalGreen, originalBlue, total;
SpritePalette() { init(); }
-
~SpritePalette() { kill(); }
- void reset() {
- kill();
- init();
- }
-
-private:
void init() {
pal = nullptr;
r = g = b = nullptr;
@@ -59,15 +52,29 @@ private:
}
void kill() {
- if (pal)
+ if (pal) {
delete[] pal;
- if (r)
+ pal = nullptr;
+ }
+ if (r) {
delete[] r;
- if (g)
+ r = nullptr;
+ }
+ if (g) {
delete[] g;
- if (b)
+ g = nullptr;
+ }
+ if (b) {
delete[] b;
+ b = nullptr;
+ }
}
+
+ void setColor(byte red, byte green, byte blue) {
+ originalRed = red;
+ originalGreen = green;
+ originalBlue = blue;
+ }
};
struct SpriteBank {
diff --git a/engines/sludge/statusba.cpp b/engines/sludge/statusba.cpp
index 1aa24971f1..fc0f065ea9 100644
--- a/engines/sludge/statusba.cpp
+++ b/engines/sludge/statusba.cpp
@@ -37,8 +37,8 @@ namespace Sludge {
SpritePalette verbLinePalette;
SpritePalette litVerbLinePalette;
-StatusStuff mainStatus;
-StatusStuff *nowStatus = & mainStatus;
+StatusStuff mainStatus;
+StatusStuff *nowStatus = & mainStatus;
void setLitStatus(int i) {
nowStatus->litStatus = i;
@@ -114,14 +114,14 @@ void drawStatusBar() {
}
void statusBarColour(byte r, byte g, byte b) {
- setFontColour(verbLinePalette, r, g, b);
+ verbLinePalette.setColor(r, g, b);
nowStatus->statusR = r;
nowStatus->statusG = g;
nowStatus->statusB = b;
}
void statusBarLitColour(byte r, byte g, byte b) {
- setFontColour(litVerbLinePalette, r, g, b);
+ litVerbLinePalette.setColor(r, g, b);
nowStatus->statusLR = r;
nowStatus->statusLG = g;
nowStatus->statusLB = b;
@@ -144,7 +144,7 @@ StatusStuff *copyStatusBarStuff(StatusStuff *here) {
here->litStatus = -1;
here->firstStatusBar = NULL;
- StatusStuff *old = nowStatus;
+ StatusStuff *old = nowStatus;
nowStatus = here;
return old;
@@ -152,8 +152,8 @@ StatusStuff *copyStatusBarStuff(StatusStuff *here) {
void restoreBarStuff(StatusStuff *here) {
delete nowStatus;
- setFontColour(verbLinePalette, here->statusR, here->statusG, here->statusB);
- setFontColour(litVerbLinePalette, here->statusLR, here->statusLG, here->statusLB);
+ verbLinePalette.setColor((byte)here->statusR, (byte)here->statusG, (byte)here->statusB);
+ litVerbLinePalette.setColor((byte)here->statusLR, (byte)here->statusLG, (byte)here->statusLB);
nowStatus = here;
}
@@ -215,8 +215,8 @@ bool loadStatusBars(Common::SeekableReadStream *stream) {
nowStatus->statusLG = stream->readByte();
nowStatus->statusLB = stream->readByte();
- setFontColour(verbLinePalette, nowStatus->statusR, nowStatus->statusG, nowStatus->statusB);
- setFontColour(litVerbLinePalette, nowStatus->statusLR, nowStatus->statusLG, nowStatus->statusLB);
+ verbLinePalette.setColor((byte)nowStatus->statusR, (byte)nowStatus->statusG, (byte)nowStatus->statusB);
+ litVerbLinePalette.setColor((byte)nowStatus->statusLR, (byte)nowStatus->statusLG, (byte)nowStatus->statusLB);
// Read what's being said
StatusBar **viewLine = & (nowStatus->firstStatusBar);
StatusBar *newOne;
diff --git a/engines/sludge/thumbnail.cpp b/engines/sludge/thumbnail.cpp
index 2c7e007f71..dcbcd91db3 100644
--- a/engines/sludge/thumbnail.cpp
+++ b/engines/sludge/thumbnail.cpp
@@ -35,14 +35,23 @@
namespace Sludge {
-int thumbWidth = 0, thumbHeight = 0;
+bool GraphicsManager::setThumbnailSize(int thumbWidth, int thumbHeight)
+{
+ if (checkSizeValide(thumbWidth, thumbHeight))
+ {
+ _thumbWidth = thumbWidth;
+ _thumbHeight = thumbHeight;
+ return true;
+ }
+ return false;
+}
bool GraphicsManager::saveThumbnail(Common::WriteStream *stream) {
- stream->writeUint32LE(thumbWidth);
- stream->writeUint32LE(thumbHeight);
+ stream->writeUint32LE(_thumbWidth);
+ stream->writeUint32LE(_thumbHeight);
- if (thumbWidth && thumbHeight) {
+ if (_thumbWidth && _thumbHeight) {
if (!freeze())
return false;
@@ -117,12 +126,12 @@ void GraphicsManager::showThumbnail(const Common::String &filename, int atX, int
}
bool GraphicsManager::skipThumbnail(Common::SeekableReadStream *stream) {
- thumbWidth = stream->readUint32LE();
- thumbHeight = stream->readUint32LE();
+ _thumbWidth = stream->readUint32LE();
+ _thumbHeight = stream->readUint32LE();
// Load image
Graphics::Surface tmp;
- if (thumbWidth & thumbHeight) {
+ if (_thumbWidth & _thumbHeight) {
if (!ImgLoader::loadPNGImage(stream, &tmp))
return false;
else
diff --git a/engines/sludge/timing.cpp b/engines/sludge/timing.cpp
index 2e3865498a..c291f57a6b 100644
--- a/engines/sludge/timing.cpp
+++ b/engines/sludge/timing.cpp
@@ -25,31 +25,63 @@
namespace Sludge {
+Timer::Timer(){
+ reset();
+}
+
+void Timer::reset(void) {
+ _desiredFPS = 300;
+ _startTime = 0;
+ _endTime = 0;
+ _desiredFrameTime = 0;
+ _addNextTime = 0;
+
+ // FPS stats
+ _lastFPS = -1;
+ _thisFPS = -1;
+ _lastSeconds = 0;
+}
+
void Timer::init(void) {
- _desired_frame_time = 1000 / _desiredfps;
- _starttime = g_system->getMillis();
+ _desiredFrameTime = 1000 / _desiredFPS;
+ _startTime = g_system->getMillis();
}
void Timer::initSpecial(int t) {
- _desired_frame_time = 1000 / t;
- _starttime = g_system->getMillis();
+ _desiredFrameTime = 1000 / t;
+ _startTime = g_system->getMillis();
+}
+
+void Timer::updateFpsStats() {
+ uint32 currentSeconds = g_system->getMillis() / 1000;
+ if (_lastSeconds != currentSeconds) {
+ _lastSeconds = currentSeconds;
+ _lastFPS = _thisFPS;
+ _thisFPS = 1;
+ } else {
+ ++_thisFPS;
+ }
}
void Timer::waitFrame(void) {
- static uint32 addNextTime = 0;
uint32 timetaken;
for (;;) {
- _endtime = g_system->getMillis();
- timetaken = addNextTime + _endtime - _starttime;
- if (timetaken >= _desired_frame_time) break;
+ _endTime = g_system->getMillis();
+ timetaken = _addNextTime + _endTime - _startTime;
+ if (timetaken >= _desiredFrameTime)
+ break;
g_system->delayMillis(1);
}
- addNextTime = timetaken - _desired_frame_time;
- if (addNextTime > _desired_frame_time) addNextTime = _desired_frame_time;
+ _addNextTime = timetaken - _desiredFrameTime;
+ if (_addNextTime > _desiredFrameTime)
+ _addNextTime = _desiredFrameTime;
+
+ _startTime = _endTime;
- _starttime = _endtime;
+ // Stats
+ updateFpsStats();
}
} // End of namespace Sludge
diff --git a/engines/sludge/timing.h b/engines/sludge/timing.h
index 0d7ffece8d..e04ddf4732 100644
--- a/engines/sludge/timing.h
+++ b/engines/sludge/timing.h
@@ -25,18 +25,28 @@
namespace Sludge {
class Timer {
-private:
- int _desiredfps; // desired frames per second
- uint32 _starttime, _endtime;
- uint32 _desired_frame_time;
-
public:
- void setDesiredfps(int t) { _desiredfps = t; }
+ Timer();
+
+ void setDesiredFPS(int t) { _desiredFPS = t; }
+ void reset(void);
void init(void);
void initSpecial(int t);
void waitFrame(void);
- Timer():_desiredfps(300), _starttime(0), _endtime(0), _desired_frame_time(0){}
+ int getLastFps() const { return _lastFPS; }
+
+private:
+ int _desiredFPS; // desired frames per second
+ uint32 _startTime, _endTime;
+ uint32 _desiredFrameTime;
+ uint32 _addNextTime;
+
+ // FPS stats
+ void updateFpsStats();
+ int _lastFPS;
+ int _thisFPS;
+ uint32 _lastSeconds;
};
} // End of namespace Sludge
diff --git a/engines/sludge/transition.cpp b/engines/sludge/transition.cpp
index 3a768cb5f4..35f650e8e4 100644
--- a/engines/sludge/transition.cpp
+++ b/engines/sludge/transition.cpp
@@ -22,15 +22,22 @@
#include "sludge/allfiles.h"
#include "sludge/backdrop.h"
+#include "sludge/graphics.h"
#include "sludge/newfatal.h"
namespace Sludge {
-extern byte brightnessLevel;
-
extern float snapTexW, snapTexH;
-byte fadeMode = 2;
+void GraphicsManager::setBrightnessLevel(int brightnessLevel)
+{
+ if (brightnessLevel < 0)
+ _brightnessLevel = 0;
+ else if (brightnessLevel > 255)
+ _brightnessLevel = 255;
+ else
+ _brightnessLevel = brightnessLevel;
+}
//----------------------------------------------------
// PROPER BRIGHTNESS FADING
@@ -142,7 +149,7 @@ void transitionSnapshotBox() {
uint32 randbuffer[KK][2]; // history buffer
int p1, p2;
-void resetRandW() {
+void GraphicsManager::resetRandW() {
int32 seed = 12345;
for (int i = 0; i < KK; i++) {
@@ -373,8 +380,8 @@ void transitionBlinds() {
//----------------------------------------------------
-void fixBrightness() {
- switch (fadeMode) {
+void GraphicsManager::fixBrightness() {
+ switch (_fadeMode) {
case 0:
transitionFader();
break;
diff --git a/engines/sludge/variable.cpp b/engines/sludge/variable.cpp
index 9cbb9f49f8..44381aa97f 100644
--- a/engines/sludge/variable.cpp
+++ b/engines/sludge/variable.cpp
@@ -38,34 +38,37 @@ const char *typeName[] = { "undefined", "number", "user function", "string",
"built-in function", "file", "stack", "object type", "animation",
"costume" };
-void unlinkVar(Variable &thisVar) {
- switch (thisVar.varType) {
+void Variable::unlinkVar() {
+ switch (varType) {
case SVT_STRING:
- delete []thisVar.varData.theString;
- thisVar.varData.theString = NULL;
+ delete []varData.theString;
+ varData.theString = NULL;
break;
case SVT_STACK:
- thisVar.varData.theStack->timesUsed--;
- if (thisVar.varData.theStack->timesUsed <= 0) {
- while (thisVar.varData.theStack->first)
- trimStack(thisVar.varData.theStack->first);
- delete thisVar.varData.theStack;
- thisVar.varData.theStack = NULL;
+ varData.theStack->timesUsed--;
+ if (varData.theStack->timesUsed <= 0) {
+ while (varData.theStack->first)
+ trimStack(varData.theStack->first);
+ delete varData.theStack;
+ varData.theStack = NULL;
}
break;
case SVT_FASTARRAY:
- thisVar.varData.fastArray->timesUsed--;
- if (thisVar.varData.theStack->timesUsed <= 0) {
- delete thisVar.varData.fastArray->fastVariables;
- delete[] thisVar.varData.fastArray;
- thisVar.varData.fastArray = NULL;
+ varData.fastArray->timesUsed--;
+ if (varData.theStack->timesUsed <= 0) {
+ delete varData.fastArray->fastVariables;
+ delete[] varData.fastArray;
+ varData.fastArray = NULL;
}
break;
case SVT_ANIM:
- deleteAnim(thisVar.varData.animHandler);
+ if (varData.animHandler) {
+ delete varData.animHandler;
+ varData.animHandler = nullptr;
+ }
break;
default:
@@ -73,39 +76,39 @@ void unlinkVar(Variable &thisVar) {
}
}
-void setVariable(Variable &thisVar, VariableType vT, int value) {
- unlinkVar(thisVar);
- thisVar.varType = vT;
- thisVar.varData.intValue = value;
+void Variable::setVariable(VariableType vT, int value) {
+ unlinkVar();
+ varType = vT;
+ varData.intValue = value;
}
-void newAnimationVariable(Variable &thisVar, PersonaAnimation *i) {
- unlinkVar(thisVar);
- thisVar.varType = SVT_ANIM;
- thisVar.varData.animHandler = i;
+void Variable::makeAnimationVariable(PersonaAnimation *i) {
+ unlinkVar();
+ varType = SVT_ANIM;
+ varData.animHandler = i;
}
-PersonaAnimation *getAnimationFromVar(Variable &thisVar) {
- if (thisVar.varType == SVT_ANIM)
- return copyAnim(thisVar.varData.animHandler);
+PersonaAnimation *Variable::getAnimationFromVar() {
+ if (varType == SVT_ANIM)
+ return new PersonaAnimation(varData.animHandler);
- if (thisVar.varType == SVT_INT && thisVar.varData.intValue == 0)
- return makeNullAnim();
+ if (varType == SVT_INT && varData.intValue == 0)
+ return new PersonaAnimation();
- fatal("Expecting an animation variable; found Variable of type", typeName[thisVar.varType]);
+ fatal("Expecting an animation variable; found Variable of type", typeName[varType]);
return NULL;
}
-void newCostumeVariable(Variable &thisVar, Persona *i) {
- unlinkVar(thisVar);
- thisVar.varType = SVT_COSTUME;
- thisVar.varData.costumeHandler = i;
+void Variable::makeCostumeVariable(Persona *i) {
+ unlinkVar();
+ varType = SVT_COSTUME;
+ varData.costumeHandler = i;
}
-Persona *getCostumeFromVar(Variable &thisVar) {
+Persona *Variable::getCostumeFromVar() {
Persona *p = NULL;
- switch (thisVar.varType) {
+ switch (varType) {
case SVT_ANIM:
p = new Persona;
if (!checkNew(p))
@@ -116,24 +119,24 @@ Persona *getCostumeFromVar(Variable &thisVar) {
return NULL;
for (int iii = 0; iii < 3; iii++)
- p->animation[iii] = copyAnim(thisVar.varData.animHandler);
+ p->animation[iii] = new PersonaAnimation(varData.animHandler);
break;
case SVT_COSTUME:
- return thisVar.varData.costumeHandler;
+ return varData.costumeHandler;
break;
default:
- fatal("Expecting an animation variable; found Variable of type", typeName[thisVar.varType]);
+ fatal("Expecting an animation variable; found Variable of type", typeName[varType]);
}
return p;
}
-int stackSize(const StackHandler *me) {
+int StackHandler::getStackSize() const {
int r = 0;
- VariableStack *a = me->first;
+ VariableStack *a = first;
while (a) {
r++;
a = a->next;
@@ -141,8 +144,7 @@ int stackSize(const StackHandler *me) {
return r;
}
-bool getSavedGamesStack(StackHandler *sH, const Common::String &ext) {
-
+bool StackHandler::getSavedGamesStack(const Common::String &ext) {
// Make pattern
uint len = ext.size();
Common::String pattern = "*";
@@ -157,30 +159,30 @@ bool getSavedGamesStack(StackHandler *sH, const Common::String &ext) {
Common::StringArray::iterator it;
for (it = sa.begin(); it != sa.end(); ++it) {
(*it).erase((*it).size() - len, len);
- makeTextVar(newName, (*it));
- if (!addVarToStack(newName, sH->first))
+ newName.makeTextVar((*it));
+ if (!addVarToStack(newName, first))
return false;
- if (sH->last == NULL)
- sH->last = sH->first;
+ if (last == NULL)
+ last = first;
}
return true;
}
-bool copyStack(const Variable &from, Variable &to) {
- to.varType = SVT_STACK;
- to.varData.theStack = new StackHandler;
- if (!checkNew(to.varData.theStack))
+bool Variable::copyStack(const Variable &from) {
+ varType = SVT_STACK;
+ varData.theStack = new StackHandler;
+ if (!checkNew(varData.theStack))
return false;
- to.varData.theStack->first = NULL;
- to.varData.theStack->last = NULL;
- to.varData.theStack->timesUsed = 1;
+ varData.theStack->first = NULL;
+ varData.theStack->last = NULL;
+ varData.theStack->timesUsed = 1;
VariableStack *a = from.varData.theStack->first;
while (a) {
- addVarToStack(a->thisVar, to.varData.theStack->first);
- if (to.varData.theStack->last == NULL) {
- to.varData.theStack->last = to.varData.theStack->first;
+ addVarToStack(a->thisVar, varData.theStack->first);
+ if (varData.theStack->last == NULL) {
+ varData.theStack->last = varData.theStack->first;
}
a = a->next;
}
@@ -188,89 +190,78 @@ bool copyStack(const Variable &from, Variable &to) {
return true;
}
-void addVariablesInSecond(Variable &var1, Variable &var2) {
- if (var1.varType == SVT_INT && var2.varType == SVT_INT) {
- var2.varData.intValue += var1.varData.intValue;
+void Variable::addVariablesInSecond(const Variable &other) {
+ if (other.varType == SVT_INT && varType == SVT_INT) {
+ varData.intValue += other.varData.intValue;
} else {
- Common::String string1 = getTextFromAnyVar(var1);
- Common::String string2 = getTextFromAnyVar(var2);
+ Common::String string1 = other.getTextFromAnyVar();
+ Common::String string2 = getTextFromAnyVar();
- unlinkVar(var2);
- var2.varData.theString = createCString(string1 + string2);
- var2.varType = SVT_STRING;
+ unlinkVar();
+ varData.theString = createCString(string1 + string2);
+ varType = SVT_STRING;
}
}
-int compareVars(const Variable &var1, const Variable &var2) {
+int Variable::compareVars(const Variable &other) const {
int re = 0;
- if (var1.varType == var2.varType) {
- switch (var1.varType) {
+ if (other.varType == varType) {
+ switch (other.varType) {
case SVT_NULL:
re = 1;
break;
case SVT_COSTUME:
- re = (var1.varData.costumeHandler == var2.varData.costumeHandler);
+ re = (other.varData.costumeHandler == varData.costumeHandler);
break;
case SVT_ANIM:
- re = (var1.varData.animHandler == var2.varData.animHandler);
+ re = (other.varData.animHandler == varData.animHandler);
break;
case SVT_STRING:
- re = (strcmp(var1.varData.theString, var2.varData.theString) == 0);
+ re = (strcmp(other.varData.theString, varData.theString) == 0);
break;
case SVT_STACK:
- re = (var1.varData.theStack == var2.varData.theStack);
+ re = (other.varData.theStack == varData.theStack);
break;
default:
- re = (var1.varData.intValue == var2.varData.intValue);
+ re = (other.varData.intValue == varData.intValue);
}
}
return re;
}
-void compareVariablesInSecond(const Variable &var1, Variable &var2) {
- setVariable(var2, SVT_INT, compareVars(var1, var2));
-}
-
-char *createCString(const Common::String &s) {
- uint n = s.size() + 1;
- char *res = new char[n];
- if (!checkNew(res)) {
- fatal("createCString : Unable to copy String");
- return NULL;
- }
- memcpy(res, s.c_str(), n);
- return res;
+void Variable::compareVariablesInSecond(const Variable &other) {
+ setVariable(SVT_INT, compareVars(other));
}
-void makeTextVar(Variable &thisVar, const Common::String &txt) {
- unlinkVar(thisVar);
- thisVar.varType = SVT_STRING;
- thisVar.varData.theString = createCString(txt);
+void Variable::makeTextVar(const Common::String &txt) {
+ unlinkVar();
+ varType = SVT_STRING;
+ varData.theString = createCString(txt);
}
-bool loadStringToVar(Variable &thisVar, int value) {
- makeTextVar(thisVar, g_sludge->_resMan->getNumberedString(value));
- return (bool)(thisVar.varData.theString != NULL);
+bool Variable::loadStringToVar(int value) {
+ makeTextVar(g_sludge->_resMan->getNumberedString(value));
+ return (bool)(varData.theString != NULL);
}
-Common::String getTextFromAnyVar(const Variable &from) {
- switch (from.varType) {
+Common::String Variable::getTextFromAnyVar() const {
+ switch (varType) {
case SVT_STRING:
- return from.varData.theString;
+ return varData.theString;
case SVT_FASTARRAY: {
Common::String builder = "FAST:";
Common::String builder2 = "";
Common::String grabText = "";
- for (int i = 0; i < from.varData.fastArray->size; i++) {
+ for (int i = 0; i < varData.fastArray->size; i++) {
builder2 = builder + " ";
- grabText = getTextFromAnyVar(from.varData.fastArray->fastVariables[i]);
+ grabText = varData.fastArray->fastVariables[i].getTextFromAnyVar();
builder.clear();
builder = builder2 + grabText;
}
@@ -282,11 +273,11 @@ Common::String getTextFromAnyVar(const Variable &from) {
Common::String builder2 = "";
Common::String grabText = "";
- VariableStack *stacky = from.varData.theStack->first;
+ VariableStack *stacky = varData.theStack->first;
while (stacky) {
builder2 = builder + " ";
- grabText = getTextFromAnyVar(stacky->thisVar);
+ grabText = stacky->thisVar.getTextFromAnyVar();
builder.clear();
builder = builder2 + grabText;
stacky = stacky->next;
@@ -295,16 +286,16 @@ Common::String getTextFromAnyVar(const Variable &from) {
}
case SVT_INT: {
- Common::String buff = Common::String::format("%i", from.varData.intValue);
+ Common::String buff = Common::String::format("%i", varData.intValue);
return buff;
}
case SVT_FILE: {
- return resourceNameFromNum(from.varData.intValue);
+ return g_sludge->_resMan->resourceNameFromNum(varData.intValue);
}
case SVT_OBJTYPE: {
- ObjectType *thisType = g_sludge->_objMan->findObjectType(from.varData.intValue);
+ ObjectType *thisType = g_sludge->_objMan->findObjectType(varData.intValue);
if (thisType)
return thisType->screenName;
break;
@@ -314,25 +305,25 @@ Common::String getTextFromAnyVar(const Variable &from) {
break;
}
- return typeName[from.varType];
+ return typeName[varType];
}
-bool getBoolean(const Variable &from) {
- switch (from.varType) {
+bool Variable::getBoolean() const {
+ switch (varType) {
case SVT_NULL:
return false;
case SVT_INT:
- return (bool)(from.varData.intValue != 0);
+ return (bool)(varData.intValue != 0);
case SVT_STACK:
- return (bool)(from.varData.theStack->first != NULL);
+ return (bool)(varData.theStack->first != NULL);
case SVT_STRING:
- return (bool)(from.varData.theString[0] != 0);
+ return (bool)(varData.theString[0] != 0);
case SVT_FASTARRAY:
- return (bool)(from.varData.fastArray->size != 0);
+ return (bool)(varData.fastArray->size != 0);
default:
break;
@@ -340,37 +331,37 @@ bool getBoolean(const Variable &from) {
return true;
}
-bool copyMain(const Variable &from, Variable &to) {
- to.varType = from.varType;
- switch (to.varType) {
+bool Variable::copyMain(const Variable &from) {
+ varType = from.varType;
+ switch (varType) {
case SVT_INT:
case SVT_FUNC:
case SVT_BUILT:
case SVT_FILE:
case SVT_OBJTYPE:
- to.varData.intValue = from.varData.intValue;
+ varData.intValue = from.varData.intValue;
return true;
case SVT_FASTARRAY:
- to.varData.fastArray = from.varData.fastArray;
- to.varData.fastArray->timesUsed++;
+ varData.fastArray = from.varData.fastArray;
+ varData.fastArray->timesUsed++;
return true;
case SVT_STRING:
- to.varData.theString = createCString(from.varData.theString);
- return to.varData.theString ? true : false;
+ varData.theString = createCString(from.varData.theString);
+ return varData.theString ? true : false;
case SVT_STACK:
- to.varData.theStack = from.varData.theStack;
- to.varData.theStack->timesUsed++;
+ varData.theStack = from.varData.theStack;
+ varData.theStack->timesUsed++;
return true;
case SVT_COSTUME:
- to.varData.costumeHandler = from.varData.costumeHandler;
+ varData.costumeHandler = from.varData.costumeHandler;
return true;
case SVT_ANIM:
- to.varData.animHandler = copyAnim(from.varData.animHandler);
+ varData.animHandler = new PersonaAnimation(from.varData.animHandler);
return true;
case SVT_NULL:
@@ -383,39 +374,36 @@ bool copyMain(const Variable &from, Variable &to) {
return false;
}
-bool copyVariable(const Variable &from, Variable &to) {
- unlinkVar(to);
- return copyMain(from, to);
+bool Variable::copyFrom(const Variable &from) {
+ unlinkVar();
+ return copyMain(from);
}
-Variable *fastArrayGetByIndex(FastArrayHandler *vS, uint theIndex) {
- if ((int)theIndex >= vS->size)
+Variable *FastArrayHandler::fastArrayGetByIndex(uint theIndex) {
+ if ((int)theIndex >= size)
return NULL;
- return &vS->fastVariables[theIndex];
+ return &fastVariables[theIndex];
}
-bool makeFastArraySize(Variable &to, int size) {
+bool Variable::makeFastArraySize(int size) {
if (size < 0)
return fatal("Can't create a fast array with a negative number of elements!");
- unlinkVar(to);
- to.varType = SVT_FASTARRAY;
- to.varData.fastArray = new FastArrayHandler;
- if (!checkNew(to.varData.fastArray))
+ unlinkVar();
+ varType = SVT_FASTARRAY;
+ varData.fastArray = new FastArrayHandler;
+ if (!checkNew(varData.fastArray))
return false;
- to.varData.fastArray->fastVariables = new Variable[size];
- if (!checkNew(to.varData.fastArray->fastVariables))
+ varData.fastArray->fastVariables = new Variable[size];
+ if (!checkNew(varData.fastArray->fastVariables))
return false;
- for (int i = 0; i < size; i++) {
- initVarNew(to.varData.fastArray->fastVariables[i]);
- }
- to.varData.fastArray->size = size;
- to.varData.fastArray->timesUsed = 1;
+ varData.fastArray->size = size;
+ varData.fastArray->timesUsed = 1;
return true;
}
-bool makeFastArrayFromStack(Variable &to, const StackHandler *stacky) {
- int size = stackSize(stacky);
- if (!makeFastArraySize(to, size))
+bool Variable::makeFastArrayFromStack(const StackHandler *stacky) {
+ int size = stacky->getStackSize();
+ if (!makeFastArraySize(size))
return false;
// Now let's fill up the new array
@@ -423,7 +411,7 @@ bool makeFastArrayFromStack(Variable &to, const StackHandler *stacky) {
VariableStack *allV = stacky->first;
size = 0;
while (allV) {
- copyMain(allV->thisVar, to.varData.fastArray->fastVariables[size]);
+ varData.fastArray->fastVariables[size].copyMain(allV->thisVar);
size++;
allV = allV->next;
}
@@ -435,7 +423,7 @@ bool addVarToStack(const Variable &va, VariableStack *&thisStack) {
if (!checkNew(newStack))
return false;
- if (!copyMain(va, newStack->thisVar))
+ if (!newStack->thisVar.copyMain(va))
return false;
newStack->next = thisStack;
thisStack = newStack;
@@ -459,16 +447,18 @@ bool addVarToStackQuick(Variable &va, VariableStack *&thisStack) {
return true;
}
-bool stackSetByIndex(VariableStack *vS, uint theIndex, const Variable &va) {
+bool VariableStack::stackSetByIndex(uint theIndex, const Variable &va) {
+ VariableStack *vS = this;
while (theIndex--) {
vS = vS->next;
if (!vS)
return fatal("Index past end of stack.");
}
- return copyVariable(va, vS->thisVar);
+ return vS->thisVar.copyFrom(va);
}
-Variable *stackGetByIndex(VariableStack *vS, uint theIndex) {
+Variable *VariableStack::stackGetByIndex(uint theIndex) {
+ VariableStack *vS = this;
while (theIndex--) {
vS = vS->next;
if (!vS) {
@@ -484,10 +474,10 @@ int deleteVarFromStack(const Variable &va, VariableStack *&thisStack, bool allOf
int reply = 0;
while (*huntVar) {
- if (compareVars((*huntVar)->thisVar, va)) {
+ if (va.compareVars((*huntVar)->thisVar)) {
killMe = *huntVar;
*huntVar = killMe->next;
- unlinkVar(killMe->thisVar);
+ killMe->thisVar.unlinkVar();
delete killMe;
if (!allOfEm)
return 1;
@@ -501,28 +491,25 @@ int deleteVarFromStack(const Variable &va, VariableStack *&thisStack, bool allOf
}
// Would be a LOT better just to keep this up to date in the above function... ah well
-VariableStack *stackFindLast(VariableStack *hunt) {
- if (hunt == NULL)
- return NULL;
-
+VariableStack *VariableStack::stackFindLast() {
+ VariableStack *hunt = this;
while (hunt->next)
hunt = hunt->next;
return hunt;
}
-bool getValueType(int &toHere, VariableType vT, const Variable &v) {
- //if (! v) return false;
- if (v.varType != vT) {
+bool Variable::getValueType(int &toHere, VariableType vT) const {
+ if (varType != vT) {
Common::String e1 = "Can only perform specified operation on a value which is of type ";
e1 += typeName[vT];
Common::String e2 = "... value supplied was of type ";
- e2 += typeName[v.varType];
+ e2 += typeName[varType];
fatal(e1, e2);
return false;
}
- toHere = v.varData.intValue;
+ toHere = varData.intValue;
return true;
}
@@ -533,8 +520,212 @@ void trimStack(VariableStack *&stack) {
//debugC(2, kSludgeDebugStackMachine, "Variable %s was removed from stack", getTextFromAnyVar(killMe->thisVar));
// When calling this, we've ALWAYS checked that stack != NULL
- unlinkVar(killMe->thisVar);
+ killMe->thisVar.unlinkVar();
delete killMe;
}
+//----------------------------------------------------------------------
+// Globals (so we know what's saved already and what's a reference
+//----------------------------------------------------------------------
+
+struct stackLibrary {
+ StackHandler *stack;
+ stackLibrary *next;
+};
+
+int stackLibTotal = 0;
+stackLibrary *stackLib = NULL;
+
+//----------------------------------------------------------------------
+// For saving and loading stacks...
+//----------------------------------------------------------------------
+void saveStack(VariableStack *vs, Common::WriteStream *stream) {
+ int elements = 0;
+ int a;
+
+ VariableStack *search = vs;
+ while (search) {
+ elements++;
+ search = search->next;
+ }
+
+ stream->writeUint16BE(elements);
+ search = vs;
+ for (a = 0; a < elements; a++) {
+ search->thisVar.save(stream);
+ search = search->next;
+ }
+}
+
+VariableStack *loadStack(Common::SeekableReadStream *stream, VariableStack **last) {
+ int elements = stream->readUint16BE();
+ int a;
+ VariableStack *first = NULL;
+ VariableStack **changeMe = &first;
+
+ for (a = 0; a < elements; a++) {
+ VariableStack *nS = new VariableStack;
+ if (!checkNew(nS))
+ return NULL;
+ nS->thisVar.load(stream);
+ if (last && a == elements - 1) {
+ *last = nS;
+ }
+ nS->next = NULL;
+ (*changeMe) = nS;
+ changeMe = &(nS->next);
+ }
+
+ return first;
+}
+
+bool saveStackRef(StackHandler *vs, Common::WriteStream *stream) {
+ stackLibrary *s = stackLib;
+ int a = 0;
+ while (s) {
+ if (s->stack == vs) {
+ stream->writeByte(1);
+ stream->writeUint16BE(stackLibTotal - a);
+ return true;
+ }
+ s = s->next;
+ a++;
+ }
+ stream->writeByte(0);
+ saveStack(vs->first, stream);
+ s = new stackLibrary;
+ stackLibTotal++;
+ if (!checkNew(s))
+ return false;
+ s->next = stackLib;
+ s->stack = vs;
+ stackLib = s;
+ return true;
+}
+
+void clearStackLib() {
+ stackLibrary *k;
+ while (stackLib) {
+ k = stackLib;
+ stackLib = stackLib->next;
+ delete k;
+ }
+ stackLibTotal = 0;
+}
+
+StackHandler *getStackFromLibrary(int n) {
+ n = stackLibTotal - n;
+ while (n) {
+ stackLib = stackLib->next;
+ n--;
+ }
+ return stackLib->stack;
+}
+
+StackHandler *loadStackRef(Common::SeekableReadStream *stream) {
+ StackHandler *nsh;
+
+ if (stream->readByte()) { // It's one we've loaded already...
+ nsh = getStackFromLibrary(stream->readUint16BE());
+ nsh->timesUsed++;
+ } else {
+ // Load the new stack
+
+ nsh = new StackHandler;
+ if (!checkNew(nsh))
+ return NULL;
+ nsh->last = NULL;
+ nsh->first = loadStack(stream, &nsh->last);
+ nsh->timesUsed = 1;
+
+ // Add it to the library of loaded stacks
+
+ stackLibrary *s = new stackLibrary;
+ if (!checkNew(s))
+ return NULL;
+ s->stack = nsh;
+ s->next = stackLib;
+ stackLib = s;
+ stackLibTotal++;
+ }
+ return nsh;
+}
+
+//----------------------------------------------------------------------
+// For saving and loading variables...
+//----------------------------------------------------------------------
+bool Variable::save(Common::WriteStream *stream) {
+ stream->writeByte(varType);
+ switch (varType) {
+ case SVT_INT:
+ case SVT_FUNC:
+ case SVT_BUILT:
+ case SVT_FILE:
+ case SVT_OBJTYPE:
+ stream->writeUint32LE(varData.intValue);
+ return true;
+
+ case SVT_STRING:
+ writeString(varData.theString, stream);
+ return true;
+
+ case SVT_STACK:
+ return saveStackRef(varData.theStack, stream);
+
+ case SVT_COSTUME:
+ varData.costumeHandler->save(stream);
+ return false;
+
+ case SVT_ANIM:
+ varData.animHandler->save(stream);
+ return false;
+
+ case SVT_NULL:
+ return false;
+
+ default:
+ fatal("Can't save variables of this type:", (varType < SVT_NUM_TYPES) ? typeName[varType] : "bad ID");
+ }
+ return true;
+}
+
+bool Variable::load(Common::SeekableReadStream *stream) {
+ varType = (VariableType)stream->readByte();
+ switch (varType) {
+ case SVT_INT:
+ case SVT_FUNC:
+ case SVT_BUILT:
+ case SVT_FILE:
+ case SVT_OBJTYPE:
+ varData.intValue = stream->readUint32LE();
+ return true;
+
+ case SVT_STRING:
+ varData.theString = createCString(readString(stream));
+ return true;
+
+ case SVT_STACK:
+ varData.theStack = loadStackRef(stream);
+ return true;
+
+ case SVT_COSTUME:
+ varData.costumeHandler = new Persona;
+ if (!checkNew(varData.costumeHandler))
+ return false;
+ varData.costumeHandler->load(stream);
+ return true;
+
+ case SVT_ANIM:
+ varData.animHandler = new PersonaAnimation;
+ if (!checkNew(varData.animHandler))
+ return false;
+ varData.animHandler->load(stream);
+ return true;
+
+ default:
+ break;
+ }
+ return true;
+}
+
} // End of namespace Sludge
diff --git a/engines/sludge/variable.h b/engines/sludge/variable.h
index 005eb1cd05..1ae2acacc7 100644
--- a/engines/sludge/variable.h
+++ b/engines/sludge/variable.h
@@ -24,6 +24,8 @@
namespace Sludge {
+struct Persona;
+struct PersonaAnimation;
struct Variable;
struct VariableStack;
@@ -46,76 +48,103 @@ struct FastArrayHandler {
struct Variable *fastVariables;
int size;
int timesUsed;
+
+ Variable *fastArrayGetByIndex(uint theIndex);
};
struct StackHandler {
struct VariableStack *first;
struct VariableStack *last;
int timesUsed;
+
+ int getStackSize() const;
+ bool getSavedGamesStack(const Common::String &ext);
};
union VariableData {
signed int intValue;
const char *theString;
StackHandler *theStack;
- struct PersonaAnimation *animHandler;
- struct Persona *costumeHandler;
+ PersonaAnimation *animHandler;
+ Persona *costumeHandler;
FastArrayHandler *fastArray;
};
struct Variable {
VariableType varType;
VariableData varData;
-};
-struct VariableStack {
- Variable thisVar;
- VariableStack *next;
-};
+ Variable() {
+ varType = SVT_NULL;
+ varData.intValue = 0;
+ }
+
+ void unlinkVar();
+ void setVariable(VariableType vT, int value);
+
+ // Copy from another variable
+ bool copyFrom(const Variable &from);
+ bool copyMain(const Variable &from); // without variable unlink
+
+ // Load & save
+ bool save(Common::WriteStream *stream);
+ bool load(Common::SeekableReadStream *stream);
-// Initialisation
+ // Text variable
+ void makeTextVar(const Common::String &txt);
+ bool loadStringToVar(int value);
-#define initVarNew(thisVar) thisVar.varType = SVT_NULL
+ // Animation variable
+ void makeAnimationVariable(PersonaAnimation *i);
+ struct PersonaAnimation *getAnimationFromVar();
-// Setting variables
+ // Custome variable
+ void makeCostumeVariable(Persona *i);
+ struct Persona *getCostumeFromVar();
-void setVariable(Variable &thisVar, VariableType vT, int value);
-bool copyVariable(const Variable &from, Variable &to);
-bool loadStringToVar(Variable &thisVar, int value);
-void newAnimationVariable(Variable &thisVar, struct PersonaAnimation *i);
-void newCostumeVariable(Variable &thisVar, struct Persona *i);
-void makeTextVar(Variable &thisVar, const Common::String &txt);
-void addVariablesInSecond(Variable &var1, Variable &var2);
-void compareVariablesInSecond(const Variable &var1, Variable &var2);
-char *createCString(const Common::String &s);
+ // Fast array variable
+ bool makeFastArrayFromStack(const StackHandler *stacky);
+ bool makeFastArraySize(int size);
-// Misc.
+ // Stack variable
+ bool copyStack(const Variable &from);
-void unlinkVar(Variable &thisVar);
-Common::String getNumberedString(int value);
-Common::String getTextFromAnyVar(const Variable &from);
-struct Persona *getCostumeFromVar(Variable &thisVar);
-struct PersonaAnimation *getAnimationFromVar(Variable &thisVar);
-bool getBoolean(const Variable &from);
-bool getValueType(int &toHere, VariableType vT, const Variable &v);
+ // Add variables
+ void addVariablesInSecond(const Variable &other);
+ void compareVariablesInSecond(const Variable &other);
+ int compareVars(const Variable &other) const;
+
+ // General getters
+ Common::String getTextFromAnyVar() const;
+ bool getBoolean() const;
+ bool getValueType(int &toHere, VariableType vT) const;
+};
+
+struct VariableStack {
+ Variable thisVar;
+ VariableStack *next;
+
+ // Variable getter & setter
+ bool stackSetByIndex(uint, const Variable &);
+ Variable *stackGetByIndex(uint);
+
+ // Find last
+ VariableStack *stackFindLast();
+};
// Stacky stuff
bool addVarToStack(const Variable &va, VariableStack *&thisStack);
bool addVarToStackQuick(Variable &va, VariableStack *&thisStack);
void trimStack(VariableStack *&stack);
-int deleteVarFromStack(const Variable &va, VariableStack *&thisStack,
- bool allOfEm = false);
-VariableStack *stackFindLast(VariableStack *hunt);
-bool copyStack(const Variable &from, Variable &to);
-int stackSize(const StackHandler *me);
-bool stackSetByIndex(VariableStack *, uint, const Variable &);
-Variable *stackGetByIndex(VariableStack *, uint);
-bool getSavedGamesStack(StackHandler *sH, const Common::String &ext);
-
-bool makeFastArrayFromStack(Variable &to, const StackHandler *stacky);
-bool makeFastArraySize(Variable &to, int size);
-Variable *fastArrayGetByIndex(FastArrayHandler *vS, uint theIndex);
+int deleteVarFromStack(const Variable &va, VariableStack *&thisStack, bool allOfEm = false);
+
+// load & save
+void saveStack(VariableStack *vs, Common::WriteStream *stream);
+VariableStack *loadStack(Common::SeekableReadStream *stream, VariableStack **last);
+bool saveStackRef(StackHandler *vs, Common::WriteStream *stream);
+StackHandler *loadStackRef(Common::SeekableReadStream *stream);
+void clearStackLib();
} // End of namespace Sludge
diff --git a/engines/supernova/detection.cpp b/engines/supernova/detection.cpp
index 8e9db14db4..b172b7fa49 100644
--- a/engines/supernova/detection.cpp
+++ b/engines/supernova/detection.cpp
@@ -32,7 +32,7 @@
static const PlainGameDescriptor supernovaGames[] = {
{"msn1", "Mission Supernova 1"},
{"msn2", "Mission Supernova 2"},
- {NULL, NULL}
+ {nullptr, nullptr}
};
namespace Supernova {
@@ -40,7 +40,7 @@ static const ADGameDescription gameDescriptions[] = {
// Mission Supernova 1
{
"msn1",
- NULL,
+ nullptr,
AD_ENTRY1s("msn_data.000", "f64f16782a86211efa919fbae41e7568", 24163),
Common::DE_DEU,
Common::kPlatformDOS,
@@ -49,7 +49,7 @@ static const ADGameDescription gameDescriptions[] = {
},
{
"msn1",
- NULL,
+ nullptr,
AD_ENTRY1s("msn_data.000", "f64f16782a86211efa919fbae41e7568", 24163),
Common::EN_ANY,
Common::kPlatformDOS,
@@ -60,13 +60,22 @@ static const ADGameDescription gameDescriptions[] = {
// Mission Supernova 2
{
"msn2",
- NULL,
+ nullptr,
AD_ENTRY1s("ms2_data.000", "e595610cba4a6d24a763e428d05cc83f", 24805),
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
+ {
+ "msn2",
+ nullptr,
+ AD_ENTRY1s("ms2_data.000", "e595610cba4a6d24a763e428d05cc83f", 24805),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
AD_TABLE_END_MARKER
};
@@ -122,7 +131,7 @@ bool SupernovaMetaEngine::createInstance(OSystem *syst, Engine **engine, const A
*engine = new Supernova::SupernovaEngine(syst);
}
- return desc != NULL;
+ return desc != nullptr;
}
SaveStateList SupernovaMetaEngine::listSaves(const char *target) const {
@@ -200,7 +209,11 @@ SaveStateDescriptor SupernovaMetaEngine::querySaveMetaInfos(const char *target,
desc.setPlayTime(playTime * 1000);
if (Graphics::checkThumbnailHeader(*savefile)) {
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*savefile);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*savefile, thumbnail)) {
+ delete savefile;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
}
diff --git a/engines/supernova/graphics.cpp b/engines/supernova/graphics.cpp
index 3a29bacacc..9a05a424ca 100644
--- a/engines/supernova/graphics.cpp
+++ b/engines/supernova/graphics.cpp
@@ -28,13 +28,14 @@
#include "graphics/palette.h"
#include "graphics/surface.h"
-#include "graphics.h"
-#include "msn_def.h"
-#include "supernova.h"
+#include "supernova/graphics.h"
+#include "supernova/msn_def.h"
+#include "supernova/screen.h"
+#include "supernova/supernova.h"
namespace Supernova {
-MSNImageDecoder::MSNImageDecoder() {
+MSNImage::MSNImage() {
_palette = nullptr;
_encodedImage = nullptr;
_filenumber = -1;
@@ -43,11 +44,11 @@ MSNImageDecoder::MSNImageDecoder() {
_numClickFields = 0;
}
-MSNImageDecoder::~MSNImageDecoder() {
+MSNImage::~MSNImage() {
destroy();
}
-bool MSNImageDecoder::init(int filenumber) {
+bool MSNImage::init(int filenumber) {
Common::File file;
if (!file.open(Common::String::format("msn_data.%03d", filenumber))) {
warning("Image data file msn_data.%03d could not be read!", filenumber);
@@ -60,7 +61,7 @@ bool MSNImageDecoder::init(int filenumber) {
return true;
}
-bool MSNImageDecoder::loadFromEngineDataFile() {
+bool MSNImage::loadFromEngineDataFile() {
Common::String name;
if (_filenumber == 1)
name = "IMG1";
@@ -102,7 +103,7 @@ bool MSNImageDecoder::loadFromEngineDataFile() {
return false;
}
-bool MSNImageDecoder::loadStream(Common::SeekableReadStream &stream) {
+bool MSNImage::loadStream(Common::SeekableReadStream &stream) {
destroy();
uint size = 0;
@@ -199,7 +200,7 @@ bool MSNImageDecoder::loadStream(Common::SeekableReadStream &stream) {
return true;
}
-bool MSNImageDecoder::loadSections() {
+bool MSNImage::loadSections() {
bool isNewspaper = _filenumber == 1 || _filenumber == 2;
int imageWidth = isNewspaper ? 640 : 320;
int imageHeight = isNewspaper ? 480 : 200;
@@ -238,14 +239,14 @@ bool MSNImageDecoder::loadSections() {
return true;
}
-void MSNImageDecoder::destroy() {
+void MSNImage::destroy() {
if (_palette) {
delete[] _palette;
- _palette = NULL;
+ _palette = nullptr;
}
if (_encodedImage) {
delete[] _encodedImage;
- _encodedImage = NULL;
+ _encodedImage = nullptr;
}
for (Common::Array<Graphics::Surface *>::iterator it = _sectionSurfaces.begin();
it != _sectionSurfaces.end(); ++it) {
diff --git a/engines/supernova/graphics.h b/engines/supernova/graphics.h
index 2a820c9432..058da45ba8 100644
--- a/engines/supernova/graphics.h
+++ b/engines/supernova/graphics.h
@@ -36,10 +36,10 @@ struct Surface;
namespace Supernova {
-class MSNImageDecoder : public Image::ImageDecoder {
+class MSNImage : public Image::ImageDecoder {
public:
- MSNImageDecoder();
- virtual ~MSNImageDecoder();
+ MSNImage();
+ virtual ~MSNImage();
virtual void destroy();
virtual bool loadStream(Common::SeekableReadStream &stream);
diff --git a/engines/supernova/imageid.h b/engines/supernova/imageid.h
new file mode 100644
index 0000000000..7cfa08370e
--- /dev/null
+++ b/engines/supernova/imageid.h
@@ -0,0 +1,654 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public 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 SUPERNOVA_IMAGEID_H
+#define SUPERNOVA_IMAGEID_H
+
+namespace Supernova {
+
+enum ImageId {
+ // file 0
+ kAxacussanShipBackground,
+ kAxacussanShipCenterMouthOpen,
+ kAxacussanShipRightMouthOpen,
+ // file 1
+ kNewspaper1,
+ // file 2
+ kNewspaper2,
+ // file 3
+ kElevatorBackground,
+ kElevatorGreenButton,
+ kElevatorRedButton,
+ kElevatorDoorAnimation1,
+ kElevatorDoorAnimation2,
+ kElevatorDoorAnimation3,
+ kElevatorDoorAnimation4,
+ kElevatorDoorAnimation5,
+ kElevatorDummy1,
+ kElevatorDummy2,
+ kElevatorDummy3,
+ kElevatorDummy4,
+ // file 4
+ kShipSpaceBackground,
+ kShipSpaceRope,
+ kShipSpaceDummy1,
+ kShipSpaceDummy2,
+ // file 5
+ kBusStationBackground,
+ kBusStationArrived,
+ kBusStationPlantAnimation1,
+ kBusStationPlantAnimation2,
+ kBusStationPlantAnimation3,
+ kBusStationPlantAnimation4,
+ kBusStationPlantAnimation5,
+ kBusStationPlantAnimation6,
+ kBusStationPlantAnimation7,
+ kBusStationDoorOpened,
+ // file 6
+ kOfficesBackground,
+ kOfficesDoorOpenTopLeft,
+ kOfficesDoorOpenBottomLeft,
+ kOfficesDoorOpenTopRight,
+ kOfficesDoorOpenBottomRight,
+ kOfficesAlienCorridorAnimation1,
+ kOfficesAlienCorridorAnimation2,
+ kOfficesAlienCorridorAnimation3,
+ kOfficesAlienCorridorAnimation4,
+ kOfficesAlienCorridorAnimation5,
+ kOfficesAlienCorridorAnimation6,
+ kOfficesAlienTopOfficeAnimation1,
+ kOfficesAlienTopOfficeAnimation2,
+ kOfficesAlienTopOfficeAnimation3,
+ kOfficesAlienTopOfficeAnimation4,
+ kOfficesAlienTopOfficeAnimation5,
+ kOfficesAlienBottomOfficeAnimation1,
+ kOfficesAlienBottomOfficeAnimation2,
+ kOfficesAlienBottomOfficeAnimation3,
+ kOfficesAlienBottomOfficeAnimation4,
+ kOfficesAlienBottomOfficeAnimation5,
+ kOfficesAlienBottom,
+ // file 7
+ kOfficeLeftBackground,
+ kOfficeLeftDecoration,
+ kOfficeLeftMemo,
+ kOfficeLeftGraffiti,
+ kOfficeLeftTerminalSmashed,
+ kOfficeLeftDrawerMoney,
+ kOfficeLeftSafeOpen,
+ kOfficeLeftSafeClosed,
+ kOfficeLeftSafeMoney,
+ kOfficeLeftDoorOpen,
+ kOfficeLeftAlienShootAnimation1,
+ kOfficeLeftAlienShootAnimation2,
+ kOfficeLeftAlienShootAnimation3,
+ kOfficeLeftAlienShootAnimation4,
+ kOfficeLeftAlienShootAnimation5,
+ kOfficeLeftAlienShootAnimation6,
+ kOfficeLeftTerminalText,
+ kOfficeLeftDoorClosed,
+ kOfficeLeftDummy1,
+ kOfficeLeftDummy2,
+ kOfficeLeftDummy3,
+ kOfficeLeftDummy4,
+ kOfficeLeftDummy5,
+ // file 8
+ kOfficeRightBackground,
+ kOfficeRightDecorationPictures,
+ kOfficeRightDecorationPlants,
+ kOfficeRightDoorOpen,
+ kOfficeRightTerminalSmashed,
+ kOfficeRightAlienShootAnimation1,
+ kOfficeRightAlienShootAnimation2,
+ kOfficeRightAlienShootAnimation3,
+ kOfficeRightAlienTalking,
+ kOfficeRightDummy1,
+ kOfficeRightDummy2,
+ kOfficeRightDummy3,
+ kOfficeRightDummy4,
+ // file 9
+ kShipCockpitBackground,
+ kShipCockpitPilotAnimation1,
+ kShipCockpitPilotAnimation2,
+ kShipCockpitPilotAnimation3,
+ kShipCockpitPilotAnimation4,
+ kShipCockpitPilotAnimation5,
+ kShipCockpitPilotAnimation6,
+ kShipCockpitPilotAnimation7,
+ kShipCockpitPilotAnimation8,
+ kShipCockpitPilotAnimation9,
+ kShipCockpitPilotAnimation10,
+ kShipCockpitPilotAnimation11,
+ kShipCockpitPilotAnimation12,
+ kShipCockpitPilotAnimation13,
+ kShipCockpitPilotAnimation14,
+ kShipCockpitPilotAnimation15,
+ kShipCockpitPilotAnimation16,
+ kShipCockpitPilotAnimation17,
+ kShipCockpitPilotAnimation18,
+ kShipCockpitPilotAnimation19,
+ kShipCockpitPilotAnimation20,
+ kShipCockpitDisplayStatusAnimation1,
+ kShipCockpitDisplayStatusAnimation2,
+ kShipCockpitWindowRocks,
+ // file 10
+ kRestaurantEntranceBackground,
+ kRestaurantEntrancePorterAnimation1,
+ kRestaurantEntrancePorterAnimation2,
+ kRestaurantEntrancePorterAnimation3,
+ kRestaurantEntrancePorterAnimation4,
+ kRestaurantEntranceBathroomDoorAnimation1,
+ kRestaurantEntranceBathroomDoorAnimation2,
+ kRestaurantEntranceBathroomDoorAnimation3,
+ kRestaurantEntranceBathroomDoorAnimation4,
+ kRestaurantEntranceBathroomDoorAnimation5,
+ kRestaurantEntranceGreenCandy,
+ kRestaurantEntranceBlueCandy,
+ kRestaurantEntrancePinkCandy,
+ kRestaurantEntranceWhiteCandy,
+ kRestaurantEntranceBlackCandy,
+ kRestaurantEntraceDummy1,
+ kRestaurantEntraceDummy2,
+ // file 11
+ kDeathScreen,
+ // file 12
+ kRocksBackground,
+ kRocksRockAnimation1,
+ kRocksRockAnimation2,
+ kRocksRockAnimation3,
+ // file 13
+ kBluePlanetBackground,
+ kBluePlanetShipAnimation1,
+ kBluePlanetShipAnimation2,
+ kBluePlanetShipAnimation3,
+ kBluePlanetShipAnimation4,
+ kBluePlanetShipAnimation5,
+ kBluePlanetShipAnimation6,
+ kBluePlanetShipAnimation7,
+ kBluePlanetShipAnimation8,
+ kBluePlanetShipAnimation9,
+ kBluePlanetShipAnimation10,
+ kBluePlanetShipAnimation11,
+ kBluePlanetShipAnimation12,
+ kBluePlanetShipAnimation13,
+ // file 14
+ kRogerCrashBackground,
+ kRogerCrashAnimation1,
+ kRogerCrashAnimation2,
+ kRogerCrashAnimation3,
+ kRogerCrashAnimation4,
+ kRogerCrashAnimation5,
+ kRogerCrashAnimation6,
+ kRogerCrashAnimation7,
+ kRogerCrashAnimation8,
+ kRogerCrashAnimation9,
+ kRogerCrashAnimation10,
+ kRogerCrashAnimation11,
+ kRogerCrashAnimation12,
+ kRogerCrashAnimation13,
+ kRogerCrashAnimation14,
+ kRogerCrashAnimation15,
+ kRogerCrashAnimation16,
+ kRogerCrashAnimation17,
+ kRogerCrashAnimation18,
+ kRogerCrashAnimation19,
+ // file 15
+ kShipCorridorBackground,
+ kShipCorridorCockpitDoorOpen,
+ kShipCorridorSleepCabinDoorAnimation1,
+ kShipCorridorSleepCabinDoorAnimation2,
+ kShipCorridorSleepCabinDoorAnimation3,
+ kShipCorridorDummy1,
+ // file 16
+ kAxacussCorridorTileWalled,
+ kAxacussCorridorToLeft,
+ kAxacussCorridorToRight,
+ kAxacussCorridorToTop,
+ kAxacussCorridorToBottom,
+ kAxacussCorridorTile,
+ kAxacussCorridorDoorClosed,
+ kAxacussCorridorDoorOpen,
+ kAxacussCorridorDesk,
+ kAxacussCorridorLaptop,
+ kAxacussCorridorStuff10,
+ kAxacussCorridorStuff11,
+ kAxacussCorridorStuff12,
+ kAxacussCorridorStuff13,
+ kAxacussCorridorStuff14,
+ kAxacussCorridorStuff15,
+ kAxacussCorridorStuff16,
+ kAxacussCorridorStuff17,
+ kAxacussCorridorStuff18,
+ kAxacussCorridorStuff19,
+ kAxacussCorridorStuff21,
+ kAxacussCorridorStuff22,
+ kAxacussCorridorStuff23,
+ kAxacussCorridorStuff24,
+ kAxacussCorridorStuff25,
+ kAxacussCorridorStuff26,
+ kAxacussCorridorStuff27,
+ kAxacussCorridorStuff28,
+ kAxacussCorridorAlarmStatus,
+ kAxacussCorridorAlienRight,
+ kAxacussCorridorAlienLeft,
+ kAxacussCorridorAlienBottom,
+ kAxacussCorridorAlienTop,
+ kAxacussCorridorDummy1,
+ // file 17
+ kShipCorridorCabinBackground,
+ kShipCorridorCabinL1Open,
+ kShipCorridorCabinL2Open,
+ kShipCorridorCabinL3Open,
+ kShipCorridorCabinR1Open,
+ kShipCorridorCabinR2Open,
+ kShipCorridorCabinR3Open,
+ kShipCorridorCabinAirlockDoorAnimation1,
+ kShipCorridorCabinAirlockDoorAnimation2,
+ kShipCorridorCabinAirlockDoorAnimation3,
+ kShipCorridorCabinDummy1,
+ kShipCorridorCabinDummy2,
+ kShipCorridorCabinDummy3,
+ kShipCorridorCabinDummy4,
+ kShipCorridorCabinDummy5,
+ kShipCorridorCabinDummy6,
+ // file 18
+ kShipGeneratorBackground,
+ kShipGeneratorHatchOpen,
+ kShipGeneratorJunctionBoxOpen,
+ kShipGeneratorJunctionBoxOffline,
+ kShipGeneratorJunctionBoxDisplay,
+ kShipGeneratorKeycard,
+ kShipGeneratorSpoolFloating,
+ kShipGeneratorSpoolOnGround,
+ kShipGeneratorCableUnplugged,
+ kShipGeneratorCablePluggedIn,
+ kShipGeneratorHatchRocks,
+ kShipGeneratorRopeRocks,
+ kShipGeneratorRopeSpace,
+ kShipGeneratorRopeFloor,
+ kShipGeneratorDummy1,
+ kShipGeneratorDummy2,
+ kShipGeneratorDummy3,
+ kShipGeneratorDummy4,
+ kShipGeneratorDummy5,
+ kShipGeneratorDummy6,
+ kShipGeneratorDummy7,
+ kShipGeneratorDummy8,
+ // file 19
+ kRogerShipBackground,
+ kRogerShipButtonPressed1,
+ kRogerShipButtonPressed2,
+ kRogerShipButtonPressed3,
+ kRogerShipButtonPressed4,
+ kRogerShipCardInSlot,
+ kRogerShipCompartmentOpen,
+ kRogerShipUnknown7,
+ kRogerShipDisplayLeftOn,
+ kRogerShipGreenDisplayAnimation1,
+ kRogerShipGreenDisplayAnimation2,
+ kRogerShipGreenDisplayAnimation3,
+ kRogerShipGreenDisplayAnimation4,
+ kRogerShipGreenDisplayAnimation5,
+ kRogerShipGreenDisplayAnimation6,
+ kRogerShipGreenDisplayAnimation7,
+ kRogerShipBlueDisplayAnimation1,
+ kRogerShipBlueDisplayAnimation2,
+ kRogerShipBlueDisplayAnimation3,
+ kRogerShipBlueDisplayAnimation4,
+ kRogerShipBlueDisplayAnimation5,
+ kRogerShipBlueDisplayAnimation6,
+ kRogerShipBlueDisplayAnimation7,
+ kRogerShipUnknown23,
+ kRogerShipDisplaySinewaveAnimation1,
+ kRogerShipDisplaySinewaveAnimation2,
+ kRogerShipDisplaySinewaveAnimation3,
+ kRogerShipDisplaySinewaveAnimation4,
+ kRogerShipDisplaySinewaveAnimation5,
+ kRogerShipDisplaySinewaveAnimation6,
+ kRogerShipDisplaySinewaveAnimation7,
+ kRogerShipDisplaySinewaveAnimation8,
+ kRogerShipDisplaySinewaveAnimation9,
+ kRogerShipDisplaySinewaveAnimation10,
+ kRogerShipDisplaySinewaveAnimation11,
+ kRogerShipDisplaySinewaveAnimation12,
+ kRogerShipDisplaySinewaveAnimation13,
+ kRogerShipDisplaySinewaveAnimation14,
+ kRogerShipCompartmentContent,
+ kRogerShipDummy1,
+ kRogerShipDummy2,
+ // file 20
+ kHelpScreen,
+ // file 21
+ kShipCabinLeftBackground,
+ kShipCabinLeftPaintingSunset,
+ kShipCabinLeftPaintingLandscape,
+ kShipCabinLeftPaintingAbstract,
+ kShipCabinLeftTableStuff1,
+ kShipCabinLeftCeilingPencil,
+ kShipCabinLeft3Decoration,
+ kShipCabinLeftSocketPluggedIn,
+ kShipCabinLeftVinyl,
+ kShipCabinLeftTurntable,
+ kShipCabinLeftSocketUnplugged,
+ kShipCabinLeftTurntableCableCut,
+ kShipCabinLeftTurntableCable,
+ kShipCabinLeftTurntableAnimation1,
+ kShipCabinLeftTurntableAnimation2,
+ kShipCabinLeftTurntableAnimation3,
+ kShipCabinLeftTableStuff2,
+ kShipCabinLeftLockerOpen,
+ kShipCabinLeftLockerBooksOpen,
+ kShipCabinLeftLockerSpoolOpen,
+ kShipCabinLeftLockerPistolRemoved,
+ kShipCabinLeftLockerSpoolRemoved,
+ kShipCabinLeftBedSafeOpen,
+ kShipCabinLeftBedSafeEmpty,
+ kShipCabinLeftDoorClosed,
+ kShipCabinLeftTurntableCableSparks,
+ kShipCabinLeftTurntableCableCutEnd,
+ kShipCabinLeftDummy1,
+ kShipCabinLeftDummy2,
+ kShipCabinLeftDummy3,
+ kShipCabinLeftDummy4,
+ kShipCabinLeftDummy5,
+ kShipCabinLeftDummy6,
+ kShipCabinLeftDummy7,
+ kShipCabinLeftDummy8,
+ kShipCabinLeftDummy9,
+ kShipCabinLeftDummy10,
+ kShipCabinLeftDummy11,
+ kShipCabinLeftDummy12,
+ // file 22
+ kShipCabinRightBackground,
+ kShipCabinRightPosterSnowman,
+ kShipCabinRightTableStuff,
+ kShipCabinRightCeilingChess,
+ kShipCabinRightTennisRacket,
+ kShipCabinRightTennisBallsFloating,
+ kShipCabinRightTennisBallsOnGround,
+ kShipCabinRightTableChess,
+ kShipCabinRight2Bed,
+ kShipCabinRightLockerBooksOpen,
+ kShipCabinRightLockerRopeOpen,
+ kShipCabinRightLockerOpen,
+ kShipCabinRightLockerRopeRemoved,
+ kShipCabinRightBedSafeOpen,
+ kShipCabinRightBedSafeEmpty,
+ kShipCabinRightDoorClosed,
+ kShipCabinRightLockerDiscmanRemoved,
+ kShipCabinRightDummy1,
+ kShipCabinRightDummy2,
+ // file 23
+ kShipBathroomBackground,
+ // file 24
+ kShipHoldBackgroundFloating,
+ kShipHoldBackgroundOnGround,
+ kShipHoldLandingModuleDoorOpen,
+ kShipHoldGeneratorHatchOpen,
+ kShipHoldLandingModuleSpool,
+ kShipHoldCableToGeneratorUnplugged,
+ kShipHoldCableToGeneratorPluggedIn,
+ kShipHoldDummy1,
+ kShipHoldDummy2,
+ // file 25
+ kShipLandingModuleBackground,
+ kShipLandingModuleDoorClosed,
+ kShipLandingModuleDisplayLeftOn,
+ kShipLandingModuleCablePluggedIn,
+ kShipLandingModuleCableSpoolConnected,
+ kShipLandingModuleCableToHold,
+ kShipLandingModuleDisplayRightOn,
+ kShipLandingModuleDisplayTop1On,
+ kShipLandingModuleDisplayTop2On,
+ kShipLandingModuleDisplayTop3On,
+ kShipLandingModuleCableWithTerminalStrip,
+ kShipLandingModuleDummy1,
+ kShipLandingModuleDummy2,
+ kShipLandingModuleDummy3,
+ kShipLandingModuleDummy4,
+ kShipLandingModuleDummy5,
+ kShipLandingModuleDummy6,
+ kShipLandingModuleDummy7,
+ kShipLandingModuleDummy8,
+ // file 26
+ kArsanoStar,
+ // file 27
+ kSaveLoadScreen,
+ // file 28
+ kRestaurantBackground,
+ kRestaurantAnimation1,
+ kRestaurantAnimation2,
+ kRestaurantAnimation3,
+ kRestaurantAnimation4,
+ kRestaurantAnimation5,
+ kRestaurantAnimation6,
+ kRestaurantAnimation7,
+ kRestaurantAnimation8,
+ kRestaurantAnimation9,
+ kRestaurantAnimation10,
+ kRestaurantAnimation11,
+ kRestaurantAnimation12,
+ kRestaurantAnimation13,
+ kRestaurantAnimation14,
+ kRestaurantAnimation15,
+ kRestaurantAnimation16,
+ kRestaurantAnimation17,
+ kRestaurantAnimation18,
+ kRestaurantAnimation19,
+ kRestaurantAnimation20,
+ kRestaurantAnimation21,
+ kRestaurantAnimation22,
+ // file 29
+ kRestaurantRogerBackground,
+ kRestaurantRogerEyes1Closed,
+ kRestaurantRogerMouthOpen,
+ kRestaurantRogerPlayingChess,
+ kRestaurantRogerWalletRemoved,
+ kRestaurantRogerHandAnimation1,
+ kRestaurantRogerHandAnimation2,
+ kRestaurantRogerHandAnimation3,
+ kRestaurantRogerHandAnimation4,
+ kRestaurantRogerHandAnimation5,
+ kRestaurantRogerEyes2Closed,
+ kRestaurantRogerChessBoard,
+ kRestaurantRogerEyes2Open,
+ kRestaurantRogerDummy1,
+ // file 30
+ kRogerOutsideBackground,
+ kRogerOutsideMouthOpen,
+ // file 31
+ kIntroScreenBackground,
+ kIntroScreenShipAnimation1,
+ kIntroScreenShipAnimation2,
+ kIntroScreenShipAnimation3,
+ kIntroScreenShipAnimation4,
+ kIntroScreenShipAnimation5,
+ kIntroScreenShipAnimation6,
+ // file 32
+ kBusStationSignBackground,
+ kBusStationSignPrice,
+ kBusStationSignPleaseWait,
+ kBusStationSignPleasantFlight,
+ // file 33
+ kShipSleepCabinBackground,
+ kShipSleepCabinTerminalWarning,
+ kShipSleepCabinTerminal1,
+ kShipSleepCabinTerminal2,
+ kShipSleepCabinStatusLight,
+ kShipSleepCabinTerminal3,
+ // file 34
+ kShipAirlockBackground,
+ kShipAirlockDoorLeftAnimation1,
+ kShipAirlockDoorLeftAnimation2,
+ kShipAirlockDoorLeftAnimation3,
+ kShipAirlockDoorRightAnimation1,
+ kShipAirlockDoorRightAnimation2,
+ kShipAirlockDoorRightAnimation3,
+ kShipAirlockHelmetRemoved,
+ kShipAirlockSpacesuitRemoved,
+ kShipAirlockSupplyRemoved,
+ kShipAirlockDoorLeftButton,
+ kShipAirlockDoorRightButton,
+ kShipAirlockManometerAnimation1,
+ kShipAirlockManometerAnimation2,
+ kShipAirlockManometerAnimation3,
+ kShipAirlockManometerAnimation4,
+ kShipAirlockManometerAnimation5,
+ kShipAirlockManometerAnimation6,
+ // file 35
+ kAxacussSpaceBackground,
+ kAxacussSpaceShipAnimation1,
+ kAxacussSpaceShipAnimation2,
+ kAxacussSpaceShipAnimation3,
+ kAxacussSpaceShipAnimation4,
+ kAxacussSpaceShipAnimation5,
+ kAxacussSpaceShipAnimation6,
+ kAxacussSpaceShipAnimation7,
+ kAxacussSpaceBusAnimation1,
+ kAxacussSpaceBusAnimation2,
+ kAxacussSpaceBusAnimation3,
+ kAxacussSpaceBusAnimation4,
+ kAxacussSpaceBusAnimation5,
+ kAxacussSpaceBusAnimation6,
+ kAxacussSpaceBusAnimation7,
+ kAxacussSpaceBusAnimation8,
+ kAxacussSpaceBusAnimation9,
+ kAxacussSpaceBusAnimation10,
+ kAxacussSpaceBusAnimation11,
+ kAxacussSpaceBusAnimation12,
+ kAxacussSpaceBusAnimation13,
+ kAxacussSpaceBusAnimation14,
+ // file 36
+ kAxacussanCapsuleBackground,
+ kAxacussanCapsuleRobotAnimation1,
+ kAxacussanCapsuleRobotAnimation2,
+ kAxacussanCapsuleRobotAnimation3,
+ kAxacussanCapsuleRobotAnimation4,
+ kAxacussanCapsuleDummy1,
+ // file 37
+ kArsanoMeetupBackground,
+ kArsanoMeetupRestaurantLightAnimation1,
+ kArsanoMeetupRestaurantLightAnimation2,
+ kArsanoMeetupRestaurantLightAnimation3,
+ kArsanoMeetupRestaurantLightAnimation4,
+ kArsanoMeetupRestaurantLightAnimation5,
+ kArsanoMeetupRestaurantDoorAnimation1,
+ kArsanoMeetupRestaurantDoorAnimation2,
+ kArsanoMeetupRestaurantDoorSignAnimation1,
+ kArsanoMeetupRestaurantDoorSignAnimation2,
+ kArsanoMeetupRestaurantDoorSignAnimation3,
+ kArsanoMeetupRestaurantDoorSignAnimation4,
+ kArsanoMeetupRestaurantDoorSignAnimation5,
+ kArsanoMeetupRestaurantSignAnimation1,
+ kArsanoMeetupRestaurantSignAnimation2,
+ kArsanoMeetupRestaurantSignAnimation3,
+ kArsanoMeetupRestaurantSignAnimation4,
+ kArsanoMeetupRestaurantSignAnimation5,
+ kArsanoMeetupRestaurantSignAnimation6,
+ kArsanoMeetupRestaurantSignAnimation7,
+ kArsanoMeetupRestaurantSignAnimation8,
+ kArsanoMeetupRestaurantSignAnimation9,
+ kArsanoMeetupRestaurantSignAnimation10,
+ kArsanoMeetupRestaurantSignAnimation11,
+ kArsanoMeetupRestaurantSignAnimation12,
+ kArsanoMeetupRestaurantSignAnimation13,
+ kArsanoMeetupRestaurantSignAnimation14,
+ // file 38
+ kArsanoAfterNovaBackground,
+ kArsanoAfterNovaRogerShipAnimation1,
+ kArsanoAfterNovaRogerShipAnimation2,
+ kArsanoAfterNovaRogerShipAnimation3,
+ kArsanoAfterNovaRogerShipAnimation4,
+ kArsanoAfterNovaRogerShipAnimation5,
+ kArsanoAfterNovaRogerShipAnimation6,
+ kArsanoAfterNovaRogerShipAnimation7,
+ kArsanoAfterNovaRogerShipAnimation8,
+ kArsanoAfterNovaRogerShipAnimation9,
+ kArsanoAfterNovaRogerShipAnimation10,
+ kArsanoAfterNovaRogerShipAnimation11,
+ kArsanoAfterNovaRoger,
+ // file 39
+ kArsanoDesolate,
+ // file 40
+ kIntersectionBackground,
+ kIntersectionGuardRemoved,
+ kIntersectionGuardMouthOpen,
+ kIntersectionGuardShootAnimation1,
+ kIntersectionGuardShootAnimation2,
+ kIntersectionGuardMouthClosed,
+ kIntersectionDoorOpen,
+ kIntersectoinKeycard,
+ // file 41
+ kInformationDeskBackground,
+ kInformationDeskAlienMouthOpen,
+ kInformationDeskAlienHandMoved,
+ kInformationDeskAlienShoot,
+ // file 42
+ kArtGalleryBackground,
+ kArtGalleryAlienShootAnimation1,
+ kArtGalleryAlienShootAnimation2,
+ kArtGalleryAlienShootAnimation3,
+ kArtGalleryThrowingBlockAnimation1,
+ kArtGalleryThrowingBlockAnimation2,
+ kArtGalleryThrowingBlockAnimation3,
+ kArtGalleryThrowingBlockAnimation4,
+ kArtGalleryThrowingBlockAnimation5,
+ kArtGalleryThrowingBlockAnimation6,
+ kArtGalleryThrowingBlockAnimation7,
+ kArtGalleryDummy1,
+ // file 43
+ kCellBackground,
+ kCellCablePluggedIn,
+ kCellCableUnplugged,
+ kCellCableCutUnplugged,
+ kCellCableCutPluggedIn,
+ kCellCableCutTableUnplugged,
+ kCellCableCutTablePluggedIn,
+ kCellTableTablet,
+ kCellRobotComesAnimation1,
+ kCellRobotComesAnimation2,
+ kCellRobotComesAnimation3,
+ kCellRobotComesAnimation4,
+ kCellRobotComesAnimation5,
+ kCellRobotComesAnimation6,
+ kCellRobotComesAnimation7,
+ kCellRobotComesAnimation8,
+ kCellRobotComesAnimation9,
+ kCellRobotComesAnimation10,
+ kCellRobotComesAnimation11,
+ kCellRobotLeavesAnimation1,
+ kCellRobotLeavesAnimation2,
+ kCellRobotLeavesAnimation3,
+ kCellRobotLeavesAnimation4,
+ kCellRobotLeavesAnimation5,
+ kCellRobotLeavesAnimation6,
+ kCellRobotLeavesAnimation7,
+ kCellRobotLeavesAnimation8,
+ kCellRobotLeavesAnimation9,
+ kCellRobotSparks,
+ kCellRobotBroken,
+ kCellDoorClosed,
+ kCellDummy1
+};
+
+}
+
+#endif
diff --git a/engines/supernova/module.mk b/engines/supernova/module.mk
index 9baf196c7c..722a230cde 100644
--- a/engines/supernova/module.mk
+++ b/engines/supernova/module.mk
@@ -4,9 +4,12 @@ MODULE_OBJS := \
console.o \
detection.o \
graphics.o \
- supernova.o \
+ resman.o \
rooms.o \
- state.o
+ screen.o \
+ sound.o \
+ state.o \
+ supernova.o
MODULE_DIRS += \
engines/supernova
diff --git a/engines/supernova/msn_def.h b/engines/supernova/msn_def.h
index c18baa068c..6ce16b8283 100644
--- a/engines/supernova/msn_def.h
+++ b/engines/supernova/msn_def.h
@@ -25,10 +25,6 @@
namespace Supernova {
-const int kScreenWidth = 320;
-const int kScreenHeight = 200;
-const int kFontWidth = 5;
-const int kFontHeight = 8;
const int kTextSpeed[] = {19, 14, 10, 7, 4};
const int kMsecPerTick = 55;
@@ -50,266 +46,6 @@ enum MessagePosition {
kMessageTop
};
-enum AudioIndex {
- kAudioFoundLocation, // 44|0
- kAudioCrash, // 45|0
- kAudioVoiceHalt, // 46|0
- kAudioGunShot, // 46|2510
- kAudioSmash, // 46|4020
- kAudioVoiceSupernova, // 47|0
- kAudioVoiceYeah, // 47|24010
- kAudioRobotShock, // 48|0
- kAudioRobotBreaks, // 48|2510
- kAudioShock, // 48|10520
- kAudioTurntable, // 48|13530
- kAudioSiren, // 50|0
- kAudioSnoring, // 50|12786
- kAudioRocks, // 51|0
- kAudioDeath, // 53|0
- kAudioAlarm, // 54|0
- kAudioSuccess, // 54|8010
- kAudioSlideDoor, // 54|24020
- kAudioDoorOpen, // 54|30030
- kAudioDoorClose, // 54|31040
- kAudioNumSamples
-};
-
-enum MusicIndex {
- kMusicIntro = 52,
- kMusicOutro = 49
-};
-
-struct AudioInfo {
- int _filenumber;
- int _offsetStart;
- int _offsetEnd;
-};
-
-const int kColorBlack = 0;
-const int kColorWhite25 = 1;
-const int kColorWhite35 = 2;
-const int kColorWhite44 = 3;
-const int kColorWhite99 = 4;
-const int kColorDarkGreen = 5;
-const int kColorGreen = 6;
-const int kColorDarkRed = 7;
-const int kColorRed = 8;
-const int kColorDarkBlue = 9;
-const int kColorBlue = 10;
-const int kColorWhite63 = 11;
-const int kColorLightBlue = 12;
-const int kColorLightGreen = 13;
-const int kColorLightYellow = 14;
-const int kColorLightRed = 15;
-const int kColorCursorTransparent = kColorWhite25;
-
-const byte mouseNormal[64] = {
- 0xff,0x3f,0xff,0x1f,0xff,0x0f,0xff,0x07,
- 0xff,0x03,0xff,0x01,0xff,0x00,0x7f,0x00,
- 0x3f,0x00,0x1f,0x00,0x0f,0x00,0x0f,0x00,
- 0xff,0x00,0x7f,0x18,0x7f,0x38,0x7f,0xfc,
-
- 0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x70,
- 0x00,0x78,0x00,0x7c,0x00,0x7e,0x00,0x7f,
- 0x80,0x7f,0xc0,0x7f,0xe0,0x7f,0x00,0x7e,
- 0x00,0x66,0x00,0x43,0x00,0x03,0x00,0x00
-};
-
-const byte mouseWait[64] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
- 0x01,0x80,0x01,0x80,0x11,0x88,0x31,0x8c,
- 0x31,0x8c,0x11,0x88,0x01,0x80,0x01,0x80,
- 0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0xfe,0x7f,0xf4,0x2f,0xf4,0x2f,
- 0x14,0x28,0x24,0x24,0x44,0x22,0x84,0x21,
- 0x84,0x21,0xc4,0x23,0xe4,0x27,0x74,0x2e,
- 0x34,0x2c,0x14,0x28,0xfe,0x7f,0x00,0x00
-};
-
-const byte font[][5] = {
- {0x00,0x00,0x00,0xff,0x00},
- {0x5f,0xff,0x00,0x00,0x00},
- {0x03,0x00,0x03,0xff,0x00},
- {0x14,0x7f,0x14,0x7f,0x14},
- {0x24,0x2a,0x7f,0x2a,0x12},
- {0x61,0x10,0x08,0x04,0x43},
- {0x38,0x4e,0x59,0x26,0x50},
- {0x03,0xff,0x00,0x00,0x00},
- {0x3e,0x41,0xff,0x00,0x00},
- {0x41,0x3e,0xff,0x00,0x00},
- {0x10,0x54,0x38,0x54,0x10},
- {0x10,0x10,0x7c,0x10,0x10},
- {0x80,0x40,0xff,0x00,0x00},
- {0x10,0x10,0x10,0x10,0x10},
- {0x40,0xff,0x00,0x00,0x00},
- {0x60,0x10,0x08,0x04,0x03},
-
- {0x3e,0x41,0x41,0x41,0x3e}, /* digits */
- {0x04,0x02,0x7f,0xff,0x00},
- {0x42,0x61,0x51,0x49,0x46},
- {0x22,0x41,0x49,0x49,0x36},
- {0x18,0x14,0x12,0x7f,0x10},
- {0x27,0x45,0x45,0x45,0x39},
- {0x3e,0x49,0x49,0x49,0x32},
- {0x01,0x61,0x19,0x07,0x01},
- {0x36,0x49,0x49,0x49,0x36},
- {0x26,0x49,0x49,0x49,0x3e},
-
- {0x44,0xff,0x00,0x00,0x00},
- {0x80,0x44,0xff,0x00,0x00},
- {0x10,0x28,0x44,0xff,0x00},
- {0x28,0x28,0x28,0x28,0x28},
- {0x44,0x28,0x10,0xff,0x00},
- {0x02,0x01,0x51,0x09,0x06},
- {0x3e,0x41,0x5d,0x5d,0x1e},
-
- {0x7c,0x12,0x11,0x12,0x7c}, /* uppercase letters*/
- {0x7f,0x49,0x49,0x49,0x36},
- {0x3e,0x41,0x41,0x41,0x22},
- {0x7f,0x41,0x41,0x22,0x1c},
- {0x7f,0x49,0x49,0x49,0xff},
- {0x7f,0x09,0x09,0x09,0xff},
- {0x3e,0x41,0x41,0x49,0x3a},
- {0x7f,0x08,0x08,0x08,0x7f},
- {0x41,0x7f,0x41,0xff,0x00},
- {0x20,0x40,0x40,0x3f,0xff},
- {0x7f,0x08,0x14,0x22,0x41},
- {0x7f,0x40,0x40,0x40,0xff},
- {0x7f,0x02,0x04,0x02,0x7f},
- {0x7f,0x02,0x0c,0x10,0x7f},
- {0x3e,0x41,0x41,0x41,0x3e},
- {0x7f,0x09,0x09,0x09,0x06},
- {0x3e,0x41,0x51,0x21,0x5e},
- {0x7f,0x09,0x19,0x29,0x46},
- {0x26,0x49,0x49,0x49,0x32},
- {0x01,0x01,0x7f,0x01,0x01},
- {0x3f,0x40,0x40,0x40,0x3f},
- {0x07,0x18,0x60,0x18,0x07},
- {0x1f,0x60,0x18,0x60,0x1f},
- {0x63,0x14,0x08,0x14,0x63},
- {0x03,0x04,0x78,0x04,0x03},
- {0x61,0x51,0x49,0x45,0x43},
-
- {0x7f,0x41,0x41,0xff,0x00},
- {0x03,0x04,0x08,0x10,0x60},
- {0x41,0x41,0x7f,0xff,0x00},
- {0x02,0x01,0x02,0xff,0x00},
- {0x80,0x80,0x80,0x80,0x80},
- {0x01,0x02,0xff,0x00,0x00},
-
- {0x38,0x44,0x44,0x44,0x7c}, /* lowercase letters */
- {0x7f,0x44,0x44,0x44,0x38},
- {0x38,0x44,0x44,0x44,0x44},
- {0x38,0x44,0x44,0x44,0x7f},
- {0x38,0x54,0x54,0x54,0x58},
- {0x04,0x7e,0x05,0x01,0xff},
- {0x98,0xa4,0xa4,0xa4,0x7c},
- {0x7f,0x04,0x04,0x04,0x78},
- {0x7d,0xff,0x00,0x00,0x00},
- {0x80,0x80,0x7d,0xff,0x00},
- {0x7f,0x10,0x28,0x44,0xff},
- {0x7f,0xff,0x00,0x00,0x00},
- {0x7c,0x04,0x7c,0x04,0x78},
- {0x7c,0x04,0x04,0x04,0x78},
- {0x38,0x44,0x44,0x44,0x38},
- {0xfc,0x24,0x24,0x24,0x18},
- {0x18,0x24,0x24,0x24,0xfc},
- {0x7c,0x08,0x04,0x04,0xff},
- {0x48,0x54,0x54,0x54,0x24},
- {0x04,0x3e,0x44,0x40,0xff},
- {0x7c,0x40,0x40,0x40,0x3c},
- {0x0c,0x30,0x40,0x30,0x0c},
- {0x3c,0x40,0x3c,0x40,0x3c},
- {0x44,0x28,0x10,0x28,0x44},
- {0x9c,0xa0,0xa0,0xa0,0x7c},
- {0x44,0x64,0x54,0x4c,0x44},
-
- {0x08,0x36,0x41,0xff,0x00},
- {0x77,0xff,0x00,0x00,0x00},
- {0x41,0x36,0x08,0xff,0x00},
- {0x02,0x01,0x02,0x01,0xff},
- {0xff,0x00,0x00,0x00,0x00},
-
- {0xfe,0x49,0x49,0x4e,0x30}, /* sharp S */
-
- {0x7c,0x41,0x40,0x41,0x3c}, /* umlauts */
-
- {0x04,0x06,0x7f,0x06,0x04}, /* arrows */
- {0x20,0x60,0xfe,0x60,0x20},
-
- {0x38,0x45,0x44,0x45,0x7c}, /* umlauts */
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0x79,0x14,0x12,0x14,0x79},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0x38,0x45,0x44,0x45,0x38},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0xff,0x00,0x00,0x00,0x00},
- {0x3d,0x42,0x42,0x42,0x3d},
- {0x3d,0x40,0x40,0x40,0x3d},
-};
-
-// Default palette
-const byte initVGAPalette[768] = {
- 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x58, 0x58, 0x70, 0x70, 0x70, 0xfc, 0xfc, 0xfc, 0x00, 0xd0, 0x00,
- 0x00, 0xfc, 0x00, 0xd8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xb0, 0xa0, 0xa0, 0xa0,
- 0x50, 0xc8, 0xfc, 0x28, 0xfc, 0x28, 0xf0, 0xf0, 0x00, 0xfc, 0x28, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14,
- 0x20, 0x20, 0x20, 0x2c, 0x2c, 0x2c, 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60,
- 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8,
- 0xe0, 0xe0, 0xe0, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc,
- 0xfc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00,
- 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00,
- 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc,
- 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc,
- 0xfc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c,
- 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c,
- 0x7c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc,
- 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc,
- 0xfc, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4,
- 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4,
- 0xb4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc,
- 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70,
- 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00,
- 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00,
- 0x00, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70,
- 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70,
- 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38,
- 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38,
- 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70,
- 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70,
- 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50,
- 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50,
- 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70,
- 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40,
- 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00,
- 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00,
- 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40,
- 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40,
- 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20,
- 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20,
- 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40,
- 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40,
- 0x40, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c,
- 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c,
- 0x2c, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40,
- 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
enum ObjectType {
NULLTYPE = 0,
TAKE = 1,
@@ -341,7 +77,7 @@ enum Action {
ACTION_GIVE
};
-enum RoomID {
+enum RoomId {
INTRO,CORRIDOR,HALL,SLEEP,COCKPIT,AIRLOCK,
HOLD,LANDINGMODULE,GENERATOR,OUTSIDE,
CABIN_R1,CABIN_R2,CABIN_R3,CABIN_L1,CABIN_L2,CABIN_L3,BATHROOM,
@@ -353,7 +89,7 @@ enum RoomID {
ELEVATOR,STATION,SIGN,OUTRO,NUMROOMS,NULLROOM
};
-enum ObjectID {
+enum ObjectId {
INVALIDOBJECT = -1,
NULLOBJECT = 0,
KEYCARD,KNIFE,WATCH,
@@ -397,7 +133,7 @@ enum ObjectID {
JUNGLE,STATION_SLOT,STATION_SIGN
};
-enum StringID {
+enum StringId {
kNoString = -1,
// 0
kStringCommandGo = 0, kStringCommandLook, kStringCommandTake, kStringCommandOpen, kStringCommandClose,
@@ -568,8 +304,6 @@ ObjectType &operator&=(ObjectType &a, ObjectType b);
ObjectType &operator^=(ObjectType &a, ObjectType b);
struct Object {
- static const Object nullObject;
-
Object()
: _name(kNoString)
, _description(kStringDefaultDescription)
@@ -582,8 +316,8 @@ struct Object {
, _exitRoom(NULLROOM)
, _direction(0)
{}
- Object(byte roomId, StringID name, StringID description, ObjectID id, ObjectType type,
- byte click, byte click2, byte section = 0, RoomID exitRoom = NULLROOM, byte direction = 0)
+ Object(byte roomId, StringId name, StringId description, ObjectId id, ObjectType type,
+ byte click, byte click2, byte section = 0, RoomId exitRoom = NULLROOM, byte direction = 0)
: _name(name)
, _description(description)
, _id(id)
@@ -596,12 +330,6 @@ struct Object {
, _direction(direction)
{}
- static void setObjectNull(Object *&obj) {
- obj = const_cast<Object *>(&nullObject);
- }
- static bool isNullObject(Object *obj) {
- return obj == &nullObject;
- }
void resetProperty(ObjectType type = NULLTYPE) {
_type = type;
}
@@ -618,7 +346,7 @@ struct Object {
return _type & type;
}
- static bool combine(Object &obj1, Object &obj2, ObjectID id1, ObjectID id2) {
+ static bool combine(Object &obj1, Object &obj2, ObjectId id1, ObjectId id2) {
if (obj1.hasProperty(COMBINABLE))
return (((obj1._id == id1) && (obj2._id == id2)) ||
((obj1._id == id2) && (obj2._id == id1)));
@@ -627,14 +355,14 @@ struct Object {
}
byte _roomId;
- StringID _name;
- StringID _description;
- ObjectID _id;
+ StringId _name;
+ StringId _description;
+ ObjectId _id;
ObjectTypes _type;
byte _click;
byte _click2;
byte _section;
- RoomID _exitRoom;
+ RoomId _exitRoom;
byte _direction;
};
diff --git a/engines/supernova/resman.cpp b/engines/supernova/resman.cpp
new file mode 100644
index 0000000000..1c178846ed
--- /dev/null
+++ b/engines/supernova/resman.cpp
@@ -0,0 +1,395 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "audio/mixer.h"
+#include "audio/mods/protracker.h"
+#include "common/memstream.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "graphics/palette.h"
+
+#include "supernova/graphics.h"
+#include "supernova/resman.h"
+#include "supernova/screen.h"
+#include "supernova/supernova.h"
+
+namespace Supernova {
+
+struct AudioInfo {
+ int _filenumber;
+ int _offsetStart;
+ int _offsetEnd;
+};
+
+static Common::MemoryReadStream *convertToMod(const char *filename, int version = 1);
+
+static const AudioInfo audioInfo[kAudioNumSamples] = {
+ {44, 0, -1},
+ {45, 0, -1},
+ {46, 0, 2510},
+ {46, 2510, 4020},
+ {46, 4020, -1},
+ {47, 0, 24010},
+ {47, 24010, -1},
+ {48, 0, 2510},
+ {48, 2510, 10520},
+ {48, 10520, 13530},
+ {48, 13530, -1},
+ {50, 0, 12786},
+ {50, 12786, -1},
+ {51, 0, -1},
+ {53, 0, -1},
+ {54, 0, 8010},
+ {54, 8010, 24020},
+ {54, 24020, 30030},
+ {54, 30030, 31040},
+ {54, 31040, -1}
+};
+
+static const byte mouseNormal[64] = {
+ 0xff,0x3f,0xff,0x1f,0xff,0x0f,0xff,0x07,
+ 0xff,0x03,0xff,0x01,0xff,0x00,0x7f,0x00,
+ 0x3f,0x00,0x1f,0x00,0x0f,0x00,0x0f,0x00,
+ 0xff,0x00,0x7f,0x18,0x7f,0x38,0x7f,0xfc,
+
+ 0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x70,
+ 0x00,0x78,0x00,0x7c,0x00,0x7e,0x00,0x7f,
+ 0x80,0x7f,0xc0,0x7f,0xe0,0x7f,0x00,0x7e,
+ 0x00,0x66,0x00,0x43,0x00,0x03,0x00,0x00
+};
+
+static const byte mouseWait[64] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
+ 0x01,0x80,0x01,0x80,0x11,0x88,0x31,0x8c,
+ 0x31,0x8c,0x11,0x88,0x01,0x80,0x01,0x80,
+ 0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0xfe,0x7f,0xf4,0x2f,0xf4,0x2f,
+ 0x14,0x28,0x24,0x24,0x44,0x22,0x84,0x21,
+ 0x84,0x21,0xc4,0x23,0xe4,0x27,0x74,0x2e,
+ 0x34,0x2c,0x14,0x28,0xfe,0x7f,0x00,0x00
+};
+
+
+ResourceManager::ResourceManager()
+ : _audioRate(11931) {
+ initSoundFiles();
+ initGraphics();
+}
+
+void ResourceManager::initSoundFiles() {
+ // Sound
+ // Note:
+ // - samples start with a header of 6 bytes: 01 SS SS 00 AD 00
+ // where SS SS (LE uint16) is the size of the sound sample + 2
+ // - samples end with a footer of 4 bytes: 00 00
+ // Skip those in the buffer
+ Common::File file;
+
+ for (int i = 0; i < kAudioNumSamples; ++i) {
+ if (!file.open(Common::String::format("msn_data.%03d", audioInfo[i]._filenumber))) {
+ error("File %s could not be read!", file.getName());
+ }
+
+ int length = 0;
+ byte *buffer = nullptr;
+
+ if (audioInfo[i]._offsetEnd == -1) {
+ file.seek(0, SEEK_END);
+ length = file.pos() - audioInfo[i]._offsetStart - 10;
+ } else {
+ length = audioInfo[i]._offsetEnd - audioInfo[i]._offsetStart - 10;
+ }
+ buffer = new byte[length];
+ file.seek(audioInfo[i]._offsetStart + 6);
+ file.read(buffer, length);
+ file.close();
+
+ byte streamFlag = Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN;
+ _soundSamples[i].reset(Audio::makeRawStream(buffer, length, _audioRate,
+ streamFlag, DisposeAfterUse::YES));
+ }
+
+ _musicIntroBuffer.reset(convertToMod("msn_data.052"));
+ _musicOutroBuffer.reset(convertToMod("msn_data.049"));
+}
+
+void ResourceManager::initGraphics() {
+ Screen::initPalette();
+ initCursorGraphics();
+ initImages();
+}
+
+void ResourceManager::initCursorGraphics() {
+ const uint16 *bufferNormal = reinterpret_cast<const uint16 *>(mouseNormal);
+ const uint16 *bufferWait = reinterpret_cast<const uint16 *>(mouseWait);
+ for (uint i = 0; i < sizeof(mouseNormal) / 4; ++i) {
+ for (uint bit = 0; bit < 16; ++bit) {
+ uint mask = 0x8000 >> bit;
+ uint bitIndex = i * 16 + bit;
+
+ _cursorNormal[bitIndex] = (READ_LE_UINT16(bufferNormal + i) & mask) ?
+ kColorCursorTransparent : kColorBlack;
+ if (READ_LE_UINT16(bufferNormal + i + 16) & mask)
+ _cursorNormal[bitIndex] = kColorLightRed;
+
+ _cursorWait[bitIndex] = (READ_LE_UINT16(bufferWait + i) & mask) ?
+ kColorCursorTransparent : kColorBlack;
+ if (READ_LE_UINT16(bufferWait + i + 16) & mask)
+ _cursorWait[bitIndex] = kColorLightRed;
+ }
+ }
+}
+
+void ResourceManager::initImages() {
+ for (int i = 0; i < kNumImageFiles; ++i) {
+ if (!_images[i].init(i))
+ error("Failed reading image file msn_data.%03d", i);
+ }
+}
+
+Audio::SeekableAudioStream *ResourceManager::getSoundStream(AudioId index) {
+ Audio::SeekableAudioStream *stream = _soundSamples[index].get();
+ stream->rewind();
+
+ return stream;
+}
+
+Audio::AudioStream *ResourceManager::getSoundStream(MusicId index) {
+ switch (index) {
+ case kMusicIntro:
+ _musicIntro.reset(Audio::makeProtrackerStream(_musicIntroBuffer.get()));
+ return _musicIntro.get();
+ case kMusicOutro:
+ _musicOutro.reset(Audio::makeProtrackerStream(_musicOutroBuffer.get()));
+ return _musicOutro.get();
+ default:
+ error("Invalid music constant in playAudio()");
+ }
+}
+
+const MSNImage *ResourceManager::getImage(int filenumber) const {
+ assert(filenumber < kNumImageFiles);
+
+ return &_images[filenumber];
+}
+
+const byte *ResourceManager::getImage(CursorId id) const {
+ switch (id) {
+ case kCursorNormal:
+ return _cursorNormal;
+ case kCursorWait:
+ return _cursorWait;
+ default:
+ return nullptr;
+ }
+}
+
+static Common::MemoryReadStream *convertToMod(const char *filename, int version) {
+ // MSN format
+ struct {
+ uint16 seg;
+ uint16 start;
+ uint16 end;
+ uint16 loopStart;
+ uint16 loopEnd;
+ char volume;
+ char dummy[5];
+ } instr2[22];
+ int nbInstr2; // 22 for version1, 15 for version 2
+ int16 songLength;
+ char arrangement[128];
+ int16 patternNumber;
+ int32 note2[28][64][4];
+
+ nbInstr2 = ((version == 1) ? 22 : 15);
+
+ Common::File msnFile;
+ msnFile.open(filename);
+ if (!msnFile.isOpen()) {
+ warning("Data file '%s' not found", msnFile.getName());
+ return nullptr;
+ }
+
+ for (int i = 0 ; i < nbInstr2 ; ++i) {
+ instr2[i].seg = msnFile.readUint16LE();
+ instr2[i].start = msnFile.readUint16LE();
+ instr2[i].end = msnFile.readUint16LE();
+ instr2[i].loopStart = msnFile.readUint16LE();
+ instr2[i].loopEnd = msnFile.readUint16LE();
+ instr2[i].volume = msnFile.readByte();
+ msnFile.read(instr2[i].dummy, 5);
+ }
+ songLength = msnFile.readSint16LE();
+ msnFile.read(arrangement, 128);
+ patternNumber = msnFile.readSint16LE();
+ for (int p = 0 ; p < patternNumber ; ++p) {
+ for (int n = 0 ; n < 64 ; ++n) {
+ for (int k = 0 ; k < 4 ; ++k) {
+ note2[p][n][k] = msnFile.readSint32LE();
+ }
+ }
+ }
+
+ /* MOD format */
+ struct {
+ char iname[22];
+ uint16 length;
+ char finetune;
+ char volume;
+ uint16 loopStart;
+ uint16 loopLength;
+ } instr[31];
+ int32 note[28][64][4];
+
+ // We can't recover some MOD effects since several of them are mapped to 0.
+ // Assume the MSN effect of value 0 is Arpeggio (MOD effect of value 0).
+ const char invConvEff[8] = {0, 1, 2, 3, 10, 12, 13 ,15};
+
+ // Reminder from convertToMsn
+ // 31 30 29 28 27 26 25 24 - 23 22 21 20 19 18 17 16 - 15 14 13 12 11 10 09 08 - 07 06 05 04 03 02 01 00
+ // h h h h g g g g f f f f e e e e d d d d c c c c b b b b a a a a
+ //
+ // MSN:
+ // hhhh (4 bits) Cleared to 0
+ // dddd c (5 bits) Sample index | after mapping through convInstr
+ // ccc (3 bits) Effect type | after mapping through convEff
+ // bbbb aaaa (8 bits) Effect value | unmodified
+ // gggg ffff eeee (12 bits) Sample period | unmodified
+ //
+ // MS2:
+ // hhhh (4 bits) Cleared to 0
+ // dddd (4 bits) Sample index | after mapping through convInstr
+ // cccc (4 bits) Effect type | unmodified
+ // bbbb aaaa (8 bits) Effect value | unmodified
+ // gggg ffff eeee (12 bits) Sample period | transformed (0xE000 / p) - 256
+ //
+ // MOD:
+ // hhhh dddd (8 bits) Sample index
+ // cccc (4 bits) Effect type for this channel/division
+ // bbbb aaaa (8 bits) Effect value
+ // gggg ffff eeee (12 bits) Sample period
+
+ // Can we recover the instruments mapping? I don't think so as part of the original instrument index is cleared.
+ // And it doesn't really matter as long as we are consistent.
+ // However we need to make sure 31 (or 15 in MS2) is mapped to 0 in MOD.
+ // We just add 1 to all other values, and this means a 1 <-> 1 mapping for the instruments
+ for (int p = 0; p < patternNumber; ++p) {
+ for (int n = 0; n < 64; ++n) {
+ for (int k = 0; k < 4; ++k) {
+ int32* l = &(note[p][n][k]);
+ *l = note2[p][n][k];
+ int32 i = 0;
+ if (nbInstr2 == 22) { // version 1
+ i = ((*l & 0xF800) >> 11);
+ int32 e = ((*l & 0x0700) >> 8);
+ int32 e1 = invConvEff[e];
+ *l &= 0x0FFF00FF;
+ *l |= (e1 << 8);
+ } else { // version 2
+ int32 h = (*l >> 16);
+ i = ((*l & 0xF000) >> 12);
+ *l &= 0x00000FFF;
+ if (h)
+ h = 0xE000 / (h + 256);
+ *l |= (h << 16);
+ if (i == 15)
+ i = 31;
+ }
+
+ // Add back index in note
+ if (i != 31) {
+ ++i;
+ *l |= ((i & 0x0F) << 12);
+ *l |= ((i & 0xF0) << 24);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < 31; ++i) {
+ // iname is not stored in the mod file. Just set it to 'instrument#'
+ // finetune is not stored either. Assume 0.
+ memset(instr[i].iname, 0, 22);
+ sprintf(instr[i].iname, "instrument%d", i+1);
+ instr[i].length = 0;
+ instr[i].finetune = 0;
+ instr[i].volume = 0;
+ instr[i].loopStart = 0;
+ instr[i].loopLength = 0;
+
+ if (i < nbInstr2) {
+ instr[i].length = ((instr2[i].end - instr2[i].start) >> 1);
+ instr[i].loopStart = ((instr2[i].loopStart - instr2[i].start) >> 1);
+ instr[i].loopLength = (( instr2[i].loopEnd - instr2[i].loopStart) >> 1);
+ instr[i].volume = instr2[i].volume;
+ }
+ }
+
+ // The ciaaSpeed is kind of useless and not present in the MSN file.
+ // Traditionally 0x78 in SoundTracker. Was used in NoiseTracker as a restart point.
+ // ProTracker uses 0x7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses 0x7F like ProTracker.
+ // You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types.
+ char ciaaSpeed = 0x7F;
+
+ // The mark cannot be recovered either. Since we have 4 channels and 31 instrument it can be either ID='M.K.' or ID='4CHN'.
+ // Assume 'M.K.'
+ const char mark[4] = { 'M', '.', 'K', '.' };
+
+ Common::MemoryWriteStreamDynamic buffer(DisposeAfterUse::NO);
+
+ buffer.write(msnFile.getName(), 19);
+ buffer.writeByte(0);
+
+ for (int i = 0 ; i < 31 ; ++i) {
+ buffer.write(instr[i].iname, 22);
+ buffer.writeUint16BE(instr[i].length);
+ buffer.writeByte(instr[i].finetune);
+ buffer.writeByte(instr[i].volume);
+ buffer.writeUint16BE(instr[i].loopStart);
+ buffer.writeUint16BE(instr[i].loopLength);
+ }
+ buffer.writeByte((char)songLength);
+ buffer.writeByte(ciaaSpeed);
+ buffer.write(arrangement, 128);
+ buffer.write(mark, 4);
+
+ for (int p = 0 ; p < patternNumber ; ++p) {
+ for (int n = 0 ; n < 64 ; ++n) {
+ for (int k = 0 ; k < 4 ; ++k) {
+// buffer.writeUint32BE(*((uint32*)(note[p][n]+k)));
+ buffer.writeSint32BE(note[p][n][k]);
+ }
+ }
+ }
+
+ uint nb;
+ char buf[4096];
+ while ((nb = msnFile.read(buf, 4096)) > 0)
+ buffer.write(buf, nb);
+
+ return new Common::MemoryReadStream(buffer.getData(), buffer.size(), DisposeAfterUse::YES);
+}
+
+}
diff --git a/engines/supernova/resman.h b/engines/supernova/resman.h
new file mode 100644
index 0000000000..080ecc5da4
--- /dev/null
+++ b/engines/supernova/resman.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 SUPERNOVA_RESOURCES_H
+#define SUPERNOVA_RESOURCES_H
+
+#include "audio/audiostream.h"
+#include "common/ptr.h"
+
+#include "supernova/graphics.h"
+#include "supernova/sound.h"
+
+
+namespace Common {
+class MemoryReadStream;
+}
+
+namespace Supernova {
+
+class ResourceManager {
+public:
+ enum CursorId {
+ kCursorNormal,
+ kCursorWait
+ };
+
+public:
+ static const int kNumImageFiles = 44;
+
+public:
+ ResourceManager();
+
+ Audio::SeekableAudioStream *getSoundStream(AudioId index);
+ Audio::AudioStream *getSoundStream(MusicId index);
+ const MSNImage *getImage(int filenumber) const;
+ const byte *getImage(CursorId id) const;
+
+private:
+ void initSoundFiles();
+ void initGraphics();
+ void initCursorGraphics();
+ void initImages();
+
+private:
+ Common::ScopedPtr<Audio::SeekableAudioStream> _soundSamples[kAudioNumSamples];
+ Common::ScopedPtr<Common::MemoryReadStream> _musicIntroBuffer;
+ Common::ScopedPtr<Common::MemoryReadStream> _musicOutroBuffer;
+ Common::ScopedPtr<Audio::AudioStream> _musicIntro;
+ Common::ScopedPtr<Audio::AudioStream> _musicOutro;
+ int _audioRate;
+ MSNImage _images[kNumImageFiles];
+ byte _cursorNormal[256];
+ byte _cursorWait[256];
+};
+
+}
+
+#endif
diff --git a/engines/supernova/rooms.cpp b/engines/supernova/rooms.cpp
index faa6129723..9360d58aa1 100644
--- a/engines/supernova/rooms.cpp
+++ b/engines/supernova/rooms.cpp
@@ -24,6 +24,7 @@
#include "graphics/palette.h"
#include "graphics/cursorman.h"
+#include "supernova/screen.h"
#include "supernova/supernova.h"
#include "supernova/state.h"
@@ -79,15 +80,15 @@ bool Room::deserialize(Common::ReadStream *in, int version) {
int numObjects = in->readSint32LE();
for (int i = 0; i < numObjects; ++i) {
- _objectState[i]._name = static_cast<StringID>(in->readSint32LE());
- _objectState[i]._description = static_cast<StringID>(in->readSint32LE());
+ _objectState[i]._name = static_cast<StringId>(in->readSint32LE());
+ _objectState[i]._description = static_cast<StringId>(in->readSint32LE());
_objectState[i]._roomId = in->readByte();
- _objectState[i]._id = static_cast<ObjectID>(in->readSint32LE());
+ _objectState[i]._id = static_cast<ObjectId>(in->readSint32LE());
_objectState[i]._type = static_cast<ObjectType>(in->readSint32LE());
_objectState[i]._click = in->readByte();
_objectState[i]._click2 = in->readByte();
_objectState[i]._section = in->readByte();
- _objectState[i]._exitRoom = static_cast<RoomID>(in->readSint32LE());
+ _objectState[i]._exitRoom = static_cast<RoomId>(in->readSint32LE());
_objectState[i]._direction = in->readByte();
}
@@ -147,102 +148,11 @@ void Intro::onEntrance() {
leaveCutscene();
}
-class Marquee {
-public:
- enum MarqueeIndex {
- kMarqueeIntro,
- kMarqueeOutro
- };
-
- Marquee(SupernovaEngine *vm, MarqueeIndex id, const char *text)
- : _text(text)
- , _textBegin(text)
- , _delay(0)
- , _color(kColorLightBlue)
- , _loop(false)
- , _vm(vm)
- {
- if (id == kMarqueeIntro) {
- _y = 191;
- _loop = true;
- } else if (id == kMarqueeOutro) {
- _y = 1;
- }
- _textWidth = _vm->textWidth(_text);
- _x = kScreenWidth / 2 - _textWidth / 2;
- _vm->_textCursorX = _x;
- _vm->_textCursorY = _y;
- _vm->_textColor = _color;
- }
-
- void renderCharacter();
-
-private:
- void clearText();
-
- SupernovaEngine *_vm;
- MarqueeIndex _id;
- const char *const _textBegin;
- const char *_text;
- bool _loop;
- int _delay;
- int _color;
- int _x;
- int _y;
- int _textWidth;
-};
-
-void Marquee::clearText() {
- _vm->renderBox(_x, _y - 1, _textWidth + 1, 9, kColorBlack);
-}
-
-void Marquee::renderCharacter() {
- if (_delay != 0) {
- _delay--;
- return;
- }
-
- switch (*_text) {
- case '\233':
- if (_loop) {
- _loop = false;
- _text = _textBegin;
- clearText();
- _textWidth = _vm->textWidth(_text);
- _x = kScreenWidth / 2 - _textWidth / 2;
- _vm->_textCursorX = _x;
- }
- break;
- case '\0':
- clearText();
- _text++;
- _textWidth = _vm->textWidth(_text);
- _x = kScreenWidth / 2 - _textWidth / 2;
- _vm->_textCursorX = _x;
- _color = kColorLightBlue;
- _vm->_textColor = _color;
- break;
- case '^':
- _color = kColorLightYellow;
- _vm->_textColor = _color;
- _text++;
- break;
- case '#':
- _delay = 50;
- _text++;
- break;
- default:
- _vm->renderText((uint16)*_text++);
- _delay = 1;
- break;
- }
-}
-
void Intro::titleScreen() {
// Newspaper
CursorMan.showMouse(false);
- _vm->_brightness = 0;
- _vm->_menuBrightness = 0;
+ _vm->_screen->setViewportBrightness(0);
+ _vm->_screen->setGuiBrightness(0);
_vm->paletteBrightness();
_vm->setCurrentImage(1);
_vm->renderImage(0);
@@ -254,25 +164,25 @@ void Intro::titleScreen() {
_vm->setCurrentImage(31);
_vm->renderImage(0);
_vm->paletteFadeIn();
- _gm->wait2(1);
+ _gm->wait(1);
_vm->playSound(kAudioVoiceSupernova);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
titleFadeIn();
_vm->renderText(kStringTitleVersion, 295, 190, kColorWhite44);
const Common::String& title1 = _vm->getGameString(kStringTitle1);
const Common::String& title2 = _vm->getGameString(kStringTitle2);
const Common::String& title3 = _vm->getGameString(kStringTitle3);
- _vm->renderText(title1, 78 - _vm->textWidth(title1) / 2, 120, kColorLightBlue);
- _vm->renderText(title2, 78 - _vm->textWidth(title2) / 2, 132, kColorWhite99);
- _vm->renderText(title3, 78 - _vm->textWidth(title3) / 2, 142, kColorWhite99);
- _gm->wait2(1);
+ _vm->_screen->renderText(title1, 78 - Screen::textWidth(title1) / 2, 120, kColorLightBlue);
+ _vm->_screen->renderText(title2, 78 - Screen::textWidth(title2) / 2, 132, kColorWhite99);
+ _vm->_screen->renderText(title3, 78 - Screen::textWidth(title3) / 2, 142, kColorWhite99);
+ _gm->wait(1);
CursorMan.showMouse(true);
- _vm->playSoundMod(kMusicIntro);
+ _vm->playSound(kMusicIntro);
- Marquee marquee(_vm, Marquee::kMarqueeIntro, _introText.c_str());
+ Marquee marquee(_vm->_screen, Marquee::kMarqueeIntro, _introText.c_str());
while (!_vm->shouldQuit()) {
- _vm->updateEvents();
+ _gm->updateEvents();
marquee.renderCharacter();
if (_gm->_mouseClicked || _gm->_keyPressed)
break;
@@ -280,8 +190,8 @@ void Intro::titleScreen() {
g_system->delayMillis(_vm->_delay);
}
_vm->playSound(kAudioVoiceYeah);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
_vm->paletteFadeOut();
}
@@ -319,7 +229,7 @@ bool Intro::animate(int section1, int section2, int duration) {
}
bool Intro::animate(int section1, int section2, int duration,
- MessagePosition position, StringID textId) {
+ MessagePosition position, StringId textId) {
Common::KeyCode key = Common::KEYCODE_INVALID;
const Common::String& text = _vm->getGameString(textId);
_vm->renderMessage(text, position);
@@ -344,7 +254,7 @@ bool Intro::animate(int section1, int section2, int duration,
}
bool Intro::animate(int section1, int section2, int section3, int section4,
- int duration, MessagePosition position, StringID textId) {
+ int duration, MessagePosition position, StringId textId) {
Common::KeyCode key = Common::KEYCODE_INVALID;
const Common::String& text = _vm->getGameString(textId);
_vm->renderMessage(text, position);
@@ -381,11 +291,11 @@ void Intro::cutscene() {
_vm->_system->fillScreen(kColorBlack);
_vm->setCurrentImage(31);
- _vm->_menuBrightness = 255;
+ _vm->_screen->setGuiBrightness(255);
_vm->paletteBrightness();
if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene1))
return;
- _vm->_menuBrightness = 0;
+ _vm->_screen->setGuiBrightness(0);
_vm->paletteBrightness();
exitOnEscape(1);
@@ -423,7 +333,7 @@ void Intro::cutscene() {
exitOnEscape(28);
_vm->removeMessage();
- StringID textCounting[4] =
+ StringId textCounting[4] =
{kStringIntroCutscene7, kStringIntroCutscene8, kStringIntroCutscene9, kStringIntroCutscene10};
_vm->setCurrentImage(31);
_vm->renderImage(0);
@@ -527,15 +437,15 @@ void Intro::cutscene() {
return;
_vm->paletteFadeOut();
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ while (_vm->_sound->isPlaying())
exitOnEscape(1);
_vm->_system->fillScreen(kColorBlack);
- _vm->_menuBrightness = 255;
+ _vm->_screen->setGuiBrightness(255);
_vm->paletteBrightness();
if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene25))
return;
- _vm->_menuBrightness = 5;
+ _vm->_screen->setGuiBrightness(5);
_vm->paletteBrightness();
_vm->setCurrentImage(31);
@@ -558,20 +468,20 @@ void Intro::cutscene() {
return;
CursorMan.showMouse(false);
- _vm->_brightness = 0;
+ _vm->_screen->setViewportBrightness(0);
_vm->paletteBrightness();
exitOnEscape(10);
_vm->playSound(kAudioSnoring);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
exitOnEscape(10);
_vm->playSound(kAudioSnoring);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
exitOnEscape(10);
_vm->playSound(kAudioSnoring);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
exitOnEscape(30);
CursorMan.showMouse(true);
@@ -605,7 +515,7 @@ void Intro::cutscene() {
}
void Intro::leaveCutscene() {
- _vm->_brightness = 255;
+ _vm->_screen->setViewportBrightness(255);
_vm->removeMessage();
_gm->changeRoom(CABIN_R3);
_gm->_guiEnabled = true;
@@ -620,19 +530,19 @@ bool ShipCorridor::interact(Action verb, Object &obj1, Object &obj2) {
_objectState[6].disableProperty(OPENED);
_vm->renderImage(8);
setSectionVisible(9, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(7);
setSectionVisible(8, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(7));
} else {
_vm->playSound(kAudioSlideDoor);
_objectState[6].setProperty(OPENED);
_vm->renderImage(7);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(8);
setSectionVisible(7, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(9);
setSectionVisible(8, false);
}
@@ -649,18 +559,18 @@ bool ShipHall::interact(Action verb, Object &obj1, Object &obj2) {
_objectState[2].disableProperty(OPENED);
_vm->renderImage(3);
setSectionVisible(4, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(2);
setSectionVisible(3, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(2));
} else {
_objectState[2].setProperty(OPENED);
_vm->renderImage(2);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(3);
setSectionVisible(2, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(4);
setSectionVisible(3, false);
_gm->great(1);
@@ -727,13 +637,13 @@ bool ShipSleepCabin::interact(Action verb, Object &obj1, Object &obj2) {
if (daysSleep != 0) {
_gm->_state._timeSleep = daysSleep;
_vm->renderText(kStringShipSleepCabin8, 30, 105, kColorWhite99);
- _gm->wait2(18);
+ _gm->wait(18);
setSectionVisible(5, true);
}
} while (daysSleep == 0);
} else {
_vm->renderText(kStringShipSleepCabin9, 100, 125, kColorLightRed);
- _gm->wait2(18);
+ _gm->wait(18);
}
}
}
@@ -813,12 +723,12 @@ bool ShipSleepCabin::interact(Action verb, Object &obj1, Object &obj2) {
_gm->_state._dream = true;
_gm->loadTime();
}
- _gm->wait2(18);
+ _gm->wait(18);
_vm->paletteFadeIn();
if (_gm->_state._arrivalDaysLeft == 0) {
_vm->playSound(kAudioCrash);
_gm->screenShake();
- _gm->wait2(18);
+ _gm->wait(18);
_vm->renderMessage(kStringShipSleepCabin12);
}
}
@@ -860,10 +770,10 @@ void ShipSleepCabin::animation() {
void ShipSleepCabin::onEntrance() {
if (_gm->_state._dream && (_gm->_rooms[CAVE]->getObject(1)->_exitRoom == MEETUP3)) {
_vm->renderMessage(kStringShipSleepCabin14);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringShipSleepCabin15);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringShipSleepCabin16);
_gm->_state._dream = false;
@@ -1004,7 +914,7 @@ bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) {
setSectionVisible(15, false);
for (int i = 3; i; i--) {
_vm->playSound(kAudioTurntable);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) {
+ while (_vm->_sound->isPlaying()) {
if (isSectionVisible(13)) {
_vm->renderImage(14);
setSectionVisible(13, false);
@@ -1012,7 +922,7 @@ bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) {
_vm->renderImage(13);
setSectionVisible(14, false);
}
- _gm->wait2(3);
+ _gm->wait(3);
}
}
@@ -1037,7 +947,7 @@ bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) {
setSectionVisible(10, false);
getObject(10)->_click = 20;
} else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, WIRE2))
- _vm->renderMessage(kStringShipCabinL3_4);
+ _vm->renderMessage(kStringShipCabinL3_4); // cutting near plug
else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, WIRE)) {
r = _gm->_rooms[AIRLOCK];
if (!isSectionVisible(10) && !r->getObject(5)->hasProperty(WORN)) {
@@ -1125,20 +1035,20 @@ bool ShipAirlock::interact(Action verb, Object &obj1, Object &obj2) {
if (getObject(0)->hasProperty(OPENED)) {
getObject(0)->disableProperty(OPENED);
_vm->renderImage(1);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(2);
setSectionVisible(1, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(3);
setSectionVisible(2, false);
} else {
getObject(0)->setProperty(OPENED);
_vm->renderImage(2);
setSectionVisible(3, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(1);
setSectionVisible(2, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(1));
}
_vm->renderImage(_gm->invertSection(10));
@@ -1150,53 +1060,53 @@ bool ShipAirlock::interact(Action verb, Object &obj1, Object &obj2) {
_vm->playSound(kAudioSlideDoor);
getObject(1)->disableProperty(OPENED);
_vm->renderImage(4);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(5);
setSectionVisible(4, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(6);
setSectionVisible(5, false);
_vm->renderImage(16);
setSectionVisible(17, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(15);
setSectionVisible(16, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(14);
setSectionVisible(15, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(13);
setSectionVisible(14, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(12);
setSectionVisible(13, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(_gm->invertSection(12));
} else {
getObject(1)->setProperty(OPENED);
_vm->renderImage(12);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(13);
setSectionVisible(12, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(14);
setSectionVisible(13, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(15);
setSectionVisible(14, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(16);
setSectionVisible(15, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(17);
setSectionVisible(16, false);
_vm->playSound(kAudioSlideDoor);
_vm->renderImage(5);
setSectionVisible(6, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(4);
setSectionVisible(5, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(4));
r = _gm->_rooms[AIRLOCK];
if (!r->getObject(4)->hasProperty(WORN) ||
@@ -1302,13 +1212,13 @@ bool ShipLandingModule::interact(Action verb, Object &obj1, Object &obj2) {
r = _gm->_rooms[SLEEP];
r->setSectionVisible(1, false);
r->setSectionVisible(2, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(2);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(8);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(9);
- _gm->wait2(1);
+ _gm->wait(1);
_vm->renderImage(10);
}
}
@@ -1529,9 +1439,9 @@ bool ArsanoRocks::interact(Action verb, Object &obj1, Object &obj2) {
if (((verb == ACTION_PULL) || (verb == ACTION_PRESS)) &&
(obj1._id == STONE) && !isSectionVisible(3)) {
_vm->renderImage(1);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(2);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(3);
_vm->playSound(kAudioRocks);
obj1._click = 3;
@@ -1544,10 +1454,10 @@ bool ArsanoRocks::interact(Action verb, Object &obj1, Object &obj2) {
void ArsanoMeetup::onEntrance() {
if (isSectionVisible(7)) {
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(6);
setSectionVisible(7, false);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(_gm->invertSection(6));
}
if (!(_gm->_state._greatFlag & 0x8000)) {
@@ -1591,10 +1501,10 @@ bool ArsanoMeetup::interact(Action verb, Object &obj1, Object &obj2) {
_vm->paletteBrightness();
} else if ((verb == ACTION_WALK) && (obj1._id == DOOR)) {
_vm->renderImage(6);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(7);
setSectionVisible(6, false);
- _gm->wait2(3);
+ _gm->wait(3);
return false;
} else if ((verb == ACTION_LOOK) && (obj1._id == MEETUP_SIGN) && _gm->_state._language) {
@@ -1616,21 +1526,21 @@ bool ArsanoMeetup::interact(Action verb, Object &obj1, Object &obj2) {
}
void ArsanoEntrance::animation() {
- if (!_vm->_messageDisplayed && isSectionVisible(kMaxSection - 5)) {
+ if (!_vm->_screen->isMessageShown() && isSectionVisible(kMaxSection - 5)) {
_gm->animationOff(); // to avoid recursive call
_vm->playSound(kAudioSlideDoor);
_vm->renderImage(8);
setSectionVisible(9, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(7);
setSectionVisible(8, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(6);
setSectionVisible(7, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(5);
setSectionVisible(6, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(5));
getObject(11)->_click = 255;
setSectionVisible(kMaxSection - 5, false);
@@ -1695,7 +1605,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
}
} else if ((verb == ACTION_WALK) && (obj1._id == STAIRCASE) && (_gm->_state._shoes != 3)) {
_vm->renderImage(3);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(4);
setSectionVisible(3, false);
if (_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN))
@@ -1706,7 +1616,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
_gm->reply(kStringArsanoEntrance12, 1, _gm->invertSection(1));
_vm->renderImage(3);
setSectionVisible(4, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(3));
if (!_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN)) {
if (_gm->_state._language) {
@@ -1732,13 +1642,13 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
break;
case 3:
_vm->renderImage(3);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(4);
setSectionVisible(3, false);
_gm->reply(kStringArsanoEntrance16, 1, 1 + 128);
_vm->renderImage(3);
setSectionVisible(4, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(3));
break;
}
@@ -1752,16 +1662,16 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
} else if ((verb == ACTION_PRESS) && (obj1._id == BATHROOM_BUTTON)) {
_vm->playSound(kAudioSlideDoor);
_vm->renderImage(5);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(6);
setSectionVisible(5, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(7);
setSectionVisible(6, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(8);
setSectionVisible(7, false);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(9);
setSectionVisible(8, false);
getObject(11)->_click = 9;
@@ -1782,7 +1692,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
_vm->renderMessage(kStringArsanoEntrance20);
else {
_vm->renderMessage(kStringArsanoEntrance21);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringArsanoEntrance22);
_gm->takeObject(*getObject(16));
@@ -1829,7 +1739,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
_gm->_rooms[AIRLOCK]->getObject(4)->setProperty(WORN);
_gm->_rooms[AIRLOCK]->getObject(5)->setProperty(WORN);
_gm->_rooms[AIRLOCK]->getObject(6)->setProperty(WORN);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
}
return false;
@@ -2097,12 +2007,12 @@ bool ArsanoRoger::interact(Action verb, Object &obj1, Object &obj2) {
_vm->paletteFadeOut();
_gm->_inventory.remove(*_gm->_rooms[CABIN_R3]->getObject(0)); // Chess board
g_system->fillScreen(kColorBlack);
- _vm->_menuBrightness = 255;
+ _vm->_screen->setGuiBrightness(255);
_vm->paletteBrightness();
_vm->renderMessage(kStringArsanoRoger39);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
- _vm->_menuBrightness = 0;
+ _vm->_screen->setGuiBrightness(0);
_vm->paletteBrightness();
_gm->_state._time += ticksToMsec(125000); // 2 hours
_gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time);
@@ -2117,7 +2027,7 @@ bool ArsanoRoger::interact(Action verb, Object &obj1, Object &obj2) {
getObject(6)->_click = 7;
_vm->paletteFadeIn();
_vm->renderMessage(kStringArsanoRoger40);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
} else
return false;
@@ -2140,7 +2050,7 @@ bool ArsanoGlider::interact(Action verb, Object &obj1, Object &obj2) {
static char l, r;
if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KEYCARD_R, GLIDER_SLOT)) {
_vm->renderImage(5);
- _gm->wait2(7);
+ _gm->wait(7);
_vm->renderImage(8);
getObject(5)->_click = 10;
_gm->_inventory.remove(*_gm->_rooms[ROGER]->getObject(8));
@@ -2192,7 +2102,7 @@ bool ArsanoGlider::interact(Action verb, Object &obj1, Object &obj2) {
}
}
}
- _gm->wait2(4);
+ _gm->wait(4);
_vm->renderImage(_gm->invertSection(i));
} else if ((verb == ACTION_USE) && (obj1._id == GLIDER_BUTTONS))
_vm->renderMessage(kStringArsanoGlider1);
@@ -2264,40 +2174,40 @@ bool ArsanoMeetup2::interact(Action verb, Object &obj1, Object &obj2) {
_vm->setCurrentImage(13);
_vm->renderImage(0);
_vm->paletteBrightness();
- _gm->wait2(36);
+ _gm->wait(36);
for (int i = 1; i <= 13; i++) {
if (i > 1)
_vm->renderImage(_gm->invertSection(i - 1));
_vm->renderImage(i);
- _gm->wait2(2);
+ _gm->wait(2);
}
_vm->renderImage(_gm->invertSection(13));
- _gm->wait2(20);
+ _gm->wait(20);
_vm->setCurrentImage(14);
_vm->renderImage(0);
_vm->paletteBrightness();
- _gm->wait2(36);
+ _gm->wait(36);
for (int i = 1; i <= 13; i++) {
if (i > 1)
_vm->renderImage(_gm->invertSection(i - 1));
_vm->renderImage(i);
- _gm->wait2(2);
+ _gm->wait(2);
}
_vm->renderImage(_gm->invertSection(13));
- _gm->wait2(9);
+ _gm->wait(9);
_vm->playSound(kAudioCrash);
for (int i = 14; i <= 19; i++) {
_vm->renderImage(i);
- _gm->wait2(3);
+ _gm->wait(3);
}
_vm->paletteFadeOut();
_vm->setCurrentImage(11);
_vm->renderImage(0);
_vm->paletteFadeIn();
- _gm->wait2(18);
+ _gm->wait(18);
_vm->renderMessage(kStringArsanoMeetup2_12);
_gm->great(0);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
_vm->paletteFadeOut();
g_system->fillScreen(kColorBlack);
@@ -2321,14 +2231,14 @@ bool ArsanoMeetup2::interact(Action verb, Object &obj1, Object &obj2) {
}
void ArsanoMeetup2::shipStart() {
- _gm->wait2(12);
+ _gm->wait(12);
for (int i = 2; i <= 11; ++i) {
if (i >= 9)
_vm->renderImage(i - 1 + 128);
else
setSectionVisible(i - 1, false);
_vm->renderImage(i);
- _gm->wait2(2);
+ _gm->wait(2);
}
_vm->renderImage(11 + 128);
}
@@ -2354,34 +2264,34 @@ bool ArsanoMeetup3::interact(Action verb, Object &obj1, Object &obj2) {
_vm->paletteBrightness();
_gm->dialog(3, rowsX, _dialogsX, 0);
_vm->renderImage(1);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(2);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(3);
- _gm->wait2(6);
+ _gm->wait(6);
_vm->renderImage(4);
_vm->playSound(kAudioGunShot);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
_vm->renderImage(5);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(4);
_vm->playSound(kAudioGunShot);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
_vm->renderImage(5);
_vm->paletteFadeOut();
- _gm->wait2(12);
+ _gm->wait(12);
_vm->setCurrentImage(0);
_vm->renderImage(0);
_vm->paletteFadeIn();
- _gm->wait2(18);
+ _gm->wait(18);
_gm->reply(kStringArsanoMeetup3_1, 2, 2 + 128);
- _gm->wait2(10);
+ _gm->wait(10);
_gm->reply(kStringArsanoMeetup3_2, 1, 1 + 128);
do {
@@ -2604,8 +2514,8 @@ bool AxacussCell::interact(Action verb, Object &obj1, Object &obj2) {
return false;
_vm->playSound(kAudioGunShot);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- _gm->wait2(1);
+ while (_vm->_sound->isPlaying())
+ _gm->wait(1);
_vm->playSound(kAudioGunShot);
_vm->playSound(kAudioGunShot);
@@ -2693,26 +2603,29 @@ bool AxacussCorridor5::handleMoneyDialog() {
}
switch (_gm->dialog(4, _rows, _dialog3, 2)) {
case 1:
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(1);
_vm->playSound(kAudioVoiceHalt);
_vm->renderImage(_gm->invertSection(1));
- _gm->wait2(5);
+ _gm->wait(5);
_vm->renderImage(2);
- _gm->wait2(2);
+ _gm->wait(2);
_gm->shot(3, _gm->invertSection(3));
break;
- case 3:
- if (_gm->_state._money >= 900) {
- stopInteract(_gm->_state._money);
- return true;
- }
case 2:
if (_gm->_state._money > 1100) {
stopInteract(_gm->_state._money - 200);
return true;
}
_gm->reply(kStringAxacussCorridor5_6, 1, 1 + 128);
+ break;
+ case 3:
+ if (_gm->_state._money >= 900) {
+ stopInteract(_gm->_state._money);
+ return true;
+ }
+ _gm->reply(kStringAxacussCorridor5_6, 1, 1 + 128);
+ break;
}
}
return false;
@@ -2958,7 +2871,7 @@ bool AxacussExit::interact(Action verb, Object &obj1, Object &obj2) {
_vm->renderImage(i);
if (i == 11)
_vm->playSound(kAudioSmash); // 046/4020
- _gm->wait2(1);
+ _gm->wait(1);
_vm->renderImage(i + 128);
}
_gm->_state._powerOff = true;
@@ -3175,9 +3088,9 @@ bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) {
_vm->renderImage(1);
getObject(2)->resetProperty();
_vm->playSound(kAudioSlideDoor);
- _gm->wait2(25);
+ _gm->wait(25);
for (int i = 3; i <= 7; i++) {
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(i);
}
getObject(3)->resetProperty(EXIT);
@@ -3195,10 +3108,10 @@ bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) {
getObject(3)->_click = 255;
_vm->playSound(kAudioSlideDoor);
for (int i = 7; i >= 3; i--) {
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(i));
}
- _gm->wait2(25);
+ _gm->wait(25);
_vm->playSound(kAudioSlideDoor);
getObject(2)->resetProperty(EXIT);
_vm->renderImage(_gm->invertSection(2));
@@ -3206,12 +3119,12 @@ bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) {
} else if ((verb == ACTION_WALK) && (obj1._id == JUNGLE)) {
_vm->paletteFadeOut();
g_system->fillScreen(kColorBlack);
- _vm->_menuBrightness = 255;
+ _vm->_screen->setGuiBrightness(255);
_vm->paletteBrightness();
_vm->renderMessage(kStringAxacussElevator_3);
- _gm->waitOnInput(_gm->_timer1);
+ _gm->waitOnInput(_gm->_messageDuration);
_vm->removeMessage();
- _vm->_menuBrightness = 0;
+ _vm->_screen->setGuiBrightness(0);
_vm->paletteBrightness();
_gm->_state._time += ticksToMsec(125000); // 2 hours
_gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time);
@@ -3280,24 +3193,24 @@ void Outro::onEntrance() {
_vm->renderImage(0);
_vm->renderImage(1);
_vm->paletteFadeIn();
- _gm->wait2(10);
+ _gm->wait(10);
for (int i = 8; i <= 21; i++) {
_vm->renderImage(i);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(_gm->invertSection(i));
}
- _gm->wait2(18);
+ _gm->wait(18);
_vm->renderImage(_gm->invertSection(1));
for (int i = 2; i <= 7; i++) {
_vm->renderImage(i);
- _gm->wait2(3);
+ _gm->wait(3);
_vm->renderImage(_gm->invertSection(i));
}
- _vm->playSoundMod(kMusicOutro);
- Marquee marquee(_vm, Marquee::kMarqueeOutro, _outroText.c_str());
+ _vm->playSound(kMusicOutro);
+ Marquee marquee(_vm->_screen, Marquee::kMarqueeOutro, _outroText.c_str());
while (!_vm->shouldQuit()) {
- _vm->updateEvents();
+ _gm->updateEvents();
marquee.renderCharacter();
if (_gm->_mouseClicked || _gm->_keyPressed)
break;
@@ -3310,7 +3223,7 @@ void Outro::onEntrance() {
_vm->paletteFadeIn();
_gm->getInput();
_vm->paletteFadeOut();
- _vm->_brightness = 1;
+ _vm->_screen->setViewportBrightness(1);
Common::Event event;
event.type = Common::EVENT_RTL;
@@ -3324,9 +3237,9 @@ void Outro::animate(int filenumber, int section1, int section2, int duration) {
_vm->setCurrentImage(filenumber);
while (duration) {
_vm->renderImage(section1);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(section2);
- _gm->wait2(2);
+ _gm->wait(2);
--duration;
}
}
@@ -3339,10 +3252,10 @@ void Outro::animate(int filenumber, int section1, int section2, int duration,
while (delay) {
if (section1)
_vm->renderImage(section1);
- _gm->wait2(2);
+ _gm->wait(2);
if (section2)
_vm->renderImage(section2);
- _gm->wait2(2);
+ _gm->wait(2);
--delay;
}
_vm->removeMessage();
@@ -3358,10 +3271,10 @@ void Outro::animate(int filenumber, int section1, int section2, int section3, in
while(duration) {
_vm->renderImage(section1);
_vm->renderImage(section3);
- _gm->wait2(2);
+ _gm->wait(2);
_vm->renderImage(section2);
_vm->renderImage(section4);
- _gm->wait2(2);
+ _gm->wait(2);
duration--;
}
_vm->removeMessage();
diff --git a/engines/supernova/rooms.h b/engines/supernova/rooms.h
index 3cedc356db..5c9b283dcd 100644
--- a/engines/supernova/rooms.h
+++ b/engines/supernova/rooms.h
@@ -27,6 +27,11 @@
#include "msn_def.h"
+namespace Common {
+class ReadStream;
+class WriteStream;
+}
+
namespace Supernova {
class GameManager;
@@ -52,7 +57,7 @@ public:
int getFileNumber() const {
return _fileNumber;
}
- RoomID getId() const {
+ RoomId getId() const {
return _id;
}
@@ -112,7 +117,7 @@ protected:
bool _shown[kMaxSection];
byte _sentenceRemoved[kMaxDialog];
Object _objectState[kMaxObject];
- RoomID _id;
+ RoomId _id;
SupernovaEngine *_vm;
GameManager *_gm;
@@ -129,9 +134,9 @@ public:
private:
bool animate(int section1, int section2, int duration);
bool animate(int section1, int section2, int duration, MessagePosition position,
- StringID text);
+ StringId text);
bool animate(int section1, int section2, int section3, int section4, int duration,
- MessagePosition position, StringID text);
+ MessagePosition position, StringId text);
void titleScreen();
void titleFadeIn();
@@ -681,9 +686,9 @@ public:
virtual void animation();
private:
- StringID _dialog1[5];
- StringID _dialog2[5];
- StringID _dialog3[5];
+ StringId _dialog1[5];
+ StringId _dialog2[5];
+ StringId _dialog3[5];
byte _eyewitness;
};
class ArsanoRemaining : public Room {
@@ -742,7 +747,7 @@ public:
virtual bool interact(Action verb, Object &obj1, Object &obj2);
private:
- StringID _dialog1[4];
+ StringId _dialog1[4];
byte _eyewitness;
byte _hands;
};
@@ -809,10 +814,10 @@ public:
private:
// TODO: change to 6, fix initialization
- StringID _dialog1[2];
- StringID _dialog2[2];
- StringID _dialog3[4];
- StringID _dialog4[3];
+ StringId _dialog1[2];
+ StringId _dialog2[2];
+ StringId _dialog3[4];
+ StringId _dialog4[3];
bool _found;
bool _flug;
@@ -846,11 +851,11 @@ public:
virtual bool interact(Action verb, Object &obj1, Object &obj2);
private:
- StringID _dialog2[4];
- StringID _dialog3[2];
+ StringId _dialog2[4];
+ StringId _dialog3[2];
// TODO: Hack, to be move away and renamed when the other uses are found
- StringID _dialogsX[6];
+ StringId _dialogsX[6];
//
};
@@ -1025,9 +1030,9 @@ private:
bool handleMoneyDialog();
// TODO: Change to 6, or change struct, and fix initialization
- StringID _dialog1[2];
- StringID _dialog2[2];
- StringID _dialog3[4];
+ StringId _dialog1[2];
+ StringId _dialog2[2];
+ StringId _dialog3[4];
byte _rows[6];
};
@@ -1176,7 +1181,7 @@ public:
virtual bool interact(Action verb, Object &obj1, Object &obj2);
private:
- StringID _dialogsX[6];
+ StringId _dialogsX[6];
};
class AxacussExit : public Room {
@@ -1205,7 +1210,7 @@ public:
virtual bool interact(Action verb, Object &obj1, Object &obj2);
private:
- StringID _dialogsX[6];
+ StringId _dialogsX[6];
};
class AxacussOffice1 : public Room {
public:
diff --git a/engines/supernova/screen.cpp b/engines/supernova/screen.cpp
new file mode 100644
index 0000000000..2c441acf7b
--- /dev/null
+++ b/engines/supernova/screen.cpp
@@ -0,0 +1,636 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "common/str.h"
+#include "common/system.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+#include "supernova/imageid.h"
+#include "supernova/resman.h"
+#include "supernova/state.h"
+#include "supernova/screen.h"
+#include "supernova/supernova.h"
+
+#include "supernova/screenstatic.cpp"
+
+namespace Supernova {
+
+ScreenBuffer::ScreenBuffer()
+ : _x(0)
+ , _y(0)
+ , _width(0)
+ , _height(0)
+ , _pixels(nullptr) {
+}
+
+ScreenBufferStack::ScreenBufferStack()
+ : _last(_buffer) {
+}
+
+void ScreenBufferStack::push(int x, int y, int width, int height) {
+ if (_last == ARRAYEND(_buffer))
+ return;
+
+ Graphics::Surface *screenSurface = g_system->lockScreen();
+
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+
+ if (x + width > screenSurface->w)
+ width = screenSurface->w - x;
+
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+
+ if (y + height > screenSurface->h)
+ height = screenSurface->h - y;
+
+ _last->_pixels = new byte[width * height];
+ byte *pixels = _last->_pixels;
+ const byte *screen = static_cast<const byte *>(screenSurface->getBasePtr(x, y));
+ for (int i = 0; i < height; ++i) {
+ Common::copy(screen, screen + width, pixels);
+ screen += screenSurface->pitch;
+ pixels += width;
+ }
+ g_system->unlockScreen();
+
+ _last->_x = x;
+ _last->_y = y;
+ _last->_width = width;
+ _last->_height = height;
+
+ ++_last;
+}
+
+void ScreenBufferStack::restore() {
+ if (_last == _buffer)
+ return;
+
+ --_last;
+ g_system->lockScreen()->copyRectToSurface(_last->_pixels, _last->_width, _last->_x,
+ _last->_y, _last->_width, _last->_height);
+ g_system->unlockScreen();
+
+ delete[] _last->_pixels;
+}
+
+Marquee::Marquee(Screen *screen, MarqueeId id, const char *text)
+ : _text(text)
+ , _textBegin(text)
+ , _delay(0)
+ , _color(kColorLightBlue)
+ , _loop(false)
+ , _screen(screen) {
+ if (id == kMarqueeIntro) {
+ _y = 191;
+ _loop = true;
+ } else if (id == kMarqueeOutro) {
+ _y = 1;
+ }
+
+ _textWidth = Screen::textWidth(_text);
+ _x = kScreenWidth / 2 - _textWidth / 2;
+ _screen->_textCursorX = _x;
+ _screen->_textCursorY = _y;
+ _screen->_textColor = _color;
+}
+
+void Marquee::clearText() {
+ _screen->renderBox(_x, _y - 1, _textWidth + 1, 9, kColorBlack);
+}
+
+void Marquee::renderCharacter() {
+ if (_delay != 0) {
+ _delay--;
+ return;
+ }
+
+ switch (*_text) {
+ case '\233':
+ if (_loop) {
+ _loop = false;
+ _text = _textBegin;
+ clearText();
+ _textWidth = Screen::textWidth(_text);
+ _x = kScreenWidth / 2 - _textWidth / 2;
+ _screen->_textCursorX = _x;
+ }
+ break;
+ case '\0':
+ clearText();
+ _text++;
+ _textWidth = Screen::textWidth(_text);
+ _x = kScreenWidth / 2 - _textWidth / 2;
+ _screen->_textCursorX = _x;
+ _color = kColorLightBlue;
+ _screen->_textColor = _color;
+ break;
+ case '^':
+ _color = kColorLightYellow;
+ _screen->_textColor = _color;
+ _text++;
+ break;
+ case '#':
+ _delay = 50;
+ _text++;
+ break;
+ default:
+ _screen->renderText((uint16)*_text++);
+ _delay = 1;
+ break;
+ }
+}
+
+Screen::Screen(SupernovaEngine *vm, GameManager *gm, ResourceManager *resMan)
+ : _vm(vm)
+ , _gm(gm)
+ , _resMan(resMan)
+ , _currentImage(nullptr)
+ , _viewportBrightness(255)
+ , _guiBrightness(255)
+ , _screenWidth(320)
+ , _screenHeight(200)
+ , _textColor(kColorBlack)
+ , _textCursorX(0)
+ , _textCursorY(0)
+ , _messageShown(false) {
+
+ CursorMan.replaceCursor(_resMan->getImage(ResourceManager::kCursorNormal),
+ 16, 16, 0, 0, kColorCursorTransparent);
+ CursorMan.replaceCursorPalette(initVGAPalette, 0, 16);
+ CursorMan.showMouse(true);
+}
+
+int Screen::getGuiBrightness() const {
+ return _guiBrightness;
+}
+
+void Screen::setViewportBrightness(int brightness) {
+ _viewportBrightness = brightness;
+}
+
+int Screen::getViewportBrightness() const {
+ return _viewportBrightness;
+}
+
+void Screen::setGuiBrightness(int brightness) {
+ _guiBrightness = brightness;
+}
+
+const MSNImage *Screen::getCurrentImage() const {
+ return _currentImage;
+}
+
+bool Screen::isMessageShown() const {
+ return _messageShown;
+}
+
+Common::Point Screen::getTextCursorPos() {
+ return Common::Point(_textCursorX, _textCursorY);
+}
+
+void Screen::setTextCursorPos(int x, int y) {
+ _textCursorX = x;
+ _textCursorY = y;
+}
+
+byte Screen::getTextCursorColor() {
+ return _textColor;
+}
+
+void Screen::setTextCursorColor(byte color) {
+ _textColor = color;
+}
+
+void Screen::renderMessage(StringId stringId, MessagePosition position,
+ Common::String var1, Common::String var2) {
+ Common::String text = _vm->getGameString(stringId);
+
+ if (!var1.empty()) {
+ if (!var2.empty())
+ text = Common::String::format(text.c_str(), var1.c_str(), var2.c_str());
+ else
+ text = Common::String::format(text.c_str(), var1.c_str());
+ }
+
+ renderMessage(text, position);
+}
+
+void Screen::renderMessage(const Common::String &text, MessagePosition position) {
+ if (!text.empty())
+ renderMessage(text.c_str(), position);
+}
+
+void Screen::renderText(const uint16 character) {
+ char text[2];
+ text[0] = character & 0xFF;
+ text[1] = 0;
+ renderText(text, _textCursorX, _textCursorY, _textColor);
+}
+
+void Screen::renderText(const char *text) {
+ renderText(text, _textCursorX, _textCursorY, _textColor);
+}
+
+void Screen::renderText(StringId stringId) {
+ renderText(_vm->getGameString(stringId));
+}
+
+void Screen::renderText(const Common::String &text) {
+ if (!text.empty())
+ renderText(text.c_str());
+}
+
+void Screen::renderText(const GuiElement &guiElement) {
+ renderText(guiElement.getText(), guiElement.getTextPos().x,
+ guiElement.getTextPos().y, guiElement.getTextColor());
+}
+
+void Screen::renderText(const uint16 character, int x, int y, byte color) {
+ char text[2];
+ text[0] = character & 0xFF;
+ text[1] = 0;
+ renderText(text, x, y, color);
+}
+
+void Screen::renderText(const char *text, int x, int y, byte color) {
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+ byte *cursor = static_cast<byte *>(screen->getBasePtr(x, y));
+ const byte *basePtr = cursor;
+
+ byte c;
+ while ((c = *text++) != '\0') {
+ if (c < 32) {
+ continue;
+ } else if (c == 225) {
+ c = 128;
+ }
+
+ for (uint i = 0; i < 5; ++i) {
+ if (font[c - 32][i] == 0xff) {
+ break;
+ }
+
+ byte *ascentLine = cursor;
+ for (byte j = font[c - 32][i]; j != 0; j >>= 1) {
+ if (j & 1) {
+ *cursor = color;
+ }
+ cursor += kScreenWidth;
+ }
+ cursor = ++ascentLine;
+ }
+ ++cursor;
+ }
+ _vm->_system->unlockScreen();
+
+ uint numChars = cursor - basePtr;
+ uint absPosition = y * kScreenWidth + x + numChars;
+ _textCursorX = absPosition % kScreenWidth;
+ _textCursorY = absPosition / kScreenWidth;
+ _textColor = color;
+}
+
+void Screen::renderText(const Common::String &text, int x, int y, byte color) {
+ if (!text.empty())
+ renderText(text.c_str(), x, y, color);
+}
+
+void Screen::renderText(StringId stringId, int x, int y, byte color) {
+ renderText(_vm->getGameString(stringId), x, y, color);
+}
+
+void Screen::renderImageSection(const MSNImage *image, int section) {
+ // Note: inverting means we are removing the section. So we should get the rect for that
+ // section but draw the background (section 0) instead.
+ bool invert = false;
+ if (section > 128) {
+ section -= 128;
+ invert = true;
+ }
+ if (section > image->_numSections - 1)
+ return;
+
+ Common::Rect sectionRect(image->_section[section].x1,
+ image->_section[section].y1,
+ image->_section[section].x2 + 1,
+ image->_section[section].y2 + 1);
+ if (image->_filenumber == 1 || image->_filenumber == 2) {
+ sectionRect.setWidth(640);
+ sectionRect.setHeight(480);
+ if (_screenWidth != 640) {
+ _screenWidth = 640;
+ _screenHeight = 480;
+ initGraphics(_screenWidth, _screenHeight);
+ }
+ } else {
+ if (_screenWidth != 320) {
+ _screenWidth = 320;
+ _screenHeight = 200;
+ initGraphics(_screenWidth, _screenHeight);
+ }
+ }
+
+ uint offset = 0;
+ int pitch = sectionRect.width();
+ if (invert) {
+ pitch = image->_pitch;
+ offset = image->_section[section].y1 * pitch +
+ image->_section[section].x1;
+ section = 0;
+ }
+
+ void *pixels = image->_sectionSurfaces[section]->getPixels();
+ _vm->_system->copyRectToScreen(static_cast<const byte *>(pixels) + offset,
+ pitch, sectionRect.left, sectionRect.top,
+ sectionRect.width(), sectionRect.height());
+}
+
+void Screen::renderImage(ImageId id, bool removeImage) {
+ ImageInfo info = imageInfo[id];
+ const MSNImage *image = _resMan->getImage(info.filenumber);
+
+ if (_currentImage != image) {
+ _currentImage = image;
+ _vm->_system->getPaletteManager()->setPalette(image->getPalette(), 16, 239);
+ }
+
+ do {
+ if (removeImage)
+ renderImageSection(image, info.section + 128);
+ else
+ renderImageSection(image, info.section);
+
+ info.section = image->_section[info.section].next;
+ } while (info.section != 0);
+}
+
+void Screen::renderImage(int section) {
+ if (!_currentImage)
+ return;
+
+ bool sectionVisible = true;
+
+ if (section > 128) {
+ sectionVisible = false;
+ section -= 128;
+ }
+
+ _gm->_currentRoom->setSectionVisible(section, sectionVisible);
+
+ do {
+ if (sectionVisible)
+ renderImageSection(_currentImage, section);
+ else
+ renderImageSection(_currentImage, section + 128);
+ section = _currentImage->_section[section].next;
+ } while (section != 0);
+}
+
+bool Screen::setCurrentImage(int filenumber) {
+ _currentImage = _resMan->getImage(filenumber);
+ _vm->_system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239);
+ paletteBrightness();
+
+ return true;
+}
+
+void Screen::saveScreen(int x, int y, int width, int height) {
+ _screenBuffer.push(x, y, width, height);
+}
+
+void Screen::saveScreen(const GuiElement &guiElement) {
+ saveScreen(guiElement.left, guiElement.top, guiElement.width(), guiElement.height());
+}
+
+void Screen::restoreScreen() {
+ _screenBuffer.restore();
+}
+
+void Screen::renderRoom(Room &room) {
+ if (room.getId() == INTRO)
+ return;
+
+ if (setCurrentImage(room.getFileNumber())) {
+ for (int i = 0; i < _currentImage->_numSections; ++i) {
+ int section = i;
+ if (room.isSectionVisible(section)) {
+ do {
+ renderImageSection(_currentImage, section);
+ section = _currentImage->_section[section].next;
+ } while (section != 0);
+ }
+ }
+ }
+}
+
+int Screen::textWidth(const uint16 key) {
+ char text[2];
+ text[0] = key & 0xFF;
+ text[1] = 0;
+ return textWidth(text);
+}
+
+int Screen::textWidth(const char *text) {
+ int charWidth = 0;
+ while (*text != '\0') {
+ byte c = *text++;
+ if (c < 32) {
+ continue;
+ } else if (c == 225) {
+ c = 35;
+ }
+
+ for (uint i = 0; i < 5; ++i) {
+ if (font[c - 32][i] == 0xff) {
+ break;
+ }
+ ++charWidth;
+ }
+ ++charWidth;
+ }
+
+ return charWidth;
+}
+
+int Screen::textWidth(const Common::String &text) {
+ return Screen::textWidth(text.c_str());
+}
+
+void Screen::renderMessage(const char *text, MessagePosition position) {
+ Common::String t(text);
+ char *row[20];
+ Common::String::iterator p = t.begin();
+ uint numRows = 0;
+ int rowWidthMax = 0;
+ int x = 0;
+ int y = 0;
+ byte textColor = 0;
+
+ while (*p != '\0') {
+ row[numRows] = p;
+ ++numRows;
+ while ((*p != '\0') && (*p != '|')) {
+ ++p;
+ }
+ if (*p == '|') {
+ *p = '\0';
+ ++p;
+ }
+ }
+ for (uint i = 0; i < numRows; ++i) {
+ int rowWidth = textWidth(row[i]);
+ if (rowWidth > rowWidthMax)
+ rowWidthMax = rowWidth;
+ }
+
+ switch (position) {
+ case kMessageNormal:
+ x = 160 - rowWidthMax / 2;
+ textColor = kColorWhite99;
+ break;
+ case kMessageTop:
+ x = 160 - rowWidthMax / 2;
+ textColor = kColorLightYellow;
+ break;
+ case kMessageCenter:
+ x = 160 - rowWidthMax / 2;
+ textColor = kColorLightRed;
+ break;
+ case kMessageLeft:
+ x = 3;
+ textColor = kColorLightYellow;
+ break;
+ case kMessageRight:
+ x = 317 - rowWidthMax;
+ textColor = kColorLightGreen;
+ break;
+ }
+
+ if (position == kMessageNormal) {
+ y = 70 - ((numRows * 9) / 2);
+ } else if (position == kMessageTop) {
+ y = 5;
+ } else {
+ y = 142;
+ }
+
+ int message_columns = x - 3;
+ int message_rows = y - 3;
+ int message_width = rowWidthMax + 6;
+ int message_height = numRows * 9 + 5;
+ saveScreen(message_columns, message_rows, message_width, message_height);
+ renderBox(message_columns, message_rows, message_width, message_height, kColorWhite35);
+ for (uint i = 0; i < numRows; ++i) {
+ renderText(row[i], x, y, textColor);
+ y += 9;
+ }
+
+ _messageShown = true;
+ _gm->_messageDuration = (Common::strnlen(text, 512) + 20) * _vm->_textSpeed / 10;
+}
+
+void Screen::removeMessage() {
+ if (_messageShown) {
+ restoreScreen();
+ _messageShown = false;
+ }
+}
+
+void Screen::renderBox(int x, int y, int width, int height, byte color) {
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+ screen->fillRect(Common::Rect(x, y, x + width, y + height), color);
+ _vm->_system->unlockScreen();
+}
+
+void Screen::renderBox(const GuiElement &guiElement) {
+ renderBox(guiElement.left, guiElement.top, guiElement.width(),
+ guiElement.height(), guiElement.getBackgroundColor());
+}
+
+void Screen::initPalette() {
+ g_system->getPaletteManager()->setPalette(initVGAPalette, 0, 256);
+}
+
+void Screen::paletteBrightness() {
+ byte palette[768];
+
+ _vm->_system->getPaletteManager()->grabPalette(palette, 0, 255);
+ for (uint i = 0; i < 48; ++i) {
+ palette[i] = (initVGAPalette[i] * _guiBrightness) >> 8;
+ }
+ for (uint i = 0; i < 717; ++i) {
+ const byte *imagePalette;
+ if (_currentImage && _currentImage->getPalette()) {
+ imagePalette = _currentImage->getPalette();
+ } else {
+ imagePalette = palette + 48;
+ }
+ palette[i + 48] = (imagePalette[i] * _viewportBrightness) >> 8;
+ }
+ _vm->_system->getPaletteManager()->setPalette(palette, 0, 255);
+}
+
+void Screen::paletteFadeOut() {
+ while (_guiBrightness > 10) {
+ _guiBrightness -= 10;
+ if (_viewportBrightness > _guiBrightness)
+ _viewportBrightness = _guiBrightness;
+ paletteBrightness();
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(_vm->_delay);
+ }
+ _guiBrightness = 0;
+ _viewportBrightness = 0;
+ paletteBrightness();
+ _vm->_system->updateScreen();
+}
+
+void Screen::paletteFadeIn() {
+ while (_guiBrightness < 245) {
+ if (_viewportBrightness < _gm->_roomBrightness)
+ _viewportBrightness += 10;
+ _guiBrightness += 10;
+ paletteBrightness();
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(_vm->_delay);
+ }
+ _guiBrightness = 255;
+ _viewportBrightness = _gm->_roomBrightness;
+ paletteBrightness();
+ _vm->_system->updateScreen();
+}
+
+void Screen::setColor63(byte value) {
+ byte color[3] = {value, value, value};
+ _vm->_system->getPaletteManager()->setPalette(color, 63, 1);
+}
+
+}
diff --git a/engines/supernova/screen.h b/engines/supernova/screen.h
new file mode 100644
index 0000000000..d57fb53ed2
--- /dev/null
+++ b/engines/supernova/screen.h
@@ -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.
+*
+*/
+
+#ifndef SUPERNOVA_SCREEN_H
+#define SUPERNOVA_SCREEN_H
+
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/scummsys.h"
+
+#include "supernova/imageid.h"
+#include "supernova/msn_def.h"
+
+namespace Supernova {
+
+class SupernovaEngine;
+class GameManager;
+class ResourceManager;
+class GuiElement;
+class Room;
+class MSNImage;
+class Screen;
+
+const int kScreenWidth = 320;
+const int kScreenHeight = 200;
+const int kFontWidth = 5;
+const int kFontHeight = 8;
+
+enum Color {
+ kColorBlack = 0,
+ kColorWhite25 = 1,
+ kColorWhite35 = 2,
+ kColorWhite44 = 3,
+ kColorWhite99 = 4,
+ kColorDarkGreen = 5,
+ kColorGreen = 6,
+ kColorDarkRed = 7,
+ kColorRed = 8,
+ kColorDarkBlue = 9,
+ kColorBlue = 10,
+ kColorWhite63 = 11,
+ kColorLightBlue = 12,
+ kColorLightGreen = 13,
+ kColorLightYellow = 14,
+ kColorLightRed = 15,
+ kColorCursorTransparent = kColorWhite25
+};
+
+class ScreenBuffer {
+ friend class ScreenBufferStack;
+
+public:
+ ScreenBuffer();
+
+private:
+ byte *_pixels;
+ int _x;
+ int _y;
+ int _width;
+ int _height;
+};
+
+class ScreenBufferStack {
+public:
+ ScreenBufferStack();
+
+ void push(int x, int y, int width, int height);
+ void restore();
+
+private:
+ ScreenBuffer _buffer[8];
+ ScreenBuffer *_last;
+};
+
+class Marquee {
+public:
+ enum MarqueeId {
+ kMarqueeIntro,
+ kMarqueeOutro
+ };
+
+ Marquee(Screen *screen, MarqueeId id, const char *text);
+
+ void renderCharacter();
+
+private:
+ void clearText();
+
+ Screen *_screen;
+ const char *const _textBegin;
+ const char *_text;
+ bool _loop;
+ int _delay;
+ int _color;
+ int _x;
+ int _y;
+ int _textWidth;
+};
+
+class Screen {
+ friend class Marquee;
+
+public:
+ struct ImageInfo {
+ int filenumber;
+ int section;
+ };
+
+public:
+ static void initPalette();
+ static int textWidth(const uint16 key);
+ static int textWidth(const char *text);
+ static int textWidth(const Common::String &text);
+
+public:
+ Screen(SupernovaEngine *vm, GameManager *gm, ResourceManager *resMan);
+
+ int getViewportBrightness() const;
+ void setViewportBrightness(int brightness);
+ int getGuiBrightness() const;
+ void setGuiBrightness(int brightness);
+ const MSNImage *getCurrentImage() const;
+ bool isMessageShown() const;
+ void paletteFadeIn();
+ void paletteFadeOut();
+ void paletteBrightness();
+ void renderImage(ImageId id, bool removeImage = false);
+ void renderImage(int section);
+ bool setCurrentImage(int filenumber);
+ void saveScreen(int x, int y, int width, int height);
+ void saveScreen(const GuiElement &guiElement);
+ void restoreScreen();
+ void renderRoom(Room &room);
+ void renderMessage(const char *text, MessagePosition position = kMessageNormal);
+ void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal);
+ void renderMessage(StringId stringId, MessagePosition position = kMessageNormal,
+ Common::String var1 = "", Common::String var2 = "");
+ void removeMessage();
+ void renderText(const uint16 character);
+ void renderText(const char *text);
+ void renderText(const Common::String &text);
+ void renderText(StringId stringId);
+ void renderText(const uint16 character, int x, int y, byte color);
+ void renderText(const char *text, int x, int y, byte color);
+ void renderText(const Common::String &text, int x, int y, byte color);
+ void renderText(StringId stringId, int x, int y, byte color);
+ void renderText(const GuiElement &guiElement);
+ void renderBox(int x, int y, int width, int height, byte color);
+ void renderBox(const GuiElement &guiElement);
+ void setColor63(byte value);
+ Common::Point getTextCursorPos();
+ void setTextCursorPos(int x, int y);
+ byte getTextCursorColor();
+ void setTextCursorColor(byte color);
+ void update();
+
+private:
+ void renderImageSection(const MSNImage *image, int section);
+
+private:
+ SupernovaEngine *_vm;
+ GameManager *_gm;
+ ResourceManager *_resMan;
+ const MSNImage *_currentImage;
+ ScreenBufferStack _screenBuffer;
+ int _screenWidth;
+ int _screenHeight;
+ int _textCursorX;
+ int _textCursorY;
+ int _textColor;
+ byte _viewportBrightness;
+ byte _guiBrightness;
+ bool _messageShown;
+};
+
+}
+
+#endif
diff --git a/engines/supernova/screenstatic.cpp b/engines/supernova/screenstatic.cpp
new file mode 100644
index 0000000000..db987bf2fb
--- /dev/null
+++ b/engines/supernova/screenstatic.cpp
@@ -0,0 +1,328 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+namespace Supernova {
+
+static const Screen::ImageInfo imageInfo[] = {
+ { 0, 0}, { 0, 1}, { 0, 2},
+ { 1, 0},
+ { 2, 0},
+ { 3, 0}, { 3, 1}, { 3, 2}, { 3, 3}, { 3, 4}, { 3, 5},
+ { 3, 6}, { 3, 7}, { 3, 8}, { 3, 9}, { 3, 10}, { 3, 11},
+ { 4, 0}, { 4, 1}, { 4, 2}, { 4, 3},
+ { 5, 0}, { 5, 1}, { 5, 2}, { 5, 3}, { 5, 4}, { 5, 5},
+ { 5, 6}, { 5, 7}, { 5, 8}, { 5, 9},
+ { 6, 0}, { 6, 1}, { 6, 2}, { 6, 3}, { 6, 4}, { 6, 5},
+ { 6, 6}, { 6, 7}, { 6, 8}, { 6, 9}, { 6, 10}, { 6, 11},
+ { 6, 12}, { 6, 13}, { 6, 14}, { 6, 15}, { 6, 16}, { 6, 17},
+ { 6, 18}, { 6, 19}, { 6, 20}, { 6, 21},
+ { 7, 0}, { 7, 1}, { 7, 2}, { 7, 3}, { 7, 4}, { 7, 5},
+ { 7, 6}, { 7, 7}, { 7, 8}, { 7, 9}, { 7, 10}, { 7, 11},
+ { 7, 12}, { 7, 13}, { 7, 14}, { 7, 15}, { 7, 16}, { 7, 17},
+ { 7, 18}, { 7, 19}, { 7, 20}, { 7, 21}, { 7, 22},
+ { 8, 0}, { 8, 1}, { 8, 2}, { 8, 3}, { 8, 4}, { 8, 5},
+ { 8, 6}, { 8, 7}, { 8, 8}, { 8, 9}, { 8, 10}, { 8, 11},
+ { 8, 12},
+ { 9, 0}, { 9, 1}, { 9, 2}, { 9, 3}, { 9, 4}, { 9, 5},
+ { 9, 6}, { 9, 7}, { 9, 8}, { 9, 9}, { 9, 10}, { 9, 11},
+ { 9, 12}, { 9, 13}, { 9, 14}, { 9, 15}, { 9, 16}, { 9, 17},
+ { 9, 18}, { 9, 19}, { 9, 20}, { 9, 21}, { 9, 22}, { 9, 23},
+ {10, 0}, {10, 1}, {10, 2}, {10, 3}, {10, 4}, {10, 5},
+ {10, 6}, {10, 7}, {10, 8}, {10, 9}, {10, 10}, {10, 11},
+ {10, 12}, {10, 13}, {10, 14}, {10, 15}, {10, 16},
+ {11, 0},
+ {12, 0}, {12, 1}, {12, 2}, {12, 3},
+ {13, 0}, {13, 1}, {13, 2}, {13, 3}, {13, 4}, {13, 5},
+ {13, 6}, {13, 7}, {13, 8}, {13, 9}, {13, 10}, {13, 11},
+ {13, 12}, {13, 13},
+ {14, 0}, {14, 1}, {14, 2}, {14, 3}, {14, 4}, {14, 5},
+ {14, 6}, {14, 7}, {14, 8}, {14, 9}, {14, 10}, {14, 11},
+ {14, 12}, {14, 13}, {14, 14}, {14, 15}, {14, 16}, {14, 17},
+ {14, 18}, {14, 19},
+ {15, 0}, {15, 1}, {15, 2}, {15, 3}, {15, 4}, {15, 5},
+ {16, 0}, {16, 1}, {16, 2}, {16, 3}, {16, 4}, {16, 5},
+ {16, 6}, {16, 7}, {16, 8}, {16, 9}, {16, 10}, {16, 11},
+ {16, 12}, {16, 13}, {16, 14}, {16, 15}, {16, 16}, {16, 17},
+ {16, 18}, {16, 19}, {16, 20}, {16, 21}, {16, 22}, {16, 23},
+ {16, 24}, {16, 25}, {16, 26}, {16, 27}, {16, 28}, {16, 29},
+ {16, 30}, {16, 31}, {16, 32}, {16, 33},
+ {17, 0}, {17, 1}, {17, 2}, {17, 3}, {17, 4}, {17, 5},
+ {17, 6}, {17, 7}, {17, 8}, {17, 9}, {17, 10}, {17, 11},
+ {17, 12}, {17, 13}, {17, 14}, {17, 15},
+ {18, 0}, {18, 1}, {18, 2}, {18, 3}, {18, 4}, {18, 5},
+ {18, 6}, {18, 7}, {18, 8}, {18, 9}, {18, 10}, {18, 11},
+ {18, 12}, {18, 13}, {18, 14}, {18, 15}, {18, 16}, {18, 17},
+ {18, 18}, {18, 19}, {18, 20}, {18, 21},
+ {19, 0}, {19, 1}, {19, 2}, {19, 3}, {19, 4}, {19, 5},
+ {19, 6}, {19, 7}, {19, 8}, {19, 9}, {19, 10}, {19, 11},
+ {19, 12}, {19, 13}, {19, 14}, {19, 15}, {19, 16}, {19, 17},
+ {19, 18}, {19, 19}, {19, 20}, {19, 21}, {19, 22}, {19, 23},
+ {19, 24}, {19, 25}, {19, 26}, {19, 27}, {19, 28}, {19, 29},
+ {19, 30}, {19, 31}, {19, 32}, {19, 33}, {19, 34}, {19, 35},
+ {19, 36}, {19, 37}, {19, 38}, {19, 39}, {19, 40},
+ {20, 0},
+ {21, 0}, {21, 1}, {21, 2}, {21, 3}, {21, 4}, {21, 5},
+ {21, 6}, {21, 7}, {21, 8}, {21, 9}, {21, 10}, {21, 11},
+ {21, 12}, {21, 13}, {21, 14}, {21, 15}, {21, 16}, {21, 17},
+ {21, 18}, {21, 19}, {21, 20}, {21, 21}, {21, 22}, {21, 23},
+ {21, 24}, {21, 25}, {21, 26}, {21, 27}, {21, 28}, {21, 29},
+ {21, 30}, {21, 31}, {21, 32}, {21, 33}, {21, 34}, {21, 35},
+ {21, 36}, {21, 37}, {21, 38},
+ {22, 0}, {22, 1}, {22, 2}, {22, 3}, {22, 4}, {22, 5},
+ {22, 6}, {22, 7}, {22, 8}, {22, 9}, {22, 10}, {22, 11},
+ {22, 12}, {22, 13}, {22, 14}, {22, 15}, {22, 16}, {22, 17},
+ {22, 18},
+ {23, 0},
+ {24, 0}, {24, 1}, {24, 2}, {24, 3}, {24, 4}, {24, 5},
+ {24, 6}, {24, 7}, {24, 8},
+ {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5},
+ {25, 6}, {25, 7}, {25, 8}, {25, 9}, {25, 10}, {25, 11},
+ {25, 12}, {25, 13}, {25, 14}, {25, 15}, {25, 16}, {25, 17},
+ {25, 18},
+ {26, 0},
+ {27, 0},
+ {28, 0}, {28, 1}, {28, 2}, {28, 3}, {28, 4}, {28, 5},
+ {28, 6}, {28, 7}, {28, 8}, {28, 9}, {28, 10}, {28, 11},
+ {28, 12}, {28, 13}, {28, 14}, {28, 15}, {28, 16}, {28, 17},
+ {28, 18}, {28, 19}, {28, 20}, {28, 21}, {28, 22},
+ {29, 0}, {29, 1}, {29, 2}, {29, 3}, {29, 4}, {29, 5},
+ {29, 6}, {29, 7}, {29, 8}, {29, 9}, {29, 10}, {29, 11},
+ {29, 12}, {29, 13},
+ {30, 0}, {30, 1},
+ {31, 0}, {31, 1}, {31, 2}, {31, 3}, {31, 4}, {31, 5},
+ {31, 6},
+ {32, 0}, {32, 1}, {32, 2}, {32, 3},
+ {33, 0}, {33, 1}, {33, 2}, {33, 3}, {33, 4}, {33, 5},
+ {34, 0}, {34, 1}, {34, 2}, {34, 3}, {34, 4}, {34, 5},
+ {34, 6}, {34, 7}, {34, 8}, {34, 9}, {34, 10}, {34, 11},
+ {34, 12}, {34, 13}, {34, 14}, {34, 15}, {34, 16}, {34, 17},
+ {35, 0}, {35, 1}, {35, 2}, {35, 3}, {35, 4}, {35, 5},
+ {35, 6}, {35, 7}, {35, 8}, {35, 9}, {35, 10}, {35, 11},
+ {35, 12}, {35, 13}, {35, 14}, {35, 15}, {35, 16}, {35, 17},
+ {35, 18}, {35, 19}, {35, 20}, {35, 21},
+ {36, 0}, {36, 1}, {36, 2}, {36, 3}, {36, 4}, {36, 5},
+ {37, 0}, {37, 1}, {37, 2}, {37, 3}, {37, 4}, {37, 5},
+ {37, 6}, {37, 7}, {37, 8}, {37, 9}, {37, 10}, {37, 11},
+ {37, 12}, {37, 13}, {37, 14}, {37, 15}, {37, 16}, {37, 17},
+ {37, 18}, {37, 19}, {37, 20}, {37, 21}, {37, 22}, {37, 23},
+ {37, 24}, {37, 25}, {37, 26},
+ {38, 0}, {38, 1}, {38, 2}, {38, 3}, {38, 4}, {38, 5},
+ {38, 6}, {38, 7}, {38, 8}, {38, 9}, {38, 10}, {38, 11},
+ {38, 12},
+ {39, 0},
+ {40, 0}, {40, 1}, {40, 2}, {40, 3}, {40, 4}, {40, 5},
+ {40, 6}, {40, 7},
+ {41, 0}, {41, 1}, {41, 2}, {41, 3},
+ {42, 0}, {42, 1}, {42, 2}, {42, 3}, {42, 4}, {42, 5},
+ {42, 6}, {42, 7}, {42, 8}, {42, 9}, {42, 10}, {42, 11},
+ {43, 0}, {43, 1}, {43, 2}, {43, 3}, {43, 4}, {43, 5},
+ {43, 6}, {43, 7}, {43, 8}, {43, 9}, {43, 10}, {43, 11},
+ {43, 12}, {43, 13}, {43, 14}, {43, 15}, {43, 16}, {43, 17},
+ {43, 18}, {43, 19}, {43, 20}, {43, 21}, {43, 22}, {43, 23},
+ {43, 24}, {43, 25}, {43, 26}, {43, 27}, {43, 28}, {43, 29},
+ {43, 30}, {43, 31}
+};
+
+// Default palette
+static const byte initVGAPalette[768] = {
+ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x58, 0x58, 0x70, 0x70, 0x70, 0xfc, 0xfc, 0xfc, 0x00, 0xd0, 0x00,
+ 0x00, 0xfc, 0x00, 0xd8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xb0, 0xa0, 0xa0, 0xa0,
+ 0x50, 0xc8, 0xfc, 0x28, 0xfc, 0x28, 0xf0, 0xf0, 0x00, 0xfc, 0x28, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14,
+ 0x20, 0x20, 0x20, 0x2c, 0x2c, 0x2c, 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60,
+ 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8,
+ 0xe0, 0xe0, 0xe0, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc,
+ 0xfc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00,
+ 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc,
+ 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc,
+ 0xfc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c,
+ 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c,
+ 0x7c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc,
+ 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc,
+ 0xfc, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4,
+ 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4,
+ 0xb4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc,
+ 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70,
+ 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00,
+ 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70,
+ 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70,
+ 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38,
+ 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38,
+ 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70,
+ 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70,
+ 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50,
+ 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50,
+ 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70,
+ 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40,
+ 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00,
+ 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40,
+ 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40,
+ 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20,
+ 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20,
+ 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40,
+ 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40,
+ 0x40, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c,
+ 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c,
+ 0x2c, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40,
+ 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const byte font[][5] = {
+ {0x00,0x00,0x00,0xff,0x00},
+ {0x5f,0xff,0x00,0x00,0x00},
+ {0x03,0x00,0x03,0xff,0x00},
+ {0x14,0x7f,0x14,0x7f,0x14},
+ {0x24,0x2a,0x7f,0x2a,0x12},
+ {0x61,0x10,0x08,0x04,0x43},
+ {0x38,0x4e,0x59,0x26,0x50},
+ {0x03,0xff,0x00,0x00,0x00},
+ {0x3e,0x41,0xff,0x00,0x00},
+ {0x41,0x3e,0xff,0x00,0x00},
+ {0x10,0x54,0x38,0x54,0x10},
+ {0x10,0x10,0x7c,0x10,0x10},
+ {0x80,0x40,0xff,0x00,0x00},
+ {0x10,0x10,0x10,0x10,0x10},
+ {0x40,0xff,0x00,0x00,0x00},
+ {0x60,0x10,0x08,0x04,0x03},
+
+ {0x3e,0x41,0x41,0x41,0x3e}, /* digits */
+ {0x04,0x02,0x7f,0xff,0x00},
+ {0x42,0x61,0x51,0x49,0x46},
+ {0x22,0x41,0x49,0x49,0x36},
+ {0x18,0x14,0x12,0x7f,0x10},
+ {0x27,0x45,0x45,0x45,0x39},
+ {0x3e,0x49,0x49,0x49,0x32},
+ {0x01,0x61,0x19,0x07,0x01},
+ {0x36,0x49,0x49,0x49,0x36},
+ {0x26,0x49,0x49,0x49,0x3e},
+
+ {0x44,0xff,0x00,0x00,0x00},
+ {0x80,0x44,0xff,0x00,0x00},
+ {0x10,0x28,0x44,0xff,0x00},
+ {0x28,0x28,0x28,0x28,0x28},
+ {0x44,0x28,0x10,0xff,0x00},
+ {0x02,0x01,0x51,0x09,0x06},
+ {0x3e,0x41,0x5d,0x5d,0x1e},
+
+ {0x7c,0x12,0x11,0x12,0x7c}, /* uppercase letters*/
+ {0x7f,0x49,0x49,0x49,0x36},
+ {0x3e,0x41,0x41,0x41,0x22},
+ {0x7f,0x41,0x41,0x22,0x1c},
+ {0x7f,0x49,0x49,0x49,0xff},
+ {0x7f,0x09,0x09,0x09,0xff},
+ {0x3e,0x41,0x41,0x49,0x3a},
+ {0x7f,0x08,0x08,0x08,0x7f},
+ {0x41,0x7f,0x41,0xff,0x00},
+ {0x20,0x40,0x40,0x3f,0xff},
+ {0x7f,0x08,0x14,0x22,0x41},
+ {0x7f,0x40,0x40,0x40,0xff},
+ {0x7f,0x02,0x04,0x02,0x7f},
+ {0x7f,0x02,0x0c,0x10,0x7f},
+ {0x3e,0x41,0x41,0x41,0x3e},
+ {0x7f,0x09,0x09,0x09,0x06},
+ {0x3e,0x41,0x51,0x21,0x5e},
+ {0x7f,0x09,0x19,0x29,0x46},
+ {0x26,0x49,0x49,0x49,0x32},
+ {0x01,0x01,0x7f,0x01,0x01},
+ {0x3f,0x40,0x40,0x40,0x3f},
+ {0x07,0x18,0x60,0x18,0x07},
+ {0x1f,0x60,0x18,0x60,0x1f},
+ {0x63,0x14,0x08,0x14,0x63},
+ {0x03,0x04,0x78,0x04,0x03},
+ {0x61,0x51,0x49,0x45,0x43},
+
+ {0x7f,0x41,0x41,0xff,0x00},
+ {0x03,0x04,0x08,0x10,0x60},
+ {0x41,0x41,0x7f,0xff,0x00},
+ {0x02,0x01,0x02,0xff,0x00},
+ {0x80,0x80,0x80,0x80,0x80},
+ {0x01,0x02,0xff,0x00,0x00},
+
+ {0x38,0x44,0x44,0x44,0x7c}, /* lowercase letters */
+ {0x7f,0x44,0x44,0x44,0x38},
+ {0x38,0x44,0x44,0x44,0x44},
+ {0x38,0x44,0x44,0x44,0x7f},
+ {0x38,0x54,0x54,0x54,0x58},
+ {0x04,0x7e,0x05,0x01,0xff},
+ {0x98,0xa4,0xa4,0xa4,0x7c},
+ {0x7f,0x04,0x04,0x04,0x78},
+ {0x7d,0xff,0x00,0x00,0x00},
+ {0x80,0x80,0x7d,0xff,0x00},
+ {0x7f,0x10,0x28,0x44,0xff},
+ {0x7f,0xff,0x00,0x00,0x00},
+ {0x7c,0x04,0x7c,0x04,0x78},
+ {0x7c,0x04,0x04,0x04,0x78},
+ {0x38,0x44,0x44,0x44,0x38},
+ {0xfc,0x24,0x24,0x24,0x18},
+ {0x18,0x24,0x24,0x24,0xfc},
+ {0x7c,0x08,0x04,0x04,0xff},
+ {0x48,0x54,0x54,0x54,0x24},
+ {0x04,0x3e,0x44,0x40,0xff},
+ {0x7c,0x40,0x40,0x40,0x3c},
+ {0x0c,0x30,0x40,0x30,0x0c},
+ {0x3c,0x40,0x3c,0x40,0x3c},
+ {0x44,0x28,0x10,0x28,0x44},
+ {0x9c,0xa0,0xa0,0xa0,0x7c},
+ {0x44,0x64,0x54,0x4c,0x44},
+
+ {0x08,0x36,0x41,0xff,0x00},
+ {0x77,0xff,0x00,0x00,0x00},
+ {0x41,0x36,0x08,0xff,0x00},
+ {0x02,0x01,0x02,0x01,0xff},
+ {0xff,0x00,0x00,0x00,0x00},
+
+ {0xfe,0x49,0x49,0x4e,0x30}, /* sharp S */
+
+ {0x7c,0x41,0x40,0x41,0x3c}, /* umlauts */
+
+ {0x04,0x06,0x7f,0x06,0x04}, /* arrows */
+ {0x20,0x60,0xfe,0x60,0x20},
+
+ {0x38,0x45,0x44,0x45,0x7c}, /* umlauts */
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0x79,0x14,0x12,0x14,0x79},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0x38,0x45,0x44,0x45,0x38},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0x3d,0x42,0x42,0x42,0x3d},
+ {0x3d,0x40,0x40,0x40,0x3d},
+};
+
+}
diff --git a/engines/supernova/sound.cpp b/engines/supernova/sound.cpp
new file mode 100644
index 0000000000..e7f3ce83bd
--- /dev/null
+++ b/engines/supernova/sound.cpp
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+#include "audio/mods/protracker.h"
+#include "common/system.h"
+
+#include "supernova/resman.h"
+#include "supernova/sound.h"
+#include "supernova/supernova.h"
+
+namespace Supernova {
+
+Sound::Sound(Audio::Mixer *mixer, ResourceManager *resMan)
+ : _mixer(mixer)
+ , _resMan(resMan) {
+}
+
+void Sound::play(AudioId index) {
+ Audio::AudioStream *stream = _resMan->getSoundStream(index);
+
+ stop();
+ _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, stream,
+ -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+}
+
+void Sound::play(MusicId index) {
+ Audio::AudioStream *stream = _resMan->getSoundStream(index);
+
+ stop();
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, stream,
+ -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+}
+
+bool Sound::isPlaying() {
+ return _mixer->isSoundHandleActive(_soundHandle);
+}
+
+void Sound::stop() {
+ if (_mixer->isSoundHandleActive(_soundHandle))
+ _mixer->stopHandle(_soundHandle);
+}
+
+}
diff --git a/engines/supernova/sound.h b/engines/supernova/sound.h
new file mode 100644
index 0000000000..100c9a372b
--- /dev/null
+++ b/engines/supernova/sound.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 SUPERNOVA_SOUND_H
+#define SUPERNOVA_SOUND_H
+
+#include "audio/mixer.h"
+
+namespace Supernova {
+
+class SupernovaEngine;
+class ResourceManager;
+
+enum AudioId {
+ kAudioFoundLocation, // 44|0
+ kAudioCrash, // 45|0
+ kAudioVoiceHalt, // 46|0
+ kAudioGunShot, // 46|2510
+ kAudioSmash, // 46|4020
+ kAudioVoiceSupernova, // 47|0
+ kAudioVoiceYeah, // 47|24010
+ kAudioRobotShock, // 48|0
+ kAudioRobotBreaks, // 48|2510
+ kAudioShock, // 48|10520
+ kAudioTurntable, // 48|13530
+ kAudioSiren, // 50|0
+ kAudioSnoring, // 50|12786
+ kAudioRocks, // 51|0
+ kAudioDeath, // 53|0
+ kAudioAlarm, // 54|0
+ kAudioSuccess, // 54|8010
+ kAudioSlideDoor, // 54|24020
+ kAudioDoorOpen, // 54|30030
+ kAudioDoorClose, // 54|31040
+ kAudioNumSamples
+};
+
+enum MusicId {
+ kMusicIntro = 49,
+ kMusicOutro = 52
+};
+
+class Sound {
+public:
+
+public:
+ Sound(Audio::Mixer *mixer, ResourceManager *resMan);
+
+ void play(AudioId index);
+ void play(MusicId index);
+ void stop();
+ bool isPlaying();
+private:
+ Audio::Mixer *_mixer;
+ ResourceManager *_resMan;
+ Audio::SoundHandle _soundHandle;
+};
+
+}
+
+#endif
diff --git a/engines/supernova/state.cpp b/engines/supernova/state.cpp
index e41edbf1d5..f50d665000 100644
--- a/engines/supernova/state.cpp
+++ b/engines/supernova/state.cpp
@@ -21,11 +21,13 @@
*/
#include "common/system.h"
+#include "graphics/cursorman.h"
#include "graphics/palette.h"
#include "gui/message.h"
+
+#include "supernova/screen.h"
#include "supernova/supernova.h"
#include "supernova/state.h"
-#include "graphics/cursorman.h"
namespace Supernova {
@@ -136,13 +138,13 @@ bool GameManager::deserialize(Common::ReadStream *in, int version) {
_inventoryScroll = in->readSint32LE();
_inventory.clear();
for (int i = 0; i < inventorySize; ++i) {
- RoomID objectRoom = static_cast<RoomID>(in->readSint32LE());
+ RoomId objectRoom = static_cast<RoomId>(in->readSint32LE());
int objectIndex = in->readSint32LE();
_inventory.add(*_rooms[objectRoom]->getObject(objectIndex));
}
// Rooms
- RoomID curRoomId = static_cast<RoomID>(in->readByte());
+ RoomId curRoomId = static_cast<RoomId>(in->readByte());
for (int i = 0; i < NUMROOMS; ++i) {
_rooms[i]->deserialize(in, version);
}
@@ -194,16 +196,16 @@ Object *Inventory::get(int index) const {
if (index < _numObjects)
return _inventory[index];
- return const_cast<Object *>(&Object::nullObject);
+ return _nullObject;
}
-Object *Inventory::get(ObjectID id) const {
+Object *Inventory::get(ObjectId id) const {
for (int i = 0; i < _numObjects; ++i) {
if (_inventory[i]->_id == id)
return _inventory[i];
}
- return const_cast<Object *>(&Object::nullObject);
+ return _nullObject;
}
@@ -275,19 +277,20 @@ static Common::String timeToString(int msec) {
return Common::String(s);
}
-StringID GameManager::guiCommands[] = {
+StringId GameManager::guiCommands[] = {
kStringCommandGo, kStringCommandLook, kStringCommandTake, kStringCommandOpen, kStringCommandClose,
kStringCommandPress, kStringCommandPull, kStringCommandUse, kStringCommandTalk, kStringCommandGive
};
-StringID GameManager::guiStatusCommands[] = {
+StringId GameManager::guiStatusCommands[] = {
kStringStatusCommandGo, kStringStatusCommandLook, kStringStatusCommandTake, kStringStatusCommandOpen, kStringStatusCommandClose,
kStringStatusCommandPress, kStringStatusCommandPull, kStringStatusCommandUse, kStringStatusCommandTalk, kStringStatusCommandGive
};
-GameManager::GameManager(SupernovaEngine *vm)
- : _inventory(_inventoryScroll)
- , _vm(vm) {
+GameManager::GameManager(SupernovaEngine *vm, Sound *sound)
+ : _inventory(&_nullObject, _inventoryScroll)
+ , _vm(vm)
+ , _sound(sound) {
initRooms();
changeRoom(INTRO);
initState();
@@ -351,11 +354,10 @@ void GameManager::destroyRooms() {
delete _rooms[OUTRO];
}
-
void GameManager::initState() {
- Object::setObjectNull(_currentInputObject);
- Object::setObjectNull(_inputObject[0]);
- Object::setObjectNull(_inputObject[1]);
+ _currentInputObject = &_nullObject;
+ _inputObject[0] = &_nullObject;
+ _inputObject[1] = &_nullObject;
_inputVerb = ACTION_WALK;
_processInput = false;
_guiEnabled = true;
@@ -370,7 +372,7 @@ void GameManager::initState() {
_oldTime = g_system->getMillis();
_timerPaused = 0;
_timePaused = false;
- _timer1 = 0;
+ _messageDuration = 0;
_animationTimer = 0;
_currentSentence = -1;
@@ -466,7 +468,7 @@ void GameManager::initGui() {
int cmdAvailableSpace = 320 - (cmdCount - 1) * 2;
for (int i = 0; i < cmdCount; ++i) {
const Common::String &text = _vm->getGameString(guiCommands[i]);
- cmdAvailableSpace -= _vm->textWidth(text);
+ cmdAvailableSpace -= Screen::textWidth(text);
}
int commandButtonX = 0;
@@ -476,7 +478,7 @@ void GameManager::initGui() {
if (i < cmdCount - 1) {
int space = cmdAvailableSpace / (cmdCount - i);
cmdAvailableSpace -= space;
- width = _vm->textWidth(text) + space;
+ width = Screen::textWidth(text) + space;
} else
width = 320 - commandButtonX;
@@ -503,6 +505,75 @@ void GameManager::initGui() {
_guiInventoryArrow[1].setTextPosition(273, 186);
}
+void GameManager::updateEvents() {
+ handleTime();
+ if (_animationEnabled && !_vm->_screen->isMessageShown() && _animationTimer == 0)
+ _currentRoom->animation();
+
+ if (_state._eventCallback != kNoFn && _state._time >= _state._eventTime) {
+ _vm->_allowLoadGame = false;
+ _vm->_allowSaveGame = false;
+ _state._eventTime = kMaxTimerValue;
+ EventFunction fn = _state._eventCallback;
+ _state._eventCallback = kNoFn;
+ switch (fn) {
+ case kNoFn:
+ break;
+ case kSupernovaFn:
+ supernovaEvent();
+ break;
+ case kGuardReturnedFn:
+ guardReturnedEvent();
+ break;
+ case kGuardWalkFn:
+ guardWalkEvent();
+ break;
+ case kTaxiFn:
+ taxiEvent();
+ break;
+ case kSearchStartFn:
+ searchStartEvent();
+ break;
+ }
+ _vm->_allowLoadGame = true;
+ _vm->_allowSaveGame = true;
+ return;
+ }
+
+ if (_state._alarmOn && _state._timeAlarm <= _state._time) {
+ _state._alarmOn = false;
+ alarm();
+ return;
+ }
+
+ _mouseClicked = false;
+ _keyPressed = false;
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ _keyPressed = true;
+ processInput(event.kbd);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ // fallthrough
+ case Common::EVENT_RBUTTONUP:
+ if (_currentRoom->getId() != INTRO && _sound->isPlaying())
+ return;
+ _mouseClicked = true;
+ // fallthrough
+ case Common::EVENT_MOUSEMOVE:
+ _mouseClickType = event.type;
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ if (_guiEnabled)
+ processInput();
+ break;
+ default:
+ break;
+ }
+ }
+}
void GameManager::processInput(Common::KeyState &state) {
_key = state;
@@ -529,14 +600,18 @@ void GameManager::processInput(Common::KeyState &state) {
_vm->quitGame();
}
break;
+ case Common::KEYCODE_d:
+ if (state.flags & Common::KBD_CTRL)
+ _vm->_console->attach();
+ break;
default:
break;
}
}
void GameManager::resetInputState() {
- Object::setObjectNull(_inputObject[0]);
- Object::setObjectNull(_inputObject[1]);
+ setObjectNull(_inputObject[0]);
+ setObjectNull(_inputObject[1]);
_inputVerb = ACTION_WALK;
_processInput = false;
_mouseClicked = false;
@@ -571,7 +646,7 @@ void GameManager::processInput() {
mouseLocation = onNone;
if (_mouseClickType == Common::EVENT_LBUTTONUP) {
- if (_vm->_messageDisplayed) {
+ if (_vm->_screen->isMessageShown()) {
// Hide the message and consume the event
_vm->removeMessage();
if (mouseLocation != onCmdButton)
@@ -583,7 +658,7 @@ void GameManager::processInput() {
case onInventory:
// Fallthrough
if (_inputVerb == ACTION_GIVE || _inputVerb == ACTION_USE) {
- if (Object::isNullObject(_inputObject[0])) {
+ if (isNullObject(_inputObject[0])) {
_inputObject[0] = _currentInputObject;
if (!_inputObject[0]->hasProperty(COMBINABLE))
_processInput = true;
@@ -593,7 +668,7 @@ void GameManager::processInput() {
}
} else {
_inputObject[0] = _currentInputObject;
- if (!Object::isNullObject(_currentInputObject))
+ if (!isNullObject(_currentInputObject))
_processInput = true;
}
break;
@@ -614,13 +689,13 @@ void GameManager::processInput() {
}
} else if (_mouseClickType == Common::EVENT_RBUTTONUP) {
- if (_vm->_messageDisplayed) {
+ if (_vm->_screen->isMessageShown()) {
// Hide the message and consume the event
_vm->removeMessage();
return;
}
- if (Object::isNullObject(_currentInputObject))
+ if (isNullObject(_currentInputObject))
return;
if (mouseLocation == onObject || mouseLocation == onInventory) {
@@ -666,8 +741,9 @@ void GameManager::processInput() {
for (int i = 0; (_currentRoom->getObject(i)->_id != INVALIDOBJECT) &&
(field == -1) && i < kMaxObject; i++) {
click = _currentRoom->getObject(i)->_click;
- if (click != 255 && _vm->_currentImage) {
- MSNImageDecoder::ClickField *clickField = _vm->_currentImage->_clickField;
+ const MSNImage *image = _vm->_screen->getCurrentImage();
+ if (click != 255 && image) {
+ const MSNImage::ClickField *clickField = image->_clickField;
do {
if ((_mouseX >= clickField[click].x1) && (_mouseX <= clickField[click].x2) &&
(_mouseY >= clickField[click].y1) && (_mouseY <= clickField[click].y2))
@@ -698,7 +774,7 @@ void GameManager::processInput() {
break;
}
- Object::setObjectNull(_currentInputObject);
+ setObjectNull(_currentInputObject);
_mouseField = field;
if (_mouseField >= 0 && _mouseField < 256)
@@ -737,6 +813,14 @@ void GameManager::processInput() {
}
}
+void GameManager::setObjectNull(Object *&obj) {
+ obj = &_nullObject;
+}
+
+bool GameManager::isNullObject(Object *obj) {
+ return obj == &_nullObject;
+}
+
void GameManager::corridorOnEntrance() {
if (_state._corridorSearch)
busted(0);
@@ -761,7 +845,7 @@ void GameManager::telomat(int nr) {
"Alga Hurz Li"
};
- StringID dial1[4];
+ StringId dial1[4];
dial1[0] = kStringTelomat1;
dial1[1] = kNoString;
dial1[2] = kStringTelomat3;
@@ -769,7 +853,7 @@ void GameManager::telomat(int nr) {
static byte rows1[3] = {1, 2, 1};
- StringID dial2[4];
+ StringId dial2[4];
dial2[0] = kStringTelomat4;
dial2[1] = kStringTelomat5;
dial2[2] = kStringTelomat6;
@@ -792,9 +876,9 @@ void GameManager::telomat(int nr) {
_vm->renderBox(0, 0, 320, 200, kColorDarkBlue);
_vm->renderText(kStringTelomat12, 50, 80, kColorGreen);
_vm->renderText(kStringTelomat13, 50, 91, kColorGreen);
- do
+ do {
edit(input, 50, 105, 30);
- while ((_key.keycode != Common::KEYCODE_RETURN) && (_key.keycode != Common::KEYCODE_ESCAPE));
+ } while ((_key.keycode != Common::KEYCODE_RETURN) && (_key.keycode != Common::KEYCODE_ESCAPE));
if (_key.keycode == Common::KEYCODE_ESCAPE) {
_vm->renderBox(0, 0, 320, 200, kColorBlack);
@@ -813,7 +897,7 @@ void GameManager::telomat(int nr) {
i >>= 1;
if (i == 4) {
_vm->renderText(kStringTelomat14, 50, 120, kColorGreen);
- wait2(10);
+ wait(10);
_vm->renderBox(0, 0, 320, 200, kColorBlack);
_vm->renderRoom(*_currentRoom);
_vm->paletteBrightness();
@@ -824,7 +908,7 @@ void GameManager::telomat(int nr) {
if ((i == nr) || _rooms[BCORRIDOR]->getObject(4 + i)->hasProperty(CAUGHT)) {
_vm->renderText(kStringTelomat15, 50, 120, kColorGreen);
- wait2(10);
+ wait(10);
_vm->renderBox(0, 0, 320, 200, kColorBlack);
_vm->renderRoom(*_currentRoom);
_vm->paletteBrightness();
@@ -834,12 +918,12 @@ void GameManager::telomat(int nr) {
}
_vm->renderText(kStringTelomat16, 50, 120, kColorGreen);
- wait2(10);
+ wait(10);
_vm->renderBox(0, 0, 320, 200, kColorBlack);
_vm->renderRoom(*_currentRoom);
_vm->paletteBrightness();
_vm->renderMessage(kStringTelomat17, kMessageTop, name2[i]);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
if (_state._nameSeen[nr]) {
Common::String string = _vm->getGameString(kStringTelomat2);
@@ -851,7 +935,7 @@ void GameManager::telomat(int nr) {
switch (dialog(3, rows1, dial1, 1)) {
case 1: _vm->renderMessage(kStringTelomat18, kMessageTop);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
if ((_state._destination == 255) && !_rooms[BCORRIDOR]->isSectionVisible(7)) {
_state._eventTime = _state._time + ticksToMsec(150);
@@ -861,10 +945,10 @@ void GameManager::telomat(int nr) {
}
break;
case 0: _vm->renderMessage(kStringTelomat19, kMessageTop);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
if (dialog(4, rows2, dial2, 0) != 3) {
- wait2(10);
+ wait(10);
say(kStringTelomat20);
}
_rooms[BCORRIDOR]->setSectionVisible(7, true);
@@ -882,13 +966,13 @@ void GameManager::telomat(int nr) {
_vm->renderBox(0, 0, 320, 200, kColorDarkBlue);
_vm->renderText(kStringTelomat21, 100, 90, kColorGreen);
input = "";
- do
+ do {
edit(input, 100, 105, 30);
- while ((_key.keycode != Common::KEYCODE_RETURN) && (_key.keycode != Common::KEYCODE_ESCAPE));
+ } while ((_key.keycode != Common::KEYCODE_RETURN) && (_key.keycode != Common::KEYCODE_ESCAPE));
if (_key.keycode == Common::KEYCODE_RETURN) {
_vm->renderText(kStringShipSleepCabin9, 100, 120, kColorGreen);
- wait2(10);
+ wait(10);
}
// fallthrough
case Common::KEYCODE_ESCAPE:
@@ -926,7 +1010,7 @@ void GameManager::guardNoticed() {
_vm->paletteFadeIn();
_vm->renderImage(2);
reply(kStringGuardNoticed1, 2, 5);
- wait2(2);
+ wait(2);
reply(kStringGuardNoticed2, 2, 5);
_vm->paletteFadeOut();
_currentRoom->setSectionVisible(2, false);
@@ -947,19 +1031,19 @@ void GameManager::busted(int i) {
i = 5;
if (!_currentRoom->getObject(0)->hasProperty(OPENED)) {
_vm->renderImage(i - 1);
- _vm->playSound(kAudioDoorOpen);
- wait2(2);
+ _sound->play(kAudioDoorOpen);
+ wait(2);
}
_vm->renderImage(i);
- wait2(3);
+ wait(3);
_vm->renderImage(i + 3);
- _vm->playSound(kAudioVoiceHalt);
+ _sound->play(kAudioVoiceHalt);
_vm->renderImage(i);
- wait2(5);
+ wait(5);
if (_currentRoom->getId() == OFFICE_L2)
i = 13;
_vm->renderImage(i + 1);
- wait2(3);
+ wait(3);
_vm->renderImage(i + 2);
shot(0, 0);
} else if (_currentRoom->getId() == BCORRIDOR)
@@ -973,8 +1057,8 @@ void GameManager::busted(int i) {
else
_vm->renderImage(33); // above
}
- _vm->playSound(kAudioVoiceHalt);
- wait2(3);
+ _sound->play(kAudioVoiceHalt);
+ wait(3);
shot(0, 0);
}
@@ -1025,7 +1109,7 @@ void GameManager::supernovaEvent() {
CursorMan.showMouse(false);
if (_currentRoom->getId() <= CAVE) {
_vm->renderMessage(kStringSupernova1);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->paletteFadeOut();
changeRoom(MEETUP);
@@ -1038,7 +1122,7 @@ void GameManager::supernovaEvent() {
_vm->paletteFadeIn();
}
_vm->renderMessage(kStringSupernova2);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->setCurrentImage(26);
_vm->renderImage(0);
@@ -1046,28 +1130,28 @@ void GameManager::supernovaEvent() {
novaScroll();
_vm->paletteFadeOut();
_vm->renderBox(0, 0, 320, 200, kColorBlack);
- _vm->_menuBrightness = 255;
+ _vm->_screen->setGuiBrightness(255);
_vm->paletteBrightness();
if (_currentRoom->getId() == GLIDER) {
_vm->renderMessage(kStringSupernova3);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
- _vm->_menuBrightness = 0;
+ _vm->_screen->setGuiBrightness(0);
_vm->paletteBrightness();
_vm->renderRoom(*_currentRoom);
_vm->paletteFadeIn();
_vm->renderMessage(kStringSupernova4, kMessageTop);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringSupernova5, kMessageTop);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringSupernova6, kMessageTop);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringSupernova7, kMessageTop);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
changeRoom(MEETUP2);
_rooms[MEETUP2]->setSectionVisible(1, true);
@@ -1077,9 +1161,9 @@ void GameManager::supernovaEvent() {
_inventory.remove(*(_rooms[ROGER]->getObject(8)));
} else {
_vm->renderMessage(kStringSupernova8);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
- _vm->_menuBrightness = 0;
+ _vm->_screen->setGuiBrightness(0);
_vm->paletteBrightness();
changeRoom(MEETUP2);
if (_rooms[ROGER]->getObject(3)->hasProperty(CARRIED) && !_rooms[GLIDER]->isSectionVisible(5)) {
@@ -1121,7 +1205,7 @@ void GameManager::walk(int imgId) {
_vm->renderImage(_prevImgId + 128);
_vm->renderImage(imgId);
_prevImgId = imgId;
- wait2(3);
+ wait(3);
}
void GameManager::guardWalkEvent() {
@@ -1130,14 +1214,14 @@ void GameManager::guardWalkEvent() {
_rooms[BCORRIDOR]->getObject(_state._origin + 4)->hasProperty(OPENED));
_rooms[BCORRIDOR]->getObject(_state._origin + 4)->disableProperty(OCCUPIED);
if (_currentRoom == _rooms[BCORRIDOR]) {
- if (_vm->_messageDisplayed)
+ if (_vm->_screen->isMessageShown())
_vm->removeMessage();
if (!behind) {
_vm->renderImage(_state._origin + 1);
_prevImgId = _state._origin + 1;
- _vm->playSound(kAudioDoorOpen);
- wait2(3);
+ _sound->play(kAudioDoorOpen);
+ wait(3);
}
int imgId;
@@ -1158,13 +1242,13 @@ void GameManager::guardWalkEvent() {
}
_vm->renderImage(imgId);
if (!behind) {
- wait2(3);
+ wait(3);
_vm->renderImage(_prevImgId + 128);
- _vm->playSound(kAudioDoorClose);
+ _sound->play(kAudioDoorClose);
}
_prevImgId = imgId;
- wait2(3);
+ wait(3);
switch (_state._origin) {
case 0:
walk(12);
@@ -1221,12 +1305,12 @@ void GameManager::guardWalkEvent() {
if (behind) {
_vm->renderImage(_state._destination + 1);
- _vm->playSound(kAudioDoorOpen);
- wait2(3);
+ _sound->play(kAudioDoorOpen);
+ wait(3);
_vm->renderImage(_prevImgId + 128);
- wait2(3);
+ wait(3);
_vm->renderImage(_state._destination + 1 + 128);
- _vm->playSound(kAudioDoorClose);
+ _sound->play(kAudioDoorClose);
_rooms[BCORRIDOR]->getObject(_state._destination + 4)->setProperty(OCCUPIED);
_state._destination = 255;
} else if (_rooms[BCORRIDOR]->isSectionVisible(_state._destination + 1)) {
@@ -1236,7 +1320,7 @@ void GameManager::guardWalkEvent() {
_state._eventTime = _state._time + ticksToMsec(60);
_state._eventCallback = kGuardWalkFn;
} else {
- wait2(18);
+ wait(18);
SWAP(_state._origin, _state._destination);
_state._eventCallback = kGuardWalkFn;
}
@@ -1266,7 +1350,7 @@ void GameManager::taxiEvent() {
_vm->renderImage(1);
_vm->renderImage(2);
- _vm->playSound(kAudioRocks);
+ _sound->play(kAudioRocks);
screenShake();
_vm->renderImage(9);
_currentRoom->getObject(1)->setProperty(OPENED);
@@ -1274,7 +1358,7 @@ void GameManager::taxiEvent() {
_currentRoom->setSectionVisible(2, false);
_vm->renderImage(3);
for (int i = 4; i <= 8; i++) {
- wait2(2);
+ wait(2);
_vm->renderImage(invertSection(i - 1));
_vm->renderImage(i);
}
@@ -1292,7 +1376,7 @@ void GameManager::great(uint number) {
if (number && (_state._greatFlag & (1 << number)))
return;
- _vm->playSound(kAudioSuccess);
+ _sound->play(kAudioSuccess);
_state._greatFlag |= 1 << number;
}
@@ -1321,7 +1405,7 @@ void GameManager::sentence(int number, bool brightness) {
}
}
-void GameManager::say(StringID textId) {
+void GameManager::say(StringId textId) {
Common::String str = _vm->getGameString(textId);
if (!str.empty())
say(str.c_str());
@@ -1351,7 +1435,7 @@ void GameManager::say(const char *text) {
_vm->renderBox(0, 138, 320, 62, kColorBlack);
}
-void GameManager::reply(StringID textId, int aus1, int aus2) {
+void GameManager::reply(StringId textId, int aus1, int aus2) {
Common::String str = _vm->getGameString(textId);
if (!str.empty())
reply(str.c_str(), aus1, aus2);
@@ -1375,7 +1459,7 @@ void GameManager::reply(const char *text, int aus1, int aus2) {
_vm->removeMessage();
}
-int GameManager::dialog(int num, byte rowLength[6], StringID text[6], int number) {
+int GameManager::dialog(int num, byte rowLength[6], StringId text[6], int number) {
_vm->_allowLoadGame = false;
_guiEnabled = false;
@@ -1407,7 +1491,12 @@ int GameManager::dialog(int num, byte rowLength[6], StringID text[6], int number
_currentSentence = -1;
do {
- mouseInput3();
+ do {
+ updateEvents();
+ mousePosDialog(_mouseX, _mouseY);
+ g_system->updateScreen();
+ g_system->delayMillis(_vm->_delay);
+ } while (!_mouseClicked && !_vm->shouldQuit());
} while (_currentSentence == -1 && !_vm->shouldQuit());
_vm->renderBox(0, 138, 320, 62, kColorBlack);
@@ -1443,7 +1532,7 @@ void GameManager::turnOn() {
return;
_state._powerOff = false;
- _vm->_brightness = 255;
+ _vm->_screen->setViewportBrightness(255);
_rooms[SLEEP]->setSectionVisible(1, false);
_rooms[SLEEP]->setSectionVisible(2, false);
_rooms[COCKPIT]->setSectionVisible(22, false);
@@ -1462,7 +1551,7 @@ void GameManager::takeObject(Object &obj) {
void GameManager::drawCommandBox() {
for (int i = 0; i < ARRAYSIZE(_guiCommandButton); ++i) {
_vm->renderBox(_guiCommandButton[i]);
- int space = (_guiCommandButton[i].width() - _vm->textWidth(_guiCommandButton[i].getText())) / 2;
+ int space = (_guiCommandButton[i].width() - Screen::textWidth(_guiCommandButton[i].getText())) / 2;
_vm->renderText(_guiCommandButton[i].getText(),
_guiCommandButton[i].getTextPos().x + space,
_guiCommandButton[i].getTextPos().y,
@@ -1491,7 +1580,7 @@ void GameManager::drawInventory() {
uint16 GameManager::getKeyInput(bool blockForPrintChar) {
while (!_vm->shouldQuit()) {
- _vm->updateEvents();
+ updateEvents();
if (_keyPressed) {
if (blockForPrintChar) {
if (Common::isPrint(_key.keycode) ||
@@ -1521,7 +1610,7 @@ uint16 GameManager::getKeyInput(bool blockForPrintChar) {
Common::EventType GameManager::getMouseInput() {
while (!_vm->shouldQuit()) {
- _vm->updateEvents();
+ updateEvents();
if (_mouseClicked)
return _mouseClickType;
g_system->updateScreen();
@@ -1532,7 +1621,7 @@ Common::EventType GameManager::getMouseInput() {
void GameManager::getInput() {
while (!_vm->shouldQuit()) {
- _vm->updateEvents();
+ updateEvents();
if (_mouseClicked || _keyPressed)
break;
g_system->updateScreen();
@@ -1540,15 +1629,6 @@ void GameManager::getInput() {
}
}
-void GameManager::mouseInput3() {
- do {
- _vm->updateEvents();
- mousePosDialog(_mouseX, _mouseY);
- g_system->updateScreen();
- g_system->delayMillis(_vm->_delay);
- } while (!_mouseClicked && !_vm->shouldQuit());
-}
-
void GameManager::roomBrightness() {
_roomBrightness = 255;
if ((_currentRoom->getId() != OUTSIDE) && (_currentRoom->getId() < ROCKS) && _state._powerOff)
@@ -1558,22 +1638,22 @@ void GameManager::roomBrightness() {
else if ((_currentRoom->getId() == GUARD3) && _state._powerOff)
_roomBrightness = 0;
- if (_vm->_brightness != 0)
- _vm->_brightness = _roomBrightness;
+ if (_vm->_screen->getViewportBrightness() != 0)
+ _vm->_screen->setViewportBrightness(_roomBrightness);
_vm->paletteBrightness();
}
-void GameManager::changeRoom(RoomID id) {
+void GameManager::changeRoom(RoomId id) {
_currentRoom = _rooms[id];
_newRoom = true;
}
-void GameManager::wait2(int ticks) {
+void GameManager::wait(int ticks) {
int32 end = _state._time + ticksToMsec(ticks);
do {
g_system->delayMillis(_vm->_delay);
- _vm->updateEvents();
+ updateEvents();
g_system->updateScreen();
} while (_state._time < end && !_vm->shouldQuit());
}
@@ -1582,7 +1662,7 @@ void GameManager::waitOnInput(int ticks) {
int32 end = _state._time + ticksToMsec(ticks);
do {
g_system->delayMillis(_vm->_delay);
- _vm->updateEvents();
+ updateEvents();
g_system->updateScreen();
} while (_state._time < end && !_vm->shouldQuit() && !_keyPressed && !_mouseClicked);
}
@@ -1592,7 +1672,7 @@ bool GameManager::waitOnInput(int ticks, Common::KeyCode &keycode) {
int32 end = _state._time + ticksToMsec(ticks);
do {
g_system->delayMillis(_vm->_delay);
- _vm->updateEvents();
+ updateEvents();
g_system->updateScreen();
if (_keyPressed) {
keycode = _key.keycode;
@@ -1652,14 +1732,14 @@ void GameManager::saveTime() {
void GameManager::screenShake() {
for (int i = 0; i < 12; ++i) {
_vm->_system->setShakePos(8);
- wait2(1);
+ wait(1);
_vm->_system->setShakePos(0);
- wait2(1);
+ wait(1);
}
}
void GameManager::shock() {
- _vm->playSound(kAudioShock);
+ _sound->play(kAudioShock);
dead(kStringShock);
}
@@ -1704,24 +1784,24 @@ void GameManager::edit(Common::String &input, int x, int y, uint length) {
kScreenWidth - x : (length + 1) * (kFontWidth + 2);
while (isEditing) {
- _vm->_textCursorX = x;
- _vm->_textCursorY = y;
- _vm->_textColor = kColorWhite99;
+ _vm->_screen->setTextCursorPos(x, y);
+ _vm->_screen->setTextCursorColor(kColorWhite99);
_vm->renderBox(x, y - 1, overdrawWidth, 9, kColorDarkBlue);
for (uint i = 0; i < input.size(); ++i) {
// Draw char highlight depending on cursor position
if (i == cursorIndex) {
- _vm->renderBox(_vm->_textCursorX, y - 1, _vm->textWidth(input[i]), 9, kColorWhite99);
- _vm->_textColor = kColorDarkBlue;
+ _vm->renderBox(_vm->_screen->getTextCursorPos().x, y - 1,
+ Screen::textWidth(input[i]), 9, kColorWhite99);
+ _vm->_screen->setTextCursorColor(kColorDarkBlue);
_vm->renderText(input[i]);
- _vm->_textColor = kColorWhite99;
+ _vm->_screen->setTextCursorColor(kColorWhite99);
} else
_vm->renderText(input[i]);
}
if (cursorIndex == input.size()) {
- _vm->renderBox(_vm->_textCursorX + 1, y - 1, 6, 9, kColorDarkBlue);
- _vm->renderBox(_vm->_textCursorX , y - 1, 1, 9, kColorWhite99);
+ _vm->renderBox(_vm->_screen->getTextCursorPos().x + 1, y - 1, 6, 9, kColorDarkBlue);
+ _vm->renderBox(_vm->_screen->getTextCursorPos().x, y - 1, 1, 9, kColorWhite99);
}
getKeyInput(true);
@@ -1767,15 +1847,15 @@ void GameManager::edit(Common::String &input, int x, int y, uint length) {
void GameManager::shot(int a, int b) {
if (a)
_vm->renderImage(a);
- _vm->playSound(kAudioGunShot);
- wait2(2);
+ _sound->play(kAudioGunShot);
+ wait(2);
if (b)
_vm->renderImage(b);
- wait2(2);
+ wait(2);
if (a)
_vm->renderImage(a);
- _vm->playSound(kAudioGunShot);
- wait2(2);
+ _sound->play(kAudioGunShot);
+ wait(2);
if (b)
_vm->renderImage(b);
@@ -1801,7 +1881,7 @@ void GameManager::drawStatus() {
_vm->renderBox(0, 140, 320, 9, kColorWhite25);
_vm->renderText(_vm->getGameString(guiStatusCommands[index]), 1, 141, kColorDarkGreen);
- if (Object::isNullObject(_inputObject[0]))
+ if (isNullObject(_inputObject[0]))
_vm->renderText(_currentInputObject->_name);
else {
_vm->renderText(_inputObject[0]->_name);
@@ -1832,19 +1912,18 @@ void GameManager::closeLocker(const Room *room, Object *obj, Object *lock, int s
}
}
-void GameManager::dead(StringID messageId) {
+void GameManager::dead(StringId messageId) {
_vm->paletteFadeOut();
_guiEnabled = false;
_vm->setCurrentImage(11);
_vm->renderImage(0);
_vm->renderMessage(messageId);
- _vm->playSound(kAudioDeath);
+ _sound->play(kAudioDeath);
_vm->paletteFadeIn();
getInput();
_vm->paletteFadeOut();
_vm->removeMessage();
- // TODO: Load screen
destroyRooms();
initRooms();
initState();
@@ -1926,10 +2005,10 @@ bool GameManager::genericInteract(Action verb, Object &obj1, Object &obj2) {
}
} else if ((verb == ACTION_LOOK) && (obj1._id == NEWSPAPER)) {
_vm->renderMessage(kStringGenericInteract_10);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringGenericInteract_11);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->setCurrentImage(2);
_vm->renderImage(0);
@@ -2127,7 +2206,7 @@ bool GameManager::genericInteract(Action verb, Object &obj1, Object &obj2) {
_vm->renderMessage(kStringGenericInteract_30);
else if ((verb == ACTION_LOOK) && (obj1._id == BOOK2)) {
_vm->renderMessage(kStringGenericInteract_31);
- waitOnInput(_timer1);
+ waitOnInput(_messageDuration);
_vm->removeMessage();
_vm->renderMessage(kStringGenericInteract_32);
} else
@@ -2192,7 +2271,7 @@ void GameManager::handleInput() {
byte i = _inputObject[0]->_click;
_inputObject[0]->_click = _inputObject[0]->_click2;
_inputObject[0]->_click2 = i;
- _vm->playSound(kAudioDoorOpen);
+ _sound->play(kAudioDoorOpen);
}
break;
@@ -2211,7 +2290,7 @@ void GameManager::handleInput() {
byte i = _inputObject[0]->_click;
_inputObject[0]->_click = _inputObject[0]->_click2;
_inputObject[0]->_click2 = i;
- _vm->playSound(kAudioDoorClose);
+ _sound->play(kAudioDoorClose);
}
break;
@@ -2230,7 +2309,7 @@ void GameManager::handleInput() {
}
void GameManager::executeRoom() {
- if (_processInput && !_vm->_messageDisplayed && _guiEnabled) {
+ if (_processInput && !_vm->_screen->isMessageShown() && _guiEnabled) {
handleInput();
if (_mouseClicked) {
Common::Event event;
@@ -2246,7 +2325,7 @@ void GameManager::executeRoom() {
}
if (_guiEnabled) {
- if (!_vm->_messageDisplayed) {
+ if (!_vm->_screen->isMessageShown()) {
g_system->fillScreen(kColorBlack);
_vm->renderRoom(*_currentRoom);
}
@@ -2257,7 +2336,7 @@ void GameManager::executeRoom() {
}
roomBrightness();
- if (_vm->_brightness == 0)
+ if (_vm->_screen->getViewportBrightness() == 0)
_vm->paletteFadeIn();
if (!_currentRoom->hasSeen() && _newRoom) {
@@ -2269,31 +2348,31 @@ void GameManager::executeRoom() {
void GameManager::guardShot() {
_vm->renderImage(2);
_vm->renderImage(5);
- wait2(3);
+ wait(3);
_vm->renderImage(2);
- _vm->playSound(kAudioVoiceHalt);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- wait2(1);
+ _sound->play(kAudioVoiceHalt);
+ while (_sound->isPlaying())
+ wait(1);
_vm->renderImage(5);
- wait2(5);
+ wait(5);
_vm->renderImage(3);
- wait2(3);
+ wait(3);
shot(4, 3);
}
void GameManager::guard3Shot() {
_vm->renderImage(1);
- wait2(3);
- _vm->playSound(kAudioVoiceHalt); // 46/0
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
- wait2(1);
+ wait(3);
+ _sound->play(kAudioVoiceHalt); // 46/0
+ while (_sound->isPlaying())
+ wait(1);
- wait2(5);
+ wait(5);
_vm->renderImage(2);
- wait2(3);
+ wait(3);
shot(3,2);
}
@@ -2337,12 +2416,12 @@ void GameManager::alarmSound() {
_vm->removeMessage();
_vm->renderMessage(kStringAlarm);
- int32 end = _state._time + ticksToMsec(_timer1);
+ int32 end = _state._time + ticksToMsec(_messageDuration);
do {
- _vm->playSound(kAudioAlarm);
- while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) {
+ _sound->play(kAudioAlarm);
+ while (_sound->isPlaying()) {
g_system->delayMillis(_vm->_delay);
- _vm->updateEvents();
+ updateEvents();
g_system->updateScreen();
}
} while (_state._time < end && !_vm->shouldQuit());
diff --git a/engines/supernova/state.h b/engines/supernova/state.h
index ab21842296..7d7b2284ad 100644
--- a/engines/supernova/state.h
+++ b/engines/supernova/state.h
@@ -23,9 +23,11 @@
#ifndef SUPERNOVA_STATE_H
#define SUPERNOVA_STATE_H
+#include "common/events.h"
#include "common/rect.h"
#include "common/keyboard.h"
#include "supernova/rooms.h"
+#include "supernova/sound.h"
namespace Supernova {
@@ -63,8 +65,9 @@ struct GameState {
class Inventory {
public:
- Inventory(int &inventoryScroll)
+ Inventory(Object *nullObject, int &inventoryScroll)
: _numObjects(0)
+ , _nullObject(nullObject)
, _inventoryScroll(inventoryScroll)
{}
@@ -72,11 +75,12 @@ public:
void remove(Object &obj);
void clear();
Object *get(int index) const;
- Object *get(ObjectID id) const;
+ Object *get(ObjectId id) const;
int getSize() const { return _numObjects; }
private:
Object *_inventory[kMaxCarry];
+ Object *_nullObject;
int &_inventoryScroll;
int _numObjects;
};
@@ -121,18 +125,20 @@ private:
class GameManager {
public:
- GameManager(SupernovaEngine *vm);
+ GameManager(SupernovaEngine *vm, Sound *sound);
~GameManager();
+ void updateEvents();
void processInput(Common::KeyState &state);
void processInput();
void executeRoom();
bool serialize(Common::WriteStream *out);
bool deserialize(Common::ReadStream *in, int version);
- static StringID guiCommands[];
- static StringID guiStatusCommands[];
+ static StringId guiCommands[];
+ static StringId guiStatusCommands[];
SupernovaEngine *_vm;
+ Sound *_sound;
Common::KeyState _key;
Common::EventType _mouseClickType;
bool _mouseClicked;
@@ -150,13 +156,13 @@ public:
bool _animationEnabled;
byte _roomBrightness;
Action _inputVerb;
+ Object _nullObject;
Object *_currentInputObject;
Object *_inputObject[2];
- bool _waitEvent;
int32 _oldTime;
uint _timePaused;
bool _timerPaused;
- int32 _timer1;
+ int32 _messageDuration;
int32 _animationTimer;
int _inventoryScroll;
int _exitList[25];
@@ -166,11 +172,13 @@ public:
// Dialog
int _currentSentence;
int _sentenceNumber[6];
- StringID _texts[6];
+ StringId _texts[6];
byte _rows[6];
byte _rowsStart[6];
void takeObject(Object &obj);
+ void setObjectNull(Object *&obj);
+ bool isNullObject(Object *obj);
void initState();
void initRooms();
@@ -184,8 +192,7 @@ public:
Common::EventType getMouseInput();
uint16 getKeyInput(bool blockForPrintChar = false);
void getInput();
- void mouseInput3();
- void wait2(int ticks);
+ void wait(int ticks);
void waitOnInput(int ticks);
bool waitOnInput(int ticks, Common::KeyCode &keycode);
void turnOff();
@@ -203,7 +210,7 @@ public:
void drawStatus();
void drawCommandBox();
void drawInventory();
- void changeRoom(RoomID id);
+ void changeRoom(RoomId id);
void resetInputState();
void handleInput();
void handleTime();
@@ -211,12 +218,12 @@ public:
void loadTime();
void saveTime();
void setAnimationTimer(int ticks);
- void dead(StringID messageId);
- int dialog(int num, byte rowLength[6], StringID text[6], int number);
+ void dead(StringId messageId);
+ int dialog(int num, byte rowLength[6], StringId text[6], int number);
void sentence(int number, bool brightness);
- void say(StringID textId);
+ void say(StringId textId);
void say(const char *text);
- void reply(StringID textId, int aus1, int aus2);
+ void reply(StringId textId, int aus1, int aus2);
void reply(const char *text, int aus1, int aus2);
void mousePosDialog(int x, int y);
void shot(int a, int b);
diff --git a/engines/supernova/supernova.cpp b/engines/supernova/supernova.cpp
index 50731ae52f..c47e476de7 100644
--- a/engines/supernova/supernova.cpp
+++ b/engines/supernova/supernova.cpp
@@ -20,7 +20,6 @@
*
*/
-#include "audio/mods/protracker.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/debug-channels.h"
@@ -42,36 +41,14 @@
#include "graphics/thumbnail.h"
#include "gui/saveload.h"
+#include "supernova/resman.h"
+#include "supernova/screen.h"
+#include "supernova/sound.h"
#include "supernova/supernova.h"
#include "supernova/state.h"
namespace Supernova {
-const AudioInfo audioInfo[kAudioNumSamples] = {
- {44, 0, -1},
- {45, 0, -1},
- {46, 0, 2510},
- {46, 2510, 4020},
- {46, 4020, -1},
- {47, 0, 24010},
- {47, 24010, -1},
- {48, 0, 2510},
- {48, 2510, 10520},
- {48, 10520, 13530},
- {48, 13530, -1},
- {50, 0, 12786},
- {50, 12786, -1},
- {51, 0, -1},
- {53, 0, -1},
- {54, 0, 8010},
- {54, 8010, 24020},
- {54, 24020, 30030},
- {54, 30030, 31040},
- {54, 31040, -1}
-};
-
-const Object Object::nullObject;
-
ObjectType operator|(ObjectType a, ObjectType b) {
return static_cast<ObjectType>(+a | +b);
}
@@ -98,74 +75,37 @@ ObjectType &operator^=(ObjectType &a, ObjectType b) {
SupernovaEngine::SupernovaEngine(OSystem *syst)
: Engine(syst)
- , _console(NULL)
- , _gm(NULL)
- , _currentImage(NULL)
- , _soundMusicIntro(NULL)
- , _soundMusicOutro(NULL)
- , _rnd("supernova")
- , _brightness(255)
- , _menuBrightness(255)
+ , _console(nullptr)
+ , _gm(nullptr)
+ , _sound(nullptr)
+ , _resMan(nullptr)
+ , _screen(nullptr)
, _delay(33)
, _textSpeed(kTextSpeed[2])
- , _screenWidth(320)
- , _screenHeight(200)
- , _messageDisplayed(false)
, _allowLoadGame(true)
- , _allowSaveGame(true)
-{
-// const Common::FSNode gameDataDir(ConfMan.get("path"));
-// SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
-
+ , _allowSaveGame(true) {
if (ConfMan.hasKey("textspeed"))
_textSpeed = ConfMan.getInt("textspeed");
- // setup engine specific debug channels
DebugMan.addDebugChannel(kDebugGeneral, "general", "Supernova general debug channel");
}
SupernovaEngine::~SupernovaEngine() {
DebugMan.clearAllDebugChannels();
- delete _currentImage;
delete _console;
delete _gm;
- delete _soundMusicIntro;
- delete _soundMusicOutro;
+ delete _sound;
+ delete _resMan;
+ delete _screen;
}
Common::Error SupernovaEngine::run() {
- Graphics::ModeList modes;
- modes.push_back(Graphics::Mode(320, 200));
- modes.push_back(Graphics::Mode(640, 480));
- initGraphicsModes(modes);
- initGraphics(_screenWidth, _screenHeight);
-
- Common::Error status = loadGameStrings();
- if (status.getCode() != Common::kNoError)
- return status;
-
- _gm = new GameManager(this);
- _console = new Console(this, _gm);
-
- initData();
- initPalette();
-
- CursorMan.replaceCursor(_mouseNormal, 16, 16, 0, 0, kColorCursorTransparent);
- CursorMan.replaceCursorPalette(initVGAPalette, 0, 16);
- CursorMan.showMouse(true);
-
- setTotalPlayTime(0);
-
- int saveSlot = ConfMan.getInt("save_slot");
- if (saveSlot >= 0) {
- if (loadGameState(saveSlot).getCode() != Common::kNoError)
- error("Failed to load save game from slot %i", saveSlot);
- }
+ init();
while (!shouldQuit()) {
uint32 start = _system->getMillis();
- updateEvents();
+ _gm->updateEvents();
_gm->executeRoom();
_console->onFrame();
_system->updateScreen();
@@ -174,89 +114,34 @@ Common::Error SupernovaEngine::run() {
_system->delayMillis(end);
}
- stopSound();
+ _mixer->stopAll();
return Common::kNoError;
}
-void SupernovaEngine::updateEvents() {
- _gm->handleTime();
- if (_gm->_animationEnabled && !_messageDisplayed && _gm->_animationTimer == 0)
- _gm->_currentRoom->animation();
-
- if (_gm->_state._eventCallback != kNoFn && _gm->_state._time >= _gm->_state._eventTime) {
- _allowLoadGame = false;
- _allowSaveGame = false;
- _gm->_state._eventTime = kMaxTimerValue;
- EventFunction fn = _gm->_state._eventCallback;
- _gm->_state._eventCallback = kNoFn;
- switch (fn) {
- case kNoFn:
- break;
- case kSupernovaFn:
- _gm->supernovaEvent();
- break;
- case kGuardReturnedFn:
- _gm->guardReturnedEvent();
- break;
- case kGuardWalkFn:
- _gm->guardWalkEvent();
- break;
- case kTaxiFn:
- _gm->taxiEvent();
- break;
- case kSearchStartFn:
- _gm->searchStartEvent();
- break;
- }
- _allowLoadGame = true;
- _allowSaveGame = true;
- return;
- }
-
- if (_gm->_state._alarmOn && _gm->_state._timeAlarm <= _gm->_state._time) {
- _gm->_state._alarmOn = false;
- _gm->alarm();
- return;
- }
+void SupernovaEngine::init() {
+ Graphics::ModeList modes;
+ modes.push_back(Graphics::Mode(320, 200));
+ modes.push_back(Graphics::Mode(640, 480));
+ initGraphicsModes(modes);
+ initGraphics(320, 200);
- _gm->_mouseClicked = false;
- _gm->_keyPressed = false;
- Common::Event event;
- while (g_system->getEventManager()->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_KEYDOWN:
- _gm->_keyPressed = true;
- if (event.kbd.keycode == Common::KEYCODE_d &&
- (event.kbd.flags & Common::KBD_CTRL)) {
- _console->attach();
- }
- if (event.kbd.keycode == Common::KEYCODE_x &&
- (event.kbd.flags & Common::KBD_CTRL)) {
- // TODO: Draw exit box
- }
+ Common::Error status = loadGameStrings();
+ if (status.getCode() != Common::kNoError)
+ error("Failed reading game strings");
- _gm->processInput(event.kbd);
- break;
+ _resMan = new ResourceManager();
+ _sound = new Sound(_mixer, _resMan);
+ _gm = new GameManager(this, _sound);
+ _screen = new Screen(this, _gm, _resMan);
+ _console = new Console(this, _gm);
- case Common::EVENT_LBUTTONUP:
- // fallthrough
- case Common::EVENT_RBUTTONUP:
- if (_gm->_currentRoom->getId() != INTRO && _mixer->isSoundHandleActive(_soundHandle))
- return;
- _gm->_mouseClicked = true;
- // fallthrough
- case Common::EVENT_MOUSEMOVE:
- _gm->_mouseClickType = event.type;
- _gm->_mouseX = event.mouse.x;
- _gm->_mouseY = event.mouse.y;
- if (_gm->_guiEnabled)
- _gm->processInput();
- break;
+ setTotalPlayTime(0);
- default:
- break;
- }
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0) {
+ if (loadGameState(saveSlot).getCode() != Common::kNoError)
+ error("Failed to load save game from slot %i", saveSlot);
}
}
@@ -337,440 +222,133 @@ Common::Error SupernovaEngine::loadGameStrings() {
return Common::kReadingFailed;
}
-void SupernovaEngine::initData() {
- // Sound
- // Note:
- // - samples start with a header of 6 bytes: 01 SS SS 00 AD 00
- // where SS SS (LE uint16) is the size of the sound sample + 2
- // - samples end with a footer of 4 bytes: 00 00
- // Skip those in the buffer
- Common::File file;
-
- for (int i = 0; i < kAudioNumSamples; ++i) {
- if (!file.open(Common::String::format("msn_data.%03d", audioInfo[i]._filenumber))) {
- error("File %s could not be read!", file.getName());
- }
-
- if (audioInfo[i]._offsetEnd == -1) {
- file.seek(0, SEEK_END);
- _soundSamples[i]._length = file.pos() - audioInfo[i]._offsetStart - 10;
- } else {
- _soundSamples[i]._length = audioInfo[i]._offsetEnd - audioInfo[i]._offsetStart - 10;
- }
- _soundSamples[i]._buffer = new byte[_soundSamples[i]._length];
- file.seek(audioInfo[i]._offsetStart + 6);
- file.read(_soundSamples[i]._buffer, _soundSamples[i]._length);
- file.close();
- }
-
- _soundMusicIntro = convertToMod("msn_data.049");
- _soundMusicOutro = convertToMod("msn_data.052");
-
- // Cursor
- const uint16 *bufferNormal = reinterpret_cast<const uint16 *>(mouseNormal);
- const uint16 *bufferWait = reinterpret_cast<const uint16 *>(mouseWait);
- for (uint i = 0; i < sizeof(mouseNormal) / 4; ++i) {
- for (uint bit = 0; bit < 16; ++bit) {
- uint mask = 0x8000 >> bit;
- uint bitIndex = i * 16 + bit;
-
- _mouseNormal[bitIndex] = (READ_LE_UINT16(bufferNormal + i) & mask) ? kColorCursorTransparent : kColorBlack;
- if (READ_LE_UINT16(bufferNormal + i + 16) & mask)
- _mouseNormal[bitIndex] = kColorLightRed;
- _mouseWait[bitIndex] = (READ_LE_UINT16(bufferWait + i) & mask) ? kColorCursorTransparent : kColorBlack;
- if (READ_LE_UINT16(bufferWait + i + 16) & mask)
- _mouseWait[bitIndex] = kColorLightRed;
- }
- }
+const Common::String &SupernovaEngine::getGameString(int idx) const {
+ if (idx < 0 || idx >= (int)_gameStrings.size())
+ return _nullString;
+ return _gameStrings[idx];
}
-void SupernovaEngine::initPalette() {
- _system->getPaletteManager()->setPalette(initVGAPalette, 0, 256);
-}
-
-void SupernovaEngine::playSound(AudioIndex sample) {
- if (sample > kAudioNumSamples - 1)
+void SupernovaEngine::setGameString(int idx, const Common::String &string) {
+ if (idx < 0)
return;
-
- Audio::SeekableAudioStream *audioStream = Audio::makeRawStream(
- _soundSamples[sample]._buffer, _soundSamples[sample]._length,
- 11931, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN, DisposeAfterUse::NO);
- stopSound();
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, audioStream);
-}
-
-void SupernovaEngine::stopSound() {
- if (_mixer->isSoundHandleActive(_soundHandle))
- _mixer->stopHandle(_soundHandle);
+ while ((int)_gameStrings.size() <= idx)
+ _gameStrings.push_back(Common::String());
+ _gameStrings[idx] = string;
}
-void SupernovaEngine::playSoundMod(int filenumber)
-{
- Audio::AudioStream *audioStream;
- if (filenumber == 49)
- audioStream = Audio::makeProtrackerStream(_soundMusicIntro);
- else if (filenumber == 52)
- audioStream = Audio::makeProtrackerStream(_soundMusicOutro);
- else
- return;
-
- stopSound();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, audioStream,
- -1, Audio::Mixer::kMaxChannelVolume, 0);
+void SupernovaEngine::playSound(AudioId sample) {
+ _sound->play(sample);
}
-void SupernovaEngine::renderImageSection(int section) {
- // Note: inverting means we are removing the section. So we should get the rect for that
- // section but draw the background (section 0) instead.
- bool invert = false;
- if (section > 128) {
- section -= 128;
- invert = true;
- }
- if (!_currentImage || section > _currentImage->_numSections - 1)
- return;
-
- Common::Rect sectionRect(_currentImage->_section[section].x1,
- _currentImage->_section[section].y1,
- _currentImage->_section[section].x2 + 1,
- _currentImage->_section[section].y2 + 1) ;
- if (_currentImage->_filenumber == 1 || _currentImage->_filenumber == 2) {
- sectionRect.setWidth(640);
- sectionRect.setHeight(480);
- if (_screenWidth != 640) {
- _screenWidth = 640;
- _screenHeight = 480;
- initGraphics(_screenWidth, _screenHeight);
- }
- } else {
- if (_screenWidth != 320) {
- _screenWidth = 320;
- _screenHeight = 200;
- initGraphics(_screenWidth, _screenHeight);
- }
- }
-
- uint offset = 0;
- int pitch = sectionRect.width();
- if (invert) {
- pitch = _currentImage->_pitch;
- offset = _currentImage->_section[section].y1 * pitch + _currentImage->_section[section].x1;
- section = 0;
- }
-
- _system->copyRectToScreen(static_cast<const byte *>(_currentImage->_sectionSurfaces[section]->getPixels()) + offset,
- pitch,
- sectionRect.left, sectionRect.top,
- sectionRect.width(), sectionRect.height());
+void SupernovaEngine::playSound(MusicId index) {
+ _sound->play(index);
}
void SupernovaEngine::renderImage(int section) {
- if (!_currentImage)
- return;
-
- bool sectionVisible = true;
-
- if (section > 128) {
- sectionVisible = false;
- section -= 128;
- }
-
- _gm->_currentRoom->setSectionVisible(section, sectionVisible);
-
- do {
- if (sectionVisible)
- renderImageSection(section);
- else
- renderImageSection(section + 128);
- section = _currentImage->_section[section].next;
- } while (section != 0);
+ _screen->renderImage(section);
}
bool SupernovaEngine::setCurrentImage(int filenumber) {
- if (_currentImage && _currentImage->_filenumber == filenumber)
- return true;
-
- delete _currentImage;
- _currentImage = new MSNImageDecoder();
- if (!_currentImage->init(filenumber)) {
- delete _currentImage;
- _currentImage = NULL;
- return false;
- }
-
- _system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239);
- paletteBrightness();
- return true;
+ return _screen->setCurrentImage(filenumber);
}
void SupernovaEngine::saveScreen(int x, int y, int width, int height) {
- _screenBuffer.push(x, y, width, height);
+ _screen->saveScreen(x, y, width, height);
}
void SupernovaEngine::saveScreen(const GuiElement &guiElement) {
- saveScreen(guiElement.left, guiElement.top, guiElement.width(), guiElement.height());
+ _screen->saveScreen(guiElement);
}
void SupernovaEngine::restoreScreen() {
- _screenBuffer.restore();
+ _screen->restoreScreen();
}
void SupernovaEngine::renderRoom(Room &room) {
- if (room.getId() == INTRO)
- return;
-
- if (setCurrentImage(room.getFileNumber())) {
- for (int i = 0; i < _currentImage->_numSections; ++i) {
- int section = i;
- if (room.isSectionVisible(section)) {
- do {
- renderImageSection(section);
- section = _currentImage->_section[section].next;
- } while (section != 0);
- }
- }
- }
+ _screen->renderRoom(room);
}
-int SupernovaEngine::textWidth(const uint16 key) {
- char text[2];
- text[0] = key & 0xFF;
- text[1] = 0;
- return textWidth(text);
+void SupernovaEngine::renderMessage(const char *text, MessagePosition position) {
+ _screen->renderMessage(text, position);
}
-int SupernovaEngine::textWidth(const char *text) {
- int charWidth = 0;
- while (*text != '\0') {
- byte c = *text++;
- if (c < 32) {
- continue;
- } else if (c == 225) {
- c = 35;
- }
-
- for (uint i = 0; i < 5; ++i) {
- if (font[c - 32][i] == 0xff) {
- break;
- }
- ++charWidth;
- }
- ++charWidth;
- }
-
- return charWidth;
+void SupernovaEngine::renderMessage(const Common::String &text, MessagePosition position) {
+ _screen->renderMessage(text, position);
}
-void SupernovaEngine::renderMessage(const char *text, MessagePosition position) {
- Common::String t(text);
- char *row[20];
- Common::String::iterator p = t.begin();
- uint numRows = 0;
- int rowWidthMax = 0;
- int x = 0;
- int y = 0;
- byte textColor = 0;
-
- while (*p != '\0') {
- row[numRows] = p;
- ++numRows;
- while ((*p != '\0') && (*p != '|')) {
- ++p;
- }
- if (*p == '|') {
- *p = '\0';
- ++p;
- }
- }
- for (uint i = 0; i < numRows; ++i) {
- int rowWidth = textWidth(row[i]);
- if (rowWidth > rowWidthMax)
- rowWidthMax = rowWidth;
- }
-
- switch (position) {
- case kMessageNormal:
- x = 160 - rowWidthMax / 2;
- textColor = kColorWhite99;
- break;
- case kMessageTop:
- x = 160 - rowWidthMax / 2;
- textColor = kColorLightYellow;
- break;
- case kMessageCenter:
- x = 160 - rowWidthMax / 2;
- textColor = kColorLightRed;
- break;
- case kMessageLeft:
- x = 3;
- textColor = kColorLightYellow;
- break;
- case kMessageRight:
- x = 317 - rowWidthMax;
- textColor = kColorLightGreen;
- break;
- }
-
- if (position == kMessageNormal) {
- y = 70 - ((numRows * 9) / 2);
- } else if (position == kMessageTop) {
- y = 5;
- } else {
- y = 142;
- }
-
- int message_columns = x - 3;
- int message_rows = y - 3;
- int message_width = rowWidthMax + 6;
- int message_height = numRows * 9 + 5;
- saveScreen(message_columns, message_rows, message_width, message_height);
- renderBox(message_columns, message_rows, message_width, message_height, kColorWhite35);
- for (uint i = 0; i < numRows; ++i) {
- renderText(row[i], x, y, textColor);
- y += 9;
- }
-
- _messageDisplayed = true;
- _gm->_timer1 = (Common::strnlen(text, 512) + 20) * _textSpeed / 10;
+void SupernovaEngine::renderMessage(StringId stringId, MessagePosition position, Common::String var1, Common::String var2) {
+ _screen->renderMessage(stringId, position, var1, var2);
}
void SupernovaEngine::removeMessage() {
- if (_messageDisplayed) {
- restoreScreen();
- _messageDisplayed = false;
- }
+ _screen->removeMessage();
}
-void SupernovaEngine::renderText(const char *text, int x, int y, byte color) {
- Graphics::Surface *screen = _system->lockScreen();
- byte *cursor = static_cast<byte *>(screen->getBasePtr(x, y));
- const byte *basePtr = cursor;
-
- byte c;
- while ((c = *text++) != '\0') {
- if (c < 32) {
- continue;
- } else if (c == 225) {
- c = 128;
- }
+void SupernovaEngine::renderText(const uint16 character) {
+ _screen->renderText(character);
+}
- for (uint i = 0; i < 5; ++i) {
- if (font[c - 32][i] == 0xff) {
- break;
- }
+void SupernovaEngine::renderText(const char *text) {
+ _screen->renderText(text);
+}
- byte *ascentLine = cursor;
- for (byte j = font[c - 32][i]; j != 0; j >>= 1) {
- if (j & 1) {
- *cursor = color;
- }
- cursor += kScreenWidth;
- }
- cursor = ++ascentLine;
- }
- ++cursor;
- }
- _system->unlockScreen();
+void SupernovaEngine::renderText(const Common::String &text) {
+ _screen->renderText(text);
+}
- uint numChars = cursor - basePtr;
- uint absPosition = y * kScreenWidth + x + numChars;
- _textCursorX = absPosition % kScreenWidth;
- _textCursorY = absPosition / kScreenWidth;
- _textColor = color;
+void SupernovaEngine::renderText(StringId stringId) {
+ _screen->renderText(stringId);
+}
+
+void SupernovaEngine::renderText(const GuiElement &guiElement) {
+ _screen->renderText(guiElement);
}
void SupernovaEngine::renderText(const uint16 character, int x, int y, byte color) {
- char text[2];
- text[0] = character & 0xFF;
- text[1] = 0;
- renderText(text, x, y, color);
+ _screen->renderText(character, x, y, color);
}
-void SupernovaEngine::renderText(const char *text) {
- renderText(text, _textCursorX, _textCursorY, _textColor);
+void SupernovaEngine::renderText(const char *text, int x, int y, byte color) {
+ _screen->renderText(text, x, y, color);
}
-void SupernovaEngine::renderText(const uint16 character) {
- char text[2];
- text[0] = character & 0xFF;
- text[1] = 0;
- renderText(text, _textCursorX, _textCursorY, _textColor);
+void SupernovaEngine::renderText(const Common::String &text, int x, int y, byte color) {
+ _screen->renderText(text, x, y, color);
}
-void SupernovaEngine::renderText(const GuiElement &guiElement) {
- renderText(guiElement.getText(), guiElement.getTextPos().x,
- guiElement.getTextPos().y, guiElement.getTextColor());
+
+void SupernovaEngine::renderText(StringId stringId, int x, int y, byte color) {
+ _screen->renderText(stringId, x, y, color);
}
void SupernovaEngine::renderBox(int x, int y, int width, int height, byte color) {
- Graphics::Surface *screen = _system->lockScreen();
- screen->fillRect(Common::Rect(x, y, x + width, y + height), color);
- _system->unlockScreen();
+ _screen->renderBox(x, y, width, height, color);
}
void SupernovaEngine::renderBox(const GuiElement &guiElement) {
- renderBox(guiElement.left, guiElement.top, guiElement.width(),
- guiElement.height(), guiElement.getBackgroundColor());
+ _screen->renderBox(guiElement);
}
void SupernovaEngine::paletteBrightness() {
- byte palette[768];
-
- _system->getPaletteManager()->grabPalette(palette, 0, 255);
- for (uint i = 0; i < 48; ++i) {
- palette[i] = (initVGAPalette[i] * _menuBrightness) >> 8;
- }
- for (uint i = 0; i < 717; ++i) {
- const byte *imagePalette;
- if (_currentImage && _currentImage->getPalette()) {
- imagePalette = _currentImage->getPalette();
- } else {
- imagePalette = palette + 48;
- }
- palette[i + 48] = (imagePalette[i] * _brightness) >> 8;
- }
- _system->getPaletteManager()->setPalette(palette, 0, 255);
+ _screen->paletteBrightness();
}
void SupernovaEngine::paletteFadeOut() {
- while (_menuBrightness > 10) {
- _menuBrightness -= 10;
- if (_brightness > _menuBrightness)
- _brightness = _menuBrightness;
- paletteBrightness();
- _system->updateScreen();
- _system->delayMillis(_delay);
- }
- _menuBrightness = 0;
- _brightness = 0;
- paletteBrightness();
- _system->updateScreen();
+ _screen->paletteFadeOut();
}
void SupernovaEngine::paletteFadeIn() {
- while (_menuBrightness < 245) {
- if (_brightness < _gm->_roomBrightness)
- _brightness += 10;
- _menuBrightness += 10;
- paletteBrightness();
- _system->updateScreen();
- _system->delayMillis(_delay);
- }
- _menuBrightness = 255;
- _brightness = _gm->_roomBrightness;
- paletteBrightness();
- _system->updateScreen();
+ _screen->paletteFadeIn();
}
void SupernovaEngine::setColor63(byte value) {
- byte color[3] = {value, value, value};
- _system->getPaletteManager()->setPalette(color, 63, 1);
+ _screen->setColor63(value);
}
void SupernovaEngine::setTextSpeed() {
- const Common::String& textSpeedString = getGameString(kStringTextSpeed);
- int stringWidth = textWidth(textSpeedString);
- int textX = (320 - stringWidth) / 2;
+ const Common::String &textSpeedString = getGameString(kStringTextSpeed);
+ int stringWidth = Screen::textWidth(textSpeedString);
+ int textX = (kScreenWidth - stringWidth) / 2;
int textY = 100;
stringWidth += 4;
- int boxX = stringWidth > 110 ? (320 - stringWidth) / 2 : 105;
+ int boxX = stringWidth > 110 ? (kScreenWidth - stringWidth) / 2 : 105;
int boxY = 97;
int boxWidth = stringWidth > 110 ? stringWidth : 110;
int boxHeight = 27;
@@ -878,191 +456,6 @@ bool SupernovaEngine::quitGameDialog() {
return quit;
}
-Common::MemoryReadStream *SupernovaEngine::convertToMod(const char *filename, int version) {
- // MSN format
- struct {
- uint16 seg;
- uint16 start;
- uint16 end;
- uint16 loopStart;
- uint16 loopEnd;
- char volume;
- char dummy[5];
- } instr2[22];
- int nbInstr2; // 22 for version1, 15 for version 2
- int16 songLength;
- char arrangement[128];
- int16 patternNumber;
- int32 note2[28][64][4];
-
- nbInstr2 = ((version == 1) ? 22 : 15);
-
- Common::File msnFile;
- msnFile.open(filename);
- if (!msnFile.isOpen()) {
- warning("Data file '%s' not found", msnFile.getName());
- return NULL;
- }
-
- for (int i = 0 ; i < nbInstr2 ; ++i) {
- instr2[i].seg = msnFile.readUint16LE();
- instr2[i].start = msnFile.readUint16LE();
- instr2[i].end = msnFile.readUint16LE();
- instr2[i].loopStart = msnFile.readUint16LE();
- instr2[i].loopEnd = msnFile.readUint16LE();
- instr2[i].volume = msnFile.readByte();
- msnFile.read(instr2[i].dummy, 5);
- }
- songLength = msnFile.readSint16LE();
- msnFile.read(arrangement, 128);
- patternNumber = msnFile.readSint16LE();
- for (int p = 0 ; p < patternNumber ; ++p) {
- for (int n = 0 ; n < 64 ; ++n) {
- for (int k = 0 ; k < 4 ; ++k) {
- note2[p][n][k] = msnFile.readSint32LE();
- }
- }
- }
-
- /* MOD format */
- struct {
- char iname[22];
- uint16 length;
- char finetune;
- char volume;
- uint16 loopStart;
- uint16 loopLength;
- } instr[31];
- int32 note[28][64][4];
-
- // We can't recover some MOD effects since several of them are mapped to 0.
- // Assume the MSN effect of value 0 is Arpeggio (MOD effect of value 0).
- const char invConvEff[8] = {0, 1, 2, 3, 10, 12, 13 ,15};
-
- // Reminder from convertToMsn
- // 31 30 29 28 27 26 25 24 - 23 22 21 20 19 18 17 16 - 15 14 13 12 11 10 09 08 - 07 06 05 04 03 02 01 00
- // h h h h g g g g f f f f e e e e d d d d c c c c b b b b a a a a
- //
- // MSN:
- // hhhh (4 bits) Cleared to 0
- // dddd c (5 bits) Sample index | after mapping through convInstr
- // ccc (3 bits) Effect type | after mapping through convEff
- // bbbb aaaa (8 bits) Effect value | unmodified
- // gggg ffff eeee (12 bits) Sample period | unmodified
- //
- // MS2:
- // hhhh (4 bits) Cleared to 0
- // dddd (4 bits) Sample index | after mapping through convInstr
- // cccc (4 bits) Effect type | unmodified
- // bbbb aaaa (8 bits) Effect value | unmodified
- // gggg ffff eeee (12 bits) Sample period | transformed (0xE000 / p) - 256
- //
- // MOD:
- // hhhh dddd (8 bits) Sample index
- // cccc (4 bits) Effect type for this channel/division
- // bbbb aaaa (8 bits) Effect value
- // gggg ffff eeee (12 bits) Sample period
-
- // Can we recover the instruments mapping? I don't think so as part of the original instrument index is cleared.
- // And it doesn't really matter as long as we are consistent.
- // However we need to make sure 31 (or 15 in MS2) is mapped to 0 in MOD.
- // We just add 1 to all other values, and this means a 1 <-> 1 mapping for the instruments
- for (int p = 0; p < patternNumber; ++p) {
- for (int n = 0; n < 64; ++n) {
- for (int k = 0; k < 4; ++k) {
- int32* l = &(note[p][n][k]);
- *l = note2[p][n][k];
- int32 i = 0;
- if (nbInstr2 == 22) { // version 1
- i = ((*l & 0xF800) >> 11);
- int32 e = ((*l & 0x0700) >> 8);
- int32 e1 = invConvEff[e];
- *l &= 0x0FFF00FF;
- *l |= (e1 << 8);
- } else { // version 2
- int32 h = (*l >> 16);
- i = ((*l & 0xF000) >> 12);
- *l &= 0x00000FFF;
- if (h)
- h = 0xE000 / (h + 256);
- *l |= (h << 16);
- if (i == 15)
- i = 31;
- }
-
- // Add back index in note
- if (i != 31) {
- ++i;
- *l |= ((i & 0x0F) << 12);
- *l |= ((i & 0xF0) << 24);
- }
- }
- }
- }
-
- for (int i = 0; i < 31; ++i) {
- // iname is not stored in the mod file. Just set it to 'instrument#'
- // finetune is not stored either. Assume 0.
- memset(instr[i].iname, 0, 22);
- sprintf(instr[i].iname, "instrument%d", i+1);
- instr[i].length = 0;
- instr[i].finetune = 0;
- instr[i].volume = 0;
- instr[i].loopStart = 0;
- instr[i].loopLength = 0;
-
- if (i < nbInstr2) {
- instr[i].length = ((instr2[i].end - instr2[i].start) >> 1);
- instr[i].loopStart = ((instr2[i].loopStart - instr2[i].start) >> 1);
- instr[i].loopLength = (( instr2[i].loopEnd - instr2[i].loopStart) >> 1);
- instr[i].volume = instr2[i].volume;
- }
- }
-
- // The ciaaSpeed is kind of useless and not present in the MSN file.
- // Traditionally 0x78 in SoundTracker. Was used in NoiseTracker as a restart point.
- // ProTracker uses 0x7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses 0x7F like ProTracker.
- // You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types.
- char ciaaSpeed = 0x7F;
-
- // The mark cannot be recovered either. Since we have 4 channels and 31 instrument it can be either ID='M.K.' or ID='4CHN'.
- // Assume 'M.K.'
- const char mark[4] = { 'M', '.', 'K', '.' };
-
- Common::MemoryWriteStreamDynamic buffer(DisposeAfterUse::NO);
-
- buffer.write(msnFile.getName(), 19);
- buffer.writeByte(0);
-
- for (int i = 0 ; i < 31 ; ++i) {
- buffer.write(instr[i].iname, 22);
- buffer.writeUint16BE(instr[i].length);
- buffer.writeByte(instr[i].finetune);
- buffer.writeByte(instr[i].volume);
- buffer.writeUint16BE(instr[i].loopStart);
- buffer.writeUint16BE(instr[i].loopLength);
- }
- buffer.writeByte((char)songLength);
- buffer.writeByte(ciaaSpeed);
- buffer.write(arrangement, 128);
- buffer.write(mark, 4);
-
- for (int p = 0 ; p < patternNumber ; ++p) {
- for (int n = 0 ; n < 64 ; ++n) {
- for (int k = 0 ; k < 4 ; ++k) {
-// buffer.writeUint32BE(*((uint32*)(note[p][n]+k)));
- buffer.writeSint32BE(note[p][n][k]);
- }
- }
- }
-
- uint nb;
- char buf[4096];
- while ((nb = msnFile.read(buf, 4096)) > 0)
- buffer.write(buf, nb);
-
- return new Common::MemoryReadStream(buffer.getData(), buffer.size(), DisposeAfterUse::YES);
-}
bool SupernovaEngine::canLoadGameStateCurrently() {
return _allowLoadGame;
@@ -1117,10 +510,11 @@ bool SupernovaEngine::loadGame(int slot) {
_gm->deserialize(savefile, saveVersion);
if (saveVersion >= 5) {
- _menuBrightness = savefile->readByte();
- _brightness = savefile->readByte();
+ _screen->setGuiBrightness(savefile->readByte());
+ _screen->setViewportBrightness(savefile->readByte());
} else {
- _menuBrightness = _brightness = 255;
+ _screen->setGuiBrightness(255);
+ _screen->setViewportBrightness(255);
}
delete savefile;
@@ -1153,8 +547,8 @@ bool SupernovaEngine::saveGame(int slot, const Common::String &description) {
Graphics::saveThumbnail(*savefile);
_gm->serialize(savefile);
- savefile->writeByte(_menuBrightness);
- savefile->writeByte(_brightness);
+ savefile->writeByte(_screen->getGuiBrightness());
+ savefile->writeByte(_screen->getViewportBrightness());
savefile->finalize();
delete savefile;
@@ -1169,59 +563,5 @@ void SupernovaEngine::errorTempSave(bool saving) {
error("Unrecoverable error");
}
-ScreenBufferStack::ScreenBufferStack()
- : _last(_buffer) {
-}
-
-void ScreenBufferStack::push(int x, int y, int width, int height) {
- if (_last == ARRAYEND(_buffer))
- return;
-
- Graphics::Surface* screenSurface = g_system->lockScreen();
-
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (x + width > screenSurface->w)
- width = screenSurface->w - x;
-
- if (y < 0) {
- height += y;
- y = 0;
- }
- if (y + height > screenSurface->h)
- height = screenSurface->h - y;
-
- _last->_pixels = new byte[width * height];
- byte *pixels = _last->_pixels;
- const byte *screen = static_cast<const byte *>(screenSurface->getBasePtr(x, y));
- for (int i = 0; i < height; ++i) {
- Common::copy(screen, screen + width, pixels);
- screen += screenSurface->pitch;
- pixels += width;
- }
- g_system->unlockScreen();
-
- _last->_x = x;
- _last->_y = y;
- _last->_width = width;
- _last->_height = height;
-
- ++_last;
-}
-
-void ScreenBufferStack::restore() {
- if (_last == _buffer)
- return;
-
- --_last;
- g_system->lockScreen()->copyRectToSurface(
- _last->_pixels, _last->_width, _last->_x, _last->_y,
- _last->_width, _last->_height);
- g_system->unlockScreen();
-
- delete[] _last->_pixels;
-}
}
diff --git a/engines/supernova/supernova.h b/engines/supernova/supernova.h
index e01fb778a5..132e25deeb 100644
--- a/engines/supernova/supernova.h
+++ b/engines/supernova/supernova.h
@@ -23,9 +23,6 @@
#ifndef SUPERNOVA_SUPERNOVA_H
#define SUPERNOVA_SUPERNOVA_H
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "audio/decoders/raw.h"
#include "common/array.h"
#include "common/events.h"
#include "common/random.h"
@@ -38,6 +35,7 @@
#include "supernova/graphics.h"
#include "supernova/msn_def.h"
#include "supernova/rooms.h"
+#include "supernova/sound.h"
namespace Supernova {
@@ -48,96 +46,55 @@ namespace Supernova {
#define SUPERNOVA_DAT "supernova.dat"
#define SUPERNOVA_DAT_VERSION 1
-
-struct ScreenBuffer {
- ScreenBuffer()
- : _x(0)
- , _y(0)
- , _width(0)
- , _height(0)
- , _pixels(NULL)
- {}
-
- byte *_pixels;
- int _x;
- int _y;
- int _width;
- int _height;
-};
-class ScreenBufferStack {
-public:
- ScreenBufferStack();
-
- void push(int x, int y, int width, int height);
- void restore();
-
-private:
- ScreenBuffer _buffer[8];
- ScreenBuffer *_last;
-};
-
-struct SoundSample {
- SoundSample()
- : _buffer(NULL)
- , _length(0)
- {}
-
- ~SoundSample() {
- delete[] _buffer;
- }
-
- byte *_buffer;
- int _length;
-};
-
class GuiElement;
+class ResourceManager;
+class Sound;
+class console;
+class GameManager;
+class Screen;
+
class SupernovaEngine : public Engine {
public:
explicit SupernovaEngine(OSystem *syst);
~SupernovaEngine();
virtual Common::Error run();
+ virtual Common::Error loadGameState(int slot);
+ virtual bool canLoadGameStateCurrently();
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual bool canSaveGameStateCurrently();
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual void pauseEngineIntern(bool pause);
- Common::RandomSource _rnd;
GameManager *_gm;
Console *_console;
- Audio::SoundHandle _soundHandle;
- ScreenBufferStack _screenBuffer;
- byte _mouseNormal[256];
- byte _mouseWait[256];
- MSNImageDecoder *_currentImage;
- SoundSample _soundSamples[kAudioNumSamples];
- Common::MemoryReadStream *_soundMusicIntro;
- Common::MemoryReadStream *_soundMusicOutro;
- int _screenWidth;
- int _screenHeight;
+ Sound *_sound;
+ ResourceManager *_resMan;
+ Screen *_screen;
bool _allowLoadGame;
bool _allowSaveGame;
Common::StringArray _gameStrings;
Common::String _nullString;
- byte _menuBrightness;
- byte _brightness;
uint _delay;
- bool _messageDisplayed;
int _textSpeed;
- int _textCursorX;
- int _textCursorY;
- int _textColor;
- int textWidth(const char *text);
- int textWidth(const uint16 key);
Common::Error loadGameStrings();
- void initData();
- void initPalette();
+ void init();
+ bool loadGame(int slot);
+ bool saveGame(int slot, const Common::String &description);
+ bool quitGameDialog();
+ void errorTempSave(bool saving);
+ void setTextSpeed();
+ const Common::String &getGameString(int idx) const;
+ void setGameString(int idx, const Common::String &string);
+
+ // forwarding calls
+ void playSound(AudioId sample);
+ void playSound(MusicId index);
void paletteFadeIn();
void paletteFadeOut();
void paletteBrightness();
- void updateEvents();
- void playSound(AudioIndex sample);
- void playSoundMod(int filenumber);
- void stopSound();
- void renderImageSection(int section);
void renderImage(int section);
bool setCurrentImage(int filenumber);
void saveScreen(int x, int y, int width, int height);
@@ -145,77 +102,22 @@ public:
void restoreScreen();
void renderRoom(Room &room);
void renderMessage(const char *text, MessagePosition position = kMessageNormal);
+ void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal);
+ void renderMessage(StringId stringId, MessagePosition position = kMessageNormal,
+ Common::String var1 = "", Common::String var2 = "");
void removeMessage();
- void renderText(const char *text, int x, int y, byte color);
- void renderText(const uint16 character, int x, int y, byte color);
- void renderText(const char *text);
void renderText(const uint16 character);
+ void renderText(const char *text);
+ void renderText(const Common::String &text);
+ void renderText(StringId stringId);
+ void renderText(const uint16 character, int x, int y, byte color);
+ void renderText(const char *text, int x, int y, byte color);
+ void renderText(const Common::String &text, int x, int y, byte color);
+ void renderText(StringId stringId, int x, int y, byte color);
void renderText(const GuiElement &guiElement);
void renderBox(int x, int y, int width, int height, byte color);
void renderBox(const GuiElement &guiElement);
void setColor63(byte value);
- bool loadGame(int slot);
- bool saveGame(int slot, const Common::String &description);
- bool quitGameDialog();
- void errorTempSave(bool saving);
- void setTextSpeed();
-
- const Common::String &getGameString(int idx) const {
- if (idx < 0 || idx >= (int)_gameStrings.size())
- return _nullString;
- return _gameStrings[idx];
- }
-
- void setGameString(int idx, const Common::String &string) {
- if (idx < 0)
- return;
- while ((int)_gameStrings.size() <= idx)
- _gameStrings.push_back(Common::String());
- _gameStrings[idx] = string;
- }
-
- int textWidth(const Common::String &text) {
- if (text.empty())
- return 0;
- return textWidth(text.c_str());
- }
- void renderMessage(StringID stringId, MessagePosition position = kMessageNormal, Common::String var1 = "", Common::String var2 = "") {
- Common::String text = getGameString(stringId);
- if (!var1.empty()) {
- if (!var2.empty())
- text = Common::String::format(text.c_str(), var1.c_str(), var2.c_str());
- else
- text = Common::String::format(text.c_str(), var1.c_str());
- }
- renderMessage(text, position);
- }
- void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal) {
- if (!text.empty())
- renderMessage(text.c_str(), position);
- }
- void renderText(StringID stringId, int x, int y, byte color) {
- renderText(getGameString(stringId), x, y, color);
- }
- void renderText(const Common::String &text, int x, int y, byte color) {
- if (!text.empty())
- renderText(text.c_str(), x, y, color);
- }
- void renderText(StringID stringId) {
- renderText(getGameString(stringId));
- }
- void renderText(const Common::String &text) {
- if (!text.empty())
- renderText(text.c_str());
- }
-
- Common::MemoryReadStream *convertToMod(const char *filename, int version = 1);
-
- virtual Common::Error loadGameState(int slot);
- virtual bool canLoadGameStateCurrently();
- virtual Common::Error saveGameState(int slot, const Common::String &desc);
- virtual bool canSaveGameStateCurrently();
- virtual bool hasFeature(EngineFeature f) const;
- virtual void pauseEngineIntern(bool pause);
};
}
diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp
index d4343c8a9f..52394cec41 100644
--- a/engines/sword1/detection.cpp
+++ b/engines/sword1/detection.cpp
@@ -87,9 +87,9 @@ public:
}
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist) const;
+ PlainGameList getSupportedGames() const override;
+ PlainGameDescriptor findGame(const char *gameId) const override;
+ DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
@@ -116,31 +116,31 @@ bool Sword1::SwordEngine::hasFeature(EngineFeature f) const {
(f == kSupportsLoadingDuringRuntime);
}
-GameList SwordMetaEngine::getSupportedGames() const {
- GameList games;
- games.push_back(GameDescriptor(sword1FullSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1DemoSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1MacFullSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1MacDemoSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1PSXSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1PSXDemoSettings, GUIO_NOMIDI));
+PlainGameList SwordMetaEngine::getSupportedGames() const {
+ PlainGameList games;
+ games.push_back(sword1FullSettings);
+ games.push_back(sword1DemoSettings);
+ games.push_back(sword1MacFullSettings);
+ games.push_back(sword1MacDemoSettings);
+ games.push_back(sword1PSXSettings);
+ games.push_back(sword1PSXDemoSettings);
return games;
}
-GameDescriptor SwordMetaEngine::findGame(const char *gameid) const {
- if (0 == scumm_stricmp(gameid, sword1FullSettings.gameId))
+PlainGameDescriptor SwordMetaEngine::findGame(const char *gameId) const {
+ if (0 == scumm_stricmp(gameId, sword1FullSettings.gameId))
return sword1FullSettings;
- if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1DemoSettings.gameId))
return sword1DemoSettings;
- if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1MacFullSettings.gameId))
return sword1MacFullSettings;
- if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1MacDemoSettings.gameId))
return sword1MacDemoSettings;
- if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1PSXSettings.gameId))
return sword1PSXSettings;
- if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1PSXDemoSettings.gameId))
return sword1PSXDemoSettings;
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
void Sword1CheckDirectory(const Common::FSList &fslist, bool *filesFound, bool recursion = false) {
@@ -175,9 +175,9 @@ void Sword1CheckDirectory(const Common::FSList &fslist, bool *filesFound, bool r
}
}
-GameList SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
+DetectedGames SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
int i, j;
- GameList detectedGames;
+ DetectedGames detectedGames;
bool filesFound[NUM_FILES_TO_CHECK];
for (i = 0; i < NUM_FILES_TO_CHECK; i++)
filesFound[i] = false;
@@ -212,31 +212,33 @@ GameList SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
if (!filesFound[i] || psxFilesFound)
psxDemoFilesFound = false;
- GameDescriptor gd;
+ DetectedGame game;
if (mainFilesFound && pcFilesFound && demoFilesFound)
- gd = GameDescriptor(sword1DemoSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1DemoSettings);
else if (mainFilesFound && pcFilesFound && psxFilesFound)
- gd = GameDescriptor(sword1PSXSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1PSXSettings);
else if (mainFilesFound && pcFilesFound && psxDemoFilesFound)
- gd = GameDescriptor(sword1PSXDemoSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1PSXDemoSettings);
else if (mainFilesFound && pcFilesFound && !psxFilesFound)
- gd = GameDescriptor(sword1FullSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1FullSettings);
else if (mainFilesFound && macFilesFound)
- gd = GameDescriptor(sword1MacFullSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1MacFullSettings);
else if (mainFilesFound && macDemoFilesFound)
- gd = GameDescriptor(sword1MacDemoSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1MacDemoSettings);
else
return detectedGames;
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::DE_DEU));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::FR_FRA));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::IT_ITA));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::ES_ESP));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::PT_BRA));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::CZ_CZE));
+ game.setGUIOptions(GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
- detectedGames.push_back(gd);
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::DE_DEU));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::FR_FRA));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::IT_ITA));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::ES_ESP));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::PT_BRA));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::CZ_CZE));
+
+ detectedGames.push_back(game);
return detectedGames;
}
@@ -300,7 +302,11 @@ SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int
in->skip(1);
if (Graphics::checkThumbnailHeader(*in)) {
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ delete in;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
}
diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp
index a2761eb5ce..4d8399e630 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -92,10 +92,10 @@ public:
}
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
+ PlainGameList getSupportedGames() const override;
virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist) const;
+ PlainGameDescriptor findGame(const char *gameid) const override;
+ virtual DetectedGames detectGames(const Common::FSList &fslist) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
@@ -119,11 +119,11 @@ bool Sword2::Sword2Engine::hasFeature(EngineFeature f) const {
(f == kSupportsLoadingDuringRuntime);
}
-GameList Sword2MetaEngine::getSupportedGames() const {
+PlainGameList Sword2MetaEngine::getSupportedGames() const {
const Sword2::GameSettings *g = Sword2::sword2_settings;
- GameList games;
+ PlainGameList games;
while (g->gameid) {
- games.push_back(GameDescriptor(g->gameid, g->description));
+ games.push_back(PlainGameDescriptor::of(g->gameid, g->description));
g++;
}
return games;
@@ -135,20 +135,20 @@ const ExtraGuiOptions Sword2MetaEngine::getExtraGuiOptions(const Common::String
return options;
}
-GameDescriptor Sword2MetaEngine::findGame(const char *gameid) const {
+PlainGameDescriptor Sword2MetaEngine::findGame(const char *gameid) const {
const Sword2::GameSettings *g = Sword2::sword2_settings;
while (g->gameid) {
if (0 == scumm_stricmp(gameid, g->gameid))
break;
g++;
}
- return GameDescriptor(g->gameid, g->description);
+ return PlainGameDescriptor::of(g->gameid, g->description);
}
bool isFullGame(const Common::FSList &fslist) {
Common::FSList::const_iterator file;
- // We distinguish between the two versions by the presense of paris.clu
+ // We distinguish between the two versions by the presence of paris.clu
for (file = fslist.begin(); file != fslist.end(); ++file) {
if (!file->isDirectory()) {
if (file->getName().equalsIgnoreCase("paris.clu"))
@@ -159,8 +159,8 @@ bool isFullGame(const Common::FSList &fslist) {
return false;
}
-GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
- GameList detectedGames;
+DetectedGames detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
+ DetectedGames detectedGames;
const Sword2::GameSettings *g;
Common::FSList::const_iterator file;
bool isFullVersion = isFullGame(fslist);
@@ -192,7 +192,10 @@ GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
continue;
// Match found, add to list of candidates, then abort inner loop.
- detectedGames.push_back(GameDescriptor(g->gameid, g->description, Common::UNK_LANG, Common::kPlatformUnknown, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)));
+ DetectedGame game = DetectedGame(g->gameid, g->description);
+ game.setGUIOptions(GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+
+ detectedGames.push_back(game);
break;
}
}
@@ -208,7 +211,7 @@ GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
if (file->getName().equalsIgnoreCase("clusters")) {
Common::FSList recList;
if (file->getChildren(recList, Common::FSNode::kListAll)) {
- GameList recGames(detectGamesImpl(recList, true));
+ DetectedGames recGames = detectGamesImpl(recList, true);
if (!recGames.empty()) {
detectedGames.push_back(recGames);
break;
@@ -223,7 +226,7 @@ GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
return detectedGames;
}
-GameList Sword2MetaEngine::detectGames(const Common::FSList &fslist) const {
+DetectedGames Sword2MetaEngine::detectGames(const Common::FSList &fslist) const {
return detectGamesImpl(fslist);
}
@@ -278,10 +281,10 @@ Common::Error Sword2MetaEngine::createInstance(OSystem *syst, Engine **engine) c
// Invoke the detector
Common::String gameid = ConfMan.get("gameid");
- GameList detectedGames = detectGames(fslist);
+ DetectedGames detectedGames = detectGames(fslist);
for (uint i = 0; i < detectedGames.size(); i++) {
- if (detectedGames[i].gameid() == gameid) {
+ if (detectedGames[i].gameId == gameid) {
*engine = new Sword2::Sword2Engine(syst);
return Common::kNoError;
}
diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
index fd3b63aeee..ca1f37c9d3 100644
--- a/engines/sword25/gfx/graphicengine.cpp
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -362,7 +362,7 @@ void GraphicEngine::updateLastFrameDuration() {
}
bool GraphicEngine::saveThumbnailScreenshot(const Common::String &filename) {
- // Note: In ScumMVM, rather than saivng the thumbnail to a file, we store it in memory
+ // Note: In ScummVM, rather than saving the thumbnail to a file, we store it in memory
// until needed when creating savegame files
delete _thumbnail;
@@ -373,10 +373,10 @@ bool GraphicEngine::saveThumbnailScreenshot(const Common::String &filename) {
void GraphicEngine::ARGBColorToLuaColor(lua_State *L, uint color) {
lua_Number components[4] = {
- (lua_Number)((color >> 16) & 0xff), // Red
- (lua_Number)((color >> 8) & 0xff), // Green
- (lua_Number)(color & 0xff), // Blue
- (lua_Number)(color >> 24), // Alpha
+ (lua_Number)((color >> 16) & 0xff), // Red
+ (lua_Number)((color >> 8) & 0xff), // Green
+ (lua_Number)( color & 0xff), // Blue
+ (lua_Number)( color >> 24), // Alpha
};
lua_newtable(L);
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
index 8bc20180af..2e7b41c431 100644
--- a/engines/sword25/sfx/soundengine.cpp
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -203,8 +203,8 @@ bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, fl
}
uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer, uint handleId) {
- Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
#ifdef USE_VORBIS
+ Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
#endif
uint id = handleId;
diff --git a/engines/sword25/util/lua/llex.cpp b/engines/sword25/util/lua/llex.cpp
index 423f0285ca..ebda9ffbdf 100644
--- a/engines/sword25/util/lua/llex.cpp
+++ b/engines/sword25/util/lua/llex.cpp
@@ -377,8 +377,10 @@ static int llex (LexState *ls, SemInfo *seminfo) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
- else if (sep == -1) return '[';
- else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
+ else if (sep == -1)
+ return '[';
+ luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
+ break;
}
case '=': {
next(ls);
diff --git a/engines/sword25/util/lua/lstrlib.cpp b/engines/sword25/util/lua/lstrlib.cpp
index 5da45e1fea..78122030f9 100644
--- a/engines/sword25/util/lua/lstrlib.cpp
+++ b/engines/sword25/util/lua/lstrlib.cpp
@@ -799,10 +799,8 @@ static int str_format (lua_State *L) {
luaL_addvalue(&b);
continue; /* skip the `addsize' at the end */
}
- else {
- sprintf(buff, form, s);
- break;
- }
+ sprintf(buff, form, s);
+ break;
}
default: { /* also treat cases `pnLlh' */
return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index caa7bdbec9..e35e7033d5 100644
--- a/engines/teenagent/detection.cpp
+++ b/engines/teenagent/detection.cpp
@@ -178,8 +178,11 @@ public:
SaveStateDescriptor ssd(slot, desc);
//checking for the thumbnail
- if (Graphics::Surface *const thumb = Graphics::loadThumbnail(*in))
- ssd.setThumbnail(thumb);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*in, thumbnail)) {
+ return SaveStateDescriptor();
+ }
+ ssd.setThumbnail(thumbnail);
return ssd;
}
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index 1b5af76ee7..65833d1de8 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -464,7 +464,7 @@ TestExitStatus GFXtests::fullScreenMode() {
}
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !isFeatureEnabled);
g_system->endGFXTransaction();
// Current state should be now !isFeatureEnabled
@@ -482,7 +482,7 @@ TestExitStatus GFXtests::fullScreenMode() {
}
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !isFeatureEnabled);
g_system->endGFXTransaction();
g_system->delayMillis(1000);
@@ -536,7 +536,7 @@ TestExitStatus GFXtests::filteringMode() {
if (g_system->hasFeature(OSystem::kFeatureFullscreenMode) && !g_system->getFeatureState(OSystem::kFeatureFullscreenMode)) {
fullScreenToggled = true;
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureFullscreenMode, true);
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, true);
g_system->endGFXTransaction();
}
@@ -557,7 +557,7 @@ TestExitStatus GFXtests::filteringMode() {
}
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureFilteringMode, !isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureFilteringMode, !isFeatureEnabled);
g_system->endGFXTransaction();
// Current state should be now !isFeatureEnabled
@@ -575,7 +575,7 @@ TestExitStatus GFXtests::filteringMode() {
}
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureFilteringMode, !isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureFilteringMode, !isFeatureEnabled);
g_system->endGFXTransaction();
g_system->delayMillis(1000);
@@ -591,7 +591,7 @@ TestExitStatus GFXtests::filteringMode() {
// Restore fullscreen state
if (fullScreenToggled) {
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureFullscreenMode, false);
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, false);
g_system->endGFXTransaction();
}
@@ -601,7 +601,7 @@ TestExitStatus GFXtests::filteringMode() {
return passed;
}
-
+
/**
* Tests the aspect ratio correction by: drawing an ellipse, when corrected the ellipse should render to a circle
*/
@@ -639,7 +639,7 @@ TestExitStatus GFXtests::aspectRatio() {
}
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, !isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, !isFeatureEnabled);
g_system->endGFXTransaction();
g_system->delayMillis(1000);
@@ -653,7 +653,7 @@ TestExitStatus GFXtests::aspectRatio() {
}
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, isFeatureEnabled);
g_system->endGFXTransaction();
} else {
Testsuite::displayMessage("feature not supported");
@@ -835,13 +835,13 @@ TestExitStatus GFXtests::iconifyWindow() {
// Toggle
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureIconifyWindow, !isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureIconifyWindow, !isFeatureEnabled);
g_system->endGFXTransaction();
g_system->delayMillis(1000);
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureIconifyWindow, isFeatureEnabled);
+ g_system->setFeatureState(OSystem::kFeatureIconifyWindow, isFeatureEnabled);
g_system->endGFXTransaction();
} else {
Testsuite::displayMessage("feature not supported");
@@ -884,7 +884,7 @@ TestExitStatus GFXtests::scaledCursors() {
if (isAspectRatioCorrected) {
g_system->beginGFXTransaction();
- g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, false);
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, false);
g_system->endGFXTransaction();
}
@@ -911,8 +911,8 @@ TestExitStatus GFXtests::scaledCursors() {
g_system->beginGFXTransaction();
- bool isGFXModeSet = g_system->setGraphicsMode(gfxMode->id);
- g_system->initSize(320, 200);
+ bool isGFXModeSet = g_system->setGraphicsMode(gfxMode->id);
+ g_system->initSize(320, 200);
OSystem::TransactionError gfxError = g_system->endGFXTransaction();
@@ -947,12 +947,13 @@ TestExitStatus GFXtests::scaledCursors() {
// Restore Original State
g_system->beginGFXTransaction();
- bool isGFXModeSet = g_system->setGraphicsMode(currGFXMode);
- g_system->initSize(320, 200);
- if (isAspectRatioCorrected) {
- g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, true);
- }
+ bool isGFXModeSet = g_system->setGraphicsMode(currGFXMode);
+ g_system->initSize(320, 200);
+
+ if (isAspectRatioCorrected) {
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, true);
+ }
OSystem::TransactionError gfxError = g_system->endGFXTransaction();
@@ -1226,7 +1227,7 @@ TestExitStatus GFXtests::pixelFormats() {
// Switch to that pixel Format
g_system->beginGFXTransaction();
- g_system->initSize(320, 200, &(*iter));
+ g_system->initSize(320, 200, &(*iter));
g_system->endGFXTransaction();
Testsuite::clearScreen(true);
@@ -1272,7 +1273,7 @@ TestExitStatus GFXtests::pixelFormats() {
// Revert back to 8bpp
g_system->beginGFXTransaction();
- g_system->initSize(320, 200);
+ g_system->initSize(320, 200);
g_system->endGFXTransaction();
GFXTestSuite::setCustomColor(255, 0, 0);
initMousePalette();
diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp
index e69031d572..c23e4f2845 100644
--- a/engines/tinsel/cursor.cpp
+++ b/engines/tinsel/cursor.cpp
@@ -375,6 +375,10 @@ void SetAuxCursor(SCNHANDLE hFilm) {
DelAuxCursor(); // Get rid of previous
+ // WORKAROUND: There's no palette when loading a DW1 savegame with a held item, so exit if so
+ if (!BgPal())
+ return;
+
GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear
pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index d6bcfe5ea0..1c60c5eb8a 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -97,7 +97,7 @@ public:
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const;
@@ -185,7 +185,7 @@ typedef Common::Array<const ADGameDescription *> ADGameDescList;
* Fallback detection scans the list of Discworld 2 targets to see if it can detect an installation
* where the files haven't been renamed (i.e. don't have the '1' just before the extension)
*/
-const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
+ADDetectedGame TinselMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
Common::String extra;
FileMap allFiles;
SizeMD5Map filesSizeMD5;
@@ -194,7 +194,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
const Tinsel::TinselGameDescription *g;
if (fslist.empty())
- return NULL;
+ return ADDetectedGame();
// TODO: The following code is essentially a slightly modified copy of the
// complete code of function detectGame() in engines/advancedDetector.cpp.
@@ -262,7 +262,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
}
}
- ADGameDescList matched;
+ ADDetectedGame matched;
int maxFilesMatched = 0;
// MD5 based matching
@@ -310,22 +310,15 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++)
curFilesMatched++;
- if (curFilesMatched > maxFilesMatched) {
+ if (curFilesMatched >= maxFilesMatched) {
maxFilesMatched = curFilesMatched;
- matched.clear(); // Remove any prior, lower ranked matches.
- matched.push_back((const ADGameDescription *)g);
- } else if (curFilesMatched == maxFilesMatched) {
- matched.push_back((const ADGameDescription *)g);
+ matched = ADDetectedGame(&g->desc);
}
}
}
- // We didn't find a match
- if (matched.empty())
- return NULL;
-
- return *matched.begin();
+ return matched;
}
int TinselMetaEngine::getMaximumSaveSlot() const { return 99; }
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index b5d090ec15..755b9275c6 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -1907,6 +1907,11 @@ extern void HoldItem(int item, bool bKeepFilm) {
invObj = GetInvObject(item);
SetAuxCursor(invObj->hIconFilm); // and is aux. cursor
}
+
+ // WORKAROUND: If a held item is being removed that's not in either inventory (i.e. it was picked up
+ // but never put in them), then when removing it from being held, drop it in the luggage
+ if (g_heldItem != INV_NOICON && InventoryPos(g_heldItem) == INV_HELDNOTIN)
+ AddToInventory(INV_1, g_heldItem);
}
g_heldItem = item; // Item held
diff --git a/engines/tinsel/multiobj.cpp b/engines/tinsel/multiobj.cpp
index 75894aea89..2cd46ae90b 100644
--- a/engines/tinsel/multiobj.cpp
+++ b/engines/tinsel/multiobj.cpp
@@ -122,8 +122,7 @@ void MultiDeleteObject(OBJECT **pObjList, OBJECT *pMultiObj) {
// next obj in list
pMultiObj = pMultiObj->pSlave;
- }
- while (pMultiObj != NULL);
+ } while (pMultiObj != NULL);
}
/**
@@ -180,8 +179,7 @@ void MultiVerticalFlip(OBJECT *pFlipObj) {
// next obj in list
pFlipObj = pFlipObj->pSlave;
- }
- while (pFlipObj != NULL);
+ } while (pFlipObj != NULL);
}
/**
@@ -351,8 +349,7 @@ void MultiSetZPosition(OBJECT *pMultiObj, int newZ) {
// next obj in list
pMultiObj = pMultiObj->pSlave;
- }
- while (pMultiObj != NULL);
+ } while (pMultiObj != NULL);
}
/**
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index dc19f39405..8899eea65b 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -156,6 +156,7 @@ static const byte fragment14[] = {OP_LIBCALL | OPSIZE8, 58,
OP_IMM, FRAGMENT_DWORD((42 << 23)), OP_ONE, OP_ZERO, OP_LIBCALL | OPSIZE8, 44,
OP_LIBCALL | OPSIZE8, 97, OP_JUMP | OPSIZE16, FRAGMENT_WORD(2220)
};
+static const byte fragment15[] = { OP_JMPFALSE | OPSIZE16, FRAGMENT_WORD(154) };
#undef FRAGMENT_WORD
@@ -226,6 +227,9 @@ const WorkaroundEntry workaroundList[] = {
// quitting the game when no user input happens for a while
{TINSEL_V1, true, true, Common::kPlatformPSX, 0, 2186, sizeof(fragment14), fragment14},
+ // DW1-GRA: Fixes hang in Temple, when trying to use items on the big hammer
+ {TINSEL_V1, false, false, Common::kPlatformUnknown, 276915849, 0x98, sizeof(fragment15), fragment15},
+
{TINSEL_V0, false, false, Common::kPlatformUnknown, 0, 0, 0, NULL}
};
diff --git a/engines/titanic/continue_save_dialog.cpp b/engines/titanic/continue_save_dialog.cpp
index 6de267e9fe..0aee87328b 100644
--- a/engines/titanic/continue_save_dialog.cpp
+++ b/engines/titanic/continue_save_dialog.cpp
@@ -185,7 +185,7 @@ void CContinueSaveDialog::mouseMove(const Point &mousePos) {
void CContinueSaveDialog::leftButtonDown(const Point &mousePos) {
Rect eye1(188, 190, 192, 195), eye2(209, 192, 213, 197);
- if (g_vm->_events->isSpecialPressed(MK_SHIFT) &&
+ if (g_vm->_events->isSpecialPressed(MK_SHIFT) &&
(eye1.contains(mousePos) || eye2.contains(mousePos))) {
// Show the Easter Egg "Evil Twin"
_evilTwinShown = true;
diff --git a/engines/titanic/core/game_object.cpp b/engines/titanic/core/game_object.cpp
index af34526329..d75bca0a7e 100644
--- a/engines/titanic/core/game_object.cpp
+++ b/engines/titanic/core/game_object.cpp
@@ -697,6 +697,7 @@ void CGameObject::playClip(uint startFrame, uint endFrame) {
CRoomItem *room = gameManager->getRoom();
gameManager->playClip(clip, room, room);
+ delete clip;
}
void CGameObject::playRandomClip(const char *const *names, uint flags) {
diff --git a/engines/titanic/core/list.h b/engines/titanic/core/list.h
index 09068fb06a..6da3a9224a 100644
--- a/engines/titanic/core/list.h
+++ b/engines/titanic/core/list.h
@@ -106,7 +106,7 @@ public:
for (uint idx = 0; idx < count; ++idx) {
// Validate the class start header
- if (!file->IsClassStart())
+ if (!file->isClassStart())
error("Unexpected class end");
// Get item's class name and use it to instantiate an item
@@ -120,7 +120,7 @@ public:
Common::List<T *>::push_back(newItem);
// Validate the class end footer
- if (file->IsClassStart())
+ if (file->isClassStart())
error("Unexpected class start");
}
}
diff --git a/engines/titanic/core/project_item.cpp b/engines/titanic/core/project_item.cpp
index b2bd5cd92b..99eec803ac 100644
--- a/engines/titanic/core/project_item.cpp
+++ b/engines/titanic/core/project_item.cpp
@@ -190,16 +190,12 @@ void CProjectItem::loadGame(int slotId) {
// Load the savegame header in
TitanicSavegameHeader header;
readSavegameHeader(&file, header);
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
g_vm->_events->setTotalPlayTicks(header._totalFrames);
// Load the contents in
CProjectItem *newProject = loadData(&file);
- file.IsClassStart();
+ file.isClassStart();
getGameManager()->load(&file);
file.close();
@@ -254,7 +250,7 @@ void CProjectItem::clear() {
}
CProjectItem *CProjectItem::loadData(SimpleFile *file) {
- if (!file->IsClassStart())
+ if (!file->isClassStart())
return nullptr;
CProjectItem *root = nullptr;
@@ -295,8 +291,8 @@ CProjectItem *CProjectItem::loadData(SimpleFile *file) {
item->load(file);
}
- file->IsClassStart();
- } while (file->IsClassStart());
+ file->isClassStart();
+ } while (file->isClassStart());
return root;
}
@@ -488,13 +484,9 @@ SaveStateList CProjectItem::getSavegameList(const Common::String &target) {
if (in) {
SimpleFile f;
f.open(in);
- if (!readSavegameHeader(&f, header))
- continue;
-
- saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+ if (readSavegameHeader(&f, header))
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
- header._thumbnail->free();
- delete header._thumbnail;
delete in;
}
}
@@ -503,7 +495,7 @@ SaveStateList CProjectItem::getSavegameList(const Common::String &target) {
return saveList;
}
-bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header) {
+WARN_UNUSED_RESULT bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
header._thumbnail = nullptr;
header._totalFrames = 0;
@@ -526,8 +518,7 @@ bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &h
while ((ch = (char)file->readByte()) != '\0') header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*file);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*file, header._thumbnail, skipThumbnail))
return false;
// Read in save date/time
diff --git a/engines/titanic/core/project_item.h b/engines/titanic/core/project_item.h
index c9fd6f97cb..1c5923fd0e 100644
--- a/engines/titanic/core/project_item.h
+++ b/engines/titanic/core/project_item.h
@@ -155,7 +155,7 @@ public:
/**
* Read in the header information for a savegame
*/
- static bool readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header, bool skipThumbnail = true);
public:
CLASSDEF;
CProjectItem();
diff --git a/engines/titanic/debugger.cpp b/engines/titanic/debugger.cpp
index 7438a0053b..01948dd4d3 100644
--- a/engines/titanic/debugger.cpp
+++ b/engines/titanic/debugger.cpp
@@ -357,7 +357,7 @@ bool Debugger::cmdFrame(int argc, const char **argv) {
if (argc == 3) {
CGameObject *obj = dynamic_cast<CGameObject *>(
g_vm->_window->_project->findByName(argv[1]));
-
+
if (obj) {
obj->loadFrame(strToInt(argv[2]));
return false;
diff --git a/engines/titanic/detection.cpp b/engines/titanic/detection.cpp
index b33ac51bed..c98fbbdade 100644
--- a/engines/titanic/detection.cpp
+++ b/engines/titanic/detection.cpp
@@ -128,11 +128,6 @@ SaveStateList TitanicMetaEngine::listSaves(const char *target) const {
if (Titanic::CProjectItem::readSavegameHeader(&cf, header))
saveList.push_back(SaveStateDescriptor(slot, header._saveName));
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
cf.close();
}
}
@@ -161,7 +156,10 @@ SaveStateDescriptor TitanicMetaEngine::querySaveMetaInfos(const char *target, in
file.open(f);
Titanic::TitanicSavegameHeader header;
- Titanic::CProjectItem::readSavegameHeader(&file, header);
+ if (!Titanic::CProjectItem::readSavegameHeader(&file, header, false)) {
+ file.close();
+ return SaveStateDescriptor();
+ }
file.close();
diff --git a/engines/titanic/game/bomb.cpp b/engines/titanic/game/bomb.cpp
index d9eb737c34..40651c0a88 100644
--- a/engines/titanic/game/bomb.cpp
+++ b/engines/titanic/game/bomb.cpp
@@ -374,7 +374,7 @@ bool CBomb::TimerMsg(CTimerMsg *msg) {
addTimer(0, 100, 0);
return true;
}
-
+
if (msg->_actionVal == 0) {
addTimer(1, 1000, 0);
} else {
@@ -459,7 +459,7 @@ bool CBomb::TimerMsg(CTimerMsg *msg) {
--_countdown;
addTimer(0, 1000, 0);
}
-
+
return true;
}
diff --git a/engines/titanic/game/chicken_dispensor.cpp b/engines/titanic/game/chicken_dispensor.cpp
index 8d16289647..ced0c78ef1 100644
--- a/engines/titanic/game/chicken_dispensor.cpp
+++ b/engines/titanic/game/chicken_dispensor.cpp
@@ -106,7 +106,7 @@ bool CChickenDispensor::StatusChangeMsg(CStatusChangeMsg *msg) {
bool CChickenDispensor::MovieEndMsg(CMovieEndMsg *msg) {
int movieFrame = msg->_endFrame;
-
+
if (movieFrame == 16) {
// Dispensed a chicken
_cursorId = CURSOR_HAND;
diff --git a/engines/titanic/npcs/deskbot.cpp b/engines/titanic/npcs/deskbot.cpp
index ee639c908f..c23fefce91 100644
--- a/engines/titanic/npcs/deskbot.cpp
+++ b/engines/titanic/npcs/deskbot.cpp
@@ -301,7 +301,7 @@ bool CDeskbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
CTurnOff turnOff;
CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
-
+
if (g_language == Common::DE_DEU) {
switch (msg->_dialogueId) {
case 41701:
diff --git a/engines/titanic/pet_control/pet_load_save.cpp b/engines/titanic/pet_control/pet_load_save.cpp
index d918478fb1..72770b9eb2 100644
--- a/engines/titanic/pet_control/pet_load_save.cpp
+++ b/engines/titanic/pet_control/pet_load_save.cpp
@@ -135,11 +135,6 @@ void CPetLoadSave::resetSlots() {
_slotNames[idx].setText(header._saveName);
}
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
file.close();
}
}
diff --git a/engines/titanic/sound/music_room_handler.cpp b/engines/titanic/sound/music_room_handler.cpp
index 2265e46bb2..364023ea3a 100644
--- a/engines/titanic/sound/music_room_handler.cpp
+++ b/engines/titanic/sound/music_room_handler.cpp
@@ -230,7 +230,7 @@ void CMusicRoomHandler::updateAudio() {
}
}
}
-
+
_audioBuffer->push(audioData, size);
delete[] audioData;
}
diff --git a/engines/titanic/sound/music_room_instrument.cpp b/engines/titanic/sound/music_room_instrument.cpp
index 882325c08a..99ead2f8eb 100644
--- a/engines/titanic/sound/music_room_instrument.cpp
+++ b/engines/titanic/sound/music_room_instrument.cpp
@@ -77,7 +77,7 @@ CMusicRoomInstrument::CMusicRoomInstrument(CProjectItem *project, CSoundManager
_gameObjects[0] = static_cast<CGameObject *>(_project->findByName("Tubular Bells"));
_insStartTime = 0.4;
break;
-
+
case MV_SNAKE:
_gameObjects[0] = static_cast<CGameObject *>(_project->findByName("Snake_Hammer"));
_gameObjects[1] = static_cast<CGameObject *>(_project->findByName("Snake_Glass"));
diff --git a/engines/titanic/sound/music_song.cpp b/engines/titanic/sound/music_song.cpp
index ea5f29a536..1645004c0a 100644
--- a/engines/titanic/sound/music_song.cpp
+++ b/engines/titanic/sound/music_song.cpp
@@ -127,7 +127,7 @@ bool CSongParser::parse(CValuePair &r) {
} else if (_currentChar == '^') {
if (_flag)
break;
-
+
_flag = true;
r._data = 0x7FFFFFFF;
r._length = _field10;
@@ -176,7 +176,7 @@ bool CSongParser::parse(CValuePair &r) {
FETCH_CHAR;
}
}
-
+
if (!_flag)
return false;
diff --git a/engines/titanic/star_control/base_stars.cpp b/engines/titanic/star_control/base_stars.cpp
index 0fcf8a964f..00206b1a9d 100644
--- a/engines/titanic/star_control/base_stars.cpp
+++ b/engines/titanic/star_control/base_stars.cpp
@@ -462,7 +462,7 @@ void CBaseStars::draw4(CSurfaceArea *surfaceArea, CStarCamera *camera, CStarClos
+ vector._z * pose._row3._z + pose._vector._z;
if (tempZ <= minVal)
continue;
-
+
tempY = vector._x * pose._row1._y + vector._y * pose._row2._y + vector._z * pose._row3._y + pose._vector._y;
tempX = vector._x * pose._row1._x + vector._y * pose._row2._x + vector._z * pose._row3._x + pose._vector._x;
total2 = tempY * tempY + tempX * tempX + tempZ * tempZ;
diff --git a/engines/titanic/star_control/camera_auto_mover.cpp b/engines/titanic/star_control/camera_auto_mover.cpp
index 71f7de85b2..d8808653eb 100644
--- a/engines/titanic/star_control/camera_auto_mover.cpp
+++ b/engines/titanic/star_control/camera_auto_mover.cpp
@@ -78,7 +78,7 @@ void CCameraAutoMover::calcSpeeds(int val1, int val2, float distance) {
_field40 = nMoverTransitions-1;
_field48 = nMoverTransitions-1;
_field3C = (double)val2 * _field38;
-
+
// Calculate the speeds for a graduated movement between stars
double base = 0.0, total = 0.0, power = 4.0, baseInc = 0.03125;
for (int idx = nMoverTransitions - 1; idx >= 0; --idx) {
@@ -86,7 +86,7 @@ void CCameraAutoMover::calcSpeeds(int val1, int val2, float distance) {
total += _speeds[idx];
base += baseInc;
}
-
+
for (int idx = 0; idx < nMoverTransitions; ++idx) {
_speeds[idx] = _speeds[idx] * _field3C / total;
}
diff --git a/engines/titanic/star_control/camera_auto_mover.h b/engines/titanic/star_control/camera_auto_mover.h
index db57627e33..d9b2888fc8 100644
--- a/engines/titanic/star_control/camera_auto_mover.h
+++ b/engines/titanic/star_control/camera_auto_mover.h
@@ -62,17 +62,17 @@ public:
/**
* Clear src and dest orientation and set some default values for other fields
- */
+ */
void clear();
/**
* Setup a transition to from one position to another
- */
+ */
void setPath(const FVector &srcV, const FVector &destV);
/**
* Applys speeds to the mover. More than one application is usually done for several transitions
- */
+ */
virtual MoverState move(CErrorCode &errorCode, FVector &pos, FMatrix &orientation) { return DONE_MOVING; }
/**
* Given a distance to cover, determines a bunch of speeds for a gradual transition
diff --git a/engines/titanic/star_control/frect.h b/engines/titanic/star_control/frect.h
index 654c578cfd..d792eb69b4 100644
--- a/engines/titanic/star_control/frect.h
+++ b/engines/titanic/star_control/frect.h
@@ -41,7 +41,7 @@ public:
* Returns true if the rects equal
*/
bool operator==(const FRect &p) const;
-
+
/**
* Returns true if the rects are not equal
*/
diff --git a/engines/titanic/star_control/marked_auto_mover.h b/engines/titanic/star_control/marked_auto_mover.h
index ca7fbf3b7f..d5f714b3ae 100644
--- a/engines/titanic/star_control/marked_auto_mover.h
+++ b/engines/titanic/star_control/marked_auto_mover.h
@@ -46,7 +46,7 @@ public:
/**
* Applys speeds to the mover. More than one application is usually done for several transitions
- */
+ */
virtual MoverState move(CErrorCode &errorCode, FVector &pos, FMatrix &orientation);
};
diff --git a/engines/titanic/star_control/star_camera.h b/engines/titanic/star_control/star_camera.h
index f2d27212fe..9d0c954765 100644
--- a/engines/titanic/star_control/star_camera.h
+++ b/engines/titanic/star_control/star_camera.h
@@ -234,7 +234,7 @@ public:
* Lock in the first matched star marker
*/
bool lockMarker1(FVector v1, FVector v2, FVector v3);
-
+
/**
* Lock in the second matched star marker
*/
diff --git a/engines/titanic/star_control/star_closeup.cpp b/engines/titanic/star_control/star_closeup.cpp
index 6ec94bbf38..3bc3623d58 100644
--- a/engines/titanic/star_control/star_closeup.cpp
+++ b/engines/titanic/star_control/star_closeup.cpp
@@ -69,9 +69,9 @@ bool CStarCloseup::setup2(int val1, int val2) {
const int VALUES1[] = { 0x800, 0xC00, 0x1000, 0x1400, 0x1800 };
const int VALUES2[] = {
0xF95BCD, 0xA505A0, 0xFFAD43, 0x98F4EB, 0xF3EFA5, 0,
- 0xFFFFFF, 0x81EEF5, 0x5FFD3, 0x4EE4FA, 0x11C3FF, 0x28F3F4,
- 0x36FCF2, 0x29F1FD, 0x29BCFD, 0x98E3F4, 0xBBF3D9, 0x8198F5,
- 0x5BE4F9, 0x0D6E2, 0x74EEF6, 0x68DEF8
+ 0xFFFFFF, 0x81EEF5, 0x5FFD3, 0x4EE4FA, 0x11C3FF, 0x28F3F4,
+ 0x36FCF2, 0x29F1FD, 0x29BCFD, 0x98E3F4, 0xBBF3D9, 0x8198F5,
+ 0x5BE4F9, 0x0D6E2, 0x74EEF6, 0x68DEF8
};
Entry *e = &_entries[0];
@@ -174,7 +174,7 @@ bool CStarCloseup::setup2(int val1, int val2) {
e->_pixel2 = (val >> 8) & 0xff;
e->_pixel3 = (val >> 16) & 0xff;
e->_field8 = g_vm->getRandomNumber(3) + 3;
-
+
e->_fieldC = g_vm->getRandomNumber(255);
e->_field10 = FACTOR * (float)g_vm->getRandomNumber(15);
e->_field14 = ((float)g_vm->getRandomNumber(0xfffffffe)
@@ -293,7 +293,7 @@ void CStarCloseup::draw(const FPose &pose, const FVector &vector, const FVector
}
switch (starColor) {
- case WHITE:
+ case WHITE:
surfaceArea->setMode(SA_SOLID);
surfaceArea->_pixel = MKTAG_BE(entryP->_pixel1, entryP->_pixel2,
entryP->_pixel3, 0);
@@ -424,7 +424,7 @@ void CStarCloseup::draw(const FPose &pose, const FVector &vector, const FVector
surfaceArea->drawLine(FRect(grid1._position._x, grid1._position._y,
grid2._position._x, grid2._position._y));
}
- }
+ }
break;
case PINK:
surfaceArea->setMode(SA_SOLID);
diff --git a/engines/titanic/star_control/star_control.cpp b/engines/titanic/star_control/star_control.cpp
index 8464262b31..7922a2f7f2 100644
--- a/engines/titanic/star_control/star_control.cpp
+++ b/engines/titanic/star_control/star_control.cpp
@@ -241,7 +241,7 @@ void CStarControl::doAction(StarControlAction action) {
pet->starsSetReference();
break;
}
-
+
case STAR_FADE_IN:
_view.fn3(true);
break;
diff --git a/engines/titanic/star_control/star_crosshairs.h b/engines/titanic/star_control/star_crosshairs.h
index d60541c205..3d060fd91d 100644
--- a/engines/titanic/star_control/star_crosshairs.h
+++ b/engines/titanic/star_control/star_crosshairs.h
@@ -80,12 +80,12 @@ public:
bool fn1(CStarField *starField, CSurfaceArea *surfaceArea, CStarCamera *camera);
void fn2(CVideoSurface *surface, CStarField *starField, CStarMarkers *markers);
-
+
/**
* Increments the index for the number of matches
*/
void incMatches();
-
+
/**
* Draw the crosshairs for a given star
*/
@@ -101,12 +101,12 @@ public:
* Erase crosshairs for the most recently selected star
*/
void eraseCurrent(CSurfaceArea *surfaceArea);
-
+
/**
* Draw crosshairs at the given position
*/
void drawAt(const FPoint &pt, CSurfaceArea *surfaceArea);
-
+
/**
* Returns the position of the most recently selected star
*/
diff --git a/engines/titanic/star_control/star_field.h b/engines/titanic/star_control/star_field.h
index bd3f8aecb6..3b1c3db2b5 100644
--- a/engines/titanic/star_control/star_field.h
+++ b/engines/titanic/star_control/star_field.h
@@ -78,17 +78,17 @@ public:
void set2(int val);
int get54() const;
void set54(int val);
-
+
/**
* Gets the current display mode
*/
StarMode getMode() const;
-
+
/**
* Sets the display mode
*/
void setMode(StarMode mode);
-
+
/**
* Toggles whether the big box is visible
*/
diff --git a/engines/titanic/star_control/star_view.h b/engines/titanic/star_control/star_view.h
index 553195b0c7..241efbcde5 100644
--- a/engines/titanic/star_control/star_view.h
+++ b/engines/titanic/star_control/star_view.h
@@ -148,14 +148,14 @@ public:
* Toggles between starfield and photo modes
*/
void toggleMode();
-
+
void fn11();
/**
* Toggles whether the viewpoint box is visible in the starfield
*/
void toggleBox();
-
+
void fn13();
void fn14();
@@ -163,7 +163,7 @@ public:
* Called when the photograph is used on the navigation computer
*/
void setHasReference();
-
+
/**
* Handles locking in a star
*/
diff --git a/engines/titanic/star_control/unmarked_camera_mover.cpp b/engines/titanic/star_control/unmarked_camera_mover.cpp
index c879dc25e8..401f550bee 100644
--- a/engines/titanic/star_control/unmarked_camera_mover.cpp
+++ b/engines/titanic/star_control/unmarked_camera_mover.cpp
@@ -48,7 +48,7 @@ void CUnmarkedCameraMover::moveTo(const FVector &srcV, const FVector &destV, con
void CUnmarkedCameraMover::transitionBetweenOrientations(const FVector &v1, const FVector &v2, const FVector &v3, const FMatrix &m) {
if (isLocked())
decLockCount();
-
+
FVector vector1 = v1;
FVector vector2 = v2;
FPose matrix1 = vector2.getFrameTransform(vector1);
diff --git a/engines/titanic/star_control/viewport.cpp b/engines/titanic/star_control/viewport.cpp
index e368dfa317..d66ff423c6 100644
--- a/engines/titanic/star_control/viewport.cpp
+++ b/engines/titanic/star_control/viewport.cpp
@@ -178,7 +178,7 @@ void CViewport::randomizeOrientation() {
FPose m1(X_AXIS, ranRotAngleX);
FPose m2(Y_AXIS, ranRotAngleY);
FPose m3(Z_AXIS, ranRotAngleZ);
-
+
FPose s1(m1, m2);
FPose s2(s1, m3);
diff --git a/engines/titanic/star_control/viewport.h b/engines/titanic/star_control/viewport.h
index 082d063233..ae42e84ea4 100644
--- a/engines/titanic/star_control/viewport.h
+++ b/engines/titanic/star_control/viewport.h
@@ -35,7 +35,7 @@ namespace Titanic {
* For starview it should be white
* For skyview it should be pink
*/
-enum StarColor { WHITE = 0, PINK = 2 };
+enum StarColor { WHITE = 0, PINK = 2 };
/**
* Implements the viewport functionality for viewing the star field in
@@ -111,14 +111,14 @@ public:
* The view has changed between starview and skyview
* Change the enum that tracks the color of the stars
* Also change the X coordinate pixel offset used for star drawing
- */
+ */
void changeStarColorPixel(StarMode mode, double pixelOffSet);
void reposition(double factor);
/**
* Applys a rotation matrix to the current
* orientation
- */
+ */
void changeOrientation(const FMatrix &matrix);
FPose getPose();
@@ -148,15 +148,15 @@ public:
/**
* Sets the center vector y angle
* The actual center y value doesn't
- * change untill reset is called
- */
+ * change untill reset is called
+ */
void setCenterYAngle(double angleDegrees);
/**
* Sets the center vector z angle
* The actual center z value doesn't
- * change untill reset is called
- */
+ * change untill reset is called
+ */
void setCenterZAngle(double angleDegrees);
};
diff --git a/engines/titanic/support/avi_surface.cpp b/engines/titanic/support/avi_surface.cpp
index 3b22a4fee2..ff439abe25 100644
--- a/engines/titanic/support/avi_surface.cpp
+++ b/engines/titanic/support/avi_surface.cpp
@@ -489,7 +489,7 @@ Graphics::ManagedSurface *AVISurface::duplicateTransparency() const {
bool AVISurface::playCutscene(const Rect &r, uint startFrame, uint endFrame) {
if (g_vm->shouldQuit())
return false;
-
+
// TODO: Fixes slight "jumping back" when rotating in place in Top Of Well
// balcony between two elevators. Need a more generalized fix at some point
if (_movieName == "z48.avi")
diff --git a/engines/titanic/support/simple_file.cpp b/engines/titanic/support/simple_file.cpp
index 103f062ac6..83d731f7f2 100644
--- a/engines/titanic/support/simple_file.cpp
+++ b/engines/titanic/support/simple_file.cpp
@@ -388,7 +388,7 @@ void SimpleFile::writeIndent(uint indent) const {
write("\t", 1);
}
-bool SimpleFile::IsClassStart() {
+bool SimpleFile::isClassStart() {
char c;
do {
diff --git a/engines/titanic/support/simple_file.h b/engines/titanic/support/simple_file.h
index 01aaa86925..f71ef5b717 100644
--- a/engines/titanic/support/simple_file.h
+++ b/engines/titanic/support/simple_file.h
@@ -238,7 +238,7 @@ public:
* an opening or closing squiggly bracket denoting a class
* definition start or end. Returns true if it's a class start
*/
- bool IsClassStart();
+ bool isClassStart();
/**
* Write the starting header for a class definition
diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp
index e0e4a07ce6..0931d91806 100644
--- a/engines/titanic/titanic.cpp
+++ b/engines/titanic/titanic.cpp
@@ -49,7 +49,6 @@
#include "common/translation.h"
#include "engines/util.h"
#include "graphics/scaler.h"
-#include "graphics/thumbnail.h"
#include "graphics/screen.h"
#include "gui/saveload.h"
@@ -191,7 +190,7 @@ void TitanicEngine::setRoomNames() {
bool TitanicEngine::canLoadGameStateCurrently() {
CGameManager *gameManager = _window->_gameManager;
CScreenManager *screenMan = CScreenManager::_screenManagerPtr;
-
+
if (!gameManager)
// Allow loading from copyright screen and continue dialogs
return true;
@@ -256,11 +255,6 @@ CString TitanicEngine::getSavegameName(int slot) {
TitanicSavegameHeader header;
bool isValid = CProjectItem::readSavegameHeader(&file, header);
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
file.close();
if (isValid)
diff --git a/engines/titanic/true_talk/doorbot_script.cpp b/engines/titanic/true_talk/doorbot_script.cpp
index d7389d1cb7..0b33704ba5 100644
--- a/engines/titanic/true_talk/doorbot_script.cpp
+++ b/engines/titanic/true_talk/doorbot_script.cpp
@@ -71,6 +71,8 @@ static const RoomDialogueId ROOM_DIALOGUES2_DE[] = {
DoorbotScript::DoorbotScript(int val1, const char *charClass, int v2,
const char *charName, int v3, int val2, int v4, int v5, int v6, int v7) :
TTnpcScript(val1, charClass, v2, charName, v3, val2, v4, v5, v6, v7) {
+ _stateIndex = _doorbotState = 0;
+
loadRanges("Ranges/Doorbot");
loadResponses("Responses/Doorbot");
setupSentences();
@@ -108,7 +110,7 @@ void DoorbotScript::setupSentences() {
int DoorbotScript::chooseResponse(const TTroomScript *roomScript, const TTsentence *sentence, uint tag) {
if (tag == MKTAG('D', 'N', 'A', '1') || tag == MKTAG('H', 'H', 'G', 'Q') ||
tag == MKTAG('A', 'N', 'S', 'W') || tag == MKTAG('S', 'U', 'M', 'S')) {
- if (_stateIndex > 9)
+ if (_stateIndex > 8)
_stateIndex = 0;
addResponse(TRANSLATE(STATE_ARRAY_EN[_stateIndex], STATE_ARRAY_DE[_stateIndex]));
applyResponse();
diff --git a/engines/titanic/true_talk/tt_parser.cpp b/engines/titanic/true_talk/tt_parser.cpp
index 5c48de4182..2caeef45dd 100644
--- a/engines/titanic/true_talk/tt_parser.cpp
+++ b/engines/titanic/true_talk/tt_parser.cpp
@@ -960,7 +960,7 @@ int TTparser::considerRequests(TTword *word) {
case WC_ABSTRACT:
if (word->_id != 300) {
status = processModifiers(3, word);
- } else if (!_conceptP->findByWordClass(WC_THING)) {
+ } else if (!_conceptP || !_conceptP->findByWordClass(WC_THING)) {
status = processModifiers(3, word);
} else {
word->_id = atoi(word->_text.c_str());
@@ -1760,7 +1760,7 @@ void TTparser::preprocessGerman(TTstring &line) {
continue;
const char *wordEndP = p + _replacements4[idx].size();
-
+
for (int sIdx = 0; sIdx < 12; ++sIdx) {
const char *suffixP = SUFFIXES[sIdx];
if (!strncmp(wordEndP, suffixP, strlen(suffixP))) {
diff --git a/engines/titanic/true_talk/tt_talker.h b/engines/titanic/true_talk/tt_talker.h
index 4f0b59c044..68b77d8b75 100644
--- a/engines/titanic/true_talk/tt_talker.h
+++ b/engines/titanic/true_talk/tt_talker.h
@@ -54,7 +54,7 @@ public:
* End the speech
*/
void endSpeech(int val);
-
+
/**
* Called when a speech is finished, to signal to the associated character
* that the speech is over
diff --git a/engines/titanic/true_talk/tt_vocab.cpp b/engines/titanic/true_talk/tt_vocab.cpp
index e9fc098749..0269e71cee 100644
--- a/engines/titanic/true_talk/tt_vocab.cpp
+++ b/engines/titanic/true_talk/tt_vocab.cpp
@@ -1,585 +1,585 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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 "titanic/true_talk/tt_vocab.h"
-#include "titanic/true_talk/script_handler.h"
-#include "titanic/true_talk/tt_action.h"
-#include "titanic/true_talk/tt_adj.h"
-#include "titanic/true_talk/tt_major_word.h"
-#include "titanic/true_talk/tt_picture.h"
-#include "titanic/true_talk/tt_pronoun.h"
-#include "titanic/titanic.h"
-#include "titanic/translation.h"
-#include "common/file.h"
-
-namespace Titanic {
-
-TTvocab::TTvocab(VocabMode vocabMode): _headP(nullptr), _tailP(nullptr),
- _word(nullptr), _vocabMode(vocabMode) {
- load("STVOCAB");
-}
-
-TTvocab::~TTvocab() {
- if (_headP) {
- _headP->deleteSiblings();
- delete _headP;
- _headP = _tailP = nullptr;
- }
-}
-
-int TTvocab::load(const CString &name) {
- SimpleFile *file = g_vm->_exeResources._owner->openResource(name);
- int result = 0;
- bool skipFlag;
-
- while (!result && !file->eos()) {
- skipFlag = false;
- WordClass wordClass = (WordClass)file->readNumber();
- TTstring space(" ");
-
- switch (wordClass) {
- case WC_UNKNOWN: {
- if (_word)
- result = _word->readSyn(file);
- skipFlag = true;
- break;
- }
-
- case WC_ACTION: {
- TTaction *word = new TTaction(space, WC_UNKNOWN, 0, 0, 0);
- result = word->load(file);
- _word = word;
- break;
- }
-
- case WC_THING: {
- TTpicture *word = new TTpicture(space, WC_UNKNOWN, 0, 0, 0, 0, 0);
- result = word->load(file);
- _word = word;
- break;
- }
-
- case WC_ABSTRACT:
- case WC_ADVERB: {
- TTmajorWord *word = new TTmajorWord(space, WC_UNKNOWN, 0, 0);
- result = word->load(file, wordClass);
- _word = word;
- break;
- }
-
- case WC_ARTICLE:
- case WC_CONJUNCTION:
- case WC_PREPOSITION: {
- TTword *word = new TTword(space, WC_UNKNOWN, 0);
- result = word->load(file, wordClass);
- _word = word;
- break;
- }
-
- case WC_ADJECTIVE: {
- TTadj *word = new TTadj(space, WC_UNKNOWN, 0, 0, 0);
- result = word->load(file);
- _word = word;
- break;
- }
-
- case WC_PRONOUN: {
- TTpronoun *word = new TTpronoun(space, WC_UNKNOWN, 0, 0, 0);
- result = word->load(file);
- _word = word;
- break;
- }
-
- default:
- result = 4;
- break;
- }
-
- if (!skipFlag && _word) {
- if (result) {
- // Something wrong occurred, so delete word
- delete _word;
- _word = nullptr;
- } else {
- // Add the word to the master vocab list
- addWord(_word);
- }
- }
- }
-
- // Close resource and return result
- delete file;
- return result;
-}
-
-void TTvocab::addWord(TTword *word) {
- TTword *existingWord = g_language == Common::DE_DEU ? nullptr :
- findWord(word->_text);
-
- if (existingWord) {
- if (word->_synP) {
- // Move over the synonym
- existingWord->appendNode(word->_synP);
- word->_synP = nullptr;
- }
-
- _word = nullptr;
- if (word)
- delete word;
- } else if (_tailP) {
- _tailP->_nextP = word;
- _tailP = word;
- } else {
- if (!_headP)
- _headP = word;
-
- _tailP = word;
- }
-}
-
-TTword *TTvocab::findWord(const TTstring &str) {
- TTsynonym *tempNode = new TTsynonym();
- bool flag = false;
- TTword *word = _headP;
-
- while (word && !flag) {
- if (_vocabMode != VOCAB_MODE_EN || strcmp(word->c_str(), str)) {
- if (word->findSynByName(str, tempNode, _vocabMode))
- flag = true;
- else
- word = word->_nextP;
- } else {
- flag = true;
- }
- }
-
- delete tempNode;
- return word;
-}
-
-TTword *TTvocab::getWord(TTstring &str, TTword **srcWord) const {
- TTword *word = getPrimeWord(str, srcWord);
-
- if (!word) {
- TTstring tempStr(str);
- if (tempStr.size() > 2) {
- word = getSuffixedWord(tempStr, srcWord);
-
- if (!word)
- word = getPrefixedWord(tempStr, srcWord);
- }
- }
-
- return word;
-}
-
-TTword *TTvocab::getPrimeWord(TTstring &str, TTword **srcWord) const {
- TTsynonym tempSyn;
- char c = str.charAt(0);
- TTword *newWord = nullptr;
- TTword *vocabP;
-
- if (Common::isDigit(c)) {
- // Number
- vocabP = _headP;
- newWord = new TTword(str, WC_ABSTRACT, 300);
- } else {
- // Standard word
- for (vocabP = _headP; vocabP; vocabP = vocabP->_nextP) {
- if (_vocabMode == VOCAB_MODE_EN && !strcmp(str.c_str(), vocabP->c_str())) {
- newWord = vocabP->copy();
- newWord->_nextP = nullptr;
- newWord->setSyn(nullptr);
- break;
- } else if (vocabP->findSynByName(str, &tempSyn, _vocabMode)) {
- // Create a copy of the word and the found synonym
- TTsynonym *newSyn = new TTsynonym(tempSyn);
- newSyn->_nextP = newSyn->_priorP = nullptr;
- newWord = vocabP->copy();
- newWord->_nextP = nullptr;
- newWord->setSyn(newSyn);
- break;
- }
- }
- }
-
- if (srcWord)
- // Pass out the pointer to the original word
- *srcWord = vocabP;
-
- // Return the new copy of the word
- return newWord;
-}
-
-TTword *TTvocab::getSuffixedWord(TTstring &str, TTword **srcWord) const {
- TTstring tempStr(str);
- TTword *word = nullptr;
-
- if (g_language == Common::DE_DEU) {
- static const char *const SUFFIXES[11] = {
- "est", "em", "en", "er", "es", "et", "st",
- "s", "e", "n", "t"
- };
-
- for (int idx = 0; idx < 11; ++idx) {
- if (tempStr.hasSuffix(SUFFIXES[idx])) {
- tempStr.deleteSuffix(strlen(SUFFIXES[idx]));
- word = getPrimeWord(tempStr, srcWord);
- if (word)
- break;
- tempStr = str;
- }
- }
-
- if (word)
- word->setSynStr(str);
- return word;
- }
-
- if (tempStr.hasSuffix("s")) {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (!word) {
- if (!tempStr.hasSuffix("e")) {
- tempStr = str;
- } else {
- tempStr.deleteLastChar();
- word = getPrimeWord(tempStr);
- }
- }
-
- } else if (tempStr.hasSuffix("ing")) {
- tempStr.deleteSuffix(3);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass == 1) {
- delete word;
- word = nullptr;
- } else {
- delete word;
- word = new TTadj(str, WC_ADJECTIVE, 0, 0, 0);
- }
- } else {
- tempStr += "e";
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass != 1) {
- delete word;
- word = new TTadj(str, WC_ADJECTIVE, 0, 0, 0);
- }
- } else {
- tempStr.deleteSuffix(2);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass != 1) {
- delete word;
- word = new TTadj(str, WC_ADJECTIVE, 0, 0, 0);
- }
- } else {
- tempStr = str;
- }
- }
- }
-
- } else if (tempStr.hasSuffix("ed")) {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (!word) {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
- }
-
- if (word) {
- if (word->_wordClass == WC_ACTION) {
- TTaction *action = dynamic_cast<TTaction *>(word);
- assert(action);
- action->setVal(1);
- }
- } else {
- tempStr = str;
- }
-
- } else if (tempStr.hasSuffix("ly")) {
- tempStr.deleteSuffix(2);
- word = getPrimeWord(tempStr);
-
- if (word) {
- delete word;
- word = new TTword(str, WC_ADVERB, 0);
- } else {
- tempStr = str;
- }
-
- } else if (tempStr.hasSuffix("er")) {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass == WC_ADJECTIVE) {
- TTadj *adj = static_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0) {
- adj->adjFn1(val1);
- }
- } else {
- if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
- } else {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass == WC_ADJECTIVE) {
- TTadj *adj = dynamic_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0) {
- adj->adjFn1(val1);
- }
- } else {
- if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
- } else {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (word && word->_wordClass == WC_ADJECTIVE) {
- TTadj *adj = dynamic_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0) {
- adj->adjFn1(val1);
- }
- } else {
- if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
- }
- }
-
- } else if (tempStr.hasSuffix("est")) {
- tempStr.deleteSuffix(2);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass == WC_ADJECTIVE) {
- TTadj *adj = static_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0) {
- adj->adjFn1(val1);
- }
- } else {
- if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
- } else {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass == WC_ADJECTIVE) {
- TTadj *adj = dynamic_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0) {
- adj->adjFn1(val1);
- }
- } else {
- if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
- } else {
- tempStr.deleteSuffix(1);
- word = getPrimeWord(tempStr);
-
- if (word) {
- TTadj *adj = dynamic_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0) {
- adj->adjFn1(val1);
- }
- } else {
- if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
- }
- }
-
- } else if (tempStr.hasSuffix("s*")) {
- tempStr.deleteSuffix(2);
- word = getPrimeWord(tempStr);
-
- if (word) {
- if (word->_wordClass == WC_PRONOUN || word->_wordClass == WC_ADVERB) {
- delete word;
- TTstring isStr("is");
- word = getPrimeWord(isStr);
- } else {
- switch (word->_id) {
- case 200:
- if (word->proc10() == 2) {
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 5);
- } else if (word->proc10() == 1) {
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 4);
- }
- break;
-
- case 201:
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 5);
- break;
-
- case 202:
- case 203:
- if (word->proc10() == 2) {
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 5);
- } else {
- int val = word->proc10() == 1 ? 0 : 4;
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, val);
- }
- break;
-
- case 204:
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 6);
- break;
-
- default:
- delete word;
- word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 0);
- break;
- }
- }
- }
- }
-
- if (word)
- word->setSynStr(str);
-
- return word;
-}
-
-TTword *TTvocab::getPrefixedWord(TTstring &str, TTword **srcWord) const {
- TTstring tempStr(str);
- TTword *word = nullptr;
- int prefixLen = 0;
-
- if (tempStr.hasPrefix("pre")) {
- prefixLen = 3;
- } else if (tempStr.hasPrefix("re") || tempStr.hasPrefix("co")) {
- prefixLen = 2;
- } else if (tempStr.hasPrefix("inter") || tempStr.hasPrefix("multi")) {
- prefixLen = 5;
- } else if (tempStr.hasPrefix("over") || tempStr.hasPrefix("post") || tempStr.hasPrefix("self")) {
- prefixLen = 4;
- }
-
- if (prefixLen) {
- // Known prefix found, so scan for word without prefix
- tempStr.deletePrefix(prefixLen);
- word = getPrimeWord(tempStr);
- if (word)
- tempStr = str;
-
- } else if (tempStr.hasPrefix("anti") || tempStr.hasPrefix("counter")) {
- prefixLen = tempStr[0] == 'a' ? 4 : 7;
-
- tempStr.deletePrefix(prefixLen);
- word = getPrimeWord(tempStr);
- if (!word)
- tempStr = str;
- else if (word->_wordClass == 8) {
- delete word;
- word = nullptr;
- }
-
- } else if (tempStr.hasPrefix("hyper") || tempStr.hasPrefix("super") ||
- tempStr.hasPrefix("ultra")) {
- tempStr.deletePrefix(5);
- word = getPrimeWord(tempStr);
-
- if (!word)
- tempStr = str;
- else if (word->_wordClass == WC_ADJECTIVE) {
- TTadj *adj = static_cast<TTadj *>(word);
- int val1 = word->proc15();
- int val2 = word->proc15();
-
- if (val2 < 5) {
- if (--val1 > 0)
- adj->adjFn1(val1);
- } else if (++val1 < 11) {
- adj->adjFn1(val1);
- }
- }
- }
-
- if (word) {
- // Set the original word on either the found word or synonym
- if (word->hasSynonyms())
- word->setSynStr(str);
- else
- word->_text = str;
- }
-
- return word;
-}
-
-} // End of namespace Titanic
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "titanic/true_talk/tt_vocab.h"
+#include "titanic/true_talk/script_handler.h"
+#include "titanic/true_talk/tt_action.h"
+#include "titanic/true_talk/tt_adj.h"
+#include "titanic/true_talk/tt_major_word.h"
+#include "titanic/true_talk/tt_picture.h"
+#include "titanic/true_talk/tt_pronoun.h"
+#include "titanic/titanic.h"
+#include "titanic/translation.h"
+#include "common/file.h"
+
+namespace Titanic {
+
+TTvocab::TTvocab(VocabMode vocabMode): _headP(nullptr), _tailP(nullptr),
+ _word(nullptr), _vocabMode(vocabMode) {
+ load("STVOCAB");
+}
+
+TTvocab::~TTvocab() {
+ if (_headP) {
+ _headP->deleteSiblings();
+ delete _headP;
+ _headP = _tailP = nullptr;
+ }
+}
+
+int TTvocab::load(const CString &name) {
+ SimpleFile *file = g_vm->_exeResources._owner->openResource(name);
+ int result = 0;
+ bool skipFlag;
+
+ while (!result && !file->eos()) {
+ skipFlag = false;
+ WordClass wordClass = (WordClass)file->readNumber();
+ TTstring space(" ");
+
+ switch (wordClass) {
+ case WC_UNKNOWN: {
+ if (_word)
+ result = _word->readSyn(file);
+ skipFlag = true;
+ break;
+ }
+
+ case WC_ACTION: {
+ TTaction *word = new TTaction(space, WC_UNKNOWN, 0, 0, 0);
+ result = word->load(file);
+ _word = word;
+ break;
+ }
+
+ case WC_THING: {
+ TTpicture *word = new TTpicture(space, WC_UNKNOWN, 0, 0, 0, 0, 0);
+ result = word->load(file);
+ _word = word;
+ break;
+ }
+
+ case WC_ABSTRACT:
+ case WC_ADVERB: {
+ TTmajorWord *word = new TTmajorWord(space, WC_UNKNOWN, 0, 0);
+ result = word->load(file, wordClass);
+ _word = word;
+ break;
+ }
+
+ case WC_ARTICLE:
+ case WC_CONJUNCTION:
+ case WC_PREPOSITION: {
+ TTword *word = new TTword(space, WC_UNKNOWN, 0);
+ result = word->load(file, wordClass);
+ _word = word;
+ break;
+ }
+
+ case WC_ADJECTIVE: {
+ TTadj *word = new TTadj(space, WC_UNKNOWN, 0, 0, 0);
+ result = word->load(file);
+ _word = word;
+ break;
+ }
+
+ case WC_PRONOUN: {
+ TTpronoun *word = new TTpronoun(space, WC_UNKNOWN, 0, 0, 0);
+ result = word->load(file);
+ _word = word;
+ break;
+ }
+
+ default:
+ result = 4;
+ break;
+ }
+
+ if (!skipFlag && _word) {
+ if (result) {
+ // Something wrong occurred, so delete word
+ delete _word;
+ _word = nullptr;
+ } else {
+ // Add the word to the master vocab list
+ addWord(_word);
+ }
+ }
+ }
+
+ // Close resource and return result
+ delete file;
+ return result;
+}
+
+void TTvocab::addWord(TTword *word) {
+ TTword *existingWord = g_language == Common::DE_DEU ? nullptr :
+ findWord(word->_text);
+
+ if (existingWord) {
+ if (word->_synP) {
+ // Move over the synonym
+ existingWord->appendNode(word->_synP);
+ word->_synP = nullptr;
+ }
+
+ _word = nullptr;
+ if (word)
+ delete word;
+ } else if (_tailP) {
+ _tailP->_nextP = word;
+ _tailP = word;
+ } else {
+ if (!_headP)
+ _headP = word;
+
+ _tailP = word;
+ }
+}
+
+TTword *TTvocab::findWord(const TTstring &str) {
+ TTsynonym *tempNode = new TTsynonym();
+ bool flag = false;
+ TTword *word = _headP;
+
+ while (word && !flag) {
+ if (_vocabMode != VOCAB_MODE_EN || strcmp(word->c_str(), str)) {
+ if (word->findSynByName(str, tempNode, _vocabMode))
+ flag = true;
+ else
+ word = word->_nextP;
+ } else {
+ flag = true;
+ }
+ }
+
+ delete tempNode;
+ return word;
+}
+
+TTword *TTvocab::getWord(TTstring &str, TTword **srcWord) const {
+ TTword *word = getPrimeWord(str, srcWord);
+
+ if (!word) {
+ TTstring tempStr(str);
+ if (tempStr.size() > 2) {
+ word = getSuffixedWord(tempStr, srcWord);
+
+ if (!word)
+ word = getPrefixedWord(tempStr, srcWord);
+ }
+ }
+
+ return word;
+}
+
+TTword *TTvocab::getPrimeWord(TTstring &str, TTword **srcWord) const {
+ TTsynonym tempSyn;
+ char c = str.charAt(0);
+ TTword *newWord = nullptr;
+ TTword *vocabP;
+
+ if (Common::isDigit(c)) {
+ // Number
+ vocabP = _headP;
+ newWord = new TTword(str, WC_ABSTRACT, 300);
+ } else {
+ // Standard word
+ for (vocabP = _headP; vocabP; vocabP = vocabP->_nextP) {
+ if (_vocabMode == VOCAB_MODE_EN && !strcmp(str.c_str(), vocabP->c_str())) {
+ newWord = vocabP->copy();
+ newWord->_nextP = nullptr;
+ newWord->setSyn(nullptr);
+ break;
+ } else if (vocabP->findSynByName(str, &tempSyn, _vocabMode)) {
+ // Create a copy of the word and the found synonym
+ TTsynonym *newSyn = new TTsynonym(tempSyn);
+ newSyn->_nextP = newSyn->_priorP = nullptr;
+ newWord = vocabP->copy();
+ newWord->_nextP = nullptr;
+ newWord->setSyn(newSyn);
+ break;
+ }
+ }
+ }
+
+ if (srcWord)
+ // Pass out the pointer to the original word
+ *srcWord = vocabP;
+
+ // Return the new copy of the word
+ return newWord;
+}
+
+TTword *TTvocab::getSuffixedWord(TTstring &str, TTword **srcWord) const {
+ TTstring tempStr(str);
+ TTword *word = nullptr;
+
+ if (g_language == Common::DE_DEU) {
+ static const char *const SUFFIXES[11] = {
+ "est", "em", "en", "er", "es", "et", "st",
+ "s", "e", "n", "t"
+ };
+
+ for (int idx = 0; idx < 11; ++idx) {
+ if (tempStr.hasSuffix(SUFFIXES[idx])) {
+ tempStr.deleteSuffix(strlen(SUFFIXES[idx]));
+ word = getPrimeWord(tempStr, srcWord);
+ if (word)
+ break;
+ tempStr = str;
+ }
+ }
+
+ if (word)
+ word->setSynStr(str);
+ return word;
+ }
+
+ if (tempStr.hasSuffix("s")) {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (!word) {
+ if (!tempStr.hasSuffix("e")) {
+ tempStr = str;
+ } else {
+ tempStr.deleteLastChar();
+ word = getPrimeWord(tempStr);
+ }
+ }
+
+ } else if (tempStr.hasSuffix("ing")) {
+ tempStr.deleteSuffix(3);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass == 1) {
+ delete word;
+ word = nullptr;
+ } else {
+ delete word;
+ word = new TTadj(str, WC_ADJECTIVE, 0, 0, 0);
+ }
+ } else {
+ tempStr += "e";
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass != 1) {
+ delete word;
+ word = new TTadj(str, WC_ADJECTIVE, 0, 0, 0);
+ }
+ } else {
+ tempStr.deleteSuffix(2);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass != 1) {
+ delete word;
+ word = new TTadj(str, WC_ADJECTIVE, 0, 0, 0);
+ }
+ } else {
+ tempStr = str;
+ }
+ }
+ }
+
+ } else if (tempStr.hasSuffix("ed")) {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (!word) {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+ }
+
+ if (word) {
+ if (word->_wordClass == WC_ACTION) {
+ TTaction *action = dynamic_cast<TTaction *>(word);
+ assert(action);
+ action->setVal(1);
+ }
+ } else {
+ tempStr = str;
+ }
+
+ } else if (tempStr.hasSuffix("ly")) {
+ tempStr.deleteSuffix(2);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ delete word;
+ word = new TTword(str, WC_ADVERB, 0);
+ } else {
+ tempStr = str;
+ }
+
+ } else if (tempStr.hasSuffix("er")) {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass == WC_ADJECTIVE) {
+ TTadj *adj = static_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0) {
+ adj->adjFn1(val1);
+ }
+ } else {
+ if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+ } else {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass == WC_ADJECTIVE) {
+ TTadj *adj = dynamic_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0) {
+ adj->adjFn1(val1);
+ }
+ } else {
+ if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+ } else {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (word && word->_wordClass == WC_ADJECTIVE) {
+ TTadj *adj = dynamic_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0) {
+ adj->adjFn1(val1);
+ }
+ } else {
+ if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+ }
+ }
+
+ } else if (tempStr.hasSuffix("est")) {
+ tempStr.deleteSuffix(2);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass == WC_ADJECTIVE) {
+ TTadj *adj = static_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0) {
+ adj->adjFn1(val1);
+ }
+ } else {
+ if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+ } else {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass == WC_ADJECTIVE) {
+ TTadj *adj = dynamic_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0) {
+ adj->adjFn1(val1);
+ }
+ } else {
+ if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+ } else {
+ tempStr.deleteSuffix(1);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ TTadj *adj = dynamic_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0) {
+ adj->adjFn1(val1);
+ }
+ } else {
+ if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+ }
+ }
+
+ } else if (tempStr.hasSuffix("s*")) {
+ tempStr.deleteSuffix(2);
+ word = getPrimeWord(tempStr);
+
+ if (word) {
+ if (word->_wordClass == WC_PRONOUN || word->_wordClass == WC_ADVERB) {
+ delete word;
+ TTstring isStr("is");
+ word = getPrimeWord(isStr);
+ } else {
+ switch (word->_id) {
+ case 200:
+ if (word->proc10() == 2) {
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 5);
+ } else if (word->proc10() == 1) {
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 4);
+ }
+ break;
+
+ case 201:
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 5);
+ break;
+
+ case 202:
+ case 203:
+ if (word->proc10() == 2) {
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 5);
+ } else {
+ int val = word->proc10() == 1 ? 0 : 4;
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, val);
+ }
+ break;
+
+ case 204:
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 6);
+ break;
+
+ default:
+ delete word;
+ word = new TTpronoun(tempStr, WC_PRONOUN, 601, 0, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ if (word)
+ word->setSynStr(str);
+
+ return word;
+}
+
+TTword *TTvocab::getPrefixedWord(TTstring &str, TTword **srcWord) const {
+ TTstring tempStr(str);
+ TTword *word = nullptr;
+ int prefixLen = 0;
+
+ if (tempStr.hasPrefix("pre")) {
+ prefixLen = 3;
+ } else if (tempStr.hasPrefix("re") || tempStr.hasPrefix("co")) {
+ prefixLen = 2;
+ } else if (tempStr.hasPrefix("inter") || tempStr.hasPrefix("multi")) {
+ prefixLen = 5;
+ } else if (tempStr.hasPrefix("over") || tempStr.hasPrefix("post") || tempStr.hasPrefix("self")) {
+ prefixLen = 4;
+ }
+
+ if (prefixLen) {
+ // Known prefix found, so scan for word without prefix
+ tempStr.deletePrefix(prefixLen);
+ word = getPrimeWord(tempStr);
+ if (word)
+ tempStr = str;
+
+ } else if (tempStr.hasPrefix("anti") || tempStr.hasPrefix("counter")) {
+ prefixLen = tempStr[0] == 'a' ? 4 : 7;
+
+ tempStr.deletePrefix(prefixLen);
+ word = getPrimeWord(tempStr);
+ if (!word)
+ tempStr = str;
+ else if (word->_wordClass == 8) {
+ delete word;
+ word = nullptr;
+ }
+
+ } else if (tempStr.hasPrefix("hyper") || tempStr.hasPrefix("super") ||
+ tempStr.hasPrefix("ultra")) {
+ tempStr.deletePrefix(5);
+ word = getPrimeWord(tempStr);
+
+ if (!word)
+ tempStr = str;
+ else if (word->_wordClass == WC_ADJECTIVE) {
+ TTadj *adj = static_cast<TTadj *>(word);
+ int val1 = word->proc15();
+ int val2 = word->proc15();
+
+ if (val2 < 5) {
+ if (--val1 > 0)
+ adj->adjFn1(val1);
+ } else if (++val1 < 11) {
+ adj->adjFn1(val1);
+ }
+ }
+ }
+
+ if (word) {
+ // Set the original word on either the found word or synonym
+ if (word->hasSynonyms())
+ word->setSynStr(str);
+ else
+ word->_text = str;
+ }
+
+ return word;
+}
+
+} // End of namespace Titanic
diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp
index 9303760057..0cd9596c8c 100644
--- a/engines/toltecs/detection.cpp
+++ b/engines/toltecs/detection.cpp
@@ -276,7 +276,7 @@ SaveStateList ToltecsMetaEngine::listSaves(const char *target) const {
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
if (in) {
- if (Toltecs::ToltecsEngine::readSaveHeader(in, false, header) == Toltecs::ToltecsEngine::kRSHENoError) {
+ if (Toltecs::ToltecsEngine::readSaveHeader(in, header) == Toltecs::ToltecsEngine::kRSHENoError) {
saveList.push_back(SaveStateDescriptor(slotNum, header.description));
}
delete in;
@@ -325,7 +325,7 @@ SaveStateDescriptor ToltecsMetaEngine::querySaveMetaInfos(const char *target, in
Toltecs::ToltecsEngine::SaveHeader header;
Toltecs::ToltecsEngine::kReadSaveHeaderError error;
- error = Toltecs::ToltecsEngine::readSaveHeader(in, true, header);
+ error = Toltecs::ToltecsEngine::readSaveHeader(in, header, false);
delete in;
if (error == Toltecs::ToltecsEngine::kRSHENoError) {
diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp
index 5fc0599c2a..c4373265e6 100644
--- a/engines/toltecs/menu.cpp
+++ b/engines/toltecs/menu.cpp
@@ -525,7 +525,7 @@ int MenuSystem::loadSavegamesList() {
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
if (in) {
- if (Toltecs::ToltecsEngine::readSaveHeader(in, false, header) == Toltecs::ToltecsEngine::kRSHENoError) {
+ if (Toltecs::ToltecsEngine::readSaveHeader(in, header) == Toltecs::ToltecsEngine::kRSHENoError) {
_savegames.push_back(SavegameItem(slotNum, header.description));
//debug("%s -> %s", file->c_str(), header.description.c_str());
}
diff --git a/engines/toltecs/saveload.cpp b/engines/toltecs/saveload.cpp
index 409fc97076..1f2198fc35 100644
--- a/engines/toltecs/saveload.cpp
+++ b/engines/toltecs/saveload.cpp
@@ -41,7 +41,7 @@ namespace Toltecs {
#define TOLTECS_SAVEGAME_VERSION 4
-ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
+WARN_UNUSED_RESULT ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) {
header.version = in->readUint32LE();
if (header.version > TOLTECS_SAVEGAME_VERSION)
@@ -52,10 +52,8 @@ ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::Seekab
while (descriptionLen--)
header.description += (char)in->readByte();
- if (loadThumbnail) {
- header.thumbnail = Graphics::loadThumbnail(*in);
- } else {
- Graphics::skipThumbnail(*in);
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
+ return kRSHEIoError;
}
// Not used yet, reserved for future usage
@@ -147,7 +145,7 @@ void ToltecsEngine::loadgame(const char *filename) {
SaveHeader header;
- kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
+ kReadSaveHeaderError errorCode = readSaveHeader(in, header);
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h
index ece82f4a1a..1c9e9366c7 100644
--- a/engines/toltecs/toltecs.h
+++ b/engines/toltecs/toltecs.h
@@ -225,7 +225,7 @@ public:
const char *getSavegameFilename(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
- static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
+ WARN_UNUSED_RESULT static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true);
};
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
index 27145d7c4b..a59d14d5b6 100644
--- a/engines/tony/gfxcore.cpp
+++ b/engines/tony/gfxcore.cpp
@@ -912,7 +912,7 @@ void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPri
if (prim->isFlipped()) {
// Eliminate horizontal clipping
// width = m_dimx;
-// x1=prim->Dst().x1;
+// x1=prim->getDst()._x1;
// Clipping
u = _dimx - (width + u);
@@ -1699,7 +1699,7 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
}
//width = _dimx;
- //x1 = prim->Dst().x1;
+ //x1 = prim->getDst()._x1;
// Position into the destination buffer
buf = bigBuf;
@@ -1714,7 +1714,7 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
// Loop
buf += bigBuf.getDimx(); // Skip the first line
for (int y = 1; y < height - 1; y++) {
- // if (prim->IsFlipped())
+ // if (prim->isFlipped())
// mybuf=&buf[x1+m_dimx-1];
// else
mybuf = &buf[x1];
@@ -1748,7 +1748,7 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
// Looppone
buf += bigBuf.getDimx();
for (int y = 1; y < height - 1; y++) {
- // if (prim->IsFlipped())
+ // if (prim->isFlipped())
// mybuf=&buf[x1+m_dimx-1];
// else
mybuf = &buf[x1];
diff --git a/engines/tony/loc.cpp b/engines/tony/loc.cpp
index be2b20294f..fe553b5fab 100644
--- a/engines/tony/loc.cpp
+++ b/engines/tony/loc.cpp
@@ -1005,7 +1005,7 @@ void RMCharacter::goTo(CORO_PARAM, RMPoint destcoord, bool bReversed) {
_walkCount = 0;
if (bReversed) {
- while (0) ;
+ while (0);
}
int nPatt = getCurPattern();
diff --git a/engines/tony/mpal/lzo.cpp b/engines/tony/mpal/lzo.cpp
index b9accb6c89..1bb54af1f0 100644
--- a/engines/tony/mpal/lzo.cpp
+++ b/engines/tony/mpal/lzo.cpp
@@ -94,9 +94,9 @@ int lzo1x_decompress(const byte *in, uint32 in_len, byte *out, uint32 *out_len)
if (t < 4)
goto match_next;
assert(t > 0);
- do
+ do {
*op++ = *ip++;
- while (--t > 0);
+ } while (--t > 0);
goto first_literal_run;
}
@@ -116,9 +116,9 @@ int lzo1x_decompress(const byte *in, uint32 in_len, byte *out, uint32 *out_len)
*op++ = *ip++;
*op++ = *ip++;
*op++ = *ip++;
- do
+ do {
*op++ = *ip++;
- while (--t > 0);
+ } while (--t > 0);
first_literal_run:
t = *ip++;
@@ -186,9 +186,9 @@ match:
copy_match:
*op++ = *m_pos++;
*op++ = *m_pos++;
- do
+ do {
*op++ = *m_pos++;
- while (--t > 0);
+ } while (--t > 0);
}
match_done:
diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp
index fed51dacf4..07d15e71c9 100644
--- a/engines/tony/sound.cpp
+++ b/engines/tony/sound.cpp
@@ -412,11 +412,7 @@ void FPSfx::setPause(bool pause) {
*
*/
void FPSfx::setVolume(int volume) {
- if (volume > 63)
- volume = 63;
-
- if (volume < 0)
- volume = 0;
+ volume = CLIP(volume, 0, 63);
_lastVolume = volume;
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index e93d676d87..634d286c7c 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -132,7 +132,7 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
return detectGameFilebased(allFiles, fslist, Toon::fileBasedFallback);
}
@@ -232,7 +232,11 @@ SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int s
SaveStateDescriptor desc(slot, saveName);
- Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
+ Graphics::Surface *thumbnail;
+ if (!Graphics::loadThumbnail(*file, thumbnail)) {
+ delete file;
+ return SaveStateDescriptor();
+ }
desc.setThumbnail(thumbnail);
uint32 saveDate = file->readUint32BE();
diff --git a/engines/toon/flux.cpp b/engines/toon/flux.cpp
index 14218ba4ef..65ad66ffd8 100644
--- a/engines/toon/flux.cpp
+++ b/engines/toon/flux.cpp
@@ -86,8 +86,7 @@ int32 CharacterFlux::fixFacingForAnimation(int32 originalFacing, int32 animation
}
v5 >>= 1;
v6 <<= 1;
- }
- while (!facingMask);
+ } while (!facingMask);
int32 finalFacing = 0;
for (finalFacing = 0; ; ++finalFacing) {
diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp
index 04368df5ca..cdc6dc40d9 100644
--- a/engines/toon/hotspot.cpp
+++ b/engines/toon/hotspot.cpp
@@ -57,8 +57,8 @@ void Hotspots::save(Common::WriteStream *Stream) {
}
}
-int32 Hotspots::FindBasedOnCorner(int16 x, int16 y) {
- debugC(1, kDebugHotspot, "FindBasedOnCorner(%d, %d)", x, y);
+int32 Hotspots::findBasedOnCorner(int16 x, int16 y) {
+ debugC(1, kDebugHotspot, "findBasedOnCorner(%d, %d)", x, y);
for (int32 i = 0; i < _numItems; i++) {
if (x == _items[i].getX1()) {
@@ -73,8 +73,8 @@ int32 Hotspots::FindBasedOnCorner(int16 x, int16 y) {
return -1;
}
-int32 Hotspots::Find(int16 x, int16 y) {
- debugC(6, kDebugHotspot, "Find(%d, %d)", x, y);
+int32 Hotspots::find(int16 x, int16 y) {
+ debugC(6, kDebugHotspot, "find(%d, %d)", x, y);
int32 priority = -1;
int32 foundId = -1;
@@ -96,8 +96,8 @@ int32 Hotspots::Find(int16 x, int16 y) {
return foundId;
}
-bool Hotspots::LoadRif(const Common::String &rifName, const Common::String &additionalRifName) {
- debugC(1, kDebugHotspot, "LoadRif(%s, %s)", rifName.c_str(), additionalRifName.c_str());
+bool Hotspots::loadRif(const Common::String &rifName, const Common::String &additionalRifName) {
+ debugC(1, kDebugHotspot, "loadRif(%s, %s)", rifName.c_str(), additionalRifName.c_str());
uint32 size = 0;
uint8 *rifData = _vm->resources()->getFileData(rifName, &size);
@@ -139,8 +139,8 @@ bool Hotspots::LoadRif(const Common::String &rifName, const Common::String &addi
return true;
}
-HotspotData *Hotspots::Get(int32 id) {
- debugC(5, kDebugHotspot, "Get(%d)", id);
+HotspotData *Hotspots::get(int32 id) {
+ debugC(5, kDebugHotspot, "get(%d)", id);
if (id < 0 || id >= _numItems)
return 0;
diff --git a/engines/toon/hotspot.h b/engines/toon/hotspot.h
index 782d06a9fe..387007cbf6 100644
--- a/engines/toon/hotspot.h
+++ b/engines/toon/hotspot.h
@@ -50,10 +50,10 @@ public:
Hotspots(ToonEngine *vm);
~Hotspots();
- bool LoadRif(const Common::String &rifName, const Common::String &additionalRifName);
- int32 Find(int16 x, int16 y);
- int32 FindBasedOnCorner(int16 x, int16 y);
- HotspotData *Get(int32 id);
+ bool loadRif(const Common::String &rifName, const Common::String &additionalRifName);
+ int32 find(int16 x, int16 y);
+ int32 findBasedOnCorner(int16 x, int16 y);
+ HotspotData *get(int32 id);
int32 getCount() const { return _numItems; }
void load(Common::ReadStream *Stream);
diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp
index 7a8925b766..d2a9de3c02 100644
--- a/engines/toon/script_func.cpp
+++ b/engines/toon/script_func.cpp
@@ -379,9 +379,9 @@ int32 ScriptFunc::sys_Cmd_Visited_Scene(EMCState *state) {
int32 ScriptFunc::sys_Cmd_Query_Rif_Flag(EMCState *state) {
- int32 hs = _vm->getHotspots()->FindBasedOnCorner(stackPos(0), stackPos(1));
+ int32 hs = _vm->getHotspots()->findBasedOnCorner(stackPos(0), stackPos(1));
if (hs >= 0)
- return _vm->getHotspots()->Get(hs)->getData(stackPos(2));
+ return _vm->getHotspots()->get(hs)->getData(stackPos(2));
return 0;
}
@@ -472,9 +472,9 @@ int32 ScriptFunc::sys_Cmd_Say_Lines(EMCState *state) {
}
int32 ScriptFunc::sys_Cmd_Set_Rif_Flag(EMCState *state) {
- int32 hs = _vm->getHotspots()->FindBasedOnCorner(stackPos(0), stackPos(1));
+ int32 hs = _vm->getHotspots()->findBasedOnCorner(stackPos(0), stackPos(1));
if (hs >= 0)
- _vm->getHotspots()->Get(hs)->setData(stackPos(2), stackPos(3));
+ _vm->getHotspots()->get(hs)->setData(stackPos(2), stackPos(3));
return 0;
}
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 05192ae65e..248057d539 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -1559,9 +1559,9 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
if (state()->_locations[SceneId]._flags & 0x40) {
Common::String cutaway = state()->_locations[SceneId]._cutaway;
- _hotspots->LoadRif(locationName + ".RIC", cutaway + ".RIC");
+ _hotspots->loadRif(locationName + ".RIC", cutaway + ".RIC");
} else {
- _hotspots->LoadRif(locationName + ".RIC", "");
+ _hotspots->loadRif(locationName + ".RIC", "");
}
restoreRifFlags(_gameState->_currentScene);
@@ -1837,10 +1837,10 @@ void ToonEngine::clickEvent() {
}
// find hotspot
- int32 hot = _hotspots->Find(mouseX + state()->_currentScrollValue , _mouseY);
+ int32 hot = _hotspots->find(mouseX + state()->_currentScrollValue , _mouseY);
HotspotData *currentHot = 0;
if (hot > -1) {
- currentHot = _hotspots->Get(hot);
+ currentHot = _hotspots->get(hot);
}
if (_currentHotspotItem == -3) {
@@ -2012,9 +2012,9 @@ void ToonEngine::selectHotspot() {
}
}
- int32 hot = _hotspots->Find(mouseX + state()->_currentScrollValue, _mouseY);
+ int32 hot = _hotspots->find(mouseX + state()->_currentScrollValue, _mouseY);
if (hot != -1) {
- HotspotData *hotspot = _hotspots->Get(hot);
+ HotspotData *hotspot = _hotspots->get(hot);
int32 item = hotspot->getData(14);
if (hotspot->getType() == 3)
item += 2000;
@@ -2271,8 +2271,8 @@ void ToonEngine::storeRifFlags(int32 location) {
}
for (int32 i = 0; i < _hotspots->getCount(); i++) {
- _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->Get(i)->getData(4);
- _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->Get(i)->getData(7);
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->get(i)->getData(4);
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->get(i)->getData(7);
}
}
@@ -2280,8 +2280,8 @@ void ToonEngine::restoreRifFlags(int32 location) {
if (_hotspots) {
if (!_gameState->_locations[location]._visited) {
for (int32 i = 0; i < _hotspots->getCount(); i++) {
- _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->Get(i)->getData(4);
- _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->Get(i)->getData(7);
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->get(i)->getData(4);
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->get(i)->getData(7);
}
_gameState->_locations[location]._numRifBoxes = _hotspots->getCount();
} else {
@@ -2289,8 +2289,8 @@ void ToonEngine::restoreRifFlags(int32 location) {
return;
for (int32 i = 0; i < _hotspots->getCount(); i++) {
- _hotspots->Get(i)->setData(4, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0]);
- _hotspots->Get(i)->setData(7, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1]);
+ _hotspots->get(i)->setData(4, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0]);
+ _hotspots->get(i)->setData(7, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1]);
}
}
}
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index dcb58ffae6..51b17b26d9 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -133,15 +133,8 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
-
- const ADGameDescription *matchedDesc = detectGameFilebased(allFiles, fslist, Touche::fileBasedFallback, &filesProps);
- if (!matchedDesc)
- return 0;
-
- reportUnknown(fslist.begin()->getParent(), filesProps);
- return matchedDesc;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
+ return detectGameFilebased(allFiles, fslist, Touche::fileBasedFallback);
}
virtual const char *getName() const {
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
index 15bcbbc0fc..4414ed1918 100644
--- a/engines/touche/touche.cpp
+++ b/engines/touche/touche.cpp
@@ -1370,7 +1370,8 @@ int ToucheEngine::getStringWidth(int num) const {
debug("stringwidth: %s", str);
debugN("raw:");
const char *p = str;
- while (*p) debugN(" %02X", (unsigned char)*p++);
+ while (*p)
+ debugN(" %02X", (unsigned char)*p++);
debugN("\n");
}
return Graphics::getStringWidth16(str);
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
index c76532b302..be636738a8 100644
--- a/engines/touche/touche.h
+++ b/engines/touche/touche.h
@@ -330,6 +330,7 @@ enum {
kScreenHeight = 400,
kRoomHeight = 352,
kStartupEpisode = 90,
+ // TODO: If the following truncation is intentional (it probably is) it should be clearly marked as such
kCycleDelay = 1000 / (1193180 / 32768),
kIconWidth = 58,
kIconHeight = 42,
diff --git a/engines/tsage/blue_force/blueforce_scenes9.cpp b/engines/tsage/blue_force/blueforce_scenes9.cpp
index 5bcc44a2b9..28023cf363 100644
--- a/engines/tsage/blue_force/blueforce_scenes9.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes9.cpp
@@ -3165,7 +3165,7 @@ bool Scene930::Object4::startAction(CursorType action, Event &event) {
if (BF_GLOBALS._bookmark >= bFlashBackTwo) {
_lookLineNum = 71;
NamedObject::startAction(action, event);
- scene->ShowSoleInset();
+ scene->showSoleInset();
remove();
} else
NamedObject::startAction(action, event);
@@ -3304,7 +3304,7 @@ void Scene930::Action2::signal() {
SET_Y, GLOBALS._sceneManager._scene->_sceneBounds.top + UI_INTERFACE_Y + 2,
SET_FONT, 4, SET_BG_COLOR, 1, SET_FG_COLOR, 19, SET_EXT_BGCOLOR, 9,
SET_EXT_FGCOLOR, 13, LIST_END);
- scene->ShowBoxInset();
+ scene->showBoxInset();
BF_GLOBALS._player.enableControl();
remove();
break;
@@ -3460,7 +3460,7 @@ void Scene930::showBootInset() {
_bootsInset.setDetails(930, 69, 70, 93);
}
-void Scene930::ShowBoxInset() {
+void Scene930::showBoxInset() {
_boxInset.postInit();
_boxInset.setVisage(930);
_boxInset.setStrip(1);
@@ -3470,7 +3470,7 @@ void Scene930::ShowBoxInset() {
_boxInset.setDetails(930, 73, 74, 75);
}
-void Scene930::ShowSoleInset() {
+void Scene930::showSoleInset() {
_soleInset.postInit();
_soleInset.setVisage(930);
_soleInset.setStrip(3);
diff --git a/engines/tsage/blue_force/blueforce_scenes9.h b/engines/tsage/blue_force/blueforce_scenes9.h
index 52935debd4..eb6f481edc 100644
--- a/engines/tsage/blue_force/blueforce_scenes9.h
+++ b/engines/tsage/blue_force/blueforce_scenes9.h
@@ -380,8 +380,8 @@ class Scene930: public PalettedScene {
};
void showBootInset();
- void ShowBoxInset();
- void ShowSoleInset();
+ void showBoxInset();
+ void showSoleInset();
public:
SequenceManager _sequenceManager1;
Object1 _box;
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index e476391f71..5d31cca75e 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -131,9 +131,6 @@ public:
if (in) {
if (TsAGE::Saver::readSavegameHeader(in, header)) {
saveList.push_back(SaveStateDescriptor(slot, header._saveName));
-
- header._thumbnail->free();
- delete header._thumbnail;
}
delete in;
@@ -161,7 +158,11 @@ public:
if (f) {
TsAGE::tSageSavegameHeader header;
- TsAGE::Saver::readSavegameHeader(f, header);
+ if (!TsAGE::Saver::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
+
delete f;
// Create the return descriptor
diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp
index 03f615db21..81bb973d02 100644
--- a/engines/tsage/saveload.cpp
+++ b/engines/tsage/saveload.cpp
@@ -189,10 +189,10 @@ Common::Error Saver::restore(int slot) {
// Read in the savegame header
tSageSavegameHeader header;
- readSavegameHeader(saveFile, header);
- if (header._thumbnail)
- header._thumbnail->free();
- delete header._thumbnail;
+ if (!readSavegameHeader(saveFile, header)) {
+ delete saveFile;
+ return Common::kReadingFailed;
+ }
serializer.setSaveVersion(header._version);
@@ -247,9 +247,8 @@ Common::Error Saver::restore(int slot) {
const char *SAVEGAME_STR = "SCUMMVM_TSAGE";
#define SAVEGAME_STR_SIZE 13
-bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header) {
+WARN_UNUSED_RESULT bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = NULL;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -266,9 +265,9 @@ bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &head
while ((ch = (char)in->readByte()) != '\0') header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header._saveYear = in->readSint16LE();
diff --git a/engines/tsage/saveload.h b/engines/tsage/saveload.h
index 04a1e02b28..3de34489fd 100644
--- a/engines/tsage/saveload.h
+++ b/engines/tsage/saveload.h
@@ -221,7 +221,7 @@ public:
Common::Error save(int slot, const Common::String &saveName);
Common::Error restore(int slot);
- static bool readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header, bool skipThumbnail = true);
static void writeSavegameHeader(Common::OutSaveFile *out, tSageSavegameHeader &header);
void addListener(SaveListener *obj);
diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp
index 7d07edabd3..2318947b12 100644
--- a/engines/tucker/detection.cpp
+++ b/engines/tucker/detection.cpp
@@ -149,18 +149,19 @@ public:
return desc != 0;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
for (Common::FSList::const_iterator d = fslist.begin(); d != fslist.end(); ++d) {
Common::FSList audiofslist;
if (d->isDirectory() && d->getName().equalsIgnoreCase("audio") && d->getChildren(audiofslist, Common::FSNode::kListFilesOnly)) {
for (Common::FSList::const_iterator f = audiofslist.begin(); f != audiofslist.end(); ++f) {
if (!f->isDirectory() && f->getName().equalsIgnoreCase("demorolc.raw")) {
- return &tuckerDemoGameDescription;
+ return ADDetectedGame(&tuckerDemoGameDescription);
}
}
}
}
- return 0;
+
+ return ADDetectedGame();
}
virtual SaveStateList listSaves(const char *target) const {
@@ -175,7 +176,7 @@ public:
if (ext && (slot = atoi(ext + 1)) >= 0 && slot <= Tucker::kLastSaveSlot) {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- if (Tucker::TuckerEngine::readSavegameHeader(in, header, false) == Tucker::TuckerEngine::kSavegameNoError) {
+ if (Tucker::TuckerEngine::readSavegameHeader(in, header) == Tucker::TuckerEngine::kSavegameNoError) {
saveList.push_back(SaveStateDescriptor(slot, header.description));
}
@@ -207,7 +208,7 @@ public:
}
Tucker::TuckerEngine::SavegameHeader header;
- Tucker::TuckerEngine::SavegameError savegameError = Tucker::TuckerEngine::readSavegameHeader(file, header, true);
+ Tucker::TuckerEngine::SavegameError savegameError = Tucker::TuckerEngine::readSavegameHeader(file, header, false);
if (savegameError) {
delete file;
return SaveStateDescriptor();
diff --git a/engines/tucker/locations.cpp b/engines/tucker/locations.cpp
index 28fca114b0..d78eacc55d 100644
--- a/engines/tucker/locations.cpp
+++ b/engines/tucker/locations.cpp
@@ -217,7 +217,7 @@ void TuckerEngine::execData3PreUpdate_locationNum2Helper() {
return;
}
int start, end;
- if (_locationNum == 2) {
+ if (_location == kLocationBackAlley) {
start = 116;
end = 125;
} else {
@@ -2050,8 +2050,8 @@ void TuckerEngine::execData3PreUpdate_locationNum41() {
if (_panelLockedFlag && _yPosCurrent > 130 && _selectedObject._yPos > 135 && _nextAction == 0 && _flagsTable[223] == 0) {
_panelLockedFlag = false;
_csDataLoaded = false;
- _nextLocationNum = 0;
- _selectedObject._locationObjectLocationNum = 0;
+ _nextLocation = kLocationNone;
+ _selectedObject._locationObjectLocation = kLocationNone;
_locationMaskType = 0;
_nextAction = _flagsTable[163] + 32;
++_flagsTable[163];
@@ -2084,7 +2084,7 @@ void TuckerEngine::updateSprite_locationNum42(int i) {
} else if (_flagsTable[223] == 3) {
state = 5;
_spritesTable[i]._updateDelay = 5;
- _spritesTable[i]._state = _spritesTable[i]._firstFrame - 1; // FIXME: bug, fxNum ?
+ _spritesTable[i]._state = _spritesTable[i]._firstFrame - 1;
_updateSpriteFlag1 = true;
} else {
state = 2;
@@ -2482,7 +2482,7 @@ void TuckerEngine::updateSprite_locationNum58(int i) {
void TuckerEngine::execData3PreUpdate_locationNum58() {
// workaround original game glitch #2872348: do not change position on location change
- if (_nextLocationNum == 0 && _flagsTable[190] < 3 && _xPosCurrent > 310) {
+ if (_nextLocation == kLocationNone && _flagsTable[190] < 3 && _xPosCurrent > 310) {
_xPosCurrent = 310;
_panelLockedFlag = false;
}
@@ -2893,13 +2893,25 @@ void TuckerEngine::updateSprite_locationNum66_4(int i) {
}
void TuckerEngine::execData3PreUpdate_locationNum66() {
- // FIXME: shouldn't be executed after using the map
+ // WORKAROUND
+ // If you don't have the appointment card yet and use the map to go to
+ // Seedy Street Bud ends up being teleported back to the mall.
+ // Because of the destination coordinates which warp Bud past x==583 the
+ // below 'if' triggers and automatically makes Violet refuse Bud entrance
+ // to the dentist. On top of that the graphics end up all garbled which
+ // indicates that even worse things happen under the hood.
+ // To work around this we only trigger Violet if Bud actually _walked_ past
+ // the trigger coordinates (as opposed to using the map).
+ // Fixes Trac#10452.
+ if (_nextLocation != kLocationNone)
+ return;
+
_flagsTable[137] = 0;
if (_xPosCurrent > 583 && _flagsTable[191] == 0 && _nextAction == 0 && _locationMaskType == 0) {
_panelLockedFlag = false;
_csDataLoaded = false;
- _nextLocationNum = 0;
- _selectedObject._locationObjectLocationNum = 0;
+ _nextLocation = kLocationNone;
+ _selectedObject._locationObjectLocation = kLocationNone;
if (_flagsTable[131] == 0) {
_nextAction = 13;
} else if (_flagsTable[130] == 0) {
diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp
index 0ea24adf2d..5d7ae2c2d5 100644
--- a/engines/tucker/resource.cpp
+++ b/engines/tucker/resource.cpp
@@ -491,36 +491,36 @@ void TuckerEngine::loadCTable02() {
void TuckerEngine::loadLoc() {
Common::String filename;
- int i = _locationWidthTable[_locationNum];
- _locationHeight = (_locationNum < 73) ? 140 : 200;
- filename = Common::String::format((i == 1) ? "loc%02d.pcx" : "loc%02da.pcx", _locationNum);
+ int i = _locationWidthTable[_location];
+ _locationHeight = (_location < kLocationJesusCutscene1) ? 140 : 200;
+ filename = Common::String::format((i == 1) ? "loc%02d.pcx" : "loc%02da.pcx", _location);
copyLocBitmap(filename.c_str(), 0, false);
Graphics::copyRect(_quadBackgroundGfxBuf, 320, _locationBackgroundGfxBuf, 640, 320, _locationHeight);
if (_locationHeight == 200) {
return;
}
- filename = Common::String::format((i != 2) ? "path%02d.pcx" : "path%02da.pcx", _locationNum);
+ filename = Common::String::format((i != 2) ? "path%02d.pcx" : "path%02da.pcx", _location);
copyLocBitmap(filename.c_str(), 0, true);
if (i > 1) {
- filename = Common::String::format("loc%02db.pcx", _locationNum);
+ filename = Common::String::format("loc%02db.pcx", _location);
copyLocBitmap(filename.c_str(), 320, false);
Graphics::copyRect(_quadBackgroundGfxBuf + 44800, 320, _locationBackgroundGfxBuf + 320, 640, 320, _locationHeight);
if (i == 2) {
- filename = Common::String::format("path%02db.pcx", _locationNum);
+ filename = Common::String::format("path%02db.pcx", _location);
copyLocBitmap(filename.c_str(), 320, true);
}
}
if (i > 2) {
- filename = Common::String::format("loc%02dc.pcx", _locationNum);
+ filename = Common::String::format("loc%02dc.pcx", _location);
copyLocBitmap(filename.c_str(), 0, false);
Graphics::copyRect(_quadBackgroundGfxBuf + 89600, 320, _locationBackgroundGfxBuf, 640, 320, 140);
}
- if (_locationNum == 1) {
+ if (_location == kLocationHotelRoom) {
_loadLocBufPtr = _quadBackgroundGfxBuf + 89600;
loadImage("rochpath.pcx", _loadLocBufPtr, 0);
}
if (i > 3) {
- filename = Common::String::format("loc%02dd.pcx", _locationNum);
+ filename = Common::String::format("loc%02dd.pcx", _location);
copyLocBitmap(filename.c_str(), 0, false);
Graphics::copyRect(_quadBackgroundGfxBuf + 134400, 320, _locationBackgroundGfxBuf + 320, 640, 320, 140);
}
@@ -528,13 +528,15 @@ void TuckerEngine::loadLoc() {
}
void TuckerEngine::loadObj() {
- if (_locationNum == 99) {
+ if (_location == kLocationMap) {
return;
}
- if (_locationNum < 24) {
+ if (_location <= kLocationWarehouseCutscene) {
_part = kPartOne;
_speechSoundBaseNum = 2639;
- } else if (_locationNum < 41 || (_locationNum > 69 && _locationNum < 73) || (_locationNum > 78 && _locationNum < 83)) {
+ } else if (( _location <= kLocationFarDocks)
+ || (_location >= kLocationComputerScreen && _location <= kLocationSeedyStreetCutscene)
+ || (_location >= kLocationElvisCutscene && _location <= kLocationJesusCutscene2)) {
_part = kPartTwo;
_speechSoundBaseNum = 2679;
} else {
@@ -544,7 +546,7 @@ void TuckerEngine::loadObj() {
if (_part == _currentPart) {
return;
}
- debug(2, "loadObj() part %d locationNum %d", _part, _locationNum);
+ debug(2, "loadObj() part %d location %d", _part, _location);
// If a savegame is loaded from the launcher, skip the display chapter
if (_startSlot != -1)
_startSlot = -1;
@@ -631,7 +633,7 @@ void TuckerEngine::loadData3() {
loadFile("data3.c", _loadTempBuf);
DataTokenizer t(_loadTempBuf, _fileLoadSize);
_locationAnimationsCount = 0;
- if (t.findIndex(_locationNum)) {
+ if (t.findIndex(_location)) {
while (t.findNextToken(kDataTokenDw)) {
int num = t.getNextInteger();
if (num < 0) {
@@ -678,7 +680,7 @@ void TuckerEngine::loadData4() {
_displayGameHints = t.getNextInteger() != 0;
}
_locationObjectsCount = 0;
- if (t.findIndex(_locationNum)) {
+ if (t.findIndex(_location)) {
while (t.findNextToken(kDataTokenDw)) {
int i = t.getNextInteger();
if (i < 0)
@@ -694,8 +696,8 @@ void TuckerEngine::loadData4() {
d->_standY = t.getNextInteger();
d->_textNum = t.getNextInteger();
d->_cursorStyle = (CursorStyle)t.getNextInteger();
- d->_locationNum = t.getNextInteger();
- if (d->_locationNum > 0) {
+ d->_location = (Location)t.getNextInteger();
+ if (d->_location != kLocationNone) {
d->_toX = t.getNextInteger();
d->_toY = t.getNextInteger();
d->_toX2 = t.getNextInteger();
@@ -708,29 +710,19 @@ void TuckerEngine::loadData4() {
}
void TuckerEngine::loadActionFile() {
- char filename[40];
- if ((_gameFlags & kGameFlagDemo) != 0) {
- strcpy(filename, "action.c");
+ assert(_part != kPartInit);
+
+ Common::String filename;
+ if (_gameFlags & kGameFlagDemo) {
+ filename = "action.c";
} else {
- switch (_part) {
- case kPartOne:
- strcpy(filename, "action1.c");
- break;
- case kPartTwo:
- strcpy(filename, "action2.c");
- break;
- case kPartThree:
- strcpy(filename, "action3.c");
- break;
- default:
- break;
- }
+ filename = Common::String::format("action%d.c", _part);
}
- loadFile(filename, _loadTempBuf);
+ loadFile(filename.c_str(), _loadTempBuf);
DataTokenizer t(_loadTempBuf, _fileLoadSize);
_actionsCount = 0;
- if (t.findIndex(_locationNum)) {
+ if (t.findIndex(_location)) {
while (t.findNextToken(kDataTokenDw)) {
int keyA = t.getNextInteger();
if (keyA < 0) {
@@ -763,7 +755,7 @@ void TuckerEngine::loadCharPos() {
loadFile("charpos.c", _loadTempBuf);
DataTokenizer t(_loadTempBuf, _fileLoadSize);
_charPosCount = 0;
- if (t.findIndex(_locationNum)) {
+ if (t.findIndex(_location)) {
while (t.findNextToken(kDataTokenDw)) {
const int i = t.getNextInteger();
if (i < 0) {
@@ -823,9 +815,9 @@ void TuckerEngine::loadCharPos() {
void TuckerEngine::loadSprA02_01() {
unloadSprA02_01();
- const int count = _sprA02LookupTable[_locationNum];
+ const int count = _sprA02LookupTable[_location];
for (int i = 1; i < count + 1; ++i) {
- Common::String filename = Common::String::format("sprites/a%02d_%02d.spr", _locationNum, i);
+ Common::String filename = Common::String::format("sprites/a%02d_%02d.spr", _location, i);
_sprA02Table[i] = loadFile(filename.c_str(), 0);
}
_sprA02Table[0] = _sprA02Table[1];
@@ -841,13 +833,13 @@ void TuckerEngine::unloadSprA02_01() {
void TuckerEngine::loadSprC02_01() {
unloadSprC02_01();
- const int count = _sprC02LookupTable[_locationNum];
+ const int count = _sprC02LookupTable[_location];
for (int i = 1; i < count + 1; ++i) {
- Common::String filename = Common::String::format("sprites/c%02d_%02d.spr", _locationNum, i);
+ Common::String filename = Common::String::format("sprites/c%02d_%02d.spr", _location, i);
_sprC02Table[i] = loadFile(filename.c_str(), 0);
}
_sprC02Table[0] = _sprC02Table[1];
- _spritesCount = _sprC02LookupTable2[_locationNum];
+ _spritesCount = _sprC02LookupTable2[_location];
for (int i = 0; i < kMaxCharacters; ++i) {
memset(&_spritesTable[i], 0, sizeof(Sprite));
_spritesTable[i]._state = -1;
@@ -866,7 +858,7 @@ void TuckerEngine::unloadSprC02_01() {
void TuckerEngine::loadFx() {
loadFile("fx.c", _loadTempBuf);
DataTokenizer t(_loadTempBuf, _fileLoadSize);
- if (t.findIndex(_locationNum)) {
+ if (t.findIndex(_location)) {
t.findNextToken(kDataTokenDw);
_locationSoundsCount = t.getNextInteger();
_currentFxSet = 0;
@@ -937,7 +929,7 @@ void TuckerEngine::loadFx() {
}
}
} else {
- error("loadFx() - Index not found for location %d", _locationNum);
+ error("loadFx() - Index not found for location %d", _location);
}
}
@@ -993,7 +985,7 @@ void TuckerEngine::loadActionsTable() {
do {
if (!_csDataLoaded) {
DataTokenizer t(_csDataBuf, _csDataSize);
- bool found = t.findIndex(_locationNum);
+ bool found = t.findIndex(_location);
assert(found);
for (int i = 0; i < _nextAction; ++i) {
found = t.findNextToken(kDataTokenDw);
diff --git a/engines/tucker/saveload.cpp b/engines/tucker/saveload.cpp
index 4e33988ed2..00911b9c44 100644
--- a/engines/tucker/saveload.cpp
+++ b/engines/tucker/saveload.cpp
@@ -50,36 +50,44 @@ Common::String generateGameStateFileName(const char *target, int slot, bool pref
return name;
}
-static void saveOrLoadInt(Common::WriteStream &stream, int &i) {
+static void saveOrLoadVar(Common::WriteStream &stream, int &i) {
stream.writeSint32LE(i);
}
-static void saveOrLoadInt(Common::ReadStream &stream, int &i) {
+static void saveOrLoadVar(Common::ReadStream &stream, int &i) {
i = stream.readSint32LE();
}
+static void saveOrLoadVar(Common::WriteStream &stream, Location &location) {
+ stream.writeSint32LE((int)location);
+}
+
+static void saveOrLoadVar(Common::ReadStream &stream, Location &location) {
+ location = (Location)stream.readSint32LE();
+}
+
template<class S>
TuckerEngine::SavegameError TuckerEngine::saveOrLoadGameStateData(S &s) {
for (int i = 0; i < kFlagsTableSize; ++i) {
- saveOrLoadInt(s, _flagsTable[i]);
+ saveOrLoadVar(s, _flagsTable[i]);
}
for (int i = 0; i < 40; ++i) {
- saveOrLoadInt(s, _inventoryObjectsList[i]);
+ saveOrLoadVar(s, _inventoryObjectsList[i]);
}
for (int i = 0; i < 50; ++i) {
- saveOrLoadInt(s, _inventoryItemsState[i]);
+ saveOrLoadVar(s, _inventoryItemsState[i]);
}
for (int i = 0; i < 50; ++i) {
- saveOrLoadInt(s, _panelObjectsOffsetTable[i]);
+ saveOrLoadVar(s, _panelObjectsOffsetTable[i]);
}
- saveOrLoadInt(s, _mainSpritesBaseOffset);
- saveOrLoadInt(s, _selectedObject._xPos);
- saveOrLoadInt(s, _selectedObject._yPos);
- saveOrLoadInt(s, _locationNum);
- saveOrLoadInt(s, _xPosCurrent);
- saveOrLoadInt(s, _yPosCurrent);
- saveOrLoadInt(s, _inventoryObjectsCount);
- saveOrLoadInt(s, _inventoryObjectsOffset);
+ saveOrLoadVar(s, _mainSpritesBaseOffset);
+ saveOrLoadVar(s, _selectedObject._xPos);
+ saveOrLoadVar(s, _selectedObject._yPos);
+ saveOrLoadVar(s, _location);
+ saveOrLoadVar(s, _xPosCurrent);
+ saveOrLoadVar(s, _yPosCurrent);
+ saveOrLoadVar(s, _inventoryObjectsCount);
+ saveOrLoadVar(s, _inventoryObjectsOffset);
return s.err() ? kSavegameIoError : kSavegameNoError;
}
@@ -101,18 +109,18 @@ Common::Error TuckerEngine::loadGameState(int slot) {
if (savegameError) {
switch (savegameError) {
- case kSavegameInvalidTypeError:
- warning("Invalid savegame '%s' (does not look like a ScummVM Tucker-engine savegame)", fileName.c_str());
- break;
-
- case kSavegameInvalidVersionError:
- warning("Invalid savegame '%s' (expected savegame version v%i-v%i, got v%i)",
- fileName.c_str(), kSavegameVersionMinimum, kSavegameVersionCurrent, header.version);
- break;
-
- default:
- warning("Failed to load savegame '%s'", fileName.c_str());
- break;
+ case kSavegameInvalidTypeError:
+ warning("Invalid savegame '%s' (does not look like a ScummVM Tucker-engine savegame)", fileName.c_str());
+ break;
+
+ case kSavegameInvalidVersionError:
+ warning("Invalid savegame '%s' (expected savegame version v%i-v%i, got v%i)",
+ fileName.c_str(), kSavegameVersionMinimum, kSavegameVersionCurrent, header.version);
+ break;
+
+ default:
+ warning("Failed to load savegame '%s'", fileName.c_str());
+ break;
}
delete file;
@@ -121,17 +129,19 @@ Common::Error TuckerEngine::loadGameState(int slot) {
g_engine->setTotalPlayTime(header.playTime * 1000);
- _nextLocationNum = _locationNum;
+ _nextLocation = _location;
setBlackPalette();
loadBudSpr();
_forceRedrawPanelItems = true;
+ _panelType = kPanelTypeNormal;
+ setCursorState(kCursorStateNormal);
delete file;
return Common::kNoError;
}
-TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(const char *target, int slot, SavegameHeader &header) {
+WARN_UNUSED_RESULT TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(const char *target, int slot, SavegameHeader &header) {
Common::String fileName = generateGameStateFileName(target, slot);
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
@@ -145,8 +155,8 @@ TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(const char *target,
return savegameError;
}
-TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool loadThumbnail) {
- header.version = -1;
+WARN_UNUSED_RESULT TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool skipThumbnail) {
+ header.version = 0;
header.flags = 0;
header.description.clear();
header.saveDate = 0;
@@ -186,10 +196,8 @@ TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(Common::InSaveFile
header.saveTime = file->readUint32LE();
header.playTime = file->readUint32LE();
- if (loadThumbnail) {
- header.thumbnail = Graphics::loadThumbnail(*file);
- } else {
- Graphics::skipThumbnail(*file);
+ if (!Graphics::loadThumbnail(*file, header.thumbnail, skipThumbnail)) {
+ return kSavegameIoError;
}
}
@@ -278,13 +286,19 @@ bool TuckerEngine::isAutosaveAllowed(const char *target) {
void TuckerEngine::writeAutosave() {
if (canSaveGameStateCurrently()) {
+ // unconditionally reset last autosave timestamp so we don't start
+ // hammering the disk in case we can't/don't actually write the file
+ _lastSaveTime = _system->getMillis();
+
if (!isAutosaveAllowed()) {
warning("Refusing to overwrite non-autosave savegame in slot %i, skipping autosave", kAutoSaveSlot);
return;
}
- writeSavegame(kAutoSaveSlot, "Autosave", true);
- _lastSaveTime = _system->getMillis();
+ if (writeSavegame(kAutoSaveSlot, "Autosave", true).getCode() != Common::kNoError) {
+ warning("Can't create autosave in slot %i, game not saved", kAutoSaveSlot);
+ return;
+ }
}
}
diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp
index cefb9e90e1..fd66c4f49c 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -50,13 +50,13 @@ void TuckerEngine::handleCreditsSequence() {
int counter3 = 0;
int num = 0;
int imgNum = 0;
- int prevLocationNum = _locationNum;
+ Location prevLocation = _location;
int counter2 = 0;
int counter1 = 0;
loadCharset2();
showCursor(false);
stopSounds();
- _locationNum = 74;
+ _location = kLocationCredits;
_flagsTable[236] = 74;
uint8 *imgBuf = (uint8 *)malloc(16 * 64000);
loadSprC02_01();
@@ -151,7 +151,7 @@ void TuckerEngine::handleCreditsSequence() {
}
} while (!_quitGame && isSpeechSoundPlaying());
free(imgBuf);
- _locationNum = prevLocationNum;
+ _location = prevLocation;
do {
if (_fadePaletteCounter > 0) {
fadeInPalette();
@@ -185,7 +185,9 @@ void TuckerEngine::handleCongratulationsSequence() {
}
void TuckerEngine::handleNewPartSequence() {
- char filename[40];
+ assert(_part != kPartInit);
+
+ Common::String filename;
showCursor(false);
stopSounds();
@@ -204,40 +206,29 @@ void TuckerEngine::handleNewPartSequence() {
_redrawPanelItemsCounter = 0;
}
_scrollOffset = 0;
- switch (_part) {
- case kPartOne:
- strcpy(filename, "pt1bak.pcx");
- break;
- case kPartTwo:
- strcpy(filename, "pt2bak.pcx");
- break;
- case kPartThree:
- strcpy(filename, "pt3bak.pcx");
- break;
- default:
- break;
- }
- loadImage(filename, _quadBackgroundGfxBuf, 1);
+
+ filename = Common::String::format("pt%dbak.pcx", _part);
+ loadImage(filename.c_str(), _quadBackgroundGfxBuf, 1);
_spritesCount = 1;
clearSprites();
- int currentLocation = _locationNum;
- _locationNum = 98;
+ Location currentLocation = _location;
+ _location = kLocationNewPart;
unloadSprA02_01();
unloadSprC02_01();
switch (_part) {
- case kPartOne:
- strcpy(filename, "sprites/partone.spr");
- break;
- case kPartTwo:
- strcpy(filename, "sprites/parttwo.spr");
- break;
- case kPartThree:
- strcpy(filename, "sprites/partthr.spr");
- break;
- default:
- break;
+ case kPartOne:
+ filename = "sprites/partone.spr";
+ break;
+ case kPartTwo:
+ filename = "sprites/parttwo.spr";
+ break;
+ case kPartThree:
+ filename = "sprites/partthr.spr";
+ break;
+ default:
+ break;
}
- _sprC02Table[1] = loadFile(filename, 0);
+ _sprC02Table[1] = loadFile(filename.c_str(), 0);
startSpeechSound(9000, 60);
_fadePaletteCounter = 0;
do {
@@ -269,31 +260,21 @@ void TuckerEngine::handleNewPartSequence() {
redrawScreen(0);
waitForTimer(3);
} while (_fadePaletteCounter > 0 && !_quitGame);
- _locationNum = currentLocation;
+ _location = currentLocation;
showCursor(true);
}
void TuckerEngine::handleMeanwhileSequence() {
- char filename[40];
+ assert(_part != kPartInit);
+
+ Common::String filename;
uint8 backupPalette[256 * 3];
memcpy(backupPalette, _currentPalette, 256 * 3);
- switch (_part) {
- case kPartOne:
- strcpy(filename, "meanw01.pcx");
- break;
- case kPartTwo:
- strcpy(filename, "meanw02.pcx");
- break;
- case kPartThree:
- strcpy(filename, "meanw03.pcx");
- break;
- default:
- break;
- }
+ filename = Common::String::format("meanw%02d.pcx", _part);
if (_flagsTable[215] == 0 && _flagsTable[231] == 1) {
- strcpy(filename, "loc80.pcx");
+ filename = "loc80.pcx";
}
- loadImage(filename, _quadBackgroundGfxBuf + 89600, 1);
+ loadImage(filename.c_str(), _quadBackgroundGfxBuf + 89600, 1);
showCursor(false);
_fadePaletteCounter = 0;
for (int i = 0; i < 60 && !_quitGame; ++i) {
@@ -328,7 +309,7 @@ void TuckerEngine::handleMeanwhileSequence() {
void TuckerEngine::handleMapSequence() {
loadImage("map2.pcx", _quadBackgroundGfxBuf + 89600, 0);
loadImage("map1.pcx", _loadTempBuf, 1);
- _selectedObject._locationObjectLocationNum = 0;
+ _selectedObject._locationObjectLocation = kLocationNone;
if (_flagsTable[7] > 0) {
copyMapRect(0, 0, 140, 86);
}
@@ -345,53 +326,54 @@ void TuckerEngine::handleMapSequence() {
copyMapRect(220, 0, 100, 180);
}
_fadePaletteCounter = 0;
- int xPos = 0, yPos = 0, textNum = 0;
+ int xPos = 0, yPos = 0;
while (!_quitGame) {
+ int textNum = 0;
waitForTimer(2);
updateMouseState();
Graphics::copyRect(_locationBackgroundGfxBuf + _scrollOffset, 640, _quadBackgroundGfxBuf + 89600, 320, 320, 200);
_fullRedraw = true;
if (_flagsTable[7] > 0 && _mousePosX > 30 && _mousePosX < 86 && _mousePosY > 36 && _mousePosY < 86) {
textNum = 13;
- _nextLocationNum = (_part == kPartOne) ? 3 : 65;
+ _nextLocation = (_part == kPartOne) ? kLocationSeedyStreet : kLocationSeedyStreetPartThree;
xPos = 620;
yPos = 130;
} else if (_flagsTable[7] > 1 && _mousePosX > 60 && _mousePosX < 120 && _mousePosY > 120 && _mousePosY < 170) {
textNum = 14;
- _nextLocationNum = (_part == kPartOne) ? 9 : 66;
+ _nextLocation = (_part == kPartOne) ? kLocationMall : kLocationMallPartThree;
xPos = 344;
yPos = 120;
} else if (_flagsTable[7] > 2 && _mousePosX > 160 && _mousePosX < 210 && _mousePosY > 110 && _mousePosY < 160) {
textNum = 15;
- _nextLocationNum = (_part == kPartOne) ? 16 : 61;
+ _nextLocation = (_part == kPartOne) ? kLocationPark : kLocationParkPartThree;
xPos = 590;
yPos = 130;
} else if ((_flagsTable[7] == 4 || _flagsTable[7] == 6) && _mousePosX > 150 && _mousePosX < 200 && _mousePosY > 20 && _mousePosY < 70) {
textNum = 16;
- _nextLocationNum = (_part == kPartOne) ? 20 : 68;
+ _nextLocation = (_part == kPartOne) ? kLocationOutsideMuseum : kLocationOutsideMuseumPartThree;
xPos = 20;
yPos = 130;
} else if (_flagsTable[120] == 1 && _mousePosX > 240 && _mousePosX < 290 && _mousePosY > 35 && _mousePosY < 90) {
textNum = 17;
- _nextLocationNum = (_part == kPartOne) ? 19 : 62;
+ _nextLocation = (_part == kPartOne) ? kLocationDocks : kLocationDocksPartThree;
xPos = 20;
yPos = 124;
} else if (_mousePosX > 135 && _mousePosX < 185 && _mousePosY > 170 && _mousePosY < 200) {
textNum = 18;
- _nextLocationNum = _locationNum;
+ _nextLocation = _location;
if (!_noPositionChangeAfterMap) {
xPos = _xPosCurrent;
yPos = _yPosCurrent;
- } else if (_locationNum == 3 || _locationNum == 65) {
+ } else if (_location == kLocationSeedyStreet || _location == kLocationSeedyStreetPartThree) {
xPos = 620;
yPos = 130;
- } else if (_locationNum == 9 || _locationNum == 66) {
+ } else if (_location == kLocationMall || _location == kLocationMallPartThree) {
xPos = 344;
yPos = 120;
- } else if (_locationNum == 16 || _locationNum == 61) {
+ } else if (_location == kLocationPark || _location == kLocationParkPartThree) {
xPos = 590;
yPos = 130;
- } else if (_locationNum == 20 || _locationNum == 68) {
+ } else if (_location == kLocationOutsideMuseum || _location == kLocationOutsideMuseumPartThree) {
xPos = 20;
yPos = 130;
} else {
@@ -417,11 +399,11 @@ void TuckerEngine::handleMapSequence() {
--_fadePaletteCounter;
}
_mouseClick = 1;
- if (_nextLocationNum == 9 && _noPositionChangeAfterMap) {
+ if (_nextLocation == kLocationMall && _noPositionChangeAfterMap) {
_backgroundSpriteCurrentAnimation = 2;
_backgroundSpriteCurrentFrame = 0;
setCursorState(kCursorStateDisabledHidden);
- } else if (_nextLocationNum == 66 && _noPositionChangeAfterMap) {
+ } else if (_nextLocation == kLocationMallPartThree && _noPositionChangeAfterMap) {
_backgroundSpriteCurrentAnimation = 1;
_backgroundSpriteCurrentFrame = 0;
setCursorState(kCursorStateDisabledHidden);
@@ -442,21 +424,21 @@ void TuckerEngine::copyMapRect(int x, int y, int w, int h) {
}
bool TuckerEngine::handleSpecialObjectSelectionSequence() {
- char filename[40];
+ Common::String filename;
if (_part == kPartOne && _selectedObjectNum == 6) {
- strcpy(filename, "news1.pcx");
+ filename = "news1.pcx";
_flagsTable[7] = 4;
} else if (_part == kPartThree && _selectedObjectNum == 45) {
- strcpy(filename, "profnote.pcx");
+ filename = "profnote.pcx";
} else if (_part == kPartOne && _selectedObjectNum == 26) {
- strcpy(filename, "photo.pcx");
+ filename = "photo.pcx";
} else if (_part == kPartThree && _selectedObjectNum == 39) {
- strcpy(filename, "news2.pcx");
+ filename = "news2.pcx";
_flagsTable[135] = 1;
} else if (_currentInfoString1SourceType == 0 && _currentActionObj1Num == 259) {
- strcpy(filename, "postit.pcx");
+ filename = "postit.pcx";
} else if (_currentInfoString1SourceType == 1 && _currentActionObj1Num == 91) {
- strcpy(filename, "memo.pcx");
+ filename = "memo.pcx";
} else {
return false;
}
@@ -466,7 +448,7 @@ bool TuckerEngine::handleSpecialObjectSelectionSequence() {
--_fadePaletteCounter;
}
_mouseClick = 1;
- loadImage(filename, _quadBackgroundGfxBuf, 1);
+ loadImage(filename.c_str(), _quadBackgroundGfxBuf, 1);
_fadePaletteCounter = 0;
while (!_quitGame) {
waitForTimer(2);
diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp
index 56247a126d..3a49260ab5 100644
--- a/engines/tucker/tucker.cpp
+++ b/engines/tucker/tucker.cpp
@@ -157,11 +157,11 @@ void TuckerEngine::resetVariables() {
_mainLoopCounter1 = _mainLoopCounter2 = 0;
_timerCounter2 = 0;
_part = _currentPart = kPartInit;
- _locationNum = 0;
- _nextLocationNum = (_gameFlags & kGameFlagDemo) == 0 ? kStartupLocationGame : kStartupLocationDemo;
+ _location = kLocationNone;
+ _nextLocation = (_gameFlags & kGameFlagDemo) ? kLocationInitDemo : kLocationInit;
_gamePaused = false;
_gameDebug = false;
- _displaySpeechText = (_gameFlags & kGameFlagNoSubtitles) == 0 ? ConfMan.getBool("subtitles") : false;
+ _displaySpeechText = (_gameFlags & kGameFlagNoSubtitles) ? false : ConfMan.getBool("subtitles");
memset(_flagsTable, 0, sizeof(_flagsTable));
_gameHintsIndex = 0;
@@ -400,7 +400,7 @@ void TuckerEngine::mainLoop() {
loadGameState(slot);
}
} else if (ConfMan.hasKey("boot_param")) {
- _nextLocationNum = ConfMan.getInt("boot_param");
+ _nextLocation = (Location)ConfMan.getInt("boot_param");
}
do {
@@ -427,7 +427,7 @@ void TuckerEngine::mainLoop() {
if (_nextAction != 0) {
loadActionsTable();
}
- if (_nextLocationNum > 0) {
+ if (_nextLocation != kLocationNone) {
setupNewLocation();
}
updateCharPosition();
@@ -499,13 +499,13 @@ void TuckerEngine::mainLoop() {
}
}
_mainSpritesBaseOffset = 0;
- if (_locationWidthTable[_locationNum] > 3) {
+ if (_locationWidthTable[_location] > 3) {
++_currentGfxBackgroundCounter;
if (_currentGfxBackgroundCounter > 39) {
_currentGfxBackgroundCounter = 0;
}
_currentGfxBackground = _quadBackgroundGfxBuf + (_currentGfxBackgroundCounter / 10) * 44800;
- if (_fadePaletteCounter < 34 && _locationNum == 22) {
+ if (_fadePaletteCounter < 34 && _location == kLocationFishingTrawler) {
int offset = (_currentGfxBackgroundCounter > 29 ? 1 : (_currentGfxBackgroundCounter / 10));
_spritesTable[0]._gfxBackgroundOffset = offset * 640;
_mainSpritesBaseOffset = offset;
@@ -589,7 +589,7 @@ void TuckerEngine::mainLoop() {
}
if (_inputKeys[kInputKeyPause]) {
_inputKeys[kInputKeyPause] = false;
- if (_locationNum != 70) {
+ if (_location != kLocationComputerScreen) {
_gamePaused = true;
}
}
@@ -650,6 +650,12 @@ void TuckerEngine::parseEvents() {
while (_eventMan->pollEvent(ev)) {
switch (ev.type) {
case Common::EVENT_KEYDOWN:
+ switch (ev.kbd.ascii) {
+ // do not use KEYCODE_PERIOD here so that it works with most keyboard layouts
+ case '.':
+ _inputKeys[kInputKeySkipSpeech] = true;
+ break;
+ }
switch (ev.kbd.keycode) {
case Common::KEYCODE_f:
if (ev.kbd.hasFlags(Common::KBD_CTRL)) {
@@ -672,9 +678,6 @@ void TuckerEngine::parseEvents() {
_inputKeys[kInputKeyEscape] = true;
_inputKeys[kInputKeySkipSpeech] = true;
break;
- case Common::KEYCODE_PERIOD:
- _inputKeys[kInputKeySkipSpeech] = true;
- break;
case Common::KEYCODE_d:
if (ev.kbd.hasFlags(Common::KBD_CTRL)) {
this->getDebugger()->attach();
@@ -757,10 +760,10 @@ void TuckerEngine::showCursor(bool visible) {
}
void TuckerEngine::setupNewLocation() {
- debug(2, "setupNewLocation() current %d next %d", _locationNum, _nextLocationNum);
- _locationNum = _nextLocationNum;
+ debug(2, "setupNewLocation() current %d next %d", _location, _nextLocation);
+ _location = _nextLocation;
loadObj();
- _nextLocationNum = 0;
+ _nextLocation = kLocationNone;
_fadePaletteCounter = 0;
_mainLoopCounter2 = 0;
_mainLoopCounter1 = 0;
@@ -772,7 +775,7 @@ void TuckerEngine::setupNewLocation() {
_backgroundSpriteCurrentAnimation = -1;
_backgroundSpriteCurrentFrame = 0;
}
- if (!_panelLockedFlag || (_backgroundSpriteCurrentAnimation > 0 && _locationNum != 25)) {
+ if (!_panelLockedFlag || (_backgroundSpriteCurrentAnimation > 0 && _location != kLocationVentSystem)) {
_locationMaskType = 0;
} else {
_locationMaskType = 3;
@@ -803,7 +806,7 @@ void TuckerEngine::setupNewLocation() {
void TuckerEngine::copyLocBitmap(const char *filename, int offset, bool isMask) {
int type = !isMask ? 1 : 0;
- if (offset > 0 && _locationNum == 16) {
+ if (offset > 0 && _location == kLocationPark) {
type = 0;
}
loadImage(filename, _loadTempBuf, type);
@@ -863,7 +866,7 @@ void TuckerEngine::updateCharPosition() {
if (_currentActionVerb == kVerbWalk || _locationMaskCounter == 0) {
return;
}
- if (_currentActionVerb == kVerbLook && _locationNum != 18) {
+ if (_currentActionVerb == kVerbLook && _location != kLocationRoystonsHomeBoxroom) {
int pos;
_actionPosX = _xPosCurrent;
_actionPosY = _yPosCurrent - 64;
@@ -1066,10 +1069,10 @@ void TuckerEngine::setBlackPalette() {
void TuckerEngine::updateCursor() {
setCursorStyle(kCursorNormal);
- if (_backgroundSpriteCurrentAnimation == -1 && !_panelLockedFlag && _selectedObject._locationObjectLocationNum > 0) {
- _selectedObject._locationObjectLocationNum = 0;
+ if (_backgroundSpriteCurrentAnimation == -1 && !_panelLockedFlag && _selectedObject._locationObjectLocation != kLocationNone) {
+ _selectedObject._locationObjectLocation = kLocationNone;
}
- if (_locationMaskType > 0 || _selectedObject._locationObjectLocationNum > 0 || _pendingActionDelay > 0) {
+ if (_locationMaskType > 0 || _selectedObject._locationObjectLocation != kLocationNone || _pendingActionDelay > 0) {
return;
}
if (_rightMouseButtonPressed) {
@@ -1088,7 +1091,7 @@ void TuckerEngine::updateCursor() {
}
if (!_actionVerbLocked) {
setActionVerbUnderCursor();
- if (_actionVerb == kVerbWalk && _locationNum == 63) {
+ if (_actionVerb == kVerbWalk && _location == kLocationTV) {
_actionVerb = kVerbUse;
}
}
@@ -1201,7 +1204,7 @@ void TuckerEngine::updateCharactersPath() {
if (!_panelLockedFlag) {
return;
}
- if (_backgroundSpriteCurrentAnimation != -1 && _locationNum != 25) {
+ if (_backgroundSpriteCurrentAnimation != -1 && _location != kLocationVentSystem) {
if (_xPosCurrent == _selectedObject._xPos && _yPosCurrent == _selectedObject._yPos) {
_locationMaskCounter = 1;
_panelLockedFlag = false;
@@ -1255,7 +1258,7 @@ void TuckerEngine::updateCharactersPath() {
}
}
}
- if (_locationNum == 25) {
+ if (_location == kLocationVentSystem) {
if ((_backgroundSpriteCurrentAnimation != 3 || _characterBackFrontFacing) && (_backgroundSpriteCurrentAnimation != 6 || !_characterBackFrontFacing)) {
_xPosCurrent = xPos;
_yPosCurrent = yPos;
@@ -1274,7 +1277,7 @@ void TuckerEngine::updateCharactersPath() {
if (_characterPrevFacingDirection <= 0 || _characterPrevFacingDirection >= 5) {
return;
}
- if (_selectedObject._locationObjectLocationNum == 0) {
+ if (_selectedObject._locationObjectLocation == kLocationNone) {
_characterFacingDirection = 5;
while (_spriteAnimationFramesTable[_spriteAnimationFrameIndex] != 999) {
++_spriteAnimationFrameIndex;
@@ -1319,7 +1322,7 @@ void TuckerEngine::updateData3() {
a->_animCurrentCounter = a->_animInitCounter;
a->_drawFlag = false;
}
- if (_locationNum == 24 && i == 0) {
+ if (_location == kLocationStoreRoom && i == 0) {
// workaround bug #2872385: update fish animation sequence for correct
// position in aquarium.
if (a->_animInitCounter == 505 && a->_animCurrentCounter == 513) {
@@ -1390,7 +1393,7 @@ void TuckerEngine::saveOrLoad() {
drawSpeechText(_scrollOffset + 120, 170, _infoBarBuf, 21, 102);
}
if (_mousePosY > 140) {
- if (_mouseWheelUp && _currentSaveLoadGameState < 99) {
+ if (_mouseWheelUp && _currentSaveLoadGameState < kLastSaveSlot) {
++_currentSaveLoadGameState;
_forceRedrawPanelItems = true;
return;
@@ -1403,7 +1406,7 @@ void TuckerEngine::saveOrLoad() {
if (_leftMouseButtonPressed && _mouseClick == 0) {
_mouseClick = 1;
if (_mousePosX > 228 && _mousePosX < 240 && _mousePosY > 154 && _mousePosY < 170) {
- if (_currentSaveLoadGameState < 99) {
+ if (_currentSaveLoadGameState < kLastSaveSlot) {
++_currentSaveLoadGameState;
_forceRedrawPanelItems = true;
}
@@ -1467,23 +1470,23 @@ void TuckerEngine::handleMouseOnPanel() {
void TuckerEngine::togglePanelStyle() {
switch (_panelState) {
- case kPanelStateShrinking:
- if (++_switchPanelCounter == 25) {
- _panelStyle = (_panelStyle == kPanelStyleVerbs) ? kPanelStyleIcons : kPanelStyleVerbs;
- loadPanel();
- _forceRedrawPanelItems = true;
- _panelState = kPanelStateExpanding;
- }
- break;
+ case kPanelStateShrinking:
+ if (++_switchPanelCounter == 25) {
+ _panelStyle = (_panelStyle == kPanelStyleVerbs) ? kPanelStyleIcons : kPanelStyleVerbs;
+ loadPanel();
+ _forceRedrawPanelItems = true;
+ _panelState = kPanelStateExpanding;
+ }
+ break;
- case kPanelStateExpanding:
- if (--_switchPanelCounter == 0) {
- _panelState = kPanelStateNormal;
- }
- break;
+ case kPanelStateExpanding:
+ if (--_switchPanelCounter == 0) {
+ _panelState = kPanelStateNormal;
+ }
+ break;
- default:
- break;
+ default:
+ break;
}
}
@@ -1541,11 +1544,11 @@ void TuckerEngine::drawConversationTexts() {
void TuckerEngine::updateScreenScrolling() {
int scrollPrevOffset = _scrollOffset;
- if (_locationWidthTable[_locationNum] != 2) {
+ if (_locationWidthTable[_location] != 2) {
_scrollOffset = 0;
} else if (_validInstructionId) {
_scrollOffset = _xPosCurrent - 200;
- } else if (_locationNum == 16 && _backgroundSpriteCurrentAnimation == 6 && _scrollOffset + 200 < _xPosCurrent) {
+ } else if (_location == kLocationPark && _backgroundSpriteCurrentAnimation == 6 && _scrollOffset + 200 < _xPosCurrent) {
++_scrollOffset;
if (_scrollOffset > 320) {
_scrollOffset = 320;
@@ -1641,7 +1644,7 @@ void TuckerEngine::drawData3() {
}
void TuckerEngine::execData3PreUpdate() {
- switch (_locationNum) {
+ switch (_location) {
case 1:
execData3PreUpdate_locationNum1();
break;
@@ -1774,11 +1777,13 @@ void TuckerEngine::execData3PreUpdate() {
case 70:
execData3PreUpdate_locationNum70();
break;
+ default:
+ break;
}
}
void TuckerEngine::execData3PostUpdate() {
- switch (_locationNum) {
+ switch (_location) {
case 1:
execData3PostUpdate_locationNum1();
break;
@@ -1815,6 +1820,8 @@ void TuckerEngine::execData3PostUpdate() {
case 66:
execData3PostUpdate_locationNum66();
break;
+ default:
+ break;
}
}
@@ -1825,28 +1832,23 @@ void TuckerEngine::drawBackgroundSprites() {
int srcH = READ_LE_UINT16(_backgroundSpriteDataPtr + frameOffset + 2);
int srcX = READ_LE_UINT16(_backgroundSpriteDataPtr + frameOffset + 8);
int srcY = READ_LE_UINT16(_backgroundSpriteDataPtr + frameOffset + 10);
- if (_locationNum == 22 && _backgroundSpriteCurrentAnimation > 1) {
+ if (_location == kLocationFishingTrawler && _backgroundSpriteCurrentAnimation > 1) {
srcY += _mainSpritesBaseOffset;
}
- if (_locationNum == 29 && _backgroundSpriteCurrentAnimation == 3) {
+ if (_location == kLocationSubmarineHangar && _backgroundSpriteCurrentAnimation == 3) {
srcX += 228;
- } else if (_locationNum == 58 && _backgroundSpriteCurrentAnimation == 1) {
+ } else if (_location == kLocationInsideMuseumPartThree && _backgroundSpriteCurrentAnimation == 1) {
srcX += 100;
} else if (_xPosCurrent > 320 && _xPosCurrent < 640) {
srcX += 320;
}
srcX += _backgroundSprOffset;
- Graphics::decodeRLE_248(_locationBackgroundGfxBuf + srcY * 640 + srcX, _backgroundSpriteDataPtr + frameOffset + 12, srcW, srcH, 0, _locationHeightTable[_locationNum], false);
+ Graphics::decodeRLE_248(_locationBackgroundGfxBuf + srcY * 640 + srcX, _backgroundSpriteDataPtr + frameOffset + 12, srcW, srcH, 0, _locationHeightTable[_location], false);
addDirtyRect(srcX, srcY, srcW, srcH);
}
}
void TuckerEngine::drawCurrentSprite() {
- // Workaround original game glitch: skip first bud frame drawing when entering location (tracker item #2597763)
- if ((_locationNum == 17 || _locationNum == 18) && _currentSpriteAnimationFrame == 16) {
- return;
- }
-
// WORKAROUND: original game glitch
// Locations 48 and 61 contain reserved colors from [0xE0-0xF8] in a walkable area which
// results in a number of pixels being falsely drawn in the foreground (on top of Bud).
@@ -1859,15 +1861,18 @@ void TuckerEngine::drawCurrentSprite() {
// [0xE0, ... ..., 0xEF]
static const int whitelistReservedColorsLocation48[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
static const int whitelistReservedColorsLocation61[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
- switch (_locationNum) {
- case 48:
- whitelistReservedColors = (const int *)&whitelistReservedColorsLocation48;
- break;
+ switch (_location) {
+ case kLocationCorridor:
+ whitelistReservedColors = (const int *)&whitelistReservedColorsLocation48;
+ break;
- case 61:
- if (_xPosCurrent <= 565)
- whitelistReservedColors = (const int *)&whitelistReservedColorsLocation61;
- break;
+ case kLocationParkPartThree:
+ if (_xPosCurrent <= 565)
+ whitelistReservedColors = (const int *)&whitelistReservedColorsLocation61;
+ break;
+
+ default:
+ break;
}
SpriteFrame *chr = &_spriteFramesTable[_currentSpriteAnimationFrame];
@@ -1879,7 +1884,7 @@ void TuckerEngine::drawCurrentSprite() {
xPos -= chr->_xSize + chr->_xOffset - 14;
}
Graphics::decodeRLE_248(_locationBackgroundGfxBuf + yPos * 640 + xPos, _spritesGfxBuf + chr->_sourceOffset, chr->_xSize, chr->_ySize,
- chr->_yOffset, _locationHeightTable[_locationNum], _mirroredDrawing, whitelistReservedColors);
+ chr->_yOffset, _locationHeightTable[_location], _mirroredDrawing, whitelistReservedColors);
addDirtyRect(xPos, yPos, chr->_xSize, chr->_ySize);
if (_currentSpriteAnimationLength > 1) {
SpriteFrame *chr2 = &_spriteFramesTable[_currentSpriteAnimationFrame2];
@@ -1891,7 +1896,7 @@ void TuckerEngine::drawCurrentSprite() {
xPos -= chr2->_xSize + chr2->_xOffset - 14;
}
Graphics::decodeRLE_248(_locationBackgroundGfxBuf + yPos * 640 + xPos, _spritesGfxBuf + chr2->_sourceOffset, chr2->_xSize, chr2->_ySize,
- chr2->_yOffset, _locationHeightTable[_locationNum], _mirroredDrawing, whitelistReservedColors);
+ chr2->_yOffset, _locationHeightTable[_location], _mirroredDrawing, whitelistReservedColors);
addDirtyRect(xPos, yPos, chr2->_xSize, chr2->_ySize);
}
}
@@ -1963,32 +1968,37 @@ void TuckerEngine::redrawPanelItems() {
int sz = 0;
switch (_panelType) {
- case kPanelTypeNormal:
- src = _panelGfxBuf;
- dst = _itemsGfxBuf + 3200;
- sz = 16000;
- break;
- case kPanelTypeEmpty:
- src = _panelGfxBuf + 16320;
- dst = _itemsGfxBuf;
- sz = 19200;
- break;
- case kPanelTypeLoadSavePlayQuit:
- src = _panelGfxBuf + 16320;
- dst = _itemsGfxBuf;
- sz = 19200;
- memcpy(dst, src, sz);
- src = _panelGfxBuf + 55040;
- dst = _itemsGfxBuf + 6400;
- sz = 5120;
- break;
- case kPanelTypeLoadSaveSavegame:
- src = _panelGfxBuf + 35200;
- dst = _itemsGfxBuf;
- sz = 19200;
- break;
- default:
- break;
+ case kPanelTypeNormal:
+ src = _panelGfxBuf;
+ dst = _itemsGfxBuf + 3200;
+ sz = 16000;
+ break;
+ case kPanelTypeEmpty:
+ src = _panelGfxBuf + 16320;
+ dst = _itemsGfxBuf;
+ sz = 19200;
+ break;
+ case kPanelTypeLoadSavePlayQuit:
+ // The following offset does not match disassembly on purpose to fix a
+ // "glitch" in the original game.
+ // This ensures that the background image ends up in the same place as
+ // in the case of kPanelTypeLoadSaveSavegame.
+ // This fixes Trac#10496.
+ src = _panelGfxBuf + 16000;
+ dst = _itemsGfxBuf;
+ sz = 19200;
+ memcpy(dst, src, sz);
+ src = _panelGfxBuf + 55040;
+ dst = _itemsGfxBuf + 6400;
+ sz = 5120;
+ break;
+ case kPanelTypeLoadSaveSavegame:
+ src = _panelGfxBuf + 35200;
+ dst = _itemsGfxBuf;
+ sz = 19200;
+ break;
+ default:
+ break;
}
memcpy(dst, src, sz);
if (_panelType == kPanelTypeNormal) {
@@ -2176,7 +2186,7 @@ void TuckerEngine::updateCharacterAnimation() {
assert(_backgroundSpriteCurrentAnimation >= 0 && _backgroundSpriteCurrentAnimation < kSprA02TableSize);
_backgroundSpriteDataPtr = _sprA02Table[_backgroundSpriteCurrentAnimation];
_backgroundSpriteLastFrame = READ_LE_UINT16(_backgroundSpriteDataPtr);
- } else if (_locationNum == 25 && !_panelLockedFlag && (_backgroundSpriteCurrentAnimation == 3 || _backgroundSpriteCurrentAnimation == 6)) {
+ } else if (_location == kLocationVentSystem && !_panelLockedFlag && (_backgroundSpriteCurrentAnimation == 3 || _backgroundSpriteCurrentAnimation == 6)) {
_backgroundSpriteCurrentFrame = 0;
_backgroundSpriteCurrentAnimation = -1;
} else {
@@ -2191,10 +2201,10 @@ void TuckerEngine::updateCharacterAnimation() {
}
}
}
- if (_locationNum == 24 && _flagsTable[103] == 0) {
+ if (_location == kLocationStoreRoom && _flagsTable[103] == 0) {
if (_panelLockedFlag) {
_panelLockedFlag = false;
- _selectedObject._locationObjectLocationNum = 0;
+ _selectedObject._locationObjectLocation = kLocationNone;
if (_actionVerb != kVerbTalk) {
_speechSoundNum = 2236;
startSpeechSound(_speechSoundNum, _speechVolume);
@@ -2227,7 +2237,7 @@ void TuckerEngine::updateCharacterAnimation() {
_backgroundSpriteDataPtr = _sprA02Table[_backgroundSpriteCurrentAnimation];
_backgroundSpriteLastFrame = READ_LE_UINT16(_backgroundSpriteDataPtr);
}
- } else if (_locationNum == 25) {
+ } else if (_location == kLocationVentSystem) {
if (_backgroundSpriteCurrentFrame == 0) {
if (!_characterBackFrontFacing) {
if (_characterBackFrontFacing != _characterPrevBackFrontFacing) {
@@ -2256,7 +2266,7 @@ void TuckerEngine::updateCharacterAnimation() {
_backgroundSpriteLastFrame = READ_LE_UINT16(_backgroundSpriteDataPtr);
}
_backgroundSprOffset = _xPosCurrent - 160;
- } else if (_locationNum == 63 && _backgroundSpriteCurrentFrame == 0) {
+ } else if (_location == kLocationTV && _backgroundSpriteCurrentFrame == 0) {
if (_charSpeechSoundCounter > 0 && _actionCharacterNum == 99) {
_backgroundSpriteCurrentAnimation = 1;
} else {
@@ -2267,7 +2277,7 @@ void TuckerEngine::updateCharacterAnimation() {
_backgroundSpriteLastFrame = READ_LE_UINT16(_backgroundSpriteDataPtr);
}
int frame = _spriteAnimationFramesTable[_spriteAnimationFrameIndex];
- if (!_panelLockedFlag && _characterFacingDirection < 5 && _selectedObject._locationObjectLocationNum == 0) {
+ if (!_panelLockedFlag && _characterFacingDirection < 5 && _selectedObject._locationObjectLocation == kLocationNone) {
_characterFacingDirection = 0;
}
if (_charSpeechSoundCounter > 0 && _characterFacingDirection != 6 && _actionCharacterNum == 99) {
@@ -2326,7 +2336,7 @@ void TuckerEngine::updateCharacterAnimation() {
num = 13;
} else if (getRandomNumber() < 3000) {
num = 14;
- if (_locationNum == 57) {
+ if (_location == kLocationFishShopPartThree) {
num = 18;
}
} else {
@@ -2414,7 +2424,7 @@ void TuckerEngine::handleMap() {
_panelLockedFlag = false;
}
}
- if (!_panelLockedFlag && (_backgroundSpriteCurrentAnimation == -1 || _locationNum == 25) && _locationMaskType == 3) {
+ if (!_panelLockedFlag && (_backgroundSpriteCurrentAnimation == -1 || _location == kLocationVentSystem) && _locationMaskType == 3) {
setCursorState(kCursorStateNormal);
if (_locationMaskCounter == 1) {
_characterFacingDirection = 0;
@@ -2422,10 +2432,10 @@ void TuckerEngine::handleMap() {
}
return;
}
- if (_selectedObject._locationObjectLocationNum != 0 && _locationMaskCounter != 0 && (_backgroundSpriteCurrentAnimation <= -1 || _locationNum == 25)) {
+ if (_selectedObject._locationObjectLocation != kLocationNone && _locationMaskCounter != 0 && (_backgroundSpriteCurrentAnimation <= -1 || _location == kLocationVentSystem)) {
// TODO
// This is actually "_locationNum != 25" in disassembly. Is this a typo?
- if (_locationNum == 25 || _backgroundSpriteCurrentAnimation != 4) {
+ if (_location == kLocationVentSystem || _backgroundSpriteCurrentAnimation != 4) {
if (_locationMaskType == 0) {
_locationMaskType = 1;
setCursorState(kCursorStateDisabledHidden);
@@ -2440,7 +2450,7 @@ void TuckerEngine::handleMap() {
}
_backgroundSpriteCurrentFrame = 0;
_mirroredDrawing = false;
- if (_locationNum == 25) {
+ if (_location == kLocationVentSystem) {
_backgroundSpriteDataPtr = _sprA02Table[_backgroundSpriteCurrentAnimation];
_backgroundSpriteLastFrame = READ_LE_UINT16(_backgroundSpriteDataPtr);
_backgroundSpriteCurrentFrame = 1;
@@ -2457,7 +2467,7 @@ void TuckerEngine::handleMap() {
_locationMaskType = 2;
_panelType = kPanelTypeNormal;
setCursorState(kCursorStateNormal);
- if (_selectedObject._locationObjectLocationNum == 99) {
+ if (_selectedObject._locationObjectLocation == kLocationMap) {
_noPositionChangeAfterMap = true;
handleMapSequence();
return;
@@ -2467,7 +2477,7 @@ void TuckerEngine::handleMap() {
redrawScreen(_scrollOffset);
_fadePaletteCounter = 34;
}
- _nextLocationNum = _selectedObject._locationObjectLocationNum;
+ _nextLocation = _selectedObject._locationObjectLocation;
_xPosCurrent = _selectedObject._locationObjectToX;
_yPosCurrent = _selectedObject._locationObjectToY;
if (_selectedObject._locationObjectToX2 > 800) {
@@ -2488,7 +2498,7 @@ void TuckerEngine::handleMap() {
_scrollOffset = 0;
_handleMapCounter = 0;
_locationMaskCounter = 0;
- _selectedObject._locationObjectLocationNum = 0;
+ _selectedObject._locationObjectLocation = kLocationNone;
}
}
}
@@ -2502,7 +2512,7 @@ void TuckerEngine::clearSprites() {
}
void TuckerEngine::updateSprites() {
- const int count = (_locationNum == 9) ? 3 : _spritesCount;
+ const int count = (_location == kLocationMall) ? 3 : _spritesCount;
for (int i = 0; i < count; ++i) {
if (_spritesTable[i]._stateIndex > -1) {
++_spritesTable[i]._stateIndex;
@@ -2569,7 +2579,7 @@ void TuckerEngine::updateSprite(int i) {
_updateSpriteFlag2 = false;
_spritesTable[i]._defaultUpdateDelay = 0;
_spritesTable[i]._updateDelay = 0;
- switch (_locationNum) {
+ switch (_location) {
case 2:
updateSprite_locationNum2();
break;
@@ -2942,13 +2952,23 @@ void TuckerEngine::updateSprite(int i) {
case 98:
_spritesTable[0]._state = 1;
break;
+ default:
+ break;
}
if (_spritesTable[i]._stateIndex <= -1) {
if (!_updateSpriteFlag1) {
_spritesTable[i]._animationFrame = 1;
}
if (_spritesTable[i]._state < 0 || !_sprC02Table[_spritesTable[i]._state]) {
-// warning("Invalid state %d for sprite %d location %d", _spritesTable[i].state, i, _locationNum);
+ // WORKAROUND
+ // The original game unconditionally reads into _sprC02Table[] below which
+ // results in out-of-bounds reads when _spritesTable[i]._state == -1.
+ // We reset the sprite's animation data in this case so sprite updates
+ // are triggered correctly. This most prominently fixes a bug where Lola's
+ // transition from dancing -> sitting happens too late.
+ // This fixes Trac#6644.
+ _spritesTable[i]._animationData = nullptr;
+ _spritesTable[i]._firstFrame = 0;
return;
}
_spritesTable[i]._animationData = _sprC02Table[_spritesTable[i]._state];
@@ -3046,7 +3066,7 @@ bool TuckerEngine::testLocationMask(int x, int y) {
if (_locationMaskType > 0 || _locationMaskIgnore) {
return true;
}
- if (_locationNum == 26 || _locationNum == 32) {
+ if (_location == kLocationSubwayTunnel || _location == kLocationKitchen) {
y -= 3;
}
const int offset = y * 640 + x;
@@ -3138,7 +3158,8 @@ enum TableInstructionCode {
kCode_was,
kCode_wfx,
kCode_xhr,
- kCode_xhm
+ kCode_xhm,
+ kCode_no3 // NOOP, throw away 3-byte parameter
};
static const struct {
@@ -3158,12 +3179,14 @@ static const struct {
{ "bso", kCode_bso },
{ "bus", kCode_bus },
{ "b0s", kCode_bus }, // only ref 65.25
+ { "buv", kCode_no3 },
{ "buw", kCode_buw },
{ "bdx", kCode_bux },
{ "bux", kCode_bux },
{ "c0a", kCode_c0a },
{ "c0c", kCode_c0c },
{ "c0s", kCode_c0s },
+ { "c0v", kCode_no3 },
{ "end", kCode_end },
{ "fad", kCode_fad },
{ "fw", kCode_fw },
@@ -3302,7 +3325,7 @@ int TuckerEngine::executeTableInstruction() {
// As a workaround, do not ignore the location mask during this specific
// action when entering the club.
// This fixes Trac#5838.
- if (!(_locationNum == 6 && _nextAction == 59)) {
+ if (!(_location == kLocationStripJoint && _nextAction == 59)) {
_locationMaskIgnore = true;
}
_panelLockedFlag = true;
@@ -3377,10 +3400,10 @@ int TuckerEngine::executeTableInstruction() {
_characterAnimationNum = readTableInstructionParam(2);
return 0;
case kCode_loc:
- _nextLocationNum = readTableInstructionParam(2);
+ _nextLocation = (Location)readTableInstructionParam(2);
return 1;
case kCode_mof:
- // TODO: Unknown opcode in Spanish version. Identify if this has any function.
+ setCursorState(kCursorStateDisabledHidden);
return 0;
case kCode_opt:
_conversationOptionsCount = readTableInstructionParam(2);
@@ -3449,6 +3472,27 @@ int TuckerEngine::executeTableInstruction() {
return 1;
case kCode_wsm:
_stopActionOnPanelLock = true;
+
+ // WORKAROUND
+ // Some versions have a script bug which allows you to freely click around
+ // during the sequence of Bud freeing the professor in part two which even
+ // allows Bud to leave the room while talking to the professor resulting in
+ // general glitchiness. The Spanish and Polish versions (and possibly others)
+ // fixed this by introducing the 'mof' opcode to disable the mouse during the
+ // sequence.
+ //
+ // The difference is as follows:
+ // Buggy: 61dw buw,148,125,wsm,buw,148,132,wsm,wat,050[...]
+ // Fixed: 61dw buw,148,125,wsm,buw,148,132,wsm,mof,pan,01,wat,050[...]
+ // ^^^^^^^^^^
+ // To work around the issue in the problematic versions we inject these two
+ // instructions after the first occurence of the 'wsm' instruction (which
+ // proves good enough).
+ if (_location == kLocationStoreRoom && _nextAction == 61) {
+ setCursorState(kCursorStateDisabledHidden);
+ _panelType = kPanelTypeEmpty;
+ }
+
return 1;
case kCode_wat:
_stopActionCounter = readTableInstructionParam(3);
@@ -3465,6 +3509,10 @@ int TuckerEngine::executeTableInstruction() {
case kCode_xhm:
_validInstructionId = false;
return 0;
+ case kCode_no3:
+ // opcodes mapped here are treated as NOOPs
+ readTableInstructionParam(3);
+ return 0;
}
return 2;
}
@@ -3552,7 +3600,7 @@ void TuckerEngine::setSelectedObjectKey() {
_locationMaskCounter = 0;
_actionRequiresTwoObjects = false;
_selectedObject._yPos = 0;
- _selectedObject._locationObjectLocationNum = 0;
+ _selectedObject._locationObjectLocation = kLocationNone;
_pendingActionIndex = 0;
if (_selectedObjectType == 0) {
if (_selectedObjectNum == 0) {
@@ -3562,7 +3610,7 @@ void TuckerEngine::setSelectedObjectKey() {
_selectedObject._xPos = _locationObjectsTable[_selectedCharacterNum]._standX;
_selectedObject._yPos = _locationObjectsTable[_selectedCharacterNum]._standY;
if (_actionVerb == kVerbWalk || _actionVerb == kVerbUse) {
- _selectedObject._locationObjectLocationNum = _locationObjectsTable[_selectedCharacterNum]._locationNum;
+ _selectedObject._locationObjectLocation = _locationObjectsTable[_selectedCharacterNum]._location;
_selectedObject._locationObjectToX = _locationObjectsTable[_selectedCharacterNum]._toX;
_selectedObject._locationObjectToY = _locationObjectsTable[_selectedCharacterNum]._toY;
_selectedObject._locationObjectToX2 = _locationObjectsTable[_selectedCharacterNum]._toX2;
@@ -3592,14 +3640,14 @@ void TuckerEngine::setSelectedObjectKey() {
_selectedObject._yPos = _mousePosY;
}
_selectedObjectLocationMask = testLocationMask(_selectedObject._xPos, _selectedObject._yPos);
- if (!_selectedObjectLocationMask && _objectKeysLocationTable[_locationNum] == 1) {
- if (_selectedObject._yPos < _objectKeysPosYTable[_locationNum]) {
- while (!_selectedObjectLocationMask && _selectedObject._yPos < _objectKeysPosYTable[_locationNum]) {
+ if (!_selectedObjectLocationMask && _objectKeysLocationTable[_location] == 1) {
+ if (_selectedObject._yPos < _objectKeysPosYTable[_location]) {
+ while (!_selectedObjectLocationMask && _selectedObject._yPos < _objectKeysPosYTable[_location]) {
++_selectedObject._yPos;
_selectedObjectLocationMask = testLocationMask(_selectedObject._xPos, _selectedObject._yPos);
}
} else {
- while (!_selectedObjectLocationMask && _selectedObject._yPos < _objectKeysPosYTable[_locationNum]) {
+ while (!_selectedObjectLocationMask && _selectedObject._yPos < _objectKeysPosYTable[_location]) {
--_selectedObject._yPos;
_selectedObjectLocationMask = testLocationMask(_selectedObject._xPos, _selectedObject._yPos);
}
@@ -3607,12 +3655,12 @@ void TuckerEngine::setSelectedObjectKey() {
}
if (_selectedObjectLocationMask) {
_selectedObjectLocationMask = testLocationMaskArea(_xPosCurrent, _yPosCurrent, _selectedObject._xPos, _selectedObject._yPos);
- if (_selectedObjectLocationMask && _objectKeysPosXTable[_locationNum] > 0) {
+ if (_selectedObjectLocationMask && _objectKeysPosXTable[_location] > 0) {
_selectedObject._xDefaultPos = _selectedObject._xPos;
_selectedObject._yDefaultPos = _selectedObject._yPos;
- _selectedObject._xPos = _objectKeysPosXTable[_locationNum];
- _selectedObject._yPos = _objectKeysPosYTable[_locationNum];
- if (_objectKeysLocationTable[_locationNum] == 1) {
+ _selectedObject._xPos = _objectKeysPosXTable[_location];
+ _selectedObject._yPos = _objectKeysPosYTable[_location];
+ if (_objectKeysLocationTable[_location] == 1) {
_selectedObject._xPos = _selectedObject._xDefaultPos;
}
}
@@ -3699,7 +3747,7 @@ void TuckerEngine::handleMouseClickOnInventoryObject() {
break;
case 1:
if (_actionVerb == kVerbUse && _leftMouseButtonPressed) {
- if (_mapSequenceFlagsLocationTable[_locationNum - 1] == 1) {
+ if (_mapSequenceFlagsLocationTable[_location - 1] == 1) {
handleMapSequence();
} else {
_actionPosX = _xPosCurrent;
@@ -3772,6 +3820,11 @@ int TuckerEngine::setLocationAnimationUnderCursor() {
continue;
}
if (_locationAnimationsTable[i]._selectable == 0) {
+ // WORKAROUND
+ // The original game does a "return -1" here which is not correct in
+ // case of overlapping hotspots.
+ // This most prominently fixes Trac#6645, a bug where the cellar in part three
+ // could be entered without having done the cellar door puzzle first.
continue;
}
_selectedObjectType = 1;
diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h
index cd12939443..e3748680fe 100644
--- a/engines/tucker/tucker.h
+++ b/engines/tucker/tucker.h
@@ -110,10 +110,103 @@ enum VerbPreposition {
};
enum Part {
- kPartInit = 0,
- kPartOne = 1,
- kPartTwo = 2,
- kPartThree = 3
+ kPartInit = 0,
+ kPartOne = 1,
+ kPartTwo = 2,
+ kPartThree = 3
+};
+
+enum Location {
+ kLocationNone = 0,
+
+ kLocationHotelRoom = 1,
+ kLocationBackAlley = 2,
+ kLocationSeedyStreet = 3,
+ kLocationBakersShop = 4,
+ kLocationBakersKitchen = 5,
+ kLocationStripJoint = 6,
+ kLocationPoliceHQ = 7,
+ kLocationPoliceCell = 8,
+ kLocationMall = 9,
+ kLocationFishShop = 10,
+ kLocationBurgerJoint = 11,
+ kLocationRecordShop = 12,
+ kLocationDentist = 13,
+ kLocationPlugShop = 14,
+ kLocationTouristInfo = 15,
+ kLocationPark = 16,
+ kLocationRoystonsHomeHallway = 17,
+ kLocationRoystonsHomeBoxroom = 18,
+ kLocationDocks = 19,
+ kLocationOutsideMuseum = 20,
+ kLocationInsideMuseum = 21,
+ kLocationFishingTrawler = 22,
+ kLocationWarehouseCutscene = 23,
+ kLocationStoreRoom = 24,
+ kLocationVentSystem = 25,
+ kLocationSubwayTunnel = 26,
+ kLocationStrangeRoom = 27,
+ kLocationTopCorridor = 28,
+ kLocationSubmarineHangar = 29,
+ kLocationBunkRoom = 30,
+ kLocationBottomCorridor = 31,
+ kLocationKitchen = 32,
+ kLocationCommandCentre = 33,
+ kLocationSubmarineHatch = 34,
+ kLocationSubmarineWalkway = 35,
+ kLocationSubmarineBridge = 36,
+ kLocationSubmarineOffice = 37,
+ kLocationSubmarineEngineRoom = 38,
+ kLocationLuxuryApartment = 39,
+ kLocationFarDocks = 40,
+ kLocationAlleyway = 41,
+ kLocationBasement = 42,
+ kLocationTateTowerEntrance = 43,
+ kLocationRooftop = 44,
+ kLocationConferenceRoom = 45,
+ kLocationAnteChamber = 46,
+ kLocationHelipad = 47,
+ kLocationCorridor = 48,
+ kLocationWaitingRoom = 49,
+ kLocationkLocationCorridorCutscene = 50,
+ kLocationCells = 51,
+ kLocationMachineRoom = 52,
+ kLocationRecordShopPartThree = 53,
+ kLocationPlugShopPartThree = 54,
+ kLocationTouristInfoPartThree = 55,
+ kLocationDentistPartThree = 56,
+ kLocationFishShopPartThree = 57,
+ kLocationInsideMuseumPartThree = 58,
+ kLocationBakersShopPartThree = 59,
+ kLocationStripJointPartThree = 60,
+ kLocationParkPartThree = 61,
+ kLocationDocksPartThree = 62,
+ kLocationTV = 63,
+ kLocationSewer = 64,
+ kLocationSeedyStreetPartThree = 65,
+ kLocationMallPartThree = 66,
+ kLocationBurgerJointPartThree = 67,
+ kLocationOutsideMuseumPartThree = 68,
+ kLocation69Cutscene = 69,
+ kLocationComputerScreen = 70,
+ kLocationParkCutscene = 71,
+ kLocationSeedyStreetCutscene = 72,
+ kLocationJesusCutscene1 = 73,
+ kLocationCredits = 74,
+ kLocation75Cutscene = 75,
+ kLocationBeachCutscene = 76,
+ kLocationHospitalCutscene = 77,
+ kLocation78Cutscene = 78,
+ kLocationElvisCutscene = 79,
+ kLocationPyramidCutscene = 80,
+ kLocationCleopatraCutscene = 81,
+ kLocationJesusCutscene2 = 82,
+
+ kLocationNewPart = 98,
+ kLocationMap = 99,
+
+ kLocationInit = 1,
+ kLocationInitDemo = 9
};
struct Action {
@@ -212,7 +305,7 @@ struct LocationObject {
int _xSize;
int _ySize;
int _textNum;
- int _locationNum;
+ Location _location;
int _toX;
int _toY;
int _toX2;
@@ -251,8 +344,6 @@ enum {
kScreenHeight = 200,
kScreenPitch = 640,
kFadePaletteStep = 5,
- kStartupLocationDemo = 9,
- kStartupLocationGame = 1,
kDefaultCharSpeechSoundCounter = 1,
kMaxSoundVolume = 127,
kLastSaveSlot = 99,
@@ -361,8 +452,8 @@ public:
virtual bool hasFeature(EngineFeature f) const;
GUI::Debugger *getDebugger() { return _console; }
- static SavegameError readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool loadThumbnail = false);
- static SavegameError readSavegameHeader(const char *target, int slot, SavegameHeader &header);
+ WARN_UNUSED_RESULT static SavegameError readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool skipThumbnail = true);
+ WARN_UNUSED_RESULT static SavegameError readSavegameHeader(const char *target, int slot, SavegameHeader &header);
bool isAutosaveAllowed();
static bool isAutosaveAllowed(const char *target);
protected:
@@ -719,8 +810,8 @@ protected:
int _flagsTable[kFlagsTableSize];
Part _part;
Part _currentPart;
- int _locationNum;
- int _nextLocationNum;
+ Location _location;
+ Location _nextLocation;
bool _gamePaused;
bool _gameDebug;
bool _displayGameHints;
@@ -850,7 +941,7 @@ protected:
int _yDefaultPos;
int _xPos;
int _yPos;
- int _locationObjectLocationNum;
+ Location _locationObjectLocation;
int _locationObjectToX;
int _locationObjectToY;
int _locationObjectToX2;
diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp
index eefe174e94..6452e5741f 100644
--- a/engines/voyeur/detection.cpp
+++ b/engines/voyeur/detection.cpp
@@ -132,7 +132,6 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const {
if (in) {
if (header.read(in)) {
saveList.push_back(SaveStateDescriptor(slot, header._saveName));
- header._thumbnail->free();
}
delete in;
}
@@ -159,7 +158,7 @@ SaveStateDescriptor VoyeurMetaEngine::querySaveMetaInfos(const char *target, int
if (f) {
Voyeur::VoyeurSavegameHeader header;
- header.read(f);
+ header.read(f, false);
delete f;
// Create the return descriptor
diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp
index 1b4e30665c..af8753c488 100644
--- a/engines/voyeur/files_threads.cpp
+++ b/engines/voyeur/files_threads.cpp
@@ -864,7 +864,7 @@ const byte *ThreadResource::cardPerform(const byte *card) {
if (cardPerform2(card, id)) {
card += subId;
card = cardPerform(card);
- while (*card++ != 61) ;
+ while (*card++ != 61) {}
} else {
card += subId;
while (*card != 61 && *card != 29)
diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp
index 7f2f0e312e..b7769c1fd4 100644
--- a/engines/voyeur/voyeur.cpp
+++ b/engines/voyeur/voyeur.cpp
@@ -789,9 +789,6 @@ void VoyeurEngine::loadGame(int slot) {
VoyeurSavegameHeader header;
if (!header.read(saveFile))
return;
- if (header._thumbnail)
- header._thumbnail->free();
- delete header._thumbnail;
serializer.setVersion(header._version);
synchronize(serializer);
@@ -856,9 +853,7 @@ void VoyeurEngine::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-bool VoyeurSavegameHeader::read(Common::InSaveFile *f) {
- _thumbnail = NULL;
-
+bool VoyeurSavegameHeader::read(Common::InSaveFile *f, bool skipThumbnail) {
uint32 signature = f->readUint32BE();
if (signature != MKTAG('V', 'O', 'Y', 'R')) {
warning("Invalid savegame");
@@ -875,9 +870,9 @@ bool VoyeurSavegameHeader::read(Common::InSaveFile *f) {
_saveName += c;
// Get the thumbnail
- _thumbnail = Graphics::loadThumbnail(*f);
- if (!_thumbnail)
+ if (!Graphics::loadThumbnail(*f, _thumbnail, skipThumbnail)) {
return false;
+ }
// Read in the save datet/ime
_saveYear = f->readSint16LE();
diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h
index dcd82b24a9..a098ba9e62 100644
--- a/engines/voyeur/voyeur.h
+++ b/engines/voyeur/voyeur.h
@@ -312,7 +312,7 @@ struct VoyeurSavegameHeader {
/**
* Read in the header from the specified file
*/
- bool read(Common::InSaveFile *f);
+ bool read(Common::InSaveFile *f, bool skipThumbnail = true);
/**
* Write out header information to the specified file
diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h
index cbf5d92d00..905d227d3c 100644
--- a/engines/wintermute/base/base_engine.h
+++ b/engines/wintermute/base/base_engine.h
@@ -34,10 +34,24 @@
#include "common/random.h"
#include "common/language.h"
-#include "engines/wintermute/game_description.h"
-
namespace Wintermute {
+enum WMETargetExecutable {
+ OLDEST_VERSION,
+ WME_1_0_0,
+ WME_1_1_0,
+ WME_1_2_0,
+ WME_1_3_0,
+ WME_1_4_0,
+ WME_1_5_0,
+ WME_1_6_0,
+ WME_1_7_0,
+ WME_1_8_0,
+ WME_1_8_6,
+ WME_1_9_0,
+ LATEST_VERSION
+};
+
class BaseFileManager;
class BaseRegistry;
class BaseGame;
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index 0f6a184cb3..15cd33d28c 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -125,7 +125,7 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) {
Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
g_system->beginGFXTransaction();
- g_system->initSize(_width, _height, &format);
+ g_system->initSize(_width, _height, &format);
OSystem::TransactionError gfxError = g_system->endGFXTransaction();
if (gfxError != OSystem::kTransactionSuccess) {
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
index bc267fd656..47099046e9 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
@@ -96,7 +96,7 @@ public:
bool setViewport(Rect32 *rect) override { return BaseRenderer::setViewport(rect); }
Rect32 getViewPort() override;
void modTargetRect(Common::Rect *rect);
- void pointFromScreen(Point32 *point) ;
+ void pointFromScreen(Point32 *point);
void pointToScreen(Point32 *point);
void dumpData(const char *filename) override;
diff --git a/engines/wintermute/base/particles/part_emitter.cpp b/engines/wintermute/base/particles/part_emitter.cpp
index c64a099cee..1c102d17ee 100644
--- a/engines/wintermute/base/particles/part_emitter.cpp
+++ b/engines/wintermute/base/particles/part_emitter.cpp
@@ -214,7 +214,8 @@ bool PartEmitter::initParticle(PartParticle *particle, uint32 currentTime, uint3
Vector2 vecVel(0, velocity);
Matrix4 matRot;
- matRot.rotationZ(Common::deg2rad(BaseUtils::normalizeAngle(angle - 180)));
+ float radZrot = Common::deg2rad<float>(BaseUtils::normalizeAngle(angle - 180.0));
+ matRot.rotationZ(radZrot);
matRot.transformVector2(vecVel);
if (_alphaTimeBased) {
@@ -433,7 +434,8 @@ bool PartEmitter::addForce(const Common::String &name, PartForce::TForceType typ
force->_direction = Vector2(0, strength);
Matrix4 matRot;
- matRot.rotationZ(Common::deg2rad(BaseUtils::normalizeAngle(angle - 180)));
+ float radZrot = Common::deg2rad<float>(BaseUtils::normalizeAngle(angle - 180.0));
+ matRot.rotationZ(radZrot);
matRot.transformVector2(force->_direction);
return STATUS_OK;
diff --git a/engines/wintermute/base/sound/base_sound_buffer.cpp b/engines/wintermute/base/sound/base_sound_buffer.cpp
index 5fdac12cef..0c8103339f 100644
--- a/engines/wintermute/base/sound/base_sound_buffer.cpp
+++ b/engines/wintermute/base/sound/base_sound_buffer.cpp
@@ -33,7 +33,9 @@
#include "engines/wintermute/wintermute.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
+#ifdef USE_VORBIS
#include "audio/decoders/vorbis.h"
+#endif
#include "audio/decoders/wave.h"
#include "audio/decoders/raw.h"
#include "common/system.h"
@@ -103,7 +105,11 @@ bool BaseSoundBuffer::loadFromFile(const Common::String &filename, bool forceRel
Common::String strFilename(filename);
strFilename.toLowercase();
if (strFilename.hasSuffix(".ogg")) {
+#ifdef USE_VORBIS
_stream = Audio::makeVorbisStream(_file, DisposeAfterUse::YES);
+#else
+ error("BSoundBuffer::LoadFromFile - Ogg Vorbis not supported by this version of ScummVM (please report as this shouldn't trigger)");
+#endif
} else if (strFilename.hasSuffix(".wav")) {
int waveSize, waveRate;
byte waveFlags;
diff --git a/engines/wintermute/configure.engine b/engines/wintermute/configure.engine
index 55385776de..29af5601aa 100644
--- a/engines/wintermute/configure.engine
+++ b/engines/wintermute/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit highres"
+add_engine wintermute "Wintermute" yes "" "" "zlib 16bit highres"
diff --git a/engines/wintermute/debugger/error.h b/engines/wintermute/debugger/error.h
index 4e5b973445..0798fe7cb3 100644
--- a/engines/wintermute/debugger/error.h
+++ b/engines/wintermute/debugger/error.h
@@ -28,27 +28,27 @@
namespace Wintermute {
enum ErrorLevel {
- SUCCESS,
- NOTICE,
- WARNING,
- ERROR
+ SUCCESS,
+ NOTICE,
+ WARNING,
+ ERROR
};
enum ErrorCode {
- OK,
- NO_SUCH_SOURCE,
- COULD_NOT_OPEN,
- NO_SUCH_LINE,
- NOT_ALLOWED,
- NO_SUCH_BYTECODE,
- DUPLICATE_BREAKPOINT,
- NO_SUCH_BREAKPOINT,
- WRONG_TYPE,
- PARSE_ERROR,
- NOT_YET_IMPLEMENTED,
- SOURCE_PATH_NOT_SET,
- ILLEGAL_PATH,
- UNKNOWN_ERROR
+ OK,
+ NO_SUCH_SOURCE,
+ COULD_NOT_OPEN,
+ NO_SUCH_LINE,
+ NOT_ALLOWED,
+ NO_SUCH_BYTECODE,
+ DUPLICATE_BREAKPOINT,
+ NO_SUCH_BREAKPOINT,
+ WRONG_TYPE,
+ PARSE_ERROR,
+ NOT_YET_IMPLEMENTED,
+ SOURCE_PATH_NOT_SET,
+ ILLEGAL_PATH,
+ UNKNOWN_ERROR
};
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index 9ccb75d62f..6208d775a6 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -22,6 +22,7 @@
#include "engines/advancedDetector.h"
#include "engines/wintermute/wintermute.h"
+#include "engines/wintermute/game_description.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "common/config-manager.h"
@@ -99,7 +100,7 @@ public:
return "Copyright (C) 2011 Jan Nedoma";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
// Set some defaults
s_fallbackDesc.extra = "";
s_fallbackDesc.language = Common::UNK_LANG;
@@ -129,10 +130,12 @@ public:
s_fallbackDesc.extra = offset;
s_fallbackDesc.flags |= ADGF_USEEXTRAASTITLE;
}
- return &s_fallbackDesc;
+
+ return ADDetectedGame(&s_fallbackDesc);
} // Fall through to return 0;
}
- return 0;
+
+ return ADDetectedGame();
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h
index 5b87dd439c..68ad9c1751 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -43,7 +43,7 @@ static const PlainGameDescriptor wintermuteGames[] = {
{"conspiracao", "Conspiracao Dumont"},
{"corrosion", "Corrosion: Cold Winter Waiting"},
{"deadcity", "Dead City"},
- {"dfafadventure", "DFAF Adventure"},
+ {"dfafadventure", "DFAF Adventure"},
{"dreamcat", "Dreamcat"},
{"dreaming", "Des Reves Elastiques Avec Mille Insectes Nommes Georges"},
{"dirtysplit", "Dirty Split"},
@@ -243,7 +243,7 @@ static const WMEGameDescription gameDescriptions[] = {
"data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION),
// DFAF Adventure
WME_WINENTRY("dfafadventure", "",
- WME_ENTRY1s("data.dcp","5704ebef961176f647742aa66bd09352", 10083417), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
+ WME_ENTRY1s("data.dcp","5704ebef961176f647742aa66bd09352", 10083417), Common::EN_ANY, ADGF_UNSTABLE | GF_LOWSPEC_ASSETS, LATEST_VERSION),
// Dirty Split (Czech)
WME_WINENTRY("dirtysplit", "",
WME_ENTRY2s("czech.dcp", "08a71446467cf8f9444cfea446b46ad6", 127697934,
@@ -271,7 +271,7 @@ static const WMEGameDescription gameDescriptions[] = {
WME_ENTRY1s("data.dcp", "4af26d97ea063fc1277ce30ae431de90", 8804073), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Dreamcat
WME_WINENTRY("dreamcat", "",
- WME_ENTRY1s("data.dcp","189bd4eef29034f4ff4ed30120eaac4e", 7758040), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
+ WME_ENTRY1s("data.dcp","189bd4eef29034f4ff4ed30120eaac4e", 7758040), Common::EN_ANY, ADGF_UNSTABLE | GF_LOWSPEC_ASSETS, LATEST_VERSION),
// Dreamscape
WME_WINENTRY("dreamscape", "",
WME_ENTRY1s("data.dcp", "7a5752ed4446c862be9f02d7932acf54", 17034377), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
@@ -378,7 +378,7 @@ static const WMEGameDescription gameDescriptions[] = {
"d_sounds.dcp", "7d04dff8ca11174486bd4b7a80fdcabb", 154943401), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION),
// Open Quest
WME_WINENTRY("openquest", "",
- WME_ENTRY1s("data.dcp", "16893e3fc15a211a49654ae66f684f28", 82281736), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
+ WME_ENTRY1s("data.dcp", "16893e3fc15a211a49654ae66f684f28", 82281736), Common::EN_ANY, ADGF_UNSTABLE | GF_LOWSPEC_ASSETS, LATEST_VERSION),
// Night Train Demo
WME_WINENTRY("nighttrain", "",
WME_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
@@ -589,4 +589,3 @@ static const WMEGameDescription gameDescriptions[] = {
#undef WEM_ENTRY3s
#undef WME_WINENTRY
#undef WME_PLATENTRY
-
diff --git a/engines/wintermute/game_description.h b/engines/wintermute/game_description.h
index 313fff8bbf..92f62dd7f6 100644
--- a/engines/wintermute/game_description.h
+++ b/engines/wintermute/game_description.h
@@ -24,25 +24,10 @@
#define WINTERMUTE_GAME_DESCRIPTION_H
#include "engines/advancedDetector.h"
+#include "engines/wintermute/base/base_engine.h"
namespace Wintermute {
-enum WMETargetExecutable {
- OLDEST_VERSION,
- WME_1_0_0,
- WME_1_1_0,
- WME_1_2_0,
- WME_1_3_0,
- WME_1_4_0,
- WME_1_5_0,
- WME_1_6_0,
- WME_1_7_0,
- WME_1_8_0,
- WME_1_8_6,
- WME_1_9_0,
- LATEST_VERSION
-};
-
struct WMEGameDescription {
ADGameDescription adDesc;
WMETargetExecutable targetExecutable;
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index e68004d1e5..77df30a54a 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -34,6 +34,7 @@
#include "engines/wintermute/ad/ad_game.h"
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/debugger.h"
+#include "engines/wintermute/game_description.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_engine.h"
@@ -43,6 +44,8 @@
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/debugger/debugger_controller.h"
+#include "gui/message.h"
+
namespace Wintermute {
// Simple constructor for detection - we need to setup the persistence to avoid special-casing in-engine
@@ -109,7 +112,11 @@ bool WintermuteEngine::hasFeature(EngineFeature f) const {
Common::Error WintermuteEngine::run() {
// Initialize graphics using following:
Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
- initGraphics(800, 600, &format);
+ if (_gameDescription->adDesc.flags & GF_LOWSPEC_ASSETS) {
+ initGraphics(320, 240, &format);
+ } else {
+ initGraphics(800, 600, &format);
+ }
if (g_system->getScreenFormat() != format) {
error("Wintermute currently REQUIRES 32bpp");
}
@@ -138,6 +145,18 @@ Common::Error WintermuteEngine::run() {
int WintermuteEngine::init() {
BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameId, _gameDescription->adDesc.language, _gameDescription->targetExecutable);
+
+ // check dependencies for games with high resolution assets
+ #if not defined(USE_PNG) || not defined(USE_JPEG) || not defined(USE_VORBIS)
+ if (!(_gameDescription->adDesc.flags & GF_LOWSPEC_ASSETS)) {
+ GUI::MessageDialog dialog("This game requires PNG, JPEG and Vorbis support.");
+ dialog.runModal();
+ delete _game;
+ _game = nullptr;
+ return false;
+ }
+ #endif
+
_game = new AdGame(_targetName);
if (!_game) {
return 1;
diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h
index a8f9a18530..fe999df082 100644
--- a/engines/wintermute/wintermute.h
+++ b/engines/wintermute/wintermute.h
@@ -24,9 +24,8 @@
#define WINTERMUTE_WINTERMUTE_H
#include "engines/engine.h"
-#include "engines/advancedDetector.h"
#include "gui/debugger.h"
-#include "engines/wintermute/game_description.h"
+#include "common/fs.h"
namespace Wintermute {
@@ -34,6 +33,7 @@ class Console;
class BaseGame;
class SystemClassRegistry;
class DebuggerController;
+struct WMEGameDescription;
// our engine debug channels
enum {
@@ -45,6 +45,11 @@ enum {
kWintermuteDebugGeneral = 1 << 5
};
+enum WintermuteGameFeatures {
+ /** A game with low-spec resources. */
+ GF_LOWSPEC_ASSETS = 1 << 0
+};
+
class WintermuteEngine : public Engine {
public:
WintermuteEngine(OSystem *syst, const WMEGameDescription *desc);
diff --git a/engines/xeen/POTFILES b/engines/xeen/POTFILES
new file mode 100644
index 0000000000..27314a435e
--- /dev/null
+++ b/engines/xeen/POTFILES
@@ -0,0 +1 @@
+engines/xeen/detection.cpp
diff --git a/engines/xeen/character.cpp b/engines/xeen/character.cpp
index 248d432a82..afc013ba89 100644
--- a/engines/xeen/character.cpp
+++ b/engines/xeen/character.cpp
@@ -37,14 +37,27 @@ void AttributePair::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-Character::Character():
- _weapons(this), _armor(this), _accessories(this), _misc(this),
- _items(_weapons, _armor, _accessories, _misc) {
+int CharacterArray::indexOf(const Character &c) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ if ((*this)[idx] == c)
+ return idx;
+ }
+
+ return -1;
+}
+
+/*------------------------------------------------------------------------*/
+
+Character::Character(): _weapons(this), _armor(this), _accessories(this), _misc(this), _items(this) {
clear();
_faceSprites = nullptr;
_rosterId = -1;
}
+Character::Character(const Character &src) : _weapons(this), _armor(this), _accessories(this), _misc(this), _items(this) {
+ operator=(src);
+}
+
void Character::clear() {
_sex = MALE;
_race = HUMAN;
@@ -90,6 +103,65 @@ void Character::clear() {
_misc.clear();
}
+Character &Character::operator=(const Character &src) {
+ clear();
+
+ _faceSprites = src._faceSprites;
+ _rosterId = src._rosterId;
+ _name = src._name;
+ _sex = src._sex;
+ _race = src._race;
+ _xeenSide = src._xeenSide;
+ _class = src._class;
+ _might = src._might;
+ _intellect = src._intellect;
+ _personality = src._personality;
+ _endurance = src._endurance;
+ _speed = src._speed;
+ _accuracy = src._accuracy;
+ _luck = src._luck;
+ _ACTemp = src._ACTemp;
+ _level = src._level;
+ _birthDay = src._birthDay;
+ _tempAge = src._tempAge;
+ Common::copy(&src._skills[0], &src._skills[18], &_skills[0]);
+ Common::copy(&src._awards[0], &src._awards[128], &_awards[0]);
+ Common::copy(&src._spells[0], &src._spells[SPELLS_PER_CLASS], &_spells[0]);
+ _lloydMap = src._lloydMap;
+ _lloydPosition = src._lloydPosition;
+ _hasSpells = src._hasSpells;
+ _currentSpell = src._currentSpell;
+ _quickOption = src._quickOption;
+ _weapons = src._weapons;
+ _armor = src._armor;
+ _accessories = src._accessories;
+ _misc = src._misc;
+ _lloydSide = src._lloydSide;
+ _fireResistence = src._fireResistence;
+ _coldResistence = src._coldResistence;
+ _electricityResistence = src._electricityResistence;
+ _poisonResistence = src._poisonResistence;
+ _energyResistence = src._energyResistence;
+ _magicResistence = src._magicResistence;
+ Common::copy(&src._conditions[0], &src._conditions[16], &_conditions[0]);
+ _townUnknown = src._townUnknown;
+ _savedMazeId = src._savedMazeId;
+ _currentHp = src._currentHp;
+ _currentSp = src._currentSp;
+ _birthYear = src._birthYear;
+ _experience = src._experience;
+ _currentAdventuringSpell = src._currentAdventuringSpell;
+ _currentCombatSpell = src._currentCombatSpell;
+
+ for (ItemCategory category = CATEGORY_WEAPON; category <= CATEGORY_MISC; category = (ItemCategory)((int)category + 1)) {
+ const InventoryItems &srcItems = src._items[category];
+ InventoryItems &destItems = _items[category];
+ destItems = srcItems;
+ }
+
+ return *this;
+}
+
void Character::synchronize(Common::Serializer &s) {
char name[16];
Common::fill(&name[0], &name[16], '\0');
@@ -124,7 +196,7 @@ void Character::synchronize(Common::Serializer &s) {
// upper nibble of the first 64 bytes. Except for award 9, which was a full
// byte counter counting the number of times the warzone was awarded
for (int idx = 0; idx < 64; ++idx) {
- byte b = (idx == WARZONE_AWARD) ? _awards[idx] :
+ byte b = (idx == WARZONE_AWARD) ? _awards[idx] :
(_awards[idx] ? 0x1 : 0) | (_awards[idx + 64] ? 0x10 : 0);
s.syncAsByte(b);
if (s.isLoading()) {
@@ -134,7 +206,7 @@ void Character::synchronize(Common::Serializer &s) {
}
// Synchronize spell list
- for (int i = 0; i < MAX_SPELLS_PER_CLASS; ++i)
+ for (int i = 0; i < SPELLS_PER_CLASS; ++i)
s.syncAsByte(_spells[i]);
s.syncAsByte(_lloydMap);
s.syncAsByte(_lloydPosition.x);
@@ -165,8 +237,8 @@ void Character::synchronize(Common::Serializer &s) {
s.syncAsUint16LE(_townUnknown);
s.syncAsByte(_savedMazeId);
- s.syncAsUint16LE(_currentHp);
- s.syncAsUint16LE(_currentSp);
+ s.syncAsSint16LE(_currentHp);
+ s.syncAsSint16LE(_currentSp);
s.syncAsUint16LE(_birthYear);
s.syncAsUint32LE(_experience);
s.syncAsByte(_currentAdventuringSpell);
@@ -338,7 +410,7 @@ int Character::statColor(int amount, int threshold) {
return 2;
else if (amount == threshold)
return 15;
- else if (amount <= (threshold / 4))
+ else if (amount >= (threshold / 4))
return 9;
else
return 32;
@@ -393,12 +465,12 @@ bool Character::noActions() {
Condition condition = worstCondition();
switch (condition) {
- case CURSED:
- case POISONED:
- case DISEASED:
- case INSANE:
- case IN_LOVE:
- case DRUNK: {
+ case ASLEEP:
+ case PARALYZED:
+ case UNCONSCIOUS:
+ case DEAD:
+ case STONED:
+ case ERADICATED: {
Common::String msg = Common::String::format(Res.IN_NO_CONDITION, _name.c_str());
ErrorScroll::show(Party::_vm, msg,
Party::_vm->_mode == 17 ? WT_LOC_WAIT : WT_NONFREEZED_WAIT);
@@ -482,7 +554,7 @@ int Character::itemScan(int itemId) const {
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
const XeenItem &item = _weapons[idx];
- if (item._frame && !(item._bonusFlags & 0xC0) && itemId < 11
+ if (item._frame && !item.isBad() && itemId < 11
&& itemId != 3 && item._material >= 59 && item._material <= 130) {
int mIndex = (int)item.getAttributeCategory();
if (mIndex > PERSONALITY)
@@ -497,7 +569,7 @@ int Character::itemScan(int itemId) const {
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
const XeenItem &item = _armor[idx];
- if (item._frame && !(item._bonusFlags & 0xC0)) {
+ if (item._frame && !item.isBad()) {
if (itemId < 11 && itemId != 3 && item._material >= 59 && item._material <= 130) {
int mIndex = (int)item.getAttributeCategory();
if (mIndex > PERSONALITY)
@@ -528,7 +600,7 @@ int Character::itemScan(int itemId) const {
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
const XeenItem &item = _accessories[idx];
- if (item._frame && !(item._bonusFlags & 0xC0)) {
+ if (item._frame && !item.isBad()) {
if (itemId < 11 && itemId != 3 && item._material >= 59 && item._material <= 130) {
int mIndex = (int)item.getAttributeCategory();
if (mIndex > PERSONALITY)
@@ -800,21 +872,36 @@ bool Character::guildMember() const {
FileManager &files = *g_vm->_files;
Party &party = *g_vm->_party;
- if (party._mazeId == 49 && !files._isDarkCc) {
+ if (g_vm->getGameID() == GType_Swords) {
+ switch (party._mazeId) {
+ case 49:
+ return true;
+ case 53:
+ return hasAward(83);
+ case 63:
+ return hasAward(85);
+ case 92:
+ return hasAward(84);
+ default:
+ return hasAward(87);
+ }
+ } else if (files._ccNum) {
+ switch (party._mazeId) {
+ case 29:
+ return hasAward(CASTLEVIEW_GUILD_MEMBER);
+ case 31:
+ return hasAward(SANDCASTER_GUILD_MEMBER);
+ case 33:
+ return hasAward(LAKESIDE_GUILD_MEMBER);
+ case 35:
+ return hasAward(NECROPOLIS_GUILD_MEMBER);
+ default:
+ return hasAward(OLYMPUS_GUILD_MEMBER);
+ }
+ } else if (party._mazeId == 49) {
return hasAward(SHANGRILA_GUILD_MEMBER);
- }
-
- switch (party._mazeId) {
- case 29:
- return hasAward(CASTLEVIEW_GUILD_MEMBER);
- case 31:
- return hasAward(SANDCASTER_GUILD_MEMBER);
- case 33:
- return hasAward(LAKESIDE_GUILD_MEMBER);
- case 35:
- return hasAward(NECROPOLIS_GUILD_MEMBER);
- default:
- return hasAward(OLYMPUS_GUILD_MEMBER);
+ } else {
+ return hasAward(party._mazeId - 28);
}
}
@@ -881,6 +968,7 @@ int Character::getNumAwards() const {
ItemCategory Character::makeItem(int p1, int itemIndex, int p3) {
XeenEngine *vm = Party::_vm;
Scripts &scripts = *vm->_scripts;
+ int itemOffset = vm->getGameID() == GType_Swords ? 6 : 0;
if (!p1)
return CATEGORY_WEAPON;
@@ -889,22 +977,22 @@ ItemCategory Character::makeItem(int p1, int itemIndex, int p3) {
int v4 = vm->getRandomNumber(100);
int v6 = vm->getRandomNumber(p1 < 6 ? 100 : 80);
ItemCategory category;
- int v16 = 0, v14 = 0, miscBonus = 0, miscId = 0, v8 = 0, v12 = 0;
+ int v16 = 0, v14 = 0, miscCharges = 0, miscId = 0, v8 = 0, v12 = 0;
// Randomly pick a category and item Id
if (p3 == 12) {
- if (scripts._itemType < 35) {
+ if (scripts._itemType < (35 + itemOffset)) {
category = CATEGORY_WEAPON;
itemId = scripts._itemType;
- } else if (scripts._itemType < 49) {
+ } else if (scripts._itemType < (49 + itemOffset)) {
category = CATEGORY_ARMOR;
- itemId = scripts._itemType - 35;
- } else if (scripts._itemType < 60) {
+ itemId = scripts._itemType - (35 + itemOffset);
+ } else if (scripts._itemType < (60 + itemOffset)) {
category = CATEGORY_ACCESSORY;
- itemId = scripts._itemType - 49;
+ itemId = scripts._itemType - (49 + itemOffset);
} else {
category = CATEGORY_MISC;
- itemId = scripts._itemType - 60;
+ itemId = scripts._itemType - (60 + itemOffset);
}
} else {
switch (p3) {
@@ -1081,7 +1169,7 @@ ItemCategory Character::makeItem(int p1, int itemIndex, int p3) {
break;
case 4:
- miscBonus = vm->getRandomNumber(Res.MAKE_ITEM_ARR5[p1][0], Res.MAKE_ITEM_ARR5[p1][1]);
+ miscCharges = vm->getRandomNumber(Res.MAKE_ITEM_ARR5[p1][0], Res.MAKE_ITEM_ARR5[p1][1]);
break;
default:
@@ -1094,7 +1182,7 @@ ItemCategory Character::makeItem(int p1, int itemIndex, int p3) {
if (p1 != 1) {
newItem._material = (v14 ? v14 + 58 : 0) + (v16 ? v16 + 36 : 0) + v12;
if (vm->getRandomNumber(20) == 10)
- newItem._bonusFlags = vm->getRandomNumber(1, 6);
+ newItem._state._counter = vm->getRandomNumber(1, 6);
}
break;
@@ -1107,7 +1195,7 @@ ItemCategory Character::makeItem(int p1, int itemIndex, int p3) {
case CATEGORY_MISC:
newItem._id = miscId;
- newItem._bonusFlags = miscBonus;
+ newItem._state._counter = miscCharges;
break;
default:
@@ -1134,6 +1222,7 @@ void Character::addHitPoints(int amount) {
intf.drawParty(true);
}
+ assert(_currentHp < 65000);
Common::fill(&intf._charFX[0], &intf._charFX[MAX_ACTIVE_PARTY], 0);
}
@@ -1147,7 +1236,8 @@ void Character::subtractHitPoints(int amount) {
// Subtract the given HP amount
_currentHp -= amount;
- bool flag = _currentHp <= 10;
+ bool breakFlag = _currentHp <= (g_vm->_extOptions._durableArmor ? -80 : -10);
+ assert(_currentHp < 65000);
if (_currentHp < 1) {
int v = getMaxHP() + _currentHp;
@@ -1156,17 +1246,17 @@ void Character::subtractHitPoints(int amount) {
sound.playFX(38);
} else {
_conditions[DEAD] = 1;
- flag = true;
+ breakFlag = true;
if (_currentHp > 0)
_currentHp = 0;
}
- if (flag) {
- // Check for breaking equipped armor
+ if (breakFlag) {
+ // Break any equipped armor the character has
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
XeenItem &item = _armor[idx];
if (item._id && item._frame)
- item._bonusFlags |= ITEMFLAG_BROKEN;
+ item._state._broken = true;
}
}
}
@@ -1174,7 +1264,7 @@ void Character::subtractHitPoints(int amount) {
bool Character::hasSlayerSword() const {
for (uint idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
- if (_weapons[idx]._id == 34)
+ if (_weapons[idx]._id == XEEN_SLAYER_SWORD)
// Character has Xeen Slayer sword
return true;
}
@@ -1192,18 +1282,22 @@ bool Character::hasMissileWeapon() const {
return false;
}
-int Character::getClassCategory() const {
+SpellsCategory Character::getSpellsCategory() const {
switch (_class) {
+ case CLASS_PALADIN:
+ case CLASS_CLERIC:
+ return SPELLCAT_CLERICAL;
+
case CLASS_ARCHER:
case CLASS_SORCERER:
- return 1;
+ return SPELLCAT_WIZARDRY;
case CLASS_DRUID:
case CLASS_RANGER:
- return 2;
+ return SPELLCAT_DRUIDIC;
default:
- return 0;
+ return SPELLCAT_INVALID;
}
}
diff --git a/engines/xeen/character.h b/engines/xeen/character.h
index 05a61c3f2e..47312efe66 100644
--- a/engines/xeen/character.h
+++ b/engines/xeen/character.h
@@ -34,7 +34,7 @@
namespace Xeen {
#define INV_ITEMS_TOTAL 9
-#define MAX_SPELLS_PER_CLASS 39
+#define SPELLS_PER_CLASS 39
#define AWARDS_TOTAL 88
#define WARZONE_AWARD 9
@@ -44,10 +44,6 @@ enum Award {
LAKESIDE_GUILD_MEMBER = 85, NECROPOLIS_GUILD_MEMBER = 86, OLYMPUS_GUILD_MEMBER = 87
};
-enum BonusFlags {
- ITEMFLAG_BONUS_MASK = 0xBF, ITEMFLAG_CURSED = 0x40, ITEMFLAG_BROKEN = 0x80
-};
-
enum Sex { MALE = 0, FEMALE = 1, YES_PLEASE = 2 };
enum Race { HUMAN = 0, ELF = 1, DWARF = 2, GNOME = 3, HALF_ORC = 4 };
@@ -55,7 +51,11 @@ enum Race { HUMAN = 0, ELF = 1, DWARF = 2, GNOME = 3, HALF_ORC = 4 };
enum CharacterClass {
CLASS_KNIGHT = 0, CLASS_PALADIN = 1, CLASS_ARCHER = 2, CLASS_CLERIC = 3,
CLASS_SORCERER = 4, CLASS_ROBBER = 5, CLASS_NINJA = 6, CLASS_BARBARIAN = 7,
- CLASS_DRUID = 8, CLASS_RANGER = 9, TOTAL_CLASSES = 10, CLASS_12 = 12, CLASS_15 = 15, CLASS_16 = 16
+ CLASS_DRUID = 8, CLASS_RANGER = 9, TOTAL_CLASSES = 10
+};
+
+enum HatesClass {
+ HATES_DWARF = 12, HATES_PARTY = 15, HATES_NOBODY = 16
};
enum Attribute {
@@ -83,6 +83,11 @@ enum QuickAction {
QUICK_ATTACK = 0, QUICK_SPELL = 1, QUICK_BLOCK = 2, QUICK_RUN = 3
};
+enum SpellsCategory {
+ SPELLCAT_INVALID = -1, SPELLCAT_CLERICAL = 0, SPELLCAT_WIZARDRY = 1, SPELLCAT_DRUIDIC = 2
+};
+
+
class XeenEngine;
class AttributePair {
@@ -119,17 +124,17 @@ public:
int _tempAge;
int _skills[18];
int _awards[128];
- bool _spells[MAX_SPELLS_PER_CLASS];
+ bool _spells[SPELLS_PER_CLASS];
int _lloydMap;
Common::Point _lloydPosition;
bool _hasSpells;
int8 _currentSpell;
QuickAction _quickOption;
- InventoryItemsGroup _items;
WeaponItems _weapons;
ArmorItems _armor;
AccessoryItems _accessories;
MiscItems _misc;
+ InventoryItemsGroup _items;
int _lloydSide;
AttributePair _fireResistence;
AttributePair _coldResistence;
@@ -150,14 +155,37 @@ public:
SpriteResource *_faceSprites;
int _rosterId;
public:
+ /**
+ * Constructor
+ */
Character();
/**
+ * Constructor
+ */
+ Character(const Character &src);
+
+ /**
+ * Equality operator
+ */
+ bool operator==(const Character &src) const { return src._rosterId == _rosterId; }
+
+ /**
+ * Inequality operator
+ */
+ bool operator!=(const Character &src) const { return src._rosterId != _rosterId; }
+
+ /**
* Clears the data for a character
*/
void clear();
/**
+ * Assignment operator
+ */
+ Character &operator=(const Character &src);
+
+ /**
* Synchronizes data for the character
*/
void synchronize(Common::Serializer &s);
@@ -311,9 +339,16 @@ public:
bool hasMissileWeapon() const;
/**
- * Returns a category index for a character, used such for indexing into spell data
+ * Returns the spells category for the character's class
*/
- int getClassCategory() const;
+ SpellsCategory getSpellsCategory() const;
+
+ /**
+ * Returns an expense factor for purchasing spells by certain character classes
+ */
+ int getSpellsExpenseFactor() const {
+ return (_class == CLASS_PALADIN || _class == CLASS_ARCHER || _class == CLASS_RANGER) ? 1 : 0;
+ }
/**
* Clears the character of any currently set conditions
@@ -321,6 +356,14 @@ public:
void clearConditions();
};
+class CharacterArray : public Common::Array<Character> {
+public:
+ /**
+ * Returns the index of a given character in the array
+ */
+ int indexOf(const Character &c);
+};
+
} // End of namespace Xeen
#endif /* XEEN_CHARACTER_H */
diff --git a/engines/xeen/combat.cpp b/engines/xeen/combat.cpp
index 603b6aef71..4dd2ac6e8a 100644
--- a/engines/xeen/combat.cpp
+++ b/engines/xeen/combat.cpp
@@ -114,6 +114,7 @@ Combat::Combat(XeenEngine *vm): _vm(vm), _missVoc("miss.voc") {
_monsterDamage = 0;
_weaponDamage = 0;
_weaponDie = _weaponDice = 0;
+ _weaponElemMaterial = 0;
_attackWeapon = nullptr;
_attackWeaponId = 0;
_hitChanceBonus = 0;
@@ -141,9 +142,8 @@ void Combat::giveCharDamage(int damage, DamageType attackType, int charIndex) {
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
Windows &windows = *_vm->_windows;
- int charIndex1 = charIndex + 1;
- int selectedIndex1 = 0;
- int selectedIndex2 = 0;
+ int endIndex = charIndex + 1;
+ int selectedIndex = 0;
bool breakFlag = false;
windows.closeAll();
@@ -155,11 +155,11 @@ void Combat::giveCharDamage(int damage, DamageType attackType, int charIndex) {
Condition condition = c.worstCondition();
if (!(condition >= UNCONSCIOUS && condition <= ERADICATED)) {
- if (!selectedIndex1) {
- selectedIndex1 = idx + 1;
+ if (!charIndex) {
+ charIndex = idx + 1;
} else {
- selectedIndex2 = idx + 1;
- --selectedIndex1;
+ selectedIndex = idx + 1;
+ --charIndex;
break;
}
}
@@ -167,12 +167,12 @@ void Combat::giveCharDamage(int damage, DamageType attackType, int charIndex) {
}
if (idx == (int)party._activeParty.size()) {
if (!_combatTarget)
- selectedIndex1 = 0;
+ charIndex = 0;
}
for (;;) {
- for (; selectedIndex1 < (_combatTarget ? charIndex1 : (int)party._activeParty.size()); ++selectedIndex1) {
- Character &c = party._activeParty[selectedIndex1];
+ for (; charIndex < (_combatTarget ? endIndex : (int)party._activeParty.size()); ++charIndex) {
+ Character &c = party._activeParty[charIndex];
c._conditions[ASLEEP] = 0; // Force attacked character to be awake
int frame = 0, fx = 0;
@@ -224,7 +224,7 @@ void Combat::giveCharDamage(int damage, DamageType attackType, int charIndex) {
// Draw the attack effect on the character sprite
sound.playFX(fx);
- intf._charPowSprites.draw(0, frame, Common::Point(Res.CHAR_FACES_X[selectedIndex1], 150));
+ intf._charPowSprites.draw(0, frame, Common::Point(Res.CHAR_FACES_X[charIndex], 150));
windows[33].update();
// Reduce damage if power shield active, and set it zero
@@ -235,7 +235,6 @@ void Combat::giveCharDamage(int damage, DamageType attackType, int charIndex) {
if (damage < 0)
damage = 0;
- // Attacked characters which are asleep are killed
if (attackType == DT_SLEEP) {
damage = c._currentHp;
c._conditions[DEAD] = 1;
@@ -243,15 +242,15 @@ void Combat::giveCharDamage(int damage, DamageType attackType, int charIndex) {
// Subtract the hit points from the character
c.subtractHitPoints(damage);
- if (selectedIndex2)
+ if (selectedIndex)
break;
}
// Break check and if not, move to other index
- if (!selectedIndex2 || breakFlag)
+ if (!selectedIndex || breakFlag)
break;
- selectedIndex1 = selectedIndex2 - 1;
+ charIndex = selectedIndex - 1;
breakFlag = true;
}
@@ -325,7 +324,7 @@ void Combat::doCharDamage(Character &c, int charNum, int monsterDataIndex) {
intf._charPowSprites.draw(0, frame, Common::Point(Res.CHAR_FACES_X[charNum], 150));
windows[33].update();
- damage -= party._powerShield;
+ damage = MAX(damage - party._powerShield, 0);
if (damage > 0 && monsterData._specialAttack && !c.charSavingThrow(DT_PHYSICAL)) {
switch (monsterData._specialAttack) {
case SA_POISON:
@@ -349,13 +348,7 @@ void Combat::doCharDamage(Character &c, int charNum, int monsterDataIndex) {
sound.playFX(36);
break;
case SA_CURSEITEM:
- for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
- if (c._weapons[idx]._id != 34)
- c._weapons[idx]._bonusFlags |= ITEMFLAG_CURSED;
- c._armor[idx]._bonusFlags |= ITEMFLAG_CURSED;
- c._accessories[idx]._bonusFlags |= ITEMFLAG_CURSED;
- c._misc[idx]._bonusFlags |= ITEMFLAG_CURSED;
- }
+ c._items.curseUncurse(true);
sound.playFX(37);
break;
case SA_DRAINSP:
@@ -385,8 +378,8 @@ void Combat::doCharDamage(Character &c, int charNum, int monsterDataIndex) {
case SA_BREAKWEAPON:
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
XeenItem &weapon = c._weapons[idx];
- if (weapon._id != 34 && weapon._id != 0 && weapon._frame != 0) {
- weapon._bonusFlags |= ITEMFLAG_BROKEN;
+ if (weapon._id < XEEN_SLAYER_SWORD && weapon._id != 0 && weapon._frame != 0) {
+ weapon._state._broken = true;
weapon._frame = 0;
}
}
@@ -428,15 +421,15 @@ void Combat::doCharDamage(Character &c, int charNum, int monsterDataIndex) {
default:
break;
}
-
- if (debugger._invincible)
- // Invincibility mode is on, so reset conditions that were set
- c.clearConditions();
- else
- // Standard gameplay, deal out the damage
- c.subtractHitPoints(damage);
}
+ if (debugger._invincible)
+ // Invincibility mode is on, so reset conditions that were set
+ c.clearConditions();
+ else
+ // Standard gameplay, deal out the damage
+ c.subtractHitPoints(damage);
+
events.ipause(2);
intf.drawParty(true);
}
@@ -461,7 +454,9 @@ void Combat::moveMonsters() {
for (uint idx = 0; idx < map._mobData._monsters.size(); ++idx) {
MazeMonster &monster = map._mobData._monsters[idx];
- if ((uint)monster._position.y < 32) {
+
+ // WORKAROUND: Original only checked on y, but some monsters have an invalid X instead
+ if ((uint)monster._position.x < 32 && (uint)monster._position.y < 32) {
assert((uint)monster._position.x < 32);
_monsterMap[monster._position.y][monster._position.x]++;
}
@@ -496,12 +491,12 @@ void Combat::moveMonsters() {
switch (party._mazeDirection) {
case DIR_NORTH:
case DIR_SOUTH:
- if (monsterCanMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX1[arrIndex]],
+ if (canMonsterMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX1[arrIndex]],
MONSTER_GRID_X[arrIndex], MONSTER_GRID_Y[arrIndex], idx)) {
// Move the monster
moveMonster(idx, Common::Point(MONSTER_GRID_X[arrIndex], MONSTER_GRID_Y[arrIndex]));
} else {
- if (monsterCanMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX2[arrIndex]],
+ if (canMonsterMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX2[arrIndex]],
arrIndex >= 21 && arrIndex <= 27 ? MONSTER_GRID3[arrIndex] : 0,
arrIndex >= 21 && arrIndex <= 27 ? 0 : MONSTER_GRID3[arrIndex],
idx)) {
@@ -516,7 +511,7 @@ void Combat::moveMonsters() {
case DIR_EAST:
case DIR_WEST:
- if (monsterCanMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX2[arrIndex]],
+ if (canMonsterMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX2[arrIndex]],
arrIndex >= 21 && arrIndex <= 27 ? MONSTER_GRID3[arrIndex] : 0,
arrIndex >= 21 && arrIndex <= 27 ? 0 : MONSTER_GRID3[arrIndex],
idx)) {
@@ -525,7 +520,7 @@ void Combat::moveMonsters() {
} else {
moveMonster(idx, Common::Point(0, MONSTER_GRID3[arrIndex]));
}
- } else if (monsterCanMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX1[arrIndex]],
+ } else if (canMonsterMove(pt, Res.MONSTER_GRID_BITMASK[MONSTER_GRID_BITINDEX1[arrIndex]],
MONSTER_GRID_X[arrIndex], MONSTER_GRID_Y[arrIndex], idx)) {
moveMonster(idx, Common::Point(MONSTER_GRID_X[arrIndex], MONSTER_GRID_Y[arrIndex]));
}
@@ -638,12 +633,12 @@ void Combat::monstersAttack() {
_monstersAttacking = false;
- if (_vm->_mode != MODE_SLEEPING) {
+ if (_vm->_mode == MODE_SLEEPING) {
for (uint charNum = 0; charNum < party._activeParty.size(); ++charNum) {
Condition condition = party._activeParty[charNum].worstCondition();
- if (condition != ASLEEP && (condition < PARALYZED || condition == NO_CONDITION)) {
- _vm->_mode = MODE_1;
+ if (condition == DEPRESSED || condition == CONFUSED || condition == NO_CONDITION) {
+ _vm->_mode = MODE_INTERACTIVE;
break;
}
}
@@ -675,8 +670,7 @@ void Combat::setupMonsterAttack(int monsterDataIndex, const Common::Point &pt) {
}
}
-bool Combat::monsterCanMove(const Common::Point &pt, int wallShift,
- int xDiff, int yDiff, int monsterId) {
+bool Combat::canMonsterMove(const Common::Point &pt, int wallShift, int xDiff, int yDiff, int monsterId) {
Map &map = *_vm->_map;
MazeMonster &monster = map._mobData._monsters[monsterId];
MonsterStruct &monsterData = *monster._monsterData;
@@ -709,7 +703,7 @@ bool Combat::monsterCanMove(const Common::Point &pt, int wallShift,
} else if (surfaceType == SURFTYPE_SPACE) {
return monsterData._flying;
} else {
- return _vm->_files->_isDarkCc || monster._spriteId != 59;
+ return _vm->_files->_ccNum || monster._spriteId != 59;
}
default:
return v <= map.mazeData()._difficulties._wallNoPass;
@@ -722,6 +716,10 @@ void Combat::moveMonster(int monsterId, const Common::Point &moveDelta) {
MazeMonster &monster = map._mobData._monsters[monsterId];
Common::Point newPos = monster._position + moveDelta;
+ // FIXME: Monster moved outside mapping area. Which shouldn't happen, so ignore the move if it does
+ if ((uint)newPos.x >= 32 || (uint)newPos.y >= 32)
+ return;
+
if (_monsterMap[newPos.y][newPos.x] < 3 && monster._damageType == DT_PHYSICAL && _moveMonsters) {
// Adjust monster's position
++_monsterMap[newPos.y][newPos.x];
@@ -819,15 +817,20 @@ void Combat::doMonsterTurn(int monsterId) {
}
MonsterStruct &monsterData = map._monsterData[monsterId];
- bool flag = false;
for (int attackNum = 0; attackNum < monsterData._numberOfAttacks; ++attackNum) {
int charNum = -1;
bool isHated = false;
- if (monsterData._hatesClass != -1) {
- if (monsterData._hatesClass == 15)
- // Monster hates all classes
- goto loop;
+ if (monsterData._hatesClass != CLASS_PALADIN) {
+ if (monsterData._hatesClass == HATES_PARTY) {
+ // Monster hates entire party, even the disabled/dead
+ for (uint idx = 0; idx < _combatParty.size(); ++idx) {
+ doMonsterTurn(monsterId, idx);
+ }
+
+ // Move onto monster's next attack (if any)
+ continue;
+ }
for (uint charIndex = 0; charIndex < _combatParty.size(); ++charIndex) {
Character &c = *_combatParty[charIndex];
@@ -835,10 +838,8 @@ void Combat::doMonsterTurn(int monsterId) {
if (cond >= PARALYZED && cond <= ERADICATED)
continue;
- isHated = false;
switch (monsterData._hatesClass) {
case CLASS_KNIGHT:
- case CLASS_PALADIN:
case CLASS_ARCHER:
case CLASS_CLERIC:
case CLASS_SORCERER:
@@ -849,7 +850,7 @@ void Combat::doMonsterTurn(int monsterId) {
case CLASS_RANGER:
isHated = c._class == monsterData._hatesClass;
break;
- case 12:
+ case HATES_DWARF:
isHated = c._race == DWARF;
break;
default:
@@ -864,102 +865,78 @@ void Combat::doMonsterTurn(int monsterId) {
}
if (!isHated) {
- // No particularly hated foe, so decide which character to start with
- switch (_combatParty.size()) {
- case 1:
- charNum = 0;
- break;
- case 2:
- case 3:
- case 4:
- case 5:
- charNum = _vm->getRandomNumber(0, _combatParty.size() - 1);
- break;
- case 6:
- if (_vm->getRandomNumber(1, 6) == 6)
- charNum = 5;
- else
- charNum = _vm->getRandomNumber(0, 4);
- break;
- }
+ // No particularly hated foe, so pick a random character to start with
+ // Note: Original had a whole switch statement depending on party size, that boiled down to
+ // picking a random character in all cases anyway
+ charNum = _vm->getRandomNumber(0, _combatParty.size() - 1);
}
- // Attacking loop
- do {
- if (!flag) {
- Condition cond = _combatParty[charNum]->worstCondition();
-
- if (cond >= PARALYZED && cond <= ERADICATED) {
- Common::Array<int> ableChars;
- bool skip = false;
-
- for (uint idx = 0; idx < _combatParty.size() && !skip; ++idx) {
- switch (_combatParty[idx]->worstCondition()) {
- case PARALYZED:
- case UNCONSCIOUS:
- //if (flag)
- // skip = true;
- break;
- case DEAD:
- case STONED:
- case ERADICATED:
- break;
- default:
- ableChars.push_back(idx);
- break;
- }
- }
-
- if (!skip) {
- if (ableChars.size() == 0) {
- party._dead = true;
- _vm->_mode = MODE_1;
- return;
- }
-
- charNum = ableChars[_vm->getRandomNumber(0, ableChars.size() - 1)];
- }
+ // If the chosen character is already disabled, we need to pick a still able body character
+ // from the remainder of the combat party
+ Condition cond = _combatParty[charNum]->worstCondition();
+ if (cond >= PARALYZED && cond <= ERADICATED) {
+ Common::Array<int> ableChars;
+
+ for (uint idx = 0; idx < _combatParty.size(); ++idx) {
+ switch (_combatParty[idx]->worstCondition()) {
+ case PARALYZED:
+ case UNCONSCIOUS:
+ case DEAD:
+ case STONED:
+ case ERADICATED:
+ break;
+ default:
+ ableChars.push_back(idx);
+ break;
}
}
- // Unconditional if to get around goto initialization errors
- if (true) {
- Character &c = *_combatParty[charNum];
- if (monsterData._attackType != DT_PHYSICAL || c._conditions[ASLEEP]) {
- doCharDamage(c, charNum, monsterId);
- } else {
- int v = _vm->getRandomNumber(1, 20);
- if (v == 1) {
- // Critical Save
- sound.playFX(6);
- } else {
- if (v == 20)
- // Critical failure
- doCharDamage(c, charNum, monsterId);
- v += monsterData._hitChance / 4 + _vm->getRandomNumber(1,
- monsterData._hitChance);
-
- int ac = c.getArmorClass() + (!_charsBlocked[charNum] ? 10 :
- c.getCurrentLevel() / 2 + 15);
- if (ac > v) {
- sound.playFX(6);
- } else {
- doCharDamage(c, charNum, monsterId);
- }
- }
- }
-
- if (flag)
- break;
+ if (ableChars.size() == 0) {
+ party._dead = true;
+ _vm->_mode = MODE_INTERACTIVE;
+ return;
}
-loop:
- flag = true;
- } while (++charNum < (int)_combatParty.size());
+
+ charNum = ableChars[_vm->getRandomNumber(0, ableChars.size() - 1)];
+ }
+
+ doMonsterTurn(monsterId, charNum);
}
intf.drawParty(true);
}
+void Combat::doMonsterTurn(int monsterId, int charNum) {
+ Map &map = *_vm->_map;
+ Sound &sound = *_vm->_sound;
+ MonsterStruct &monsterData = map._monsterData[monsterId];
+ Character &c = *_combatParty[charNum];
+
+ if (monsterData._attackType != DT_PHYSICAL || c._conditions[ASLEEP]) {
+ doCharDamage(c, charNum, monsterId);
+ } else {
+ int v = _vm->getRandomNumber(1, 20);
+ if (v == 1) {
+ // Critical Save
+ sound.playFX(6);
+ } else {
+ if (v == 20)
+ // Critical failure
+ doCharDamage(c, charNum, monsterId);
+ v += monsterData._hitChance / 4 + _vm->getRandomNumber(1,
+ monsterData._hitChance);
+
+ int ac = c.getArmorClass() + (!_charsBlocked[charNum] ? 10 :
+ c.getCurrentLevel() / 2 + 15);
+ if (ac > v) {
+ sound.playFX(6);
+ } else {
+ doCharDamage(c, charNum, monsterId);
+ }
+ }
+ }
+}
+
int Combat::stopAttack(const Common::Point &diffPt) {
Map &map = *_vm->_map;
Party &party = *_vm->_party;
@@ -1083,7 +1060,7 @@ void Combat::setSpeedTable() {
bool hasSpeed = _whosSpeed != -1;
int oldSpeed = hasSpeed && _whosSpeed < (int)_speedTable.size() ? _speedTable[_whosSpeed] : 0;
- // Set up speeds for party membres
+ // Set up speeds for party members
int maxSpeed = 0;
for (uint charNum = 0; charNum < _combatParty.size(); ++charNum) {
Character &c = *_combatParty[charNum];
@@ -1108,7 +1085,7 @@ void Combat::setSpeedTable() {
// Populate the _speedTable list with the character/monster indexes
// in order of attacking speed
_speedTable.clear();
- for (; maxSpeed >= 0; --maxSpeed) {
+ for (; maxSpeed > 0; --maxSpeed) {
for (uint idx = 0; idx < charSpeeds.size(); ++idx) {
if (charSpeeds[idx] == maxSpeed)
_speedTable.push_back(idx);
@@ -1116,8 +1093,10 @@ void Combat::setSpeedTable() {
}
if (hasSpeed) {
- if (_speedTable[_whosSpeed] != oldSpeed) {
- for (_whosSpeed = 0; _whosSpeed < (int)charSpeeds.size(); ++_whosSpeed) {
+ if (_speedTable.empty()) {
+ _whosSpeed = 0;
+ } else if (_whosSpeed >= (int)_speedTable.size() || _speedTable[_whosSpeed] != oldSpeed) {
+ for (_whosSpeed = 0; _whosSpeed < (int)_speedTable.size(); ++_whosSpeed) {
if (oldSpeed == _speedTable[_whosSpeed])
break;
}
@@ -1350,32 +1329,34 @@ void Combat::attack(Character &c, RangeType rangeType) {
for (int itemIndex = 0; itemIndex < INV_ITEMS_TOTAL; ++itemIndex) {
XeenItem &weapon = c._weapons[itemIndex];
- if (weapon._frame != 0) {
- switch (weapon._bonusFlags & ITEMFLAG_BONUS_MASK) {
- case 1:
+ if (weapon.isEquipped()) {
+ switch (weapon._state._counter) {
+ case EFFECTIVE_DRAGON:
if (monsterData._monsterType == MONSTER_DRAGON)
damage *= 3;
break;
- case 2:
+ case EFFECTIVE_UNDEAD :
if (monsterData._monsterType == MONSTER_UNDEAD)
damage *= 3;
break;
- case 3:
+ case EFFECTIVE_GOLEM:
if (monsterData._monsterType == MONSTER_GOLEM)
damage *= 3;
break;
- case 4:
+ case EFFECTIVE_INSECT:
if (monsterData._monsterType == MONSTER_INSECT)
damage *= 3;
break;
- case 5:
- if (monsterData._monsterType == MONSTER_0)
+ case EFFEctIVE_MONSTERS:
+ if (monsterData._monsterType == MONSTER_MONSTERS)
damage *= 3;
break;
- case 6:
+ case EFFECTIVE_ANIMAL:
if (monsterData._monsterType == MONSTER_ANIMAL)
damage *= 3;
break;
+ default:
+ break;
}
}
}
@@ -1387,28 +1368,31 @@ void Combat::attack(Character &c, RangeType rangeType) {
}
void Combat::attack2(int damage, RangeType rangeType) {
+ Debugger &debugger = *_vm->_debugger;
Interface &intf = *_vm->_interface;
Map &map = *_vm->_map;
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
- bool isDarkCc = _vm->_files->_isDarkCc;
+ int ccNum = _vm->_files->_ccNum;
MazeMonster &monster = map._mobData._monsters[_monster2Attack];
MonsterStruct &monsterData = *monster._monsterData;
bool monsterDied = false;
- if (!isDarkCc && damage && rangeType != RT_SINGLE && monster._spriteId == 89)
+ if (!ccNum && damage && rangeType != RT_SINGLE && monster._spriteId == 89)
damage = 0;
+ if (debugger._superStrength)
+ damage = 10000;
if (!damage) {
sound.playSound(_missVoc, 1);
sound.playFX(6);
} else {
- if (!isDarkCc && monster._spriteId == 89)
+ if (!ccNum && monster._spriteId == 89)
damage += 100;
if (monster._damageType == DT_SLEEP || monster._damageType == DT_DRAGONSLEEP)
monster._damageType = DT_PHYSICAL;
- if ((rangeType == RT_SINGLE || _damageType == DT_PHYSICAL) && _attackWeaponId != 34) {
+ if ((rangeType == RT_SINGLE || _damageType == DT_PHYSICAL) && _attackWeaponId < XEEN_SLAYER_SWORD) {
if (monsterData._phsyicalResistence != 0) {
if (monsterData._phsyicalResistence == 100) {
// Completely immune to the damage
@@ -1430,7 +1414,7 @@ void Combat::attack2(int damage, RangeType rangeType) {
int monsterResist = getMonsterResistence(rangeType);
damage += monsterResist;
if (monsterResist > 0) {
- _pow[_attackDurationCtr]._elemFrame = _attackWeapon->getElementalCategory();
+ _pow[_attackDurationCtr]._elemFrame = XeenItem::getElementalCategory(_weaponElemMaterial);
_pow[_attackDurationCtr]._elemScale = getDamageScale(monsterResist);
} else if (rangeType != RT_HIT) {
_pow[_attackDurationCtr]._elemFrame = 0;
@@ -1471,9 +1455,9 @@ void Combat::attack2(int damage, RangeType rangeType) {
intf.draw3d(true);
sound.stopSound();
- File powVoc(Common::String::format("pow%d.voc",
- POW_WEAPON_VOCS[_attackWeaponId]));
- sound.playFX(60 + POW_WEAPON_VOCS[_attackWeaponId]);
+ int powNum = (_attackWeaponId > XEEN_SLAYER_SWORD) ? 0 : POW_WEAPON_VOCS[_attackWeaponId];
+ File powVoc(Common::String::format("pow%d.voc", powNum));
+ sound.playFX(60 + powNum);
sound.playSound(powVoc, 1);
if (monster._hp > damage) {
@@ -1488,12 +1472,12 @@ void Combat::attack2(int damage, RangeType rangeType) {
intf.draw3d(true);
if (monsterDied) {
- if (!isDarkCc) {
+ if (!ccNum) {
if (_monster2Attack == 20 && party._mazeId == 41)
party._gameFlags[0][11] = true;
if (_monster2Attack == 8 && party._mazeId == 78) {
party._gameFlags[0][60] = true;
- party._questFlags[0][23] = false;
+ party._questFlags[23] = false;
for (uint idx = 0; idx < party._activeParty.size(); ++idx)
party._activeParty[idx].setAward(42, true);
@@ -1506,14 +1490,14 @@ void Combat::attack2(int damage, RangeType rangeType) {
giveExperience(monsterData._experience);
if (party._mazeId != 85) {
- party._treasure._gold = monsterData._gold;
- party._treasure._gems = monsterData._gems;
+ party._treasure._gold += monsterData._gold;
+ party._treasure._gems += monsterData._gems;
- if (!isDarkCc && monster._spriteId == 89) {
+ if (!ccNum && monster._spriteId == 89) {
// Xeen's Scepter of Temporal Distortion
party._treasure._weapons[0]._id = 90;
- party._treasure._weapons[0]._bonusFlags = 0;
party._treasure._weapons[0]._material = 0;
+ party._treasure._weapons[0]._state.clear();
party._treasure._hasItems = true;
party._questItems[8]++;
}
@@ -1527,7 +1511,7 @@ void Combat::attack2(int damage, RangeType rangeType) {
switch (category) {
case CATEGORY_WEAPON:
for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- if (party._treasure._weapons[idx]._id == 0) {
+ if (party._treasure._weapons[idx].empty()) {
party._treasure._weapons[idx] = tempChar._weapons[0];
party._treasure._hasItems = true;
break;
@@ -1536,7 +1520,7 @@ void Combat::attack2(int damage, RangeType rangeType) {
break;
case CATEGORY_ARMOR:
for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- if (party._treasure._armor[idx]._id == 0) {
+ if (party._treasure._armor[idx].empty()) {
party._treasure._armor[idx] = tempChar._armor[0];
party._treasure._hasItems = true;
break;
@@ -1545,7 +1529,7 @@ void Combat::attack2(int damage, RangeType rangeType) {
break;
case CATEGORY_ACCESSORY:
for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- if (party._treasure._accessories[idx]._id == 0) {
+ if (party._treasure._accessories[idx].empty()) {
party._treasure._accessories[idx] = tempChar._accessories[0];
party._treasure._hasItems = true;
break;
@@ -1554,7 +1538,7 @@ void Combat::attack2(int damage, RangeType rangeType) {
break;
case CATEGORY_MISC:
for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- if (party._treasure._accessories[idx]._id == 0) {
+ if (party._treasure._accessories[idx].empty()) {
party._treasure._accessories[idx] = tempChar._accessories[0];
party._treasure._hasItems = true;
break;
@@ -1592,7 +1576,7 @@ void Combat::quickFight() {
break;
case QUICK_SPELL:
if (c->_currentSpell != -1) {
- spells.castSpell(c, (MagicSpell)Res.SPELLS_ALLOWED[c->getClassCategory()][c->_currentSpell]);
+ spells.castSpell(c, (MagicSpell)Res.SPELLS_ALLOWED[c->getSpellsCategory()][c->_currentSpell]);
}
break;
case QUICK_BLOCK:
@@ -1676,6 +1660,7 @@ void Combat::getWeaponDamage(Character &c, RangeType rangeType) {
_weaponDie = _weaponDice = 0;
_weaponDamage = 0;
_hitChanceBonus = 0;
+ _weaponElemMaterial = 0;
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
XeenItem &weapon = c._weapons[idx];
@@ -1687,10 +1672,12 @@ void Combat::getWeaponDamage(Character &c, RangeType rangeType) {
}
if (flag) {
- if (!(weapon._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED))) {
+ if (!weapon.isBad()) {
_attackWeapon = &weapon;
- if (weapon._material >= 37 && weapon._material < 59) {
+ if (weapon._material < 37) {
+ _weaponElemMaterial = weapon._material;
+ } else if (weapon._material < 59) {
_hitChanceBonus = Res.METAL_DAMAGE_PERCENT[weapon._material - 37];
_weaponDamage = Res.METAL_DAMAGE[weapon._material - 37];
}
@@ -1761,7 +1748,7 @@ int Combat::getMonsterResistence(RangeType rangeType) {
break;
}
} else {
- int material = !_attackWeapon ? 0 : _attackWeapon->_material;
+ int material = _weaponElemMaterial;
damage = Res.ELEMENTAL_DAMAGE[material];
if (material != 0) {
@@ -1869,7 +1856,7 @@ void Combat::rangedAttack(PowType powNum) {
_attackDurationCtr = -1;
if (_monster2Attack != -1) {
- _attackDurationCtr--;
+ _attackDurationCtr = attackDurationCtr - 1;
if (attackMonsters.empty())
attackMonsters.resize(1);
attackMonsters[0] = monster2Attack;
@@ -2098,4 +2085,21 @@ void Combat::shootRangedWeapon() {
rangedAttack(POW_ARROW);
}
+bool Combat::areMonstersPresent() const {
+ for (int idx = 0; idx < 26; ++idx) {
+ if (_attackMonsters[idx] != -1)
+ return true;
+ }
+
+ return false;
+}
+
+void Combat::reset() {
+ clearShooting();
+ setupCombatParty();
+
+ _combatMode = COMBATMODE_INTERACTIVE;
+ _monster2Attack = -1;
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/combat.h b/engines/xeen/combat.h
index 938845b022..e1a02c0759 100644
--- a/engines/xeen/combat.h
+++ b/engines/xeen/combat.h
@@ -58,7 +58,7 @@ enum ShootType {
};
enum CombatMode {
- COMBATMODE_STARTUP = 0, COMBATMODE_1 = 1, COMBATMODE_2 = 2
+ COMBATMODE_STARTUP = 0, COMBATMODE_INTERACTIVE = 1, COMBATMODE_2 = 2
};
enum PowType {
@@ -77,6 +77,7 @@ enum RangeType {
class XeenEngine;
class Character;
class XeenItem;
+class MonsterStruct;
struct PowSlot {
bool _active;
@@ -151,7 +152,7 @@ private:
public:
Common::Array<Character *> _combatParty;
bool _charsBlocked[PARTY_AND_MONSTERS];
- Common::Array<int> _charsGone;
+ int _charsGone[PARTY_AND_MONSTERS];
SpriteResource _powSprites;
int _attackMonsters[ATTACK_MONSTERS_COUNT];
int _monster2Attack;
@@ -176,6 +177,7 @@ public:
int _monsterDamage;
int _weaponDamage;
int _weaponDie, _weaponDice;
+ int _weaponElemMaterial;
XeenItem *_attackWeapon;
int _attackWeaponId;
File _missVoc;
@@ -204,6 +206,11 @@ public:
void clearShooting();
/**
+ * Resets all combat related data
+ */
+ void reset();
+
+ /**
* Gives damage to character or characters in the party
*/
void giveCharDamage(int damage, DamageType attackType, int charIndex);
@@ -272,18 +279,30 @@ public:
/**
* Determines whether a given monster can move
+ * @param pt Monster position
+ * @param wallShift Shift mask for determining direction being moved
+ * @param xDiff X Delta for move
+ * @param yDiff Y Delta for move
+ * @param monsterId Monster number being tested
*/
- bool monsterCanMove(const Common::Point &pt, int wallShift,
- int v1, int v2, int monsterId);
+ bool canMonsterMove(const Common::Point &pt, int wallShift, int xDiff, int yDiff, int monsterId);
/**
* Moves a monster by a given delta amount if it's a valid move
*/
void moveMonster(int monsterId, const Common::Point &moveDelta);
+ /**
+ * Handle a monster's turn at attacking combat party members
+ */
void doMonsterTurn(int monsterId);
/**
+ * Handles a monster's turn at attacking a specific member of the combat party
+ */
+ void doMonsterTurn(int monsterId, int charNum);
+
+ /**
* Called when combat has ended
*/
void endAttack();
@@ -304,6 +323,11 @@ public:
* Fires off a ranged attack at all oncoming monsters
*/
void shootRangedWeapon();
+
+ /**
+ * Returns true if there are any monsters in the vacinity
+ */
+ bool areMonstersPresent() const;
};
} // End of namespace Xeen
diff --git a/engines/xeen/configure.engine b/engines/xeen/configure.engine
index 489254f269..6907bde982 100644
--- a/engines/xeen/configure.engine
+++ b/engines/xeen/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine xeen "World of Xeen" no
+add_engine xeen "World of Xeen" yes
diff --git a/engines/xeen/debugger.cpp b/engines/xeen/debugger.cpp
index 42f61b02b5..7d8f170129 100644
--- a/engines/xeen/debugger.cpp
+++ b/engines/xeen/debugger.cpp
@@ -45,7 +45,7 @@ static int strToInt(const char *s) {
/*------------------------------------------------------------------------*/
Debugger::Debugger(XeenEngine *vm) : GUI::Debugger(), _vm(vm),
- _invincible(false) {
+ _spellId(-1), _invincible(false), _intangible(false), _superStrength(false) {
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("spell", WRAP_METHOD(Debugger, cmdSpell));
registerCmd("spells", WRAP_METHOD(Debugger, cmdSpells));
@@ -55,8 +55,8 @@ Debugger::Debugger(XeenEngine *vm) : GUI::Debugger(), _vm(vm),
registerCmd("map", WRAP_METHOD(Debugger, cmdMap));
registerCmd("pos", WRAP_METHOD(Debugger, cmdPos));
registerCmd("invincible", WRAP_METHOD(Debugger, cmdInvincible));
-
- _spellId = -1;
+ registerCmd("strength", WRAP_METHOD(Debugger, cmdSuperStrength));
+ registerCmd("intangible", WRAP_METHOD(Debugger, cmdIntangible));
}
void Debugger::update() {
@@ -95,7 +95,7 @@ bool Debugger::cmdSpells(int argc, const char **argv) {
for (uint charIdx = 0; charIdx < party._activeParty.size(); ++charIdx) {
Character &c = party._activeParty[charIdx];
- Common::fill(c._spells, c._spells + MAX_SPELLS_PER_CLASS, true);
+ Common::fill(c._spells, c._spells + SPELLS_PER_CLASS, true);
c._currentSp = 9999;
}
@@ -160,20 +160,19 @@ bool Debugger::cmdGems(int argc, const char **argv) {
}
bool Debugger::cmdMap(int argc, const char **argv) {
- FileManager &files = *g_vm->_files;
Map &map = *g_vm->_map;
Party &party = *g_vm->_party;
if (argc < 2) {
- debugPrintf("map mapId [ sideNum [ xp, yp ]]\n");
+ debugPrintf("map mapId [ xp, yp ] [ sideNum ]\n");
return true;
} else {
int mapId = strToInt(argv[1]);
- bool side = argc < 3 ? files._isDarkCc : strToInt(argv[2]) != 0;
- int x = argc < 4 ? 8 : strToInt(argv[3]);
- int y = argc < 5 ? 8 : strToInt(argv[4]);
+ int x = argc < 3 ? 8 : strToInt(argv[2]);
+ int y = argc < 4 ? 8 : strToInt(argv[3]);
- map._loadDarkSide = side;
+ if (argc == 5)
+ map._loadCcNum = strToInt(argv[4]);
map.load(mapId);
party._mazePosition.x = x;
party._mazePosition.y = y;
@@ -202,4 +201,16 @@ bool Debugger::cmdInvincible(int argc, const char **argv) {
return true;
}
+bool Debugger::cmdSuperStrength(int argc, const char **argv) {
+ _superStrength = (argc < 2) || strcmp(argv[1], "off");
+ debugPrintf("Super-powered attacks are %s\n", _superStrength ? "on" : "off");
+ return true;
+}
+
+bool Debugger::cmdIntangible(int argc, const char **argv) {
+ _intangible = (argc < 2) || strcmp(argv[1], "off");
+ debugPrintf("Intangibility is %s\n", _intangible ? "on" : "off");
+ return true;
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/debugger.h b/engines/xeen/debugger.h
index b7e1f1c325..48eb8f35f6 100644
--- a/engines/xeen/debugger.h
+++ b/engines/xeen/debugger.h
@@ -74,8 +74,20 @@ private:
* Flags whether to make the party invincible
*/
bool cmdInvincible(int argc, const char **argv);
+
+ /**
+ * Flags whether to make the party super-strength attacks
+ */
+ bool cmdSuperStrength(int argc, const char **argv);
+
+ /**
+ * Flags whether to make the party invincible
+ */
+ bool cmdIntangible(int argc, const char **argv);
public:
bool _invincible;
+ bool _intangible;
+ bool _superStrength;
public:
Debugger(XeenEngine *vm);
diff --git a/engines/xeen/detection.cpp b/engines/xeen/detection.cpp
index cf033b632f..8a5e096220 100644
--- a/engines/xeen/detection.cpp
+++ b/engines/xeen/detection.cpp
@@ -28,6 +28,7 @@
#include "common/savefile.h"
#include "engines/advancedDetector.h"
#include "common/system.h"
+#include "common/translation.h"
#define MAX_SAVES 99
@@ -60,6 +61,10 @@ Common::Platform XeenEngine::getPlatform() const {
return _gameDescription->desc.platform;
}
+bool XeenEngine::getIsCD() const {
+ return getFeatures() & ADGF_CD;
+}
+
} // End of namespace Xeen
static const PlainGameDescriptor XeenGames[] = {
@@ -71,11 +76,40 @@ static const PlainGameDescriptor XeenGames[] = {
{0, 0}
};
+#define GAMEOPTION_SHOW_ITEM_COSTS GUIO_GAMEOPTIONS1
+#define GAMEOPTION_DURABLE_ARMOR GUIO_GAMEOPTIONS2
+
#include "xeen/detection_tables.h"
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_SHOW_ITEM_COSTS,
+ {
+ _s("Show item costs in standard inventory mode"),
+ _s("Shows item costs in standard inventory mode, allowing the value of items to be compared"),
+ "ShowItemCosts",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_DURABLE_ARMOR,
+ {
+ _s("More durable armor"),
+ _s("Armor won't break until character is at -80HP, rather than merely -10HP"),
+ "DurableArmor",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
class XeenMetaEngine : public AdvancedMetaEngine {
public:
- XeenMetaEngine() : AdvancedMetaEngine(Xeen::gameDescriptions, sizeof(Xeen::XeenGameDescription), XeenGames) {
+ XeenMetaEngine() : AdvancedMetaEngine(Xeen::gameDescriptions, sizeof(Xeen::XeenGameDescription),
+ XeenGames, optionsList) {
_maxScanDepth = 3;
}
@@ -137,32 +171,29 @@ SaveStateList XeenMetaEngine::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);
+ Common::String pattern = Common::String::format("%s.###", target);
Xeen::XeenSavegameHeader header;
filenames = saveFileMan->listSavefiles(pattern);
- sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
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 < MAX_SAVES) {
+ if (slot >= 0 && slot <= MAX_SAVES) {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- Xeen::SavesManager::readSavegameHeader(in, header);
- saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+ if (Xeen::SavesManager::readSavegameHeader(in, header))
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
- if (header._thumbnail)
- header._thumbnail->free();
- delete header._thumbnail;
delete in;
}
}
}
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
@@ -181,7 +212,11 @@ SaveStateDescriptor XeenMetaEngine::querySaveMetaInfos(const char *target, int s
if (f) {
Xeen::XeenSavegameHeader header;
- Xeen::SavesManager::readSavegameHeader(f, header);
+ if (!Xeen::SavesManager::readSavegameHeader(f, header, false)) {
+ delete f;
+ return SaveStateDescriptor();
+ }
+
delete f;
// Create the return descriptor
diff --git a/engines/xeen/detection_tables.h b/engines/xeen/detection_tables.h
index c311bde202..fdb9dbd668 100644
--- a/engines/xeen/detection_tables.h
+++ b/engines/xeen/detection_tables.h
@@ -35,8 +35,8 @@ static const XeenGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
+ ADGF_TESTING,
+ GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
},
GType_WorldOfXeen,
0
@@ -54,8 +54,8 @@ static const XeenGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
},
GType_WorldOfXeen,
0
@@ -65,7 +65,7 @@ static const XeenGameDescription gameDescriptions[] = {
// World of Xeen (2 CD talkie version)
{
"worldofxeen",
- nullptr,
+ "CD",
{
{"xeen.cc", 0, "964078c53f649937ce9a1a3596ce3d9f", 13438429},
{"dark.cc", 0, "7f755ce39ea614fa6adb016f8bfc6e43", 11288403},
@@ -73,8 +73,8 @@ static const XeenGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
+ ADGF_TESTING | ADGF_CD,
+ GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
},
GType_WorldOfXeen,
0
@@ -91,8 +91,8 @@ static const XeenGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
+ ADGF_TESTING,
+ GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
},
GType_Clouds,
0
@@ -109,15 +109,15 @@ static const XeenGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
+ ADGF_TESTING,
+ GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
},
GType_DarkSide,
0
},
{
- // Swords of Xeen (GOG)
+ // Swords of Xeen
{
"swordsofxeen",
nullptr,
@@ -127,8 +127,8 @@ static const XeenGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
+ ADGF_TESTING,
+ GUIO2(GAMEOPTION_SHOW_ITEM_COSTS, GAMEOPTION_DURABLE_ARMOR)
},
GType_Swords,
0
diff --git a/engines/xeen/dialogs/credits_screen.cpp b/engines/xeen/dialogs/credits_screen.cpp
index 09547ba282..d0269ad716 100644
--- a/engines/xeen/dialogs/credits_screen.cpp
+++ b/engines/xeen/dialogs/credits_screen.cpp
@@ -28,7 +28,7 @@ namespace Xeen {
void CreditsScreen::show(XeenEngine *vm) {
CreditsScreen *dlg = new CreditsScreen(vm);
-
+
switch (vm->getGameID()) {
case GType_Clouds:
dlg->execute(Res.CLOUDS_CREDITS);
@@ -41,7 +41,7 @@ void CreditsScreen::show(XeenEngine *vm) {
dlg->execute(Res.DARK_SIDE_CREDITS);
break;
}
-
+
delete dlg;
}
diff --git a/engines/xeen/dialogs/dialogs.cpp b/engines/xeen/dialogs/dialogs.cpp
index d7a696b8d5..d5c732e51a 100644
--- a/engines/xeen/dialogs/dialogs.cpp
+++ b/engines/xeen/dialogs/dialogs.cpp
@@ -66,48 +66,54 @@ bool ButtonContainer::checkEvents(XeenEngine *vm) {
EventsManager &events = *vm->_events;
Party &party = *vm->_party;
Windows &windows = *_vm->_windows;
+ PendingEvent event;
_buttonValue = 0;
- if (events._leftButton) {
- Common::Point pt = events._mousePos;
-
- // Check for party member glyphs being clicked
- Common::Rect r(0, 0, 32, 32);
- for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
- r.moveTo(Res.CHAR_FACES_X[idx], 150);
- if (r.contains(pt)) {
- _buttonValue = Common::KEYCODE_F1 + idx;
- break;
+ if (events.getEvent(event)) {
+ if (event._leftButton) {
+ Common::Point pt = events._mousePos;
+
+ // Check for party member glyphs being clicked
+ Common::Rect r(0, 0, 32, 32);
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+ r.moveTo(Res.CHAR_FACES_X[idx], 150);
+ if (r.contains(pt)) {
+ _buttonValue = Common::KEYCODE_F1 + idx;
+ break;
+ }
}
- }
- // Check whether any button is selected
- for (uint i = 0; i < _buttons.size(); ++i) {
- if (_buttons[i]._bounds.contains(pt)) {
- events.debounceMouse();
+ // Check whether any button is selected
+ for (uint i = 0; i < _buttons.size(); ++i) {
+ if (_buttons[i]._bounds.contains(pt)) {
+ events.debounceMouse();
- _buttonValue = _buttons[i]._value;
- break;
+ _buttonValue = _buttons[i]._value;
+ break;
+ }
+ }
+
+ if (!_buttonValue && _waitBounds.contains(pt)) {
+ _buttonValue = Common::KEYCODE_SPACE;
+ return true;
}
- }
- if (!_buttonValue && Common::Rect(8, 8, 224, 135).contains(pt)) {
- _buttonValue = 1;
- return true;
+ } else if (event.isKeyboard()) {
+ const Common::KeyCode &keycode = event._keyState.keycode;
+
+ if (keycode == Common::KEYCODE_KP8)
+ _buttonValue = Common::KEYCODE_UP;
+ else if (keycode == Common::KEYCODE_KP2)
+ _buttonValue = Common::KEYCODE_DOWN;
+ else if (keycode == Common::KEYCODE_KP_ENTER)
+ _buttonValue = Common::KEYCODE_RETURN;
+ else if (keycode != Common::KEYCODE_LCTRL && keycode != Common::KEYCODE_RCTRL
+ && keycode != Common::KEYCODE_LALT && keycode != Common::KEYCODE_RALT)
+ _buttonValue = keycode;
+
+ if (_buttonValue)
+ _buttonValue |= (event._keyState.flags & ~Common::KBD_STICKY) << 16;
}
- } else if (events.isKeyPending()) {
- Common::KeyState keyState;
- events.getKey(keyState);
-
- _buttonValue = keyState.keycode;
- if (_buttonValue == Common::KEYCODE_KP8)
- _buttonValue = Common::KEYCODE_UP;
- else if (_buttonValue == Common::KEYCODE_KP2)
- _buttonValue = Common::KEYCODE_DOWN;
- else if (_buttonValue == Common::KEYCODE_KP_ENTER)
- _buttonValue = Common::KEYCODE_RETURN;
-
- _buttonValue |= (keyState.flags & ~Common::KBD_STICKY) << 16;
}
if (_buttonValue) {
@@ -118,8 +124,7 @@ bool ButtonContainer::checkEvents(XeenEngine *vm) {
if (btn._draw && btn._value == _buttonValue) {
// Found the correct button
// Draw button depressed
- btn._sprites->draw(0, btn._frameNum + 1,
- Common::Point(btn._bounds.left, btn._bounds.top));
+ btn._sprites->draw(0, btn._selectedFrame, Common::Point(btn._bounds.left, btn._bounds.top));
win.setBounds(btn._bounds);
win.update();
@@ -128,8 +133,7 @@ bool ButtonContainer::checkEvents(XeenEngine *vm) {
events.wait(2);
// Redraw button in it's original non-depressed form
- btn._sprites->draw(0, btn._frameNum,
- Common::Point(btn._bounds.left, btn._bounds.top));
+ btn._sprites->draw(0, btn._frameNum, Common::Point(btn._bounds.left, btn._bounds.top));
win.setBounds(btn._bounds);
win.update();
break;
@@ -146,6 +150,7 @@ void ButtonContainer::drawButtons(XSurface *surface) {
for (uint btnIndex = 0; btnIndex < _buttons.size(); ++btnIndex) {
UIButton &btn = _buttons[btnIndex];
if (btn._draw) {
+ assert(btn._sprites);
btn._sprites->draw(*surface, btn._frameNum,
Common::Point(btn._bounds.left, btn._bounds.top));
}
@@ -153,7 +158,7 @@ void ButtonContainer::drawButtons(XSurface *surface) {
}
bool ButtonContainer::doScroll(bool rollUp, bool fadeIn) {
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
return Cutscenes::doScroll(rollUp, fadeIn);
} else {
saveButtons();
diff --git a/engines/xeen/dialogs/dialogs.h b/engines/xeen/dialogs/dialogs.h
index 9038f75ef8..e97e46c5d3 100644
--- a/engines/xeen/dialogs/dialogs.h
+++ b/engines/xeen/dialogs/dialogs.h
@@ -39,14 +39,36 @@ public:
Common::Rect _bounds;
SpriteResource *_sprites;
int _value;
- uint _frameNum;
+ uint _frameNum, _selectedFrame;
bool _draw;
+ /**
+ * Constructor
+ */
UIButton(const Common::Rect &bounds, int value, uint frameNum, SpriteResource *sprites, bool draw) :
- _bounds(bounds), _value(value), _frameNum(frameNum),
+ _bounds(bounds), _value(value), _frameNum(frameNum), _selectedFrame(frameNum | 1),
_sprites(sprites), _draw(draw) {}
- UIButton() : _value(0), _frameNum(0), _sprites(nullptr), _draw(false) {}
+ /**
+ * Constructor
+ */
+ UIButton() : _value(0), _frameNum(0), _selectedFrame(0), _sprites(nullptr), _draw(false) {}
+
+ /**
+ * Set the frame
+ */
+ void setFrame(uint frameNum) {
+ _frameNum = frameNum;
+ _selectedFrame = frameNum | 1;
+ }
+
+ /**
+ * Set the frame
+ */
+ void setFrame(uint frameNum, uint selectedFrame) {
+ _frameNum = frameNum;
+ _selectedFrame = selectedFrame;
+ }
};
class ButtonContainer : public Cutscenes {
@@ -55,6 +77,7 @@ private:
protected:
Common::Array<UIButton> _buttons;
Common::StringArray _textStrings;
+ Common::Rect _waitBounds;
int _buttonValue;
bool checkEvents(XeenEngine *vm);
@@ -102,6 +125,11 @@ public:
* Draws the buttons onto the passed surface
*/
void drawButtons(XSurface *surface);
+
+ /**
+ * Clears any currently set button value
+ */
+ void clearEvents() { _buttonValue = 0; }
};
class SettingsBaseDialog : public ButtonContainer {
diff --git a/engines/xeen/dialogs/dialogs_char_info.cpp b/engines/xeen/dialogs/dialogs_char_info.cpp
index 0ae64ed608..aec8be5ee4 100644
--- a/engines/xeen/dialogs/dialogs_char_info.cpp
+++ b/engines/xeen/dialogs/dialogs_char_info.cpp
@@ -142,7 +142,7 @@ void CharacterInfo::execute(int charIndex) {
case Common::KEYCODE_RETURN:
case Common::KEYCODE_KP_ENTER:
_buttonValue = _cursorCell + Common::KEYCODE_a;
- // Deliberate fall-through
+ // fall through
case 1001:
case 1002:
@@ -198,6 +198,7 @@ void CharacterInfo::execute(int charIndex) {
}
_vm->_mode = MODE_CHARACTER_INFO;
+ redrawFlag = true;
break;
case Common::KEYCODE_q:
@@ -395,14 +396,18 @@ bool CharacterInfo::expandStat(int attrib, const Character &c) {
bounds.setHeight(42);
break;
- case 10:
+ case 10: {
// Hit Points
- stat1 = c._currentHp;
- stat2 = c.getMaxHP();
- msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
- stat1, stat2);
+ Common::String fmt(Res.CURRENT_MAXIMUM_TEXT);
+ const char *p;
+ while ((p = strstr(fmt.c_str(), "%u")) != nullptr)
+ fmt.setChar('d', p - fmt.c_str() + 1);
+
+ msg = Common::String::format(fmt.c_str(), Res.STAT_NAMES[attrib],
+ c._currentHp, c.getMaxHP());
bounds.setHeight(42);
break;
+ }
case 11:
// Spell Points
@@ -521,14 +526,22 @@ bool CharacterInfo::expandStat(int attrib, const Character &c) {
++total;
}
- if (party._blessed)
+ if (party._blessed) {
lines[16] = Common::String::format(Res.BLESSED, party._blessed);
- if (party._powerShield)
+ ++total;
+ }
+ if (party._powerShield) {
lines[17] = Common::String::format(Res.POWER_SHIELD, party._powerShield);
- if (party._holyBonus)
+ ++total;
+ }
+ if (party._holyBonus) {
lines[18] = Common::String::format(Res.HOLY_BONUS, party._holyBonus);
- if (party._heroism)
+ ++total;
+ }
+ if (party._heroism) {
lines[19] = Common::String::format(Res.HEROISM, party._heroism);
+ ++total;
+ }
msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\x1",
Res.CONSUMABLE_NAMES[3], lines[0].c_str(), lines[1].c_str(),
diff --git a/engines/xeen/dialogs/dialogs_control_panel.cpp b/engines/xeen/dialogs/dialogs_control_panel.cpp
index 177c7785f8..80d1715ff7 100644
--- a/engines/xeen/dialogs/dialogs_control_panel.cpp
+++ b/engines/xeen/dialogs/dialogs_control_panel.cpp
@@ -61,9 +61,10 @@ int ControlPanel::execute() {
w.writeString("\xB""000\t000\x1");
w.update();
+ events.updateGameCounter();
+ intf.draw3d(false, false);
+
do {
- events.updateGameCounter();
- intf.draw3d(false, false);
w.writeString("\r");
drawButtons(&w);
w.writeString(text);
@@ -80,7 +81,7 @@ int ControlPanel::execute() {
checkEvents(_vm);
if (_vm->shouldExit())
return 0;
- } while (!_buttonValue && !events.timeElapsed());
+ } while (!_buttonValue && events.timeElapsed() < 2);
switch (_buttonValue) {
case Common::KEYCODE_q:
@@ -97,11 +98,11 @@ int ControlPanel::execute() {
sound.playFX(51);
if (g_vm->getGameID() == GType_WorldOfXeen) {
- map._loadDarkSide = false;
+ map._loadCcNum = 0;
map.load(28);
party._mazeDirection = DIR_EAST;
} else {
- map._loadDarkSide = true;
+ map._loadCcNum = 1;
map.load(29);
party._mazeDirection = DIR_SOUTH;
}
@@ -169,7 +170,8 @@ int ControlPanel::execute() {
intf.drawParty(true);
if (result == 3) {
- saves.loadGame();
+ if (g_vm->canLoadGameStateCurrently())
+ saves.loadGame();
} else if (result == 4) {
saves.saveGame();
}
diff --git a/engines/xeen/dialogs/dialogs_copy_protection.cpp b/engines/xeen/dialogs/dialogs_copy_protection.cpp
new file mode 100644
index 0000000000..7788cb5a22
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_copy_protection.cpp
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs/dialogs_copy_protection.h"
+#include "xeen/dialogs/dialogs_input.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+bool CopyProtection::show(XeenEngine *vm) {
+ CopyProtection *dlg = new CopyProtection(vm);
+ int result = dlg->execute();
+ delete dlg;
+
+ return result;
+}
+
+CopyProtection::CopyProtection(XeenEngine *vm) : Input(vm, &(*vm->_windows)[11]) {
+ loadEntries();
+}
+
+bool CopyProtection::execute() {
+ EventsManager &events = *_vm->_events;
+ Sound &sound = *_vm->_sound;
+ Window &w = *_window;
+ bool result = false;
+ Common::String line;
+
+ // Choose a random entry
+ ProtectionEntry &protEntry = _entries[_vm->getRandomNumber(_entries.size() - 1)];
+ Common::String msg = Common::String::format(Res.WHATS_THE_PASSWORD,
+ protEntry._pageNum, protEntry._lineNum, protEntry._wordNum);
+
+ w.open();
+ w.writeString(msg);
+ w.update();
+
+ for (int tryNum = 0; tryNum < 3 && !_vm->shouldExit(); ++tryNum) {
+ line.clear();
+ if (getString(line, 20, 200, false) && !line.compareToIgnoreCase(protEntry._text)) {
+ sound.playFX(20);
+ result = true;
+ break;
+ }
+
+ sound.playFX(21);
+ w.writeString("\x3l\v040\n\x4""200");
+ w.writeString(Res.PASSWORD_INCORRECT);
+ w.update();
+
+ events.updateGameCounter();
+ events.wait(50, false);
+ }
+
+ w.close();
+ return result;
+}
+
+void CopyProtection::loadEntries() {
+ FileManager &files = *g_vm->_files;
+ File f(files._ccNum ? "timer.drv" : "cpstruct");
+ ProtectionEntry pe;
+ byte seed = 0;
+ char text[13];
+
+ while (f.pos() < f.size()) {
+ pe._pageNum = f.readByte() ^ seed++;
+ pe._lineNum = f.readByte() ^ seed++;
+ pe._wordNum = f.readByte() ^ seed++;
+
+ for (int idx = 0; idx < 13; ++idx)
+ text[idx] = f.readByte() ^ seed++;
+ text[12] = '\0';
+ pe._text = Common::String(text);
+
+ _entries.push_back(pe);
+ }
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_copy_protection.h b/engines/xeen/dialogs/dialogs_copy_protection.h
new file mode 100644
index 0000000000..97c8a6a53e
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_copy_protection.h
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_COPY_PROTECTION_H
+#define XEEN_DIALOGS_COPY_PROTECTION_H
+
+#include "xeen/dialogs/dialogs_input.h"
+#include "common/array.h"
+
+namespace Xeen {
+
+class CopyProtection : public Input {
+ struct ProtectionEntry {
+ uint8 _pageNum;
+ uint8 _lineNum;
+ uint8 _wordNum;
+ Common::String _text;
+ };
+private:
+ Common::Array<ProtectionEntry> _entries;
+private:
+ /**
+ * Constructor
+ */
+ CopyProtection(XeenEngine *vm);
+
+ /**
+ * Execute the dialog
+ */
+ bool execute();
+
+ /**
+ * Load the copy protection entries
+ */
+ void loadEntries();
+public:
+ /**
+ * Show the dialog
+ */
+ static bool show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_COPY_PROTECTION_H */
diff --git a/engines/xeen/dialogs/dialogs_create_char.cpp b/engines/xeen/dialogs/dialogs_create_char.cpp
index 577ae5314b..ab86c4939a 100644
--- a/engines/xeen/dialogs/dialogs_create_char.cpp
+++ b/engines/xeen/dialogs/dialogs_create_char.cpp
@@ -389,7 +389,8 @@ int CreateCharacterDialog::newCharDetails(Race race, Sex sex, int classId,
// Set up default skill for the race, if any
if (Res.NEW_CHAR_RACE_SKILLS[race] != -1) {
- raceSkillStr = Res.SKILL_NAMES[Res.NEW_CHAR_RACE_SKILLS[race]];
+ const char *skillP = Res.SKILL_NAMES[Res.NEW_CHAR_RACE_SKILLS[race]];
+ raceSkillStr = Common::String(skillP + Res.NEW_CHAR_SKILLS_OFFSET[race]);
}
// Set up color to use for each skill string to be displayed, based
@@ -554,7 +555,7 @@ int CreateCharacterDialog::exchangeAttribute(int srcAttr) {
break;
int destAttr = getAttribFromKeycode(_buttonValue);
-
+
if (destAttr != -1 && srcAttr != destAttr) {
result = destAttr;
break;
@@ -579,7 +580,7 @@ bool CreateCharacterDialog::saveCharacter(Character &c, int classId, Race race,
Window &w = windows[6];
Common::String name;
int result;
- bool isDarkCc = _vm->_files->_isDarkCc;
+ int ccNum = _vm->_files->_ccNum;
// Prompt for a character name
w.open();
@@ -597,11 +598,11 @@ bool CreateCharacterDialog::saveCharacter(Character &c, int classId, Race race,
c.clear();
c._name = name;
c._savedMazeId = party._priorMazeId;
- c._xeenSide = map._loadDarkSide;
+ c._xeenSide = map._loadCcNum;
c._sex = sex;
c._race = race;
c._class = (CharacterClass)classId;
- c._level._permanent = isDarkCc ? 5 : 1;
+ c._level._permanent = ccNum ? 5 : 1;
c._might._permanent = _attribs[MIGHT];
c._intellect._permanent = _attribs[INTELLECT];
diff --git a/engines/xeen/dialogs/dialogs_dismiss.cpp b/engines/xeen/dialogs/dialogs_dismiss.cpp
index 716f8f0035..7f9c8d972f 100644
--- a/engines/xeen/dialogs/dialogs_dismiss.cpp
+++ b/engines/xeen/dialogs/dialogs_dismiss.cpp
@@ -70,6 +70,10 @@ void Dismiss::execute() {
w.close();
ErrorScroll::show(_vm, Res.CANT_DISMISS_LAST_CHAR, WT_NONFREEZED_WAIT);
w.open();
+ } else if (party._activeParty[_buttonValue]._weapons.hasElderWeapon()) {
+ w.close();
+ ErrorScroll::show(_vm, Res.DELETE_CHAR_WITH_ELDER_WEAPON, WT_NONFREEZED_WAIT);
+ w.open();
} else {
// Remove the character from the party
party._activeParty.remove_at(_buttonValue);
diff --git a/engines/xeen/dialogs/dialogs_input.cpp b/engines/xeen/dialogs/dialogs_input.cpp
index 1d05c81f32..b72e47e37a 100644
--- a/engines/xeen/dialogs/dialogs_input.cpp
+++ b/engines/xeen/dialogs/dialogs_input.cpp
@@ -84,9 +84,9 @@ Common::KeyState Input::waitForKey(const Common::String &msg) {
intf._tillMove = 0;
bool flag = !_vm->_startupWindowActive && !windows[25]._enabled
- && _vm->_mode != MODE_FF && _vm->_mode != MODE_17;
+ && _vm->_mode != MODE_FF && _vm->_mode != MODE_INTERACTIVE7;
- Common::KeyState ks;
+ PendingEvent pe;
while (!_vm->shouldExit()) {
events.updateGameCounter();
@@ -100,11 +100,8 @@ Common::KeyState Input::waitForKey(const Common::String &msg) {
windows[3].update();
events.wait(1);
-
- if (events.isKeyPending()) {
- events.getKey(ks);
+ if (events.getEvent(pe) && pe.isKeyboard())
break;
- }
}
_window->writeString("");
@@ -113,7 +110,7 @@ Common::KeyState Input::waitForKey(const Common::String &msg) {
intf._tillMove = oldTillMove;
intf._upDoorText = oldUpDoorText;
- return ks;
+ return pe._keyState;
}
void Input::animateCursor() {
@@ -144,7 +141,6 @@ int StringInput::show(XeenEngine *vm, bool type, const Common::String &msg1,
int StringInput::execute(bool type, const Common::String &expected,
const Common::String &title, int opcode) {
FileManager &files = *_vm->_files;
- Interface &intf = *_vm->_interface;
Scripts &scripts = *_vm->_scripts;
Windows &windows = *_vm->_windows;
Window &w = windows[6];
@@ -158,9 +154,9 @@ int StringInput::execute(bool type, const Common::String &expected,
Common::String line;
if (getString(line, 30, 200, false)) {
if (type) {
- if (line == intf._interfaceText) {
+ if (!line.compareToIgnoreCase(scripts._message)) {
result = true;
- } else if (line == expected) {
+ } else if (!line.compareToIgnoreCase(expected)) {
result = (opcode == 55) ? -1 : 1;
}
} else {
@@ -168,14 +164,14 @@ int StringInput::execute(bool type, const Common::String &expected,
MirrorEntry me;
scripts._mirror.clear();
- File f(Common::String::format("%smirr.txt", files._isDarkCc ? "dark" : "xeen"), 1);
+ File f(Common::String::format("%smirr.txt", files._ccNum ? "dark" : "xeen"), 1);
while (me.synchronize(f))
scripts._mirror.push_back(me);
f.close();
// Load in any extended mirror entries
Common::File f2;
- if (f2.open(Common::String::format("%smirr.ext", files._isDarkCc ? "dark" : "xeen"))) {
+ if (f2.open(Common::String::format("%smirr.ext", files._ccNum ? "dark" : "xeen"))) {
while (me.synchronize(f2))
scripts._mirror.push_back(me);
f2.close();
@@ -184,7 +180,7 @@ int StringInput::execute(bool type, const Common::String &expected,
for (uint idx = 0; idx < scripts._mirror.size(); ++idx) {
if (!line.compareToIgnoreCase(scripts._mirror[idx]._name)) {
result = idx + 1;
- sound.playFX(_vm->_files->_isDarkCc ? 35 : 61);
+ sound.playFX(_vm->_files->_ccNum ? 35 : 61);
break;
}
}
@@ -219,8 +215,8 @@ int NumericInput::execute(int maxLength, int maxWidth) {
/*------------------------------------------------------------------------*/
-int Choose123::show(XeenEngine *vm, int numOptions) {
- assert(numOptions <= 3);
+int Choose123::show(XeenEngine *vm, uint numOptions) {
+ assert(numOptions <= 9);
Choose123 *dlg = new Choose123(vm);
int result = dlg->execute(numOptions);
delete dlg;
@@ -228,7 +224,7 @@ int Choose123::show(XeenEngine *vm, int numOptions) {
return result;
}
-int Choose123::execute(int numOptions) {
+int Choose123::execute(uint numOptions) {
EventsManager &events = *_vm->_events;
Interface &intf = *_vm->_interface;
LocationManager &loc = *_vm->_locations;
@@ -256,24 +252,17 @@ int Choose123::execute(int numOptions) {
}
events.wait(delay);
+ checkEvents(_vm);
+
if (_vm->shouldExit())
return 0;
} while (!_buttonValue);
- switch (_buttonValue) {
- case Common::KEYCODE_ESCAPE:
+ if (_buttonValue == Common::KEYCODE_ESCAPE) {
result = 0;
- break;
- case Common::KEYCODE_1:
- case Common::KEYCODE_2:
- case Common::KEYCODE_3: {
- int v = _buttonValue - Common::KEYCODE_1 + 1;
- if (v <= numOptions)
- result = v;
- break;
- }
- default:
- break;
+ } else if (_buttonValue >= Common::KEYCODE_1 && _buttonValue < (Common::KEYCODE_1 + (int)numOptions)) {
+ _buttonValue -= Common::KEYCODE_0;
+ result = (_buttonValue == (int)numOptions) ? 0 : _buttonValue;
}
}
@@ -283,15 +272,17 @@ int Choose123::execute(int numOptions) {
return result;
}
-void Choose123::loadButtons(int numOptions) {
+void Choose123::loadButtons(uint numOptions) {
+ assert(numOptions > 0 && numOptions <= 9);
_iconSprites.load("choose.icn");
+ const int XPOS[3] = { 235, 260, 286 };
+ const int YPOS[3] = { 75, 96, 117 };
- if (numOptions >= 1)
- addButton(Common::Rect(235, 75, 259, 95), Common::KEYCODE_1, &_iconSprites);
- if (numOptions >= 2)
- addButton(Common::Rect(260, 75, 284, 95), Common::KEYCODE_2, &_iconSprites);
- if (numOptions >= 3)
- addButton(Common::Rect(286, 75, 311, 95), Common::KEYCODE_3, &_iconSprites);
+ for (uint idx = 0; idx < numOptions; ++idx) {
+ Common::Rect r(24, 20);
+ r.moveTo(XPOS[idx % 3], YPOS[idx / 3]);
+ addButton(r, Common::KEYCODE_1 + idx, &_iconSprites);
+ }
}
/*------------------------------------------------------------------------*/
diff --git a/engines/xeen/dialogs/dialogs_input.h b/engines/xeen/dialogs/dialogs_input.h
index 270495ffd5..8cb41f3d36 100644
--- a/engines/xeen/dialogs/dialogs_input.h
+++ b/engines/xeen/dialogs/dialogs_input.h
@@ -82,11 +82,11 @@ private:
Choose123(XeenEngine *vm) : ButtonContainer(vm) {}
- int execute(int numOptions);
+ int execute(uint numOptions);
- void loadButtons(int numOptions);
+ void loadButtons(uint numOptions);
public:
- static int show(XeenEngine *vm, int numOptions);
+ static int show(XeenEngine *vm, uint numOptions);
};
class HowMuch : public ButtonContainer {
diff --git a/engines/xeen/dialogs/dialogs_items.cpp b/engines/xeen/dialogs/dialogs_items.cpp
index 24d4603617..b67e5a4aac 100644
--- a/engines/xeen/dialogs/dialogs_items.cpp
+++ b/engines/xeen/dialogs/dialogs_items.cpp
@@ -43,43 +43,35 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
Party &party = *_vm->_party;
Windows &windows = *_vm->_windows;
+ ItemsMode priorMode = ITEMMODE_INVALID;
Character *startingChar = c;
ItemCategory category = mode == ITEMMODE_RECHARGE || mode == ITEMMODE_COMBAT ?
CATEGORY_MISC : CATEGORY_WEAPON;
int varA = mode == ITEMMODE_COMBAT ? 1 : 0;
if (varA != 0)
mode = ITEMMODE_CHAR_INFO;
- bool updateStock = mode == ITEMMODE_BLACKSMITH;
+ bool updateStock = mode == ITEMMODE_BUY;
int itemIndex = -1;
Common::StringArray lines;
uint arr[40];
int actionIndex = -1;
- events.setCursor(0);
- loadButtons(mode, c);
+ if (mode == ITEMMODE_BUY) {
+ _oldCharacter = c;
+ c = &_itemsCharacter;
+ party._blacksmithWares.blackData2CharData(_itemsCharacter);
+ setEquipmentIcons();
+ } else if (mode == ITEMMODE_ENCHANT) {
+ _oldCharacter = c;
+ }
+ events.setCursor(0);
windows[29].open();
windows[30].open();
enum { REDRAW_NONE, REDRAW_TEXT, REDRAW_FULL } redrawFlag = REDRAW_FULL;
for (;;) {
if (redrawFlag == REDRAW_FULL) {
- if ((mode != ITEMMODE_CHAR_INFO || category != CATEGORY_MISC) && mode != ITEMMODE_ENCHANT
- && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
- _buttons[4]._bounds.moveTo(148, _buttons[4]._bounds.top);
- _buttons[9]._draw = false;
- } else if (mode == ITEMMODE_RECHARGE) {
- _buttons[4]._value = Common::KEYCODE_r;
- } else if (mode == ITEMMODE_ENCHANT) {
- _buttons[4]._value = Common::KEYCODE_e;
- } else if (mode == ITEMMODE_TO_GOLD) {
- _buttons[4]._value = Common::KEYCODE_g;
- } else {
- _buttons[4]._bounds.moveTo(0, _buttons[4]._bounds.top);
- _buttons[9]._draw = true;
- _buttons[9]._value = Common::KEYCODE_u;
- }
-
// Write text for the dialog
Common::String msg;
if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_8 && mode != ITEMMODE_ENCHANT
@@ -99,41 +91,22 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
}
windows[29].writeString(msg);
- drawButtons(&windows[0]);
Common::fill(&arr[0], &arr[40], 0);
itemIndex = -1;
+ priorMode = ITEMMODE_INVALID;
+ }
+
+ if (mode != priorMode) {
+ // Set up the buttons for the dialog
+ loadButtons(mode, c, category);
+ priorMode = mode;
+ drawButtons(&windows[0]);
}
if (redrawFlag == REDRAW_TEXT || redrawFlag == REDRAW_FULL) {
lines.clear();
- if (mode == ITEMMODE_CHAR_INFO || category != 3) {
- _iconSprites.draw(0, 8, Common::Point(148, 109));
- }
- if (mode != ITEMMODE_ENCHANT && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
- _iconSprites.draw(0, 10, Common::Point(182, 109));
- _iconSprites.draw(0, 12, Common::Point(216, 109));
- _iconSprites.draw(0, 14, Common::Point(250, 109));
- }
-
- switch (mode) {
- case ITEMMODE_CHAR_INFO:
- _iconSprites.draw(0, 9, Common::Point(148, 109));
- break;
- case ITEMMODE_BLACKSMITH:
- _iconSprites.draw(0, 11, Common::Point(182, 109));
- break;
- case ITEMMODE_REPAIR:
- _iconSprites.draw(0, 15, Common::Point(250, 109));
- break;
- case ITEMMODE_IDENTIFY:
- _iconSprites.draw(0, 13, Common::Point(216, 109));
- break;
- default:
- break;
- }
-
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
DrawStruct &ds = _itemsDrawList[idx];
XeenItem &i = c->_items[category][idx];
@@ -147,8 +120,8 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
case CATEGORY_ARMOR:
case CATEGORY_ACCESSORY:
if (i._id) {
- if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_8
- || mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE) {
+ if ((mode == ITEMMODE_CHAR_INFO && !g_vm->_extOptions._showItemCosts)
+ || mode == ITEMMODE_8 || mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE) {
lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE1,
arr[idx], idx + 1,
c->_items[category].getFullDescription(idx, arr[idx]).c_str()));
@@ -156,7 +129,8 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE2,
arr[idx], idx + 1,
c->_items[category].getFullDescription(idx, arr[idx]).c_str(),
- calcItemCost(c, idx, mode,
+ calcItemCost(c, idx,
+ (mode == ITEMMODE_CHAR_INFO) ? ITEMMODE_BUY : mode,
mode == ITEMMODE_TO_GOLD ? 1 : startingChar->_skills[MERCHANT],
category)
));
@@ -209,7 +183,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
case ITEMMODE_CHAR_INFO:
case ITEMMODE_8:
windows[30].writeString(Common::String::format(Res.X_FOR_THE_Y,
- category == CATEGORY_MISC ? "\x3l" : "\x3c",
+ category == CATEGORY_MISC ? "\x3l" : "\x3""c",
Res.CATEGORY_NAMES[category], c->_name.c_str(), Res.CLASS_NAMES[c->_class],
category == CATEGORY_MISC ? Res.FMT_CHARGES : " ",
lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(),
@@ -218,7 +192,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
));
break;
- case ITEMMODE_BLACKSMITH:
+ case ITEMMODE_BUY:
windows[30].writeString(Common::String::format(Res.AVAILABLE_GOLD_COST,
Res.CATEGORY_NAMES[category], party._gold,
lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(),
@@ -227,7 +201,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
));
break;
- case ITEMMODE_2:
+ case ITEMMODE_SELL:
case ITEMMODE_RECHARGE:
case ITEMMODE_ENCHANT:
case ITEMMODE_REPAIR:
@@ -265,10 +239,10 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
if (itemIndex != -1) {
switch (mode) {
- case ITEMMODE_BLACKSMITH:
+ case ITEMMODE_BUY:
actionIndex = 0;
break;
- case ITEMMODE_2:
+ case ITEMMODE_SELL:
actionIndex = 1;
break;
case ITEMMODE_REPAIR:
@@ -336,36 +310,38 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
if (_buttonValue < (int)(_vm->_mode == MODE_COMBAT ?
combat._combatParty.size() : party._activeParty.size())) {
// Character number is valid
- redrawFlag = REDRAW_TEXT;
+ redrawFlag = REDRAW_FULL;
Character *newChar = _vm->_mode == MODE_COMBAT ?
combat._combatParty[_buttonValue] : &party._activeParty[_buttonValue];
- if (mode == ITEMMODE_BLACKSMITH) {
+ if (mode == ITEMMODE_BUY) {
_oldCharacter = newChar;
startingChar = newChar;
c = &_itemsCharacter;
- } else if (mode == ITEMMODE_2 || mode == ITEMMODE_REPAIR || mode == ITEMMODE_IDENTIFY) {
+ } else if (mode == ITEMMODE_SELL || mode == ITEMMODE_REPAIR || mode == ITEMMODE_IDENTIFY) {
_oldCharacter = newChar;
startingChar = newChar;
c = newChar;
} else if (itemIndex != -1) {
+ // Switching item to another character
InventoryItems &destItems = newChar->_items[category];
- XeenItem &destItem = destItems[INV_ITEMS_TOTAL - 1];
InventoryItems &srcItems = c->_items[category];
XeenItem &srcItem = srcItems[itemIndex];
- if (srcItem._bonusFlags & ITEMFLAG_CURSED)
+ if (srcItem._state._cursed)
ErrorScroll::show(_vm, Res.CANNOT_REMOVE_CURSED_ITEM);
- else if (destItems[INV_ITEMS_TOTAL - 1]._id)
+ else if (destItems.isFull())
ErrorScroll::show(_vm, Common::String::format(
Res.CATEGORY_BACKPACK_IS_FULL[category], c->_name.c_str()));
else {
+ XeenItem &destItem = destItems[INV_ITEMS_TOTAL - 1];
destItem = srcItem;
srcItem.clear();
destItem._frame = 0;
srcItems.sort();
destItems.sort();
+ continue;
}
} else {
c = newChar;
@@ -399,9 +375,12 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
Common::fill(&arr[0], &arr[40], 0);
arr[itemIndex] = 15;
}
-
- redrawFlag = REDRAW_TEXT;
+ } else {
+ Common::fill(&arr[0], &arr[40], 0);
+ itemIndex = -1;
}
+
+ redrawFlag = REDRAW_TEXT;
break;
case Common::KEYCODE_a:
@@ -414,7 +393,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
// Buy
if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
- mode = ITEMMODE_BLACKSMITH;
+ mode = ITEMMODE_BUY;
c = &_itemsCharacter;
redrawFlag = REDRAW_FULL;
}
@@ -466,7 +445,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
case Common::KEYCODE_m:
// Misc
category = CATEGORY_MISC;
- redrawFlag = REDRAW_TEXT;
+ redrawFlag = REDRAW_FULL;
break;
case Common::KEYCODE_q:
@@ -487,7 +466,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
case Common::KEYCODE_s:
if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
- mode = ITEMMODE_2;
+ mode = ITEMMODE_SELL;
c = startingChar;
redrawFlag = REDRAW_TEXT;
}
@@ -501,7 +480,7 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
case Common::KEYCODE_w:
// Weapons category
category = CATEGORY_WEAPON;
- redrawFlag = REDRAW_TEXT;
+ redrawFlag = REDRAW_FULL;
break;
}
}
@@ -516,12 +495,13 @@ Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
return c;
}
-void ItemsDialog::loadButtons(ItemsMode mode, Character *&c) {
- Party &party = *g_vm->_party;
- _iconSprites.load(Common::String::format("%s.icn",
- (mode == ITEMMODE_CHAR_INFO) ? "items" : "buy"));
- _equipSprites.load("equip.icn");
+void ItemsDialog::loadButtons(ItemsMode mode, Character *&c, ItemCategory category) {
+ if (_iconSprites.empty())
+ _iconSprites.load(Common::String::format("%s.icn", (mode == ITEMMODE_CHAR_INFO) ? "items" : "buy"));
+ if (_equipSprites.empty())
+ _equipSprites.load("equip.icn");
+ clearButtons();
if (mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE || mode == ITEMMODE_TO_GOLD) {
// Enchant button list
addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_w, &_iconSprites);
@@ -541,14 +521,16 @@ void ItemsDialog::loadButtons(ItemsMode mode, Character *&c) {
addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
} else {
+ bool flag = mode == ITEMMODE_BUY || mode == ITEMMODE_SELL || mode == ITEMMODE_IDENTIFY
+ || mode == ITEMMODE_REPAIR;
addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_w, &_iconSprites);
addButton(Common::Rect(46, 109, 70, 129), Common::KEYCODE_a, &_iconSprites);
addButton(Common::Rect(80, 109, 104, 129), Common::KEYCODE_c, &_iconSprites);
addButton(Common::Rect(114, 109, 138, 129), Common::KEYCODE_m, &_iconSprites);
- addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_e, &_iconSprites);
- addButton(Common::Rect(182, 109, 206, 129), Common::KEYCODE_r, &_iconSprites);
- addButton(Common::Rect(216, 109, 240, 129), Common::KEYCODE_d, &_iconSprites);
- addButton(Common::Rect(250, 109, 274, 129), Common::KEYCODE_q, &_iconSprites);
+ addButton(Common::Rect(148, 109, 172, 129), flag ? Common::KEYCODE_b : Common::KEYCODE_e, &_iconSprites);
+ addButton(Common::Rect(182, 109, 206, 129), flag ? Common::KEYCODE_s : Common::KEYCODE_r, &_iconSprites);
+ addButton(Common::Rect(216, 109, 240, 129), flag ? Common::KEYCODE_i : Common::KEYCODE_d, &_iconSprites);
+ addButton(Common::Rect(250, 109, 274, 129), flag ? Common::KEYCODE_f : Common::KEYCODE_q, &_iconSprites);
addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
@@ -562,22 +544,44 @@ void ItemsDialog::loadButtons(ItemsMode mode, Character *&c) {
addPartyButtons(_vm);
}
- if (mode == ITEMMODE_BLACKSMITH) {
- _oldCharacter = c;
- c = &_itemsCharacter;
- party._blacksmithWares.blackData2CharData(_itemsCharacter);
+ if (mode == ITEMMODE_CHAR_INFO && category == CATEGORY_MISC) {
+ _buttons[4].setFrame(18);
+ _buttons[4]._value = Common::KEYCODE_u;
+ }
+ if (mode != ITEMMODE_ENCHANT && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+ _buttons[5].setFrame(10);
+ _buttons[6].setFrame(12);
+ _buttons[7].setFrame(14);
+ }
- _buttons[4]._value = Common::KEYCODE_b;
- _buttons[5]._value = Common::KEYCODE_s;
- _buttons[6]._value = Common::KEYCODE_i;
- _buttons[7]._value = Common::KEYCODE_f;
+ // Set button as depressed depending on which mode the dialog is currently in
+ switch (mode) {
+ case ITEMMODE_BUY:
+ _buttons[4].setFrame(9);
+ break;
+ case ITEMMODE_SELL:
+ _buttons[5].setFrame(11);
+ break;
+ case ITEMMODE_IDENTIFY:
+ _buttons[6].setFrame(13);
+ break;
+ case ITEMMODE_REPAIR:
+ _buttons[7].setFrame(15);
+ break;
+ default:
+ break;
+ }
- setEquipmentIcons();
- } else {
+ if ((mode != ITEMMODE_CHAR_INFO || category != CATEGORY_MISC) && mode != ITEMMODE_ENCHANT
+ && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+ _buttons[4]._bounds.moveTo(148, _buttons[4]._bounds.top);
+ _buttons[9]._draw = false;
+ } else if (mode == ITEMMODE_RECHARGE) {
+ _buttons[4]._value = Common::KEYCODE_r;
+ } else if (mode == ITEMMODE_ENCHANT) {
_buttons[4]._value = Common::KEYCODE_e;
- _buttons[5]._value = Common::KEYCODE_r;
- _buttons[6]._value = Common::KEYCODE_d;
- _buttons[7]._value = Common::KEYCODE_q;
+ } else if (mode == ITEMMODE_TO_GOLD) {
+ _buttons[4]._value = Common::KEYCODE_g;
}
}
@@ -643,10 +647,10 @@ int ItemsDialog::calcItemCost(Character *c, int itemIndex, ItemsMode mode,
};
switch (mode) {
- case ITEMMODE_BLACKSMITH:
+ case ITEMMODE_BUY:
level = 0;
break;
- case ITEMMODE_2:
+ case ITEMMODE_SELL:
case ITEMMODE_TO_GOLD:
level = level == 0 ? 1 : 0;
break;
@@ -692,8 +696,8 @@ int ItemsDialog::calcItemCost(Character *c, int itemIndex, ItemsMode mode,
amount3 = Res.ELEMENTAL_DAMAGE[i._material - 59 + 7] * 100;
switch (mode) {
- case ITEMMODE_BLACKSMITH:
- case ITEMMODE_2:
+ case ITEMMODE_BUY:
+ case ITEMMODE_SELL:
case ITEMMODE_REPAIR:
case ITEMMODE_IDENTIFY:
case ITEMMODE_TO_GOLD:
@@ -712,8 +716,8 @@ int ItemsDialog::calcItemCost(Character *c, int itemIndex, ItemsMode mode,
amount4 = Res.MISC_BASE_COSTS[i._id];
switch (mode) {
- case ITEMMODE_BLACKSMITH:
- case ITEMMODE_2:
+ case ITEMMODE_BUY:
+ case ITEMMODE_SELL:
case ITEMMODE_REPAIR:
case ITEMMODE_IDENTIFY:
case ITEMMODE_TO_GOLD:
@@ -721,6 +725,15 @@ int ItemsDialog::calcItemCost(Character *c, int itemIndex, ItemsMode mode,
if (!result)
result = 1;
break;
+
+ case ITEMMODE_3:
+ case ITEMMODE_RECHARGE:
+ case ITEMMODE_5:
+ case ITEMMODE_ENCHANT:
+ // Show number of charges
+ result = i._state._counter;
+ break;
+
default:
break;
}
@@ -742,64 +755,18 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
Sound &sound = *_vm->_sound;
Spells &spells = *_vm->_spells;
Windows &windows = *_vm->_windows;
- bool isDarkCc = _vm->_files->_isDarkCc;
+ int ccNum = _vm->_files->_ccNum;
- XeenItem *itemCategories[4] = { &c._weapons[0], &c._armor[0], &c._accessories[0], &c._misc[0] };
- XeenItem *items = itemCategories[category];
- if (!items[0]._id)
+ InventoryItems &items = c._items[category];
+ if (items[0].empty())
// Inventory is empty
return category == CATEGORY_MISC ? 0 : 2;
- Window &w = windows[11];
- SpriteResource escSprites;
- if (itemIndex < 0 || itemIndex > 8) {
- saveButtons();
-
- escSprites.load("esc.icn");
- addButton(Common::Rect(235, 111, 259, 131), Common::KEYCODE_ESCAPE, &escSprites);
- addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
- addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
- addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
- addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
- addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
- addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
- addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
- addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
- addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
-
- w.open();
- w.writeString(Common::String::format(Res.WHICH_ITEM, Res.ITEM_ACTIONS[actionIndex]));
- _iconSprites.draw(0, 0, Common::Point(235, 111));
- w.update();
-
- while (!_vm->shouldExit()) {
- while (!_buttonValue) {
- events.pollEventsAndWait();
- checkEvents(_vm);
- if (_vm->shouldExit())
- return false;
- }
-
- if (_buttonValue == Common::KEYCODE_ESCAPE) {
- itemIndex = -1;
- break;
- } else if (_buttonValue >= Common::KEYCODE_1 && _buttonValue <= Common::KEYCODE_9) {
- // Check whether there's an item at the selected index
- int selectedIndex = _buttonValue - Common::KEYCODE_1;
- if (!items[selectedIndex]._id)
- continue;
-
- itemIndex = selectedIndex;
- break;
- }
- }
-
- w.close();
- restoreButtons();
- }
+ if (itemIndex < 0 || itemIndex > 8)
+ itemIndex = ItemSelectionDialog::show(actionIndex, items);
if (itemIndex != -1) {
- XeenItem &item = c._items[category][itemIndex];
+ XeenItem &item = items[itemIndex];
switch (mode) {
case ITEMMODE_CHAR_INFO:
@@ -830,10 +797,8 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
default:
if (combat._itemFlag) {
ErrorScroll::show(_vm, Res.USE_ITEM_IN_COMBAT);
- } else if (i._id && (i._bonusFlags & ITEMFLAG_BONUS_MASK)
- && !(i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED))) {
- int charges = (i._bonusFlags & ITEMFLAG_BONUS_MASK) - 1;
- i._bonusFlags = charges;
+ } else if (i._id && !i.isBad() && i._state._counter > 0) {
+ --i._state._counter;
_oldCharacter = &c;
windows[30].close();
@@ -841,7 +806,7 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
windows[24].close();
spells.castItemSpell(i._id);
- if (!charges) {
+ if (!i._state._counter) {
// Ran out of charges, so make item disappear
c._items[category][itemIndex].clear();
c._items[category].sort();
@@ -868,7 +833,7 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
}
break;
- case ITEMMODE_BLACKSMITH: {
+ case ITEMMODE_BUY: {
InventoryItems &invItems = _oldCharacter->_items[category];
if (invItems.isFull()) {
// Character's inventory for that category is already full
@@ -880,15 +845,18 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
if (Confirm::show(_vm, Common::String::format(Res.BUY_X_FOR_Y_GOLD,
desc.c_str(), cost))) {
if (party.subtract(CONS_GOLD, cost, WHERE_PARTY, WT_FREEZE_WAIT)) {
- if (isDarkCc) {
+ if (ccNum) {
sound.stopSound();
sound.playSound("choice2.voc");
}
// Add entry to the end of the list
- XeenItem &bsItem = c._items[category][itemIndex];
- _oldCharacter->_items[category][INV_ITEMS_TOTAL - 1] = bsItem;
- bsItem.clear();
+ XeenItem &srcItem = c._items[category][itemIndex];
+ XeenItem &destItem = _oldCharacter->_items[category][INV_ITEMS_TOTAL - 1];
+ destItem = srcItem;
+ destItem._frame = 0;
+
+ srcItem.clear();
c._items[category].sort();
_oldCharacter->_items[category].sort();
}
@@ -897,14 +865,14 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
break;
}
- case ITEMMODE_2: {
+ case ITEMMODE_SELL: {
bool noNeed;
switch (category) {
case CATEGORY_WEAPON:
- noNeed = (item._bonusFlags & ITEMFLAG_CURSED) || item._id == 34;
+ noNeed = (item._state._cursed) || item._id >= XEEN_SLAYER_SWORD;
break;
default:
- noNeed = item._bonusFlags & ITEMFLAG_CURSED;
+ noNeed = item._state._cursed;
break;
}
@@ -929,17 +897,12 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
}
case ITEMMODE_RECHARGE:
- if (category != CATEGORY_MISC || c._misc[itemIndex]._material > 9
- || c._misc[itemIndex]._id == 53 || c._misc[itemIndex]._id == 0) {
+ if (category != CATEGORY_MISC || item.empty() || item._material > 9 || item._id == 53) {
sound.playFX(21);
ErrorScroll::show(_vm, Common::String::format(Res.NOT_RECHARGABLE, Res.SPELL_FAILED));
} else {
- int charges = MIN(63, _vm->getRandomNumber(1, 6) +
- (c._misc[itemIndex]._bonusFlags & ITEMFLAG_BONUS_MASK));
+ item._state._counter = MIN(63, _vm->getRandomNumber(1, 6) + item._state._counter);
sound.playFX(20);
-
- c._misc[itemIndex]._bonusFlags = (c._misc[itemIndex]._bonusFlags
- & ~ITEMFLAG_BONUS_MASK) | charges;
}
return 2;
@@ -951,7 +914,7 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
}
case ITEMMODE_REPAIR:
- if (!(item._bonusFlags & ITEMFLAG_BROKEN)) {
+ if (!item._state._broken) {
ErrorScroll::show(_vm, Res.ITEM_NOT_BROKEN);
} else {
int cost = calcItemCost(&c, itemIndex, mode, actionIndex, category);
@@ -961,7 +924,7 @@ int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, Ite
cost);
if (Confirm::show(_vm, msg) && party.subtract(CONS_GOLD, cost, WHERE_PARTY)) {
- item._bonusFlags &= ~ITEMFLAG_BROKEN;
+ item._state._broken = false;
}
}
break;
@@ -1016,11 +979,11 @@ void ItemsDialog::itemToGold(Character &c, int itemIndex, ItemCategory category,
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
- if (category == CATEGORY_WEAPON && item._id == 34) {
+ if (category == CATEGORY_WEAPON && item._id >= XEEN_SLAYER_SWORD) {
sound.playFX(21);
ErrorScroll::show(_vm, Common::String::format("\v012\t000\x03""c%s",
Res.SPELL_FAILED));
- } else if (item._id != 0) {
+ } else if (!item.empty()) {
// There is a valid item present
// Calculate cost of item and add it to the party's total
int cost = calcItemCost(&c, itemIndex, mode, 1, category);
@@ -1032,4 +995,67 @@ void ItemsDialog::itemToGold(Character &c, int itemIndex, ItemCategory category,
}
}
+/*------------------------------------------------------------------------*/
+
+int ItemSelectionDialog::show(int actionIndex, InventoryItems &items) {
+ ItemSelectionDialog *dlg = new ItemSelectionDialog(g_vm, actionIndex, items);
+ int result = dlg->execute();
+ delete dlg;
+
+ return result;
+}
+
+void ItemSelectionDialog::loadButtons() {
+ _icons.load("esc.icn");
+ addButton(Common::Rect(235, 111, 259, 131), Common::KEYCODE_ESCAPE, &_icons);
+ addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+ addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+ addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+ addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+ addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+ addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+ addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+ addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+ addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+}
+
+int ItemSelectionDialog::execute() {
+ EventsManager &events = *g_vm->_events;
+ Windows &windows = *g_vm->_windows;
+ Window &w = windows[13];
+
+ w.open();
+ w.writeString(Common::String::format(Res.WHICH_ITEM, Res.ITEM_ACTIONS[_actionIndex]));
+ _icons.draw(0, 0, Common::Point(235, 111));
+ w.update();
+
+ int itemIndex = -1;
+ while (!_vm->shouldExit()) {
+ _buttonValue = 0;
+ while (!_buttonValue) {
+ events.pollEventsAndWait();
+ checkEvents(_vm);
+ if (_vm->shouldExit())
+ return false;
+ }
+
+ if (_buttonValue == Common::KEYCODE_ESCAPE) {
+ itemIndex = -1;
+ break;
+ }
+ else if (_buttonValue >= Common::KEYCODE_1 && _buttonValue <= Common::KEYCODE_9) {
+ // Check whether there's an item at the selected index
+ int selectedIndex = _buttonValue - Common::KEYCODE_1;
+ if (!_items[selectedIndex]._id)
+ continue;
+
+ itemIndex = selectedIndex;
+ break;
+ }
+ }
+
+ w.close();
+ return itemIndex;
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_items.h b/engines/xeen/dialogs/dialogs_items.h
index 33930640f1..d3632dc8dc 100644
--- a/engines/xeen/dialogs/dialogs_items.h
+++ b/engines/xeen/dialogs/dialogs_items.h
@@ -30,9 +30,10 @@
namespace Xeen {
enum ItemsMode {
- ITEMMODE_CHAR_INFO = 0, ITEMMODE_BLACKSMITH = 1, ITEMMODE_2 = 2, ITEMMODE_3 = 3,
+ ITEMMODE_CHAR_INFO = 0, ITEMMODE_BUY = 1, ITEMMODE_SELL = 2, ITEMMODE_3 = 3,
ITEMMODE_RECHARGE = 4, ITEMMODE_5 = 5, ITEMMODE_ENCHANT = 6, ITEMMODE_COMBAT = 7, ITEMMODE_8 = 8,
- ITEMMODE_REPAIR = 9, ITEMMODE_IDENTIFY = 10, ITEMMODE_TO_GOLD = 11
+ ITEMMODE_REPAIR = 9, ITEMMODE_IDENTIFY = 10, ITEMMODE_TO_GOLD = 11,
+ ITEMMODE_INVALID = -1
};
class ItemsDialog : public ButtonContainer {
@@ -50,7 +51,7 @@ private:
/**
* Load the buttons for the dialog
*/
- void loadButtons(ItemsMode mode, Character *&c);
+ void loadButtons(ItemsMode mode, Character *&c, ItemCategory category);
/**
* Sets the equipment icon to use for each item for display
@@ -58,7 +59,7 @@ private:
void setEquipmentIcons();
/**
- * Calculate the cost of an item
+ * Calculate the cost of an item, or charges renaming for Misc items as appropriate
*/
int calcItemCost(Character *c, int itemIndex, ItemsMode mode, int skillLevel,
ItemCategory category);
@@ -71,6 +72,38 @@ public:
static Character *show(XeenEngine *vm, Character *c, ItemsMode mode);
};
+class ItemSelectionDialog : public ButtonContainer {
+private:
+ SpriteResource _icons;
+ int _actionIndex;
+ InventoryItems &_items;
+
+ ItemSelectionDialog(XeenEngine *vm, int actionIndex, InventoryItems &items) : ButtonContainer(vm),
+ _actionIndex(actionIndex), _items(items) {
+ loadButtons();
+ }
+
+ /**
+ * Executes the dialog
+ * @returns Selected item index
+ */
+ int execute();
+
+ /**
+ * Loads buttons
+ */
+ void loadButtons();
+public:
+ /**
+ * Shows the dialog
+ * @param actionIndex Current action type
+ * @param items Currently active items category
+ * @returns Selected item index
+ */
+ static int show(int actionIndex, InventoryItems &items);
+};
+
+
} // End of namespace Xeen
#endif /* XEEN_DIALOGS_ITEMS_H */
diff --git a/engines/xeen/dialogs/dialogs_message.cpp b/engines/xeen/dialogs/dialogs_message.cpp
index df8afea34c..f571e6e811 100644
--- a/engines/xeen/dialogs/dialogs_message.cpp
+++ b/engines/xeen/dialogs/dialogs_message.cpp
@@ -51,7 +51,7 @@ void MessageDialog::execute(const Common::String &msg, MessageWaitType waitType)
break;
case WT_ANIMATED_WAIT:
- if (windows[11]._enabled || _vm->_mode == MODE_17) {
+ if (windows[11]._enabled || _vm->_mode == MODE_INTERACTIVE7) {
g_vm->_locations->wait();
break;
}
diff --git a/engines/xeen/dialogs/dialogs_party.cpp b/engines/xeen/dialogs/dialogs_party.cpp
index c3d6843ffd..cf49007f30 100644
--- a/engines/xeen/dialogs/dialogs_party.cpp
+++ b/engines/xeen/dialogs/dialogs_party.cpp
@@ -45,6 +45,7 @@ void PartyDialog::show(XeenEngine *vm) {
void PartyDialog::execute() {
EventsManager &events = *_vm->_events;
+ FileManager &files = *_vm->_files;
Interface &intf = *_vm->_interface;
Map &map = *_vm->_map;
Party &party = *_vm->_party;
@@ -54,18 +55,19 @@ void PartyDialog::execute() {
bool modeFlag = false;
int startingChar = 0;
+ sound.playSong(files._ccNum ? "newbrigh.m" : "inn.m");
loadButtons();
setupBackground();
while (!_vm->shouldExit()) {
- _vm->_mode = MODE_1;
+ _vm->_mode = MODE_INTERACTIVE;
// Build up a list of available characters in the Roster that are on the
// same side of Xeen as the player is currently on
_charList.clear();
for (int i = 0; i < XEEN_TOTAL_CHARACTERS; ++i) {
Character &player = party._roster[i];
- if (player._name.empty() || player._xeenSide != (map._loadDarkSide ? 1 : 0))
+ if (player._name.empty() || player._xeenSide != map._loadCcNum)
continue;
_charList.push_back(i);
diff --git a/engines/xeen/dialogs/dialogs_query.cpp b/engines/xeen/dialogs/dialogs_query.cpp
index 79f46826cd..876ddafc2b 100644
--- a/engines/xeen/dialogs/dialogs_query.cpp
+++ b/engines/xeen/dialogs/dialogs_query.cpp
@@ -68,8 +68,11 @@ bool Confirm::execute(const Common::String &msg, int mode) {
bool result = false;
while (!_vm->shouldExit()) {
- events.pollEvents();
- checkEvents(_vm);
+ _buttonValue = 0;
+ while (!_vm->shouldExit() && !_buttonValue) {
+ events.pollEvents();
+ checkEvents(_vm);
+ }
if ((mode & 0x80) || _buttonValue == Common::KEYCODE_ESCAPE
|| _buttonValue == Common::KEYCODE_n)
@@ -81,6 +84,7 @@ bool Confirm::execute(const Common::String &msg, int mode) {
}
}
+ events.clearEvents();
w.close();
return result;
}
@@ -108,6 +112,7 @@ bool YesNo::execute(bool type, bool townFlag) {
Mode oldMode = _vm->_mode;
_vm->_mode = oldMode == MODE_7 ? MODE_8 : MODE_7;
+ events.clearEvents();
if (!type) {
confirmSprites.load("confirm.icn");
diff --git a/engines/xeen/dialogs/dialogs_quests.cpp b/engines/xeen/dialogs/dialogs_quests.cpp
index e4f62270ef..94834c1c02 100644
--- a/engines/xeen/dialogs/dialogs_quests.cpp
+++ b/engines/xeen/dialogs/dialogs_quests.cpp
@@ -44,6 +44,9 @@ void Quests::execute() {
int count = 0;
bool headerShown = false;
int topRow = 0;
+ const char **questItemNames = (g_vm->getGameID() == GType_Swords) ? Res.QUEST_ITEM_NAMES_SWORDS : Res.QUEST_ITEM_NAMES;
+ int itemsCount = (g_vm->getGameID() == GType_Swords) ? TOTAL_QUEST_ITEMS_SWORDS : TOTAL_QUEST_ITEMS;
+ const char *title1 = (g_vm->getGameID() == GType_Swords) ? Res.SWORDS_OF_XEEN_LINE : Res.CLOUDS_OF_XEEN_LINE;
addButtons();
loadQuestNotes();
@@ -66,37 +69,49 @@ void Quests::execute() {
switch (mode) {
case QUEST_ITEMS:
- for (int idx = 0; idx < TOTAL_QUEST_ITEMS; ++idx)
+ for (int idx = 0; idx < itemsCount; ++idx)
lines[idx] = "\b \b*";
count = 0;
headerShown = false;
- for (int idx = 0; idx < TOTAL_QUEST_ITEMS; ++idx) {
+ for (int idx = 0; idx < itemsCount; ++idx) {
if (party._questItems[idx]) {
- if (!count && !headerShown && idx < 35) {
- lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
- }
- if (idx >= 35 && !headerShown) {
+ if (!count ) {
+ if (_vm->getGameID() == GType_Swords)
+ lines[count++] = Res.SWORDS_OF_XEEN_LINE;
+ else if (idx < 35)
+ lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
+ } else if (_vm->getGameID() != GType_Swords && idx >= 35 && !headerShown) {
lines[count++] = Res.DARKSIDE_OF_XEEN_LINE;
headerShown = true;
}
- switch (idx) {
- case 17:
- case 26:
- case 79:
- case 80:
- case 81:
- case 82:
- case 83:
- case 84:
+ bool multiFlag = false;
+ if (_vm->getGameID() == GType_Swords) {
+ multiFlag = (idx == 20) || (idx == 27) || (idx == 41);
+ } else {
+ switch (idx) {
+ case 17:
+ case 26:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ multiFlag = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (multiFlag) {
lines[count++] = Common::String::format("%d %s%c",
- party._questItems[idx], Res.QUEST_ITEM_NAMES[idx],
+ party._questItems[idx], questItemNames[idx],
party._questItems[idx] == 1 ? ' ' : 's');
- break;
- default:
- lines[count++] = Res.QUEST_ITEM_NAMES[idx];
- break;
+ } else {
+ lines[count++] = questItemNames[idx];
}
}
}
@@ -115,17 +130,17 @@ void Quests::execute() {
break;
case CURRENT_QUESTS:
- for (int idx = 0; idx < TOTAL_QUEST_ITEMS; ++idx)
+ for (int idx = 0; idx < itemsCount; ++idx)
lines[idx] = "";
count = 0;
headerShown = false;
for (int idx = 0; idx < TOTAL_QUEST_FLAGS; ++idx) {
- if (party._questFlags[(idx + 1) / 30][(idx + 1) % 30]) {
- if (!count && !headerShown && idx < 29) {
- lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
+ if (party._questFlags[idx + 1]) {
+ if (!count && !headerShown && (_vm->getGameID() == GType_Swords || idx < 29)) {
+ lines[count++] = title1;
}
- if (idx > 28 && !headerShown) {
+ if (_vm->getGameID() != GType_Swords && idx > 28 && !headerShown) {
lines[count++] = Res.DARKSIDE_OF_XEEN_LINE;
headerShown = true;
}
@@ -141,23 +156,39 @@ void Quests::execute() {
lines[topRow].c_str(), lines[topRow + 1].c_str(), lines[topRow + 2].c_str()));
break;
- case AUTO_NOTES:
- for (int idx = 0; idx < MAX_DIALOG_LINES; ++idx)
+ case AUTO_NOTES: {
+ int max, offset;
+ switch (_vm->getGameID()) {
+ case GType_Swords:
+ max = 49;
+ offset = 51;
+ break;
+ case GType_Clouds:
+ max = MAX_DIALOG_LINES;
+ offset = 31;
+ break;
+ default:
+ max = MAX_DIALOG_LINES;
+ offset = 56;
+ break;
+ }
+
+ for (int idx = 0; idx < max; ++idx)
lines[idx] = "";
count = 0;
headerShown = false;
- for (int idx = 0; idx < MAX_DIALOG_LINES; ++idx) {
- if (party._worldFlags[idx]) {
- if (!count && !headerShown && idx < 72) {
- lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
+ for (int idx = 0; idx < max; ++idx) {
+ if (party._worldFlags[idx + (_vm->getGameID() != GType_Swords ? 1 : 0)]) {
+ if (!count && !headerShown && (_vm->getGameID() == GType_Swords || idx < 72)) {
+ lines[count++] = title1;
}
if (idx >= 72 && !headerShown) {
lines[count++] = Res.DARKSIDE_OF_XEEN_LINE;
headerShown = true;
}
- lines[count++] = _questNotes[idx + 56];
+ lines[count++] = _questNotes[idx + offset];
}
}
@@ -173,6 +204,7 @@ void Quests::execute() {
));
break;
}
+ }
windows[30].writeString("\v000\t000");
windows[24].update();
@@ -245,7 +277,7 @@ void Quests::addButtons() {
}
void Quests::loadQuestNotes() {
- File f("qnotes.bin");
+ File f("qnotes.bin", 1);
while (f.pos() < f.size())
_questNotes.push_back(f.readString());
f.close();
diff --git a/engines/xeen/dialogs/dialogs_spells.cpp b/engines/xeen/dialogs/dialogs_spells.cpp
index 3da5a5149e..27329e48df 100644
--- a/engines/xeen/dialogs/dialogs_spells.cpp
+++ b/engines/xeen/dialogs/dialogs_spells.cpp
@@ -31,37 +31,40 @@
namespace Xeen {
Character *SpellsDialog::show(XeenEngine *vm, ButtonContainer *priorDialog,
- Character *c, int isCasting) {
+ Character *c, SpellDialogMode mode) {
SpellsDialog *dlg = new SpellsDialog(vm);
- Character *result = dlg->execute(priorDialog, c, isCasting);
+ Character *result = dlg->execute(priorDialog, c, mode);
delete dlg;
return result;
}
-Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int isCasting) {
+Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int mode) {
EventsManager &events = *_vm->_events;
Interface &intf = *_vm->_interface;
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
Spells &spells = *_vm->_spells;
Windows &windows = *_vm->_windows;
- bool isDarkCc = _vm->_files->_isDarkCc;
+ Window &w = windows[25];
+ int ccNum = _vm->_files->_ccNum;
+
loadButtons();
+ loadStrings("spldesc.bin");
- int castingCopy = isCasting;
- isCasting &= 0x7f;
+ int modeCopy = mode;
+ mode &= 0x7f;
int selection = -1;
int topIndex = 0;
int newSelection;
- windows[25].open();
+ w.open();
do {
- if (!isCasting) {
+ if (!mode) {
if (!c->guildMember()) {
sound.stopSound();
intf._overallFrame = 5;
- sound.playSound(isDarkCc ? "skull1.voc" : "guild11.voc", 1);
+ sound.playSound(ccNum ? "skull1.voc" : "guild11.voc", 1);
break;
}
@@ -69,13 +72,12 @@ Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int
Common::String msg = Common::String::format(Res.GUILD_OPTIONS,
title.c_str(), XeenEngine::printMil(party._gold).c_str());
windows[10].writeString(msg);
-
- warning("TODO: Sprite draw using previously used button sprites");
+ priorDialog->drawButtons(&windows[10]);
}
_spells.clear();
- const char *errorMsg = setSpellText(c, castingCopy);
- windows[25].writeString(Common::String::format(Res.SPELLS_FOR,
+ const char *errorMsg = setSpellText(c, modeCopy);
+ w.writeString(Common::String::format(Res.SPELLS_FOR,
errorMsg == nullptr ? Res.SPELL_LINES_0_TO_9 : "",
c->_name.c_str()));
@@ -103,18 +105,19 @@ Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int
colors[3], names[3], colors[4], names[4], colors[5], names[5],
colors[6], names[6], colors[7], names[7], colors[8], names[8],
colors[9], names[9],
- isCasting ? Res.SPELL_PTS : Res.GOLD,
- isCasting ? c->_currentSp : party._gold
+ mode ? Res.SPELL_PTS : Res.GOLD,
+ mode ? c->_currentSp : party._gold
));
_scrollSprites.draw(0, 4, Common::Point(39, 26));
_scrollSprites.draw(0, 0, Common::Point(187, 26));
_scrollSprites.draw(0, 2, Common::Point(187, 111));
- if (isCasting)
- _scrollSprites.draw(windows[25], 5, Common::Point(132, 123));
+ if (mode)
+ _scrollSprites.draw(w, 5, Common::Point(132, 123));
- windows[25].update();
+ w.update();
+ _buttonValue = 0;
do {
events.pollEventsAndWait();
checkEvents(_vm);
@@ -134,27 +137,14 @@ Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int
spells._lastCaster = _buttonValue;
intf.highlightChar(_buttonValue);
- if (_vm->_mode == MODE_17) {
+ if (_vm->_mode == MODE_INTERACTIVE7) {
windows[10].writeString(Common::String::format(Res.GUILD_OPTIONS,
XeenEngine::printMil(party._gold).c_str(), Res.GUILD_TEXT, c->_name.c_str()));
} else {
- int category;
- switch (c->_class) {
- case CLASS_ARCHER:
- case CLASS_SORCERER:
- category = 1;
- break;
- case CLASS_DRUID:
- case CLASS_RANGER:
- category = 2;
- break;
- default:
- category = 0;
- break;
- }
+ SpellsCategory category = c->getSpellsCategory();
+ int spellIndex = (c->_currentSpell == -1) ? SPELLS_PER_CLASS : c->_currentSpell;
+ int spellId = (category == SPELLCAT_INVALID) ? NO_SPELL : Res.SPELLS_ALLOWED[category][spellIndex];
- int spellIndex = (c->_currentSpell == -1) ? 39 : c->_currentSpell;
- int spellId = Res.SPELLS_ALLOWED[category][spellIndex];
windows[10].writeString(Common::String::format(Res.CAST_SPELL_DETAILS,
c->_name.c_str(), spells._spellNames[spellId].c_str(),
spells.calcSpellPoints(spellId, c->getCurrentLevel()),
@@ -194,53 +184,31 @@ Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int
(_buttonValue - Common::KEYCODE_1));
if (newSelection < (int)_spells.size()) {
- int expenseFactor = 0;
- int category = 0;
-
- switch (c->_class) {
- case CLASS_PALADIN:
- expenseFactor = 1;
- category = 0;
- break;
- case CLASS_ARCHER:
- expenseFactor = 1;
- category = 1;
- break;
- case CLASS_CLERIC:
- category = 0;
- break;
- case CLASS_SORCERER:
- category = 1;
- break;
- case CLASS_DRUID:
- category = 2;
- break;
- case CLASS_RANGER:
- expenseFactor = 1;
- category = 2;
- break;
- default:
- break;
- }
+ SpellsCategory category = c->getSpellsCategory();
+ int expenseFactor = c->getSpellsExpenseFactor();
int spellIndex = _spells[newSelection]._spellIndex;
int spellId = Res.SPELLS_ALLOWED[category][spellIndex];
int spellCost = spells.calcSpellCost(spellId, expenseFactor);
- if (isCasting) {
+ if (mode) {
+ // Casting
selection = newSelection;
} else {
- Common::String spellName = _spells[newSelection]._name;
- Common::String msg = (castingCopy & 0x80) ?
- Common::String::format(Res.SPELLS_PRESS_A_KEY, spellName.c_str()) :
- Common::String::format(Res.SPELLS_PURCHASE, spellName.c_str(), spellCost);
+ // Guild spells dialog: Spells Info or Buy
+ const Common::String &spellName = spells._spellNames[spellId];
+ const Common::String &spellDesc = _textStrings[spellId];
- if (Confirm::show(_vm, msg, castingCopy + 1)) {
+ Common::String msg = (modeCopy & 0x80) ?
+ Common::String::format(Res.SPELL_INFO, spellName.c_str(), spellDesc.c_str()) :
+ Common::String::format(Res.SPELL_PURCHASE, spellDesc.c_str(), spellName.c_str(), spellCost);
+
+ if (Confirm::show(_vm, msg, modeCopy + 1)) {
if (party.subtract(CONS_GOLD, spellCost, WHERE_PARTY, WT_FREEZE_WAIT)) {
c->_spells[spellIndex] = true;
sound.stopSound();
intf._overallFrame = 0;
- sound.playSound(isDarkCc ? "guild12.voc" : "parrot2.voc", 1);
+ sound.playSound(ccNum ? "parrot2.voc" : "guild12.voc", 1);
} else {
sound.playFX(21);
}
@@ -273,11 +241,11 @@ Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int
}
} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
- windows[25].close();
+ w.close();
if (_vm->shouldExit())
selection = -1;
- if (isCasting && selection != -1)
+ if (mode && selection != -1)
c->_currentSpell = _spells[selection]._spellIndex;
return c;
@@ -305,52 +273,41 @@ void SpellsDialog::loadButtons() {
addPartyButtons(_vm);
}
-const char *SpellsDialog::setSpellText(Character *c, int isCasting) {
+const char *SpellsDialog::setSpellText(Character *c, int mode) {
Party &party = *_vm->_party;
Spells &spells = *_vm->_spells;
- bool isDarkCc = _vm->_files->_isDarkCc;
- int expenseFactor = 0;
+ int ccNum = _vm->_files->_ccNum;
int currLevel = c->getCurrentLevel();
- int category;
+ SpellsCategory category = c->getSpellsCategory();
+ int expenseFactor = c->getSpellsExpenseFactor();
- if ((isCasting & 0x7f) == 0) {
- switch (c->_class) {
- case CLASS_PALADIN:
- expenseFactor = 1;
- category = 0;
- break;
- case CLASS_ARCHER:
- expenseFactor = 1;
- category = 1;
- break;
- case CLASS_CLERIC:
- category = 0;
- break;
- case CLASS_SORCERER:
- category = 1;
- break;
- case CLASS_DRUID:
- category = 2;
- break;
- case CLASS_RANGER:
- expenseFactor = 1;
- category = 2;
- break;
- default:
- category = -1;
- break;
- }
+ if ((mode & 0x7f) == 0) {
+ if (category != SPELLCAT_INVALID) {
+ if (_vm->getGameID() == GType_Swords && party._mazeId == 49) {
+ for (int spellId = 0; spellId < 10; ++spellId) {
+ int idx = 0;
+ while (idx < SPELLS_PER_CLASS && Res.SPELLS_ALLOWED[category][idx] !=
+ Res.DARK_SPELL_OFFSETS[category][spellId])
+ ++idx;
- if (category != -1) {
- if (party._mazeId == 49 || party._mazeId == 37) {
- for (uint spellId = 0; spellId < 76; ++spellId) {
+ if (idx < SPELLS_PER_CLASS) {
+ if (!c->_spells[idx] || (mode & 0x80)) {
+ int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
+ _spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
+ spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
+ idx, spellId));
+ }
+ }
+ }
+ } else if (party._mazeId == 49 || party._mazeId == 37) {
+ for (uint spellId = 0; spellId < TOTAL_SPELLS; ++spellId) {
int idx = 0;
- while (idx < MAX_SPELLS_PER_CLASS && Res.SPELLS_ALLOWED[category][idx] != (int)spellId)
+ while (idx < SPELLS_PER_CLASS && Res.SPELLS_ALLOWED[category][idx] != (int)spellId)
++idx;
// Handling if the spell is appropriate for the character's class
- if (idx < MAX_SPELLS_PER_CLASS) {
- if (!c->_spells[idx] || (isCasting & 0x80)) {
+ if (idx < SPELLS_PER_CLASS) {
+ if (!c->_spells[idx] || (mode & 0x80)) {
int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
_spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
@@ -358,16 +315,38 @@ const char *SpellsDialog::setSpellText(Character *c, int isCasting) {
}
}
}
- } else if (isDarkCc) {
- int groupIndex = (party._mazeId - 29) / 2;
- for (int spellId = Res.DARK_SPELL_RANGES[groupIndex][0];
- spellId < Res.DARK_SPELL_RANGES[groupIndex][1]; ++spellId) {
+ } else if (ccNum) {
+ const int *RANGE;
+
+ if (_vm->getGameID() == GType_Swords) {
+ // Set subset of spells to sell in each Swords of Xeen guild
+ int groupIndex;
+ switch (party._mazeId) {
+ case 92:
+ groupIndex = 1;
+ break;
+ case 63:
+ groupIndex = 2;
+ break;
+ case 53:
+ default:
+ groupIndex = 0;
+ break;
+ }
+ RANGE = Res.SWORDS_SPELL_RANGES[category * 4 + groupIndex];
+ } else {
+ int groupIndex = (party._mazeId - 29) / 2;
+ RANGE = Res.DARK_SPELL_RANGES[category * 4 + groupIndex];
+ }
+
+ for (int spellId = RANGE[0]; spellId < RANGE[1]; ++spellId) {
int idx = 0;
- while (idx < 40 && Res.SPELLS_ALLOWED[category][idx] ==
- Res.DARK_SPELL_OFFSETS[category][spellId]);
+ while (idx < SPELLS_PER_CLASS && Res.SPELLS_ALLOWED[category][idx] !=
+ Res.DARK_SPELL_OFFSETS[category][spellId])
+ ++idx;
- if (idx < 40) {
- if (!c->_spells[idx] || (isCasting & 0x80)) {
+ if (idx < SPELLS_PER_CLASS) {
+ if (!c->_spells[idx] || (mode & 0x80)) {
int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
_spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
@@ -378,11 +357,12 @@ const char *SpellsDialog::setSpellText(Character *c, int isCasting) {
} else {
for (int spellId = 0; spellId < 20; ++spellId) {
int idx = 0;
- while (Res.CLOUDS_SPELL_OFFSETS[party._mazeId - 29][spellId] !=
- (int)Res.SPELLS_ALLOWED[category][idx] && idx < 40) ;
+ while (idx < SPELLS_PER_CLASS && Res.CLOUDS_GUILD_SPELLS[party._mazeId - 28][spellId] !=
+ (int)Res.SPELLS_ALLOWED[category][idx])
+ ++idx;
- if (idx < 40) {
- if (!c->_spells[idx] || (isCasting & 0x80)) {
+ if (idx < SPELLS_PER_CLASS) {
+ if (!c->_spells[idx] || (mode & 0x80)) {
int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
_spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
@@ -396,27 +376,11 @@ const char *SpellsDialog::setSpellText(Character *c, int isCasting) {
if (c->getMaxSP() == 0)
return Res.NOT_A_SPELL_CASTER;
- } else if ((isCasting & 0x7f) == 1) {
- switch (c->_class) {
- case CLASS_ARCHER:
- case CLASS_SORCERER:
- category = 1;
- break;
- case CLASS_DRUID:
- case CLASS_RANGER:
- category = 2;
- break;
- case CLASS_PALADIN:
- case CLASS_CLERIC:
- default:
- category = 0;
- break;
- }
-
+ } else if ((mode & 0x7f) == 1) {
if (c->getMaxSP() == 0) {
return Res.NOT_A_SPELL_CASTER;
} else {
- for (int spellIndex = 0; spellIndex < MAX_SPELLS_PER_CLASS; ++spellIndex) {
+ for (int spellIndex = 0; spellIndex < SPELLS_PER_CLASS; ++spellIndex) {
if (c->_spells[spellIndex]) {
int spellId = Res.SPELLS_ALLOWED[category][spellIndex];
int gemCost = Res.SPELL_GEM_COST[spellId];
@@ -430,7 +394,7 @@ const char *SpellsDialog::setSpellText(Character *c, int isCasting) {
}
}
- return nullptr;
+ return _spells.empty() ? Res.SPELLS_LEARNED_ALL : nullptr;
}
/*------------------------------------------------------------------------*/
@@ -460,6 +424,7 @@ int CastSpell::show(XeenEngine *vm) {
Interface &intf = *vm->_interface;
Party &party = *vm->_party;
Spells &spells = *vm->_spells;
+ int result = 0, spellId = 0;
int charNum;
// Get which character is doing the casting
@@ -476,23 +441,17 @@ int CastSpell::show(XeenEngine *vm) {
}
}
+ // Highlight the character
Character *c = &party._activeParty[charNum];
- intf.highlightChar(charNum);
-
- return show(vm, c);
-}
+ intf.highlightChar(c);
-int CastSpell::show(XeenEngine *vm, Character *&c) {
- Spells &spells = *vm->_spells;
CastSpell *dlg = new CastSpell(vm);
- int spellId;
- int result = -1;
-
do {
spellId = dlg->execute(c);
if (g_vm->shouldExit() || spellId == -1) {
- result = 0;
+ result = -1;
+ break;
} else {
result = spells.castSpell(c, (MagicSpell)spellId);
}
@@ -514,9 +473,10 @@ int CastSpell::execute(Character *&c) {
bool redrawFlag = true;
do {
if (redrawFlag) {
- int category = c->getClassCategory();
+ SpellsCategory category = c->getSpellsCategory();
+
int spellIndex = c->_currentSpell != -1 ? c->_currentSpell : 39;
- spellId = Res.SPELLS_ALLOWED[category][spellIndex];
+ spellId = (category == SPELLCAT_INVALID) ? NO_SPELL : Res.SPELLS_ALLOWED[category][spellIndex];
int gemCost = Res.SPELL_GEM_COST[spellId];
int spCost = spells.calcSpellPoints(spellId, c->getCurrentLevel());
@@ -553,6 +513,7 @@ int CastSpell::execute(Character *&c) {
if (_buttonValue < (int)party._activeParty.size()) {
c = &party._activeParty[_buttonValue];
intf.highlightChar(_buttonValue);
+ spells._lastCaster = _buttonValue;
redrawFlag = true;
break;
}
@@ -572,7 +533,7 @@ int CastSpell::execute(Character *&c) {
case Common::KEYCODE_n:
// Select new spell
_vm->_mode = (Mode)_oldMode;
- c = SpellsDialog::show(_vm, this, c, 1);
+ c = SpellsDialog::show(_vm, this, c, SPELLS_DIALOG_SELECT);
redrawFlag = true;
break;
@@ -698,7 +659,7 @@ int SelectElement::execute(int spellId) {
while (result == 999) {
do {
events.updateGameCounter();
- intf.draw3d(true);
+ intf.draw3d(true, false);
w.frame();
w.writeString(Res.WHICH_ELEMENT2);
drawButtons(&windows[0]);
@@ -797,14 +758,14 @@ bool LloydsBeacon::execute() {
Sound &sound = *_vm->_sound;
Windows &windows = *_vm->_windows;
Window &w = windows[10];
- bool isDarkCc = _vm->_files->_isDarkCc;
+ int ccNum = _vm->_files->_ccNum;
Character &c = *combat._oldCharacter;
loadButtons();
if (!c._lloydMap) {
// No destination previously set, so have a default ready
- if (isDarkCc) {
+ if (ccNum) {
c._lloydSide = 1;
c._lloydPosition = Common::Point(25, 21);
c._lloydMap = 29;
@@ -815,19 +776,14 @@ bool LloydsBeacon::execute() {
}
}
- // Open up the text file for the destination map and read in it's name
- File textFile(Common::String::format("%s%c%03d.txt",
- c._lloydSide == 0 ? "xeen" : "dark",
- c._lloydMap >= 100 ? 'x' : '0',
- c._lloydMap));
- Common::String mapName = textFile.readString();
- textFile.close();
+ // Get the destination map name
+ Common::String mapName = Map::getMazeName(c._lloydMap, c._lloydSide);
// Display the dialog
w.open();
- w.writeString(Common::String::format(Res.LLOYDS_BEACON,
- mapName.c_str(), c._lloydPosition.x, c._lloydPosition.y));
- drawButtons(&windows[0]);
+ w.writeString(Common::String::format(Res.LLOYDS_BEACON, mapName.c_str(),
+ c._lloydPosition.x, c._lloydPosition.y));
+ drawButtons(&w);
w.update();
bool result = true;
@@ -847,12 +803,13 @@ bool LloydsBeacon::execute() {
switch (_buttonValue) {
case Common::KEYCODE_r:
- if (!isDarkCc && c._lloydMap >= 75 && c._lloydMap <= 78 && !party._cloudsEnd) {
+ if (!ccNum && c._lloydMap >= XEEN_CASTLE1 && c._lloydMap <= XEEN_CASTLE4 && party._cloudsCompleted) {
+ // Xeen's Castle has already been destroyed
result = false;
} else {
sound.playFX(51);
- map._loadDarkSide = isDarkCc;
- if (c._lloydMap != party._mazeId || c._lloydSide != (isDarkCc ? 1 : 0)) {
+ if (c._lloydMap != party._mazeId || c._lloydSide != ccNum) {
+ map._loadCcNum = c._lloydSide;
map.load(c._lloydMap);
}
@@ -867,7 +824,7 @@ bool LloydsBeacon::execute() {
sound.playFX(20);
c._lloydMap = party._mazeId;
c._lloydPosition = party._mazePosition;
- c._lloydSide = isDarkCc ? 1 : 0;
+ c._lloydSide = ccNum;
_buttonValue = Common::KEYCODE_ESCAPE;
break;
@@ -932,10 +889,9 @@ int Teleport::execute() {
break;
}
- v = map.mazeLookup(pt, map._isOutdoors ? 0xF : 0xFFFF, 0);
+ v = map.mazeLookup(pt, 0, map._isOutdoors ? 0xF : 0xFFFF);
- if ((v != (map._isOutdoors ? 0 : INVALID_CELL)) &&
- (!map._isOutdoors || v == SURFTYPE_DWATER)) {
+ if ((v != (map._isOutdoors ? 0 : INVALID_CELL)) && (!map._isOutdoors || v != SURFTYPE_DWATER)) {
party._mazePosition = pt;
return 1;
} else {
@@ -961,20 +917,35 @@ int TownPortal::execute() {
Mode oldMode = _vm->_mode;
_vm->_mode = MODE_FF;
- // Build up a lsit of the names of the towns on the current side of Xeen
- for (int idx = 0; idx < 5; ++idx) {
- File f(Common::String::format("%s%04d.txt",
- map._sideTownPortal ? "dark" : "xeen",
- Res.TOWN_MAP_NUMBERS[map._sideTownPortal][idx]));
- townNames[idx] = f.readString();
- f.close();
+ w.open();
+
+ if (_vm->getGameID() == GType_Swords) {
+ // Build up a lsit of the names of the towns on the current side of Xeen
+ for (int idx = 0; idx < 3; ++idx) {
+ Common::String txtName = Common::String::format("%s%04d.txt", "dark", Res.TOWN_MAP_NUMBERS[2][idx]);
+ File f(txtName, 1);
+ townNames[idx] = f.readString();
+ f.close();
+ }
+
+ w.writeString(Common::String::format(Res.TOWN_PORTAL_SWORDS, townNames[0].c_str(), townNames[1].c_str(),
+ townNames[2].c_str()));
+ } else {
+ // Build up a lsit of the names of the towns on the current side of Xeen
+ for (int idx = 0; idx < 5; ++idx) {
+ Common::String txtName = Common::String::format("%s%04d.txt", map._sideTownPortal ? "dark" : "xeen",
+ Res.TOWN_MAP_NUMBERS[map._sideTownPortal][idx]);
+ File f(txtName, 1);
+ townNames[idx] = f.readString();
+ f.close();
+ }
+
+ w.writeString(Common::String::format(Res.TOWN_PORTAL,
+ townNames[0].c_str(), townNames[1].c_str(), townNames[2].c_str(),
+ townNames[3].c_str(), townNames[4].c_str()
+ ));
}
- w.open();
- w.writeString(Common::String::format(Res.TOWN_PORTAL,
- townNames[0].c_str(), townNames[1].c_str(), townNames[2].c_str(),
- townNames[3].c_str(), townNames[4].c_str()
- ));
w.update();
// Get the town number
@@ -983,7 +954,7 @@ int TownPortal::execute() {
do {
int result = Input::show(_vm, &w, num, 1, 160, true);
townNumber = !result ? 0 : atoi(num.c_str());
- } while (townNumber > 5);
+ } while (townNumber > (_vm->getGameID() == GType_Swords ? 3 : 5));
w.close();
_vm->_mode = oldMode;
@@ -1032,7 +1003,7 @@ void IdentifyMonster::execute() {
do {
events.updateGameCounter();
- intf.draw3d(false);
+ intf.draw3d(false, false);
w.frame();
windows[3].update();
@@ -1042,4 +1013,62 @@ void IdentifyMonster::execute() {
w.close();
}
+
+/*------------------------------------------------------------------------*/
+
+void DetectMonsters::show(XeenEngine *vm) {
+ DetectMonsters *dlg = new DetectMonsters(vm);
+ dlg->execute();
+ delete dlg;
+}
+
+void DetectMonsters::execute() {
+ EventsManager &events = *_vm->_events;
+ Interface &intf = *_vm->_interface;
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+ Resources &res = *_vm->_resources;
+ Sound &sound = *_vm->_sound;
+ Windows &windows = *_vm->_windows;
+ Window &w = windows[19];
+ int ccNum = _vm->_files->_ccNum;
+ int grid[7][7];
+
+ SpriteResource sprites(ccNum ? "detectmn.icn" : "detctmon.icn");
+ Common::fill(&grid[0][0], &grid[6][6], 0);
+
+ w.open();
+ w.writeString(Res.DETECT_MONSTERS);
+ sprites.draw(w, 0, Common::Point(243, 80));
+
+ for (int yDiff = 3; yDiff >= -3; --yDiff) {
+ for (int xDiff = -3; xDiff <= 3; ++xDiff) {
+ for (uint monIndex = 0; monIndex < map._mobData._monsters.size(); ++monIndex) {
+ MazeMonster &monster = map._mobData._monsters[monIndex];
+ Common::Point pt = party._mazePosition + Common::Point(xDiff, yDiff);
+ if (monster._position == pt) {
+ int &gridEntry = grid[yDiff + 3][xDiff + 3];
+ if (++gridEntry > 3)
+ gridEntry = 3;
+
+ sprites.draw(w, gridEntry, Common::Point(271 + xDiff * 9, 102 - yDiff * 7));
+ }
+ }
+ }
+ }
+
+ res._globalSprites.draw(w, party._mazeDirection + 1, Common::Point(270, 101));
+ sound.playFX(20);
+ w.update();
+
+ while (!g_vm->shouldExit() && !events.isKeyMousePressed()) {
+ events.updateGameCounter();
+ intf.draw3d(true);
+
+ events.wait(1, false);
+ }
+
+ w.close();
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_spells.h b/engines/xeen/dialogs/dialogs_spells.h
index 2bcaef43e5..26c3f00428 100644
--- a/engines/xeen/dialogs/dialogs_spells.h
+++ b/engines/xeen/dialogs/dialogs_spells.h
@@ -29,6 +29,10 @@
namespace Xeen {
+enum SpellDialogMode {
+ SPELLS_DIALOG_BUY = 0, SPELLS_DIALOG_SELECT = 1, SPELLS_DIALOG_INFO = 0x80
+};
+
struct SpellEntry {
Common::String _name;
int _spellIndex;
@@ -39,22 +43,41 @@ struct SpellEntry {
_name(name), _spellIndex(spellIndex), _spellId(spellId), _color(9) {}
};
+/**
+ * Spells list dialog. Used for both selecting spells to cast, as well as the
+ * spells listing when visiting Guild locations
+ */
class SpellsDialog : public ButtonContainer {
private:
SpriteResource _iconSprites;
SpriteResource _scrollSprites;
Common::Array<SpellEntry> _spells;
+ /**
+ * Constructor
+ */
SpellsDialog(XeenEngine *vm) : ButtonContainer(vm) {}
- Character *execute(ButtonContainer *priorDialog, Character *c, int isCasting);
+ /**
+ * Executes the dialog
+ */
+ Character *execute(ButtonContainer *priorDialog, Character *c, int mode);
+ /**
+ * Loads buttons for the dialog
+ */
void loadButtons();
+ /**
+ * Sets the spell text
+ */
const char *setSpellText(Character *c, int isCasting);
public:
+ /**
+ * Show the spells list dialog
+ */
static Character *show(XeenEngine *vm, ButtonContainer *priorDialog,
- Character *c, int isCasting);
+ Character *c, SpellDialogMode mode);
};
class CastSpell : public ButtonContainer {
@@ -70,7 +93,6 @@ private:
void loadButtons();
public:
static int show(XeenEngine *vm);
- static int show(XeenEngine *vm, Character *&c);
};
class SpellOnWho : public ButtonContainer {
@@ -146,6 +168,15 @@ public:
static void show(XeenEngine *vm);
};
+class DetectMonsters : public ButtonContainer {
+private:
+ DetectMonsters(XeenEngine *vm) : ButtonContainer(vm) {}
+
+ void execute();
+public:
+ static void show(XeenEngine *vm);
+};
+
} // End of namespace Xeen
#endif /* XEEN_DIALOGS_SPELLS_H */
diff --git a/engines/xeen/events.cpp b/engines/xeen/events.cpp
index 6ceef4406b..17306a32fc 100644
--- a/engines/xeen/events.cpp
+++ b/engines/xeen/events.cpp
@@ -31,9 +31,9 @@
namespace Xeen {
-EventsManager::EventsManager(XeenEngine *vm) : _vm(vm), _playTime(0),
- _frameCounter(0), _priorFrameCounterTime(0), _gameCounter(0),
- _leftButton(false), _rightButton(false), _sprites("mouse.icn") {
+EventsManager::EventsManager(XeenEngine *vm) : _vm(vm), _playTime(0), _gameCounter(0),
+ _frameCounter(0), _priorFrameCounterTime(0), _priorScreenRefreshTime(0),
+ _mousePressed(false), _sprites("mouse.icn") {
Common::fill(&_gameCounters[0], &_gameCounters[6], 0);
}
@@ -62,7 +62,15 @@ bool EventsManager::isCursorVisible() {
void EventsManager::pollEvents() {
uint32 timer = g_system->getMillis();
+
+ if (timer >= (_priorScreenRefreshTime + SCREEN_UPDATE_TIME)) {
+ // Refresh the screen at a higher frame rate than the game's own frame rate
+ // to allow for more responsive mouse movement
+ _priorScreenRefreshTime = timer;
+ g_vm->_screen->update();
+ }
if (timer >= (_priorFrameCounterTime + GAME_FRAME_TIME)) {
+ // Time to build up next game frame
_priorFrameCounterTime = timer;
nextFrame();
}
@@ -80,24 +88,24 @@ void EventsManager::pollEvents() {
_vm->_debugger->attach();
_vm->_debugger->onFrame();
} else {
- _keys.push(event.kbd);
+ addEvent(event.kbd);
}
break;
case Common::EVENT_MOUSEMOVE:
_mousePos = event.mouse;
break;
case Common::EVENT_LBUTTONDOWN:
- _leftButton = true;
- return;
- case Common::EVENT_LBUTTONUP:
- _leftButton = false;
+ _mousePressed = true;
+ addEvent(true, false);
return;
case Common::EVENT_RBUTTONDOWN:
- _rightButton = true;
+ _mousePressed = true;
+ addEvent(false, true);
return;
+ case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
- _rightButton = false;
- break;
+ _mousePressed = false;
+ return;
default:
break;
}
@@ -110,31 +118,38 @@ void EventsManager::pollEventsAndWait() {
}
void EventsManager::clearEvents() {
- _keys.clear();
- _leftButton = _rightButton = false;
-
+ _pendingEvents.clear();
+ _mousePressed = false;
}
void EventsManager::debounceMouse() {
- while (_leftButton && !_vm->shouldExit()) {
+ while (_mousePressed && !_vm->shouldExit()) {
pollEventsAndWait();
}
}
-bool EventsManager::getKey(Common::KeyState &key) {
- if (_keys.empty()) {
+
+void EventsManager::addEvent(const Common::KeyState &keyState) {
+ if (_pendingEvents.size() < MAX_PENDING_EVENTS)
+ _pendingEvents.push(PendingEvent(keyState));
+}
+
+void EventsManager::addEvent(bool leftButton, bool rightButton) {
+ if (_pendingEvents.size() < MAX_PENDING_EVENTS)
+ _pendingEvents.push(PendingEvent(leftButton, rightButton));
+}
+
+
+bool EventsManager::getEvent(PendingEvent &pe) {
+ if (_pendingEvents.empty()) {
return false;
} else {
- key = _keys.pop();
+ pe = _pendingEvents.pop();
return true;
}
}
-bool EventsManager::isKeyPending() const {
- return !_keys.empty();
-}
-
bool EventsManager::isKeyMousePressed() {
- bool result = _leftButton || _rightButton || isKeyPending();
+ bool result = isEventPending();
debounceMouse();
clearEvents();
@@ -144,7 +159,7 @@ bool EventsManager::isKeyMousePressed() {
bool EventsManager::wait(uint numFrames, bool interruptable) {
while (!_vm->shouldExit() && timeElapsed() < numFrames) {
pollEventsAndWait();
- if (interruptable && (_leftButton || _rightButton || isKeyPending()))
+ if (interruptable && isEventPending())
return true;
}
@@ -200,9 +215,4 @@ void EventsManager::nextFrame() {
_vm->_screen->update();
}
-/*------------------------------------------------------------------------*/
-
-GameEvent::GameEvent() {
-}
-
} // End of namespace Xeen
diff --git a/engines/xeen/events.h b/engines/xeen/events.h
index 0ef2c3a9e7..9913b2fbf1 100644
--- a/engines/xeen/events.h
+++ b/engines/xeen/events.h
@@ -32,30 +32,52 @@ namespace Xeen {
#define GAME_FRAME_RATE (1000 / 50)
#define GAME_FRAME_TIME 50
+#define SCREEN_UPDATE_TIME 10
+#define MAX_PENDING_EVENTS 5
class XeenEngine;
+struct PendingEvent {
+ Common::KeyState _keyState;
+ bool _leftButton;
+ bool _rightButton;
+
+ PendingEvent() : _leftButton(false), _rightButton(false) {}
+ PendingEvent(const Common::KeyState &keyState) : _keyState(keyState), _leftButton(false), _rightButton(false) {}
+ PendingEvent(bool leftButton, bool rightButton) : _leftButton(leftButton), _rightButton(rightButton) {}
+
+ /**
+ * Returns true if a keyboard event is pending
+ */
+ bool isKeyboard() const { return _keyState.keycode != Common::KEYCODE_INVALID; }
+
+ /**
+ * Returns ture if a mouse button event is pending
+ */
+ bool isMouse() const { return _leftButton || _rightButton; }
+};
+
class EventsManager {
private:
XeenEngine *_vm;
uint32 _frameCounter;
uint32 _priorFrameCounterTime;
+ uint32 _priorScreenRefreshTime;
uint32 _gameCounter;
uint32 _gameCounters[6];
uint32 _playTime;
- Common::Queue<Common::KeyState> _keys;
+ Common::Queue<PendingEvent> _pendingEvents;
SpriteResource _sprites;
+ bool _mousePressed;
/**
* Handles moving to the next game frame
*/
void nextFrame();
public:
- bool _leftButton, _rightButton;
Common::Point _mousePos;
public:
EventsManager(XeenEngine *vm);
-
~EventsManager();
/*
@@ -78,17 +100,45 @@ public:
*/
bool isCursorVisible();
+ /**
+ * Polls the ScummVM backend for any pending events
+ */
void pollEvents();
+ /**
+ * Polls for events, and wait a slight delay. This ensures the game doesn't use up 100% of the CPU
+ */
void pollEventsAndWait();
+ /**
+ * Clears all pending events
+ */
void clearEvents();
+ /**
+ * Waits for a mouse press to be released
+ */
void debounceMouse();
- bool getKey(Common::KeyState &key);
+ /**
+ * Adds a keyboard event to the queue
+ */
+ void addEvent(const Common::KeyState &keyState);
- bool isKeyPending() const;
+ /**
+ * Adds a mouse button event to the queue
+ */
+ void addEvent(bool leftButton, bool rightButton);
+
+ /**
+ * Returns the next pending key/mouse press, if any
+ */
+ bool getEvent(PendingEvent &pe);
+
+ /**
+ * Returns true if a key or mouse event is pending
+ */
+ bool isEventPending() const { return !_pendingEvents.empty(); }
/**
* Returns true if a key or mouse press is pending
@@ -141,11 +191,6 @@ public:
void waitForPress();
};
-class GameEvent {
-public:
- GameEvent();
-};
-
} // End of namespace Xeen
#endif /* XEEN_EVENTS_H */
diff --git a/engines/xeen/files.cpp b/engines/xeen/files.cpp
index 83a4ca9072..d18b5c4dd6 100644
--- a/engines/xeen/files.cpp
+++ b/engines/xeen/files.cpp
@@ -218,7 +218,7 @@ Common::SeekableReadStream *CCArchive::createReadStreamForMember(const Common::S
/*------------------------------------------------------------------------*/
FileManager::FileManager(XeenEngine *vm) {
- _isDarkCc = vm->getGameID() == GType_DarkSide;
+ _ccNum = vm->getGameID() == GType_DarkSide;
File::_xeenCc = File::_darkCc = File::_introCc = nullptr;
File::_xeenSave = File::_darkSave = nullptr;
File::_currentSave = nullptr;
@@ -277,7 +277,7 @@ void FileManager::setGameCc(int ccMode) {
}
File::setCurrentArchive(ccMode);
- _isDarkCc = ccMode != 0;
+ _ccNum = ccMode != 0;
}
void FileManager::load(Common::SeekableReadStream &stream) {
@@ -285,7 +285,7 @@ void FileManager::load(Common::SeekableReadStream &stream) {
}
void FileManager::save(Common::WriteStream &s) {
- s.writeByte(_isDarkCc ? 1 : 0);
+ s.writeByte(_ccNum ? 1 : 0);
}
/*------------------------------------------------------------------------*/
@@ -330,7 +330,7 @@ bool File::open(const Common::String &filename, Common::Archive &archive) {
bool File::open(const Common::String &filename, int ccMode) {
FileManager &files = *g_vm->_files;
- int oldMode = files._isDarkCc ? 1 : 0;
+ int oldNum = files._ccNum;
files.setGameCc(ccMode);
if (File::exists(filename, *_currentArchive))
@@ -338,7 +338,7 @@ bool File::open(const Common::String &filename, int ccMode) {
else
File::open(filename);
- files.setGameCc(oldMode);
+ files.setGameCc(oldNum);
return true;
}
@@ -390,11 +390,11 @@ bool File::exists(const Common::String &filename) {
bool File::exists(const Common::String &filename, int ccMode) {
FileManager &files = *g_vm->_files;
- int oldMode = files._isDarkCc ? 1 : 0;
+ int oldNum = files._ccNum;
files.setGameCc(ccMode);
bool result = exists(filename);
- files.setGameCc(oldMode);
+ files.setGameCc(oldNum);
return result;
}
@@ -480,6 +480,7 @@ Common::SeekableReadStream *SaveArchive::createReadStreamForMember(uint16 id) co
}
void SaveArchive::load(Common::SeekableReadStream &stream) {
+ _newData.clear();
loadIndex(stream);
delete[] _data;
@@ -487,8 +488,10 @@ void SaveArchive::load(Common::SeekableReadStream &stream) {
_data = new byte[_dataSize];
stream.seek(0);
stream.read(_data, _dataSize);
+}
- // Load in the character stats and active party
+void SaveArchive::loadParty() {
+ // Load in the character roster and active party
Common::SeekableReadStream *chr = createReadStreamForMember("maze.chr");
Common::Serializer sChr(chr, nullptr);
_party->_roster.synchronize(sChr);
@@ -503,6 +506,7 @@ void SaveArchive::load(Common::SeekableReadStream &stream) {
void SaveArchive::reset(CCArchive *src) {
Common::MemoryWriteStreamDynamic saveFile(DisposeAfterUse::YES);
File fIn;
+ _newData.clear();
g_vm->_files->setGameCc(g_vm->getGameID() == GType_DarkSide ? 1 : 0);
const int RESOURCES[6] = { 0x2A0C, 0x2A1C, 0x2A2C, 0x2A3C, 0x284C, 0x2A5C };
diff --git a/engines/xeen/files.h b/engines/xeen/files.h
index 306ec96657..0d421547fb 100644
--- a/engines/xeen/files.h
+++ b/engines/xeen/files.h
@@ -77,13 +77,13 @@ struct CCEntry {
*/
class FileManager {
public:
- bool _isDarkCc;
+ int _ccNum;
public:
/**
* Constructor
*/
FileManager(XeenEngine *vm);
-
+
/**
* Destructor
*/
@@ -352,6 +352,11 @@ public:
void save(Common::WriteStream &s);
/**
+ * Load the character roster and party
+ */
+ void loadParty();
+
+ /**
* Sets a new resource entry
*/
void replaceEntry(uint16 id, const byte *data, size_t size);
@@ -373,7 +378,7 @@ public:
/**
* Finishes any pending writes, pushing out the written data
*/
- void finalize();
+ void finalize() override;
/**
* Writes data
diff --git a/engines/xeen/font.cpp b/engines/xeen/font.cpp
index 58381e1516..d5f05bac0a 100644
--- a/engines/xeen/font.cpp
+++ b/engines/xeen/font.cpp
@@ -218,7 +218,7 @@ const char *FontSurface::writeString(const Common::String &s, const Common::Rect
} else if (c == 10) {
// Newline
if (newLine(bounds))
- break;
+ return _displayString;
} else if (c == 11) {
// Set y position
int yp = fontAtoi();
@@ -330,6 +330,7 @@ void FontSurface::writeChar(char c, const Common::Rect &clipRect) {
int y = _writePos.y;
if (c == 'g' || c == 'p' || c == 'q' || c == 'y')
++y;
+ int yStart = y;
// Get pointers into font data and surface to write pixels to
int charIndex = (int)c + (_fontReduced ? 0x80 : 0);
@@ -354,8 +355,8 @@ void FontSurface::writeChar(char c, const Common::Rect &clipRect) {
}
}
- addDirtyRect(Common::Rect(_writePos.x, _writePos.y, _writePos.x + FONT_WIDTH,
- _writePos.y + FONT_HEIGHT));
+ addDirtyRect(Common::Rect(_writePos.x, yStart, _writePos.x + FONT_WIDTH,
+ yStart + FONT_HEIGHT));
_writePos.x += _fontData[0x1000 + charIndex];
}
diff --git a/engines/xeen/interface.cpp b/engines/xeen/interface.cpp
index 3d9f05b5a2..82a2cbd7d1 100644
--- a/engines/xeen/interface.cpp
+++ b/engines/xeen/interface.cpp
@@ -103,6 +103,7 @@ void PartyDrawer::drawParty(bool updateFlag) {
void PartyDrawer::highlightChar(int charId) {
Resources &res = *_vm->_resources;
Windows &windows = *_vm->_windows;
+ assert(charId < MAX_ACTIVE_PARTY);
if (charId != _hiliteChar && _hiliteChar != HILIGHT_CHAR_DISABLED) {
// Handle deselecting any previusly selected char
@@ -118,6 +119,12 @@ void PartyDrawer::highlightChar(int charId) {
}
}
+void PartyDrawer::highlightChar(const Character *c) {
+ int charNum = _vm->_party->_activeParty.indexOf(*c);
+ if (charNum != -1)
+ highlightChar(charNum);
+}
+
void PartyDrawer::unhighlightChar() {
Resources &res = *_vm->_resources;
Windows &windows = *_vm->_windows;
@@ -156,6 +163,7 @@ Interface::Interface(XeenEngine *vm) : ButtonContainer(vm), InterfaceScene(vm),
_upDoorText = false;
_tillMove = 0;
Common::fill(&_charFX[0], &_charFX[MAX_ACTIVE_PARTY], 0);
+ _waitBounds = Common::Rect(8, 8, 224, 140);
}
void Interface::setup() {
@@ -202,7 +210,7 @@ void Interface::mainIconsPrint() {
Windows &windows = *_vm->_windows;
windows[38].close();
windows[12].close();
-
+
res._globalSprites.draw(0, 7, Common::Point(232, 74));
drawButtons(&windows[0]);
windows[34].update();
@@ -255,23 +263,22 @@ void Interface::perform() {
Party &party = *_vm->_party;
Scripts &scripts = *_vm->_scripts;
Sound &sound = *_vm->_sound;
- Spells &spells = *_vm->_spells;
- const Common::Rect WAIT_BOUNDS(8, 8, 224, 140);
- events.updateGameCounter();
- draw3d(true);
-
- // Wait for a frame or a user event
do {
- events.pollEventsAndWait();
- checkEvents(_vm);
+ // Draw the next frame
+ events.updateGameCounter();
+ draw3d(true);
- if (events._leftButton && WAIT_BOUNDS.contains(events._mousePos))
- _buttonValue = Common::KEYCODE_SPACE;
- } while (!_buttonValue && events.timeElapsed() < 1 && !_vm->_party->_partyDead);
+ // Wait for a frame or a user event
+ _buttonValue = 0;
+ do {
+ events.pollEventsAndWait();
+ if (g_vm->shouldExit() || g_vm->isLoadPending() || party._dead)
+ return;
- if (!_buttonValue && !_vm->_party->_partyDead)
- return;
+ checkEvents(g_vm);
+ } while (!_buttonValue && events.timeElapsed() < 1);
+ } while (!_buttonValue);
if (_buttonValue == Common::KEYCODE_SPACE) {
int lookupId = map.mazeLookup(party._mazePosition,
@@ -281,28 +288,24 @@ void Interface::perform() {
switch (lookupId) {
case 1:
if (!map._isOutdoors) {
- scripts.openGrate(13, 1);
- eventsFlag = _buttonValue != 0;
+ eventsFlag = !scripts.openGrate(13, 1);
}
break;
case 6:
// Open grate being closed
if (!map._isOutdoors) {
- scripts.openGrate(9, 0);
- eventsFlag = _buttonValue != 0;
+ eventsFlag = !scripts.openGrate(9, 0);
}
break;
case 9:
// Closed grate being opened
if (!map._isOutdoors) {
- scripts.openGrate(6, 0);
- eventsFlag = _buttonValue != 0;
+ eventsFlag = !scripts.openGrate(6, 0);
}
break;
case 13:
if (!map._isOutdoors) {
- scripts.openGrate(1, 1);
- eventsFlag = _buttonValue != 0;
+ eventsFlag = !scripts.openGrate(1, 1);
}
break;
default:
@@ -312,6 +315,8 @@ void Interface::perform() {
scripts.checkEvents();
if (_vm->shouldExit())
return;
+ } else {
+ clearEvents();
}
}
@@ -460,6 +465,13 @@ void Interface::perform() {
}
break;
+ case (Common::KBD_CTRL << 16) | Common::KEYCODE_DOWN:
+ party._mazeDirection = (Direction)((int)party._mazeDirection ^ 2);
+ _flipSky = !_flipSky;
+ _isAnimReset = true;
+ stepTime();
+ break;
+
case Common::KEYCODE_F1:
case Common::KEYCODE_F2:
case Common::KEYCODE_F3:
@@ -508,25 +520,18 @@ void Interface::perform() {
}
break;
- case Common::KEYCODE_c: {
+ case Common::KEYCODE_c:
// Cast spell
if (_tillMove) {
combat.moveMonsters();
draw3d(true);
}
- Character *c = &party._activeParty[(spells._lastCaster < 0 ||
- spells._lastCaster >= (int)party._activeParty.size()) ?
- (int)party._activeParty.size() - 1 : spells._lastCaster];
-
- int result = CastSpell::show(_vm, c);
-
- if (result == 1) {
+ if (CastSpell::show(_vm) != -1) {
chargeStep();
doStepCode();
}
break;
- }
case Common::KEYCODE_i:
// Show Info dialog
@@ -562,7 +567,7 @@ void Interface::perform() {
if (combat._attackMonsters[0] != -1 || combat._attackMonsters[1] != -1
|| combat._attackMonsters[2] != -1) {
- if ((_vm->_mode == MODE_1 || _vm->_mode == MODE_SLEEPING)
+ if ((_vm->_mode == MODE_INTERACTIVE || _vm->_mode == MODE_SLEEPING)
&& !combat._monstersAttacking && !_charsShooting) {
doCombat();
}
@@ -585,7 +590,7 @@ void Interface::perform() {
}
void Interface::chargeStep() {
- if (!_vm->_party->_partyDead) {
+ if (!_vm->_party->_dead) {
_vm->_party->changeTime(_vm->_map->_isOutdoors ? 10 : 1);
if (_tillMove) {
_vm->_combat->moveMonsters();
@@ -628,7 +633,7 @@ void Interface::doStepCode() {
switch (surfaceId) {
case SURFTYPE_SPACE:
// Wheeze.. can't breathe in space! Explosive decompression, here we come
- party._partyDead = true;
+ party._dead = true;
break;
case SURFTYPE_LAVA:
// It burns, it burns!
@@ -657,7 +662,7 @@ void Interface::doStepCode() {
break;
}
- if (_vm->_files->_isDarkCc && party._gameFlags[1][118]) {
+ if (_vm->getGameID() != GType_Swords && _vm->_files->_ccNum && party._gameFlags[1][118]) {
_falling = FALL_NONE;
} else {
if (_falling != FALL_NONE)
@@ -678,7 +683,7 @@ void Interface::doStepCode() {
combat._combatTarget = oldTarget;
_flipGround = !_flipGround;
- } else if (party._partyDead) {
+ } else if (party._dead) {
draw3d(true);
}
}
@@ -688,9 +693,9 @@ void Interface::startFalling(bool flag) {
Combat &combat = *_vm->_combat;
Map &map = *_vm->_map;
Party &party = *_vm->_party;
- bool isDarkCc = _vm->_files->_isDarkCc;
+ int ccNum = _vm->_files->_ccNum;
- if (isDarkCc && party._gameFlags[1][118]) {
+ if (ccNum && party._gameFlags[1][118]) {
_falling = FALL_NONE;
return;
}
@@ -700,10 +705,10 @@ void Interface::startFalling(bool flag) {
_falling = FALL_START;
draw3d(false);
- if (flag && (!isDarkCc || party._fallMaze != 0)) {
+ if (flag && (!ccNum || party._fallMaze != 0)) {
party._mazeId = party._fallMaze;
party._mazePosition = party._fallPosition;
- } else if (!isDarkCc) {
+ } else if (!ccNum) {
switch (party._mazeId - 25) {
case 0:
case 26:
@@ -768,8 +773,8 @@ void Interface::startFalling(bool flag) {
break;
}
} else {
- if (party._mazeId > 89 && party._mazeId < 113) {
- party._mazeId += 168;
+ if (party._mazeId > 88 && party._mazeId < 114) {
+ party._mazeId -= 88;
} else {
switch (party._mazeId - 25) {
case 0:
@@ -848,7 +853,7 @@ void Interface::startFalling(bool flag) {
break;
case 103:
case 104:
- map._loadDarkSide = false;
+ map._loadCcNum = 0;
party._mazeId = 8;
party._mazePosition = Common::Point(11, 15);
party._mazeDirection = DIR_NORTH;
@@ -893,11 +898,18 @@ void Interface::startFalling(bool flag) {
}
bool Interface::checkMoveDirection(int key) {
+ Debugger &debugger = *g_vm->_debugger;
Map &map = *_vm->_map;
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
- Direction dir = party._mazeDirection;
+ // If intangibility is turned on in the debugger, allow any movement
+ if (debugger._intangible)
+ return true;
+
+ // For strafing or moving backwards, temporarily move to face the direction being checked,
+ // since the call to getCell will the adjacent cell details in the direction being faced
+ Direction dir = party._mazeDirection;
switch (key) {
case (Common::KBD_CTRL << 16) | Common::KEYCODE_LEFT:
party._mazeDirection = (party._mazeDirection == DIR_NORTH) ? DIR_WEST :
@@ -914,16 +926,19 @@ bool Interface::checkMoveDirection(int key) {
break;
}
+ // Get next facing tile information
map.getCell(7);
+
int startSurfaceId = map._currentSurfaceId;
int surfaceId;
if (map._isOutdoors) {
+ // Reset direction back to original facing, if it was changed for strafing checks
party._mazeDirection = dir;
switch (map._currentWall) {
case 5:
- if (_vm->_files->_isDarkCc)
+ if (_vm->_files->_ccNum)
goto check;
// fall through
@@ -965,18 +980,16 @@ bool Interface::checkMoveDirection(int key) {
}
} else {
surfaceId = map.getCell(2);
+
+ // Reset direction back to original facing, if it was changed for strafing checks
+ party._mazeDirection = dir;
+
if (surfaceId >= map.mazeData()._difficulties._wallNoPass) {
- party._mazeDirection = dir;
sound.playFX(46);
return false;
} else {
- party._mazeDirection = dir;
-
- if (startSurfaceId == SURFTYPE_SWAMP || party.checkSkill(SWIMMING) ||
+ if (startSurfaceId != SURFTYPE_SWAMP || party.checkSkill(SWIMMING) ||
party._walkOnWaterActive) {
- sound.playFX(46);
- return false;
- } else {
if (_buttonValue == Common::KEYCODE_UP && _wo[107]) {
_openDoor = true;
sound.playFX(47);
@@ -984,6 +997,9 @@ bool Interface::checkMoveDirection(int key) {
_openDoor = false;
}
return true;
+ } else {
+ sound.playFX(46);
+ return false;
}
}
}
@@ -998,7 +1014,7 @@ void Interface::rest() {
map.cellFlagLookup(party._mazePosition);
if ((map._currentCantRest || (map.mazeData()._mazeFlags & RESTRICTION_REST))
- && _vm->_mode != MODE_12) {
+ && _vm->_mode != MODE_INTERACTIVE2) {
ErrorScroll::show(_vm, Res.TOO_DANGEROUS_TO_REST, WT_NONFREEZED_WAIT);
} else {
// Check whether any character is in danger of dying
@@ -1024,14 +1040,14 @@ void Interface::rest() {
Mode oldMode = _vm->_mode;
_vm->_mode = MODE_SLEEPING;
- if (oldMode == MODE_12) {
+ if (oldMode == MODE_INTERACTIVE2) {
party.changeTime(8 * 60);
} else {
for (int idx = 0; idx < 10; ++idx) {
chargeStep();
draw3d(true);
- if (_vm->_mode == MODE_1) {
+ if (_vm->_mode == MODE_INTERACTIVE) {
_vm->_mode = oldMode;
return;
}
@@ -1068,6 +1084,10 @@ void Interface::rest() {
c._conditions[UNCONSCIOUS] = 0;
c._currentHp = c.getMaxHP();
c._currentSp = c.getMaxSP();
+
+ // WORKAROUND: Resting curing weakness only originally worked due to a bug in changeTime
+ // resetting WEAK if party wasn't drunk. With that resolved, we have to reset WEAK here
+ c._conditions[WEAK] = 0;
}
}
}
@@ -1189,7 +1209,7 @@ void Interface::draw3d(bool updateFlag, bool pauseFlag) {
_flipUIFrame = (_flipUIFrame + 1) % 4;
if (_flipUIFrame == 0)
_flipWater = !_flipWater;
- if (_tillMove && (_vm->_mode == MODE_1 || _vm->_mode == MODE_COMBAT) &&
+ if (_tillMove && (_vm->_mode == MODE_INTERACTIVE || _vm->_mode == MODE_COMBAT) &&
!combat._monstersAttacking && combat._moveMonsters) {
if (--_tillMove == 0)
combat.moveMonsters();
@@ -1225,7 +1245,7 @@ void Interface::draw3d(bool updateFlag, bool pauseFlag) {
if (combat._attackMonsters[0] != -1 || combat._attackMonsters[1] != -1
|| combat._attackMonsters[2] != -1) {
- if ((_vm->_mode == MODE_1 || _vm->_mode == MODE_SLEEPING) &&
+ if ((_vm->_mode == MODE_INTERACTIVE || _vm->_mode == MODE_SLEEPING) &&
!combat._monstersAttacking && !_charsShooting && combat._moveMonsters) {
doCombat();
if (scripts._eventSkipped)
@@ -1357,9 +1377,9 @@ void Interface::assembleBorder() {
_face2UIFrame = (_face2UIFrame + 1) % 4 + 12;
if (_face2State == 0)
- _face2UIFrame += 252;
+ _face2UIFrame -= 3;
else if (_face2State == 2)
- _face2UIFrame = 0;
+ _face2UIFrame = 8;
if (!_vm->_party->_clairvoyanceActive) {
_face1UIFrame = 0;
@@ -1422,8 +1442,7 @@ void Interface::assembleBorder() {
// Draw direction character if direction sense is active
if (_vm->_party->checkSkill(DIRECTION_SENSE) && !_vm->_noDirectionSense) {
const char *dirText = Res.DIRECTION_TEXT_UPPER[_vm->_party->_mazeDirection];
- Common::String msg = Common::String::format(
- "\002""08\003""c\013""139\011""116%c\014""d\001", *dirText);
+ Common::String msg = Common::String::format("\x2\f08\x3""c\v139\t116%c\fd\x1", *dirText);
windows[0].writeString(msg);
}
@@ -1438,11 +1457,11 @@ void Interface::doCombat() {
Map &map = *_vm->_map;
Party &party = *_vm->_party;
Scripts &scripts = *_vm->_scripts;
- Spells &spells = *_vm->_spells;
Sound &sound = *_vm->_sound;
Windows &windows = *_vm->_windows;
bool upDoorText = _upDoorText;
bool reloadMap = false;
+ int index = 0;
_upDoorText = false;
combat._combatMode = COMBATMODE_2;
@@ -1454,7 +1473,6 @@ void Interface::doCombat() {
mainIconsPrint();
combat._combatParty.clear();
- combat._charsGone.clear();
combat.clearBlocked();
combat._pow[0]._duration = 0;
combat._pow[1]._duration = 0;
@@ -1467,9 +1485,8 @@ void Interface::doCombat() {
combat.setSpeedTable();
// Initialize arrays for character/monster states
- combat._charsGone.resize(combat._speedTable.size());
- Common::fill(&combat._charsGone[0], &combat._charsGone[0] + combat._speedTable.size(), 0);
- Common::fill(&combat._charsBlocked[0], &combat._charsBlocked[0] + combat._speedTable.size(), false);
+ Common::fill(&combat._charsGone[0], &combat._charsGone[PARTY_AND_MONSTERS], 0);
+ Common::fill(&combat._charsBlocked[0], &combat._charsBlocked[PARTY_AND_MONSTERS], false);
combat._whosSpeed = -1;
combat._whosTurn = -1;
@@ -1489,18 +1506,24 @@ void Interface::doCombat() {
w.open();
bool breakFlag = false;
- while (!_vm->shouldExit() && !breakFlag) {
+ while (!_vm->shouldExit() && !breakFlag && !party._dead && _vm->_mode == MODE_COMBAT) {
+ // FIXME: I've had a rare issue where the loop starts with a non-party _whosTurn. Unfortunately,
+ // I haven't been able to consistently replicate and diagnose the problem, so for now,
+ // I'm simply detecting if it happens and resetting the combat round
+ if (combat._whosTurn >= (int)party._activeParty.size())
+ goto new_round;
+
highlightChar(combat._whosTurn);
combat.setSpeedTable();
// Write out the description of the monsters being battled
w.writeString(combat.getMonsterDescriptions());
_combatIcons.draw(0, 32, Common::Point(233, combat._attackDurationCtr * 10 + 27),
- SPRFLAG_800, 1);
+ SPRFLAG_800, 0);
w.update();
// Wait for keypress
- int index = 0;
+ index = 0;
do {
events.updateGameCounter();
draw3d(true);
@@ -1517,7 +1540,7 @@ void Interface::doCombat() {
} while (!_vm->shouldExit() && events.timeElapsed() < 1 && !_buttonValue);
} while (!_vm->shouldExit() && !_buttonValue);
if (_vm->shouldExit())
- return;
+ goto exit;
switch (_buttonValue) {
case Common::KEYCODE_TAB:
@@ -1554,13 +1577,10 @@ void Interface::doCombat() {
case Common::KEYCODE_c: {
// Cast spell
- int spellId = CastSpell::show(_vm);
- if (spellId != -1) {
- Character *c = combat._combatParty[combat._whosTurn];
- spells.castSpell(c, (MagicSpell)spellId);
+ if (CastSpell::show(_vm) != -1) {
nextChar();
} else {
- highlightChar(combat._combatParty[combat._whosTurn]->_rosterId);
+ highlightChar(combat._whosTurn);
}
break;
}
@@ -1594,7 +1614,7 @@ void Interface::doCombat() {
combat.run();
nextChar();
- if (_vm->_mode == MODE_1) {
+ if (_vm->_mode == MODE_INTERACTIVE) {
party._treasure._gems = 0;
party._treasure._gold = 0;
party._treasure._hasItems = false;
@@ -1649,7 +1669,8 @@ void Interface::doCombat() {
// Handling for if the combat turn is complete
if (combat.allHaveGone()) {
- Common::fill(&combat._charsGone[0], &combat._charsGone[0] + combat._charsGone.size(), false);
+new_round:
+ Common::fill(&combat._charsGone[0], &combat._charsGone[PARTY_AND_MONSTERS], false);
combat.clearBlocked();
combat.setSpeedTable();
combat._whosTurn = -1;
@@ -1681,11 +1702,9 @@ void Interface::doCombat() {
}
party.checkPartyDead();
- if (party._dead || _vm->_mode != MODE_COMBAT)
- break;
}
- _vm->_mode = MODE_1;
+ _vm->_mode = MODE_INTERACTIVE;
if (combat._partyRan && (combat._attackMonsters[0] != -1 ||
combat._attackMonsters[1] != -1 || combat._attackMonsters[2] != -1)) {
party.checkPartyDead();
@@ -1699,14 +1718,14 @@ void Interface::doCombat() {
}
}
}
-
+exit:
w.close();
events.clearEvents();
_vm->_mode = MODE_COMBAT;
draw3d(true);
party.giveTreasure();
- _vm->_mode = MODE_1;
+ _vm->_mode = MODE_INTERACTIVE;
party._stepped = true;
unhighlightChar();
@@ -1719,21 +1738,23 @@ void Interface::doCombat() {
mainIconsPrint();
combat._monster2Attack = -1;
- if (upDoorText) {
- map.cellFlagLookup(party._mazePosition);
- if (map._currentIsEvent)
- scripts.checkEvents();
- }
+ if (!g_vm->isLoadPending()) {
+ if (upDoorText) {
+ map.cellFlagLookup(party._mazePosition);
+ if (map._currentIsEvent)
+ scripts.checkEvents();
+ }
- if (reloadMap) {
- sound.playFX(51);
- map._loadDarkSide = _vm->getGameID() != GType_WorldOfXeen;
- map.load(_vm->getGameID() == GType_WorldOfXeen ? 28 : 29);
- party._mazeDirection = _vm->getGameID() == GType_WorldOfXeen ?
- DIR_EAST : DIR_SOUTH;
+ if (reloadMap) {
+ sound.playFX(51);
+ map._loadCcNum = _vm->getGameID() != GType_WorldOfXeen ? 1 : 0;
+ map.load(_vm->getGameID() == GType_WorldOfXeen ? 28 : 29);
+ party._mazeDirection = _vm->getGameID() == GType_WorldOfXeen ?
+ DIR_EAST : DIR_SOUTH;
+ }
}
- combat._combatMode = COMBATMODE_1;
+ combat._combatMode = COMBATMODE_INTERACTIVE;
}
void Interface::nextChar() {
@@ -1744,7 +1765,7 @@ void Interface::nextChar() {
return;
if ((combat._attackMonsters[0] == -1 && combat._attackMonsters[1] == -1 &&
combat._attackMonsters[2] == -1) || combat._combatParty.size() == 0) {
- _vm->_mode = MODE_1;
+ _vm->_mode = MODE_INTERACTIVE;
return;
}
@@ -1754,7 +1775,7 @@ void Interface::nextChar() {
// Check if party is dead
party.checkPartyDead();
if (party._dead) {
- _vm->_mode = MODE_1;
+ _vm->_mode = MODE_INTERACTIVE;
break;
}
@@ -1788,7 +1809,7 @@ void Interface::nextChar() {
combat.setSpeedTable();
combat._whosTurn = -1;
combat._whosSpeed = -1;
- Common::fill(&combat._charsGone[0], &combat._charsGone[0] + combat._charsGone.size(), 0);
+ Common::fill(&combat._charsGone[0], &combat._charsGone[PARTY_AND_MONSTERS], false);
continue;
}
diff --git a/engines/xeen/interface.h b/engines/xeen/interface.h
index bbc2a77f1e..5639171c40 100644
--- a/engines/xeen/interface.h
+++ b/engines/xeen/interface.h
@@ -71,8 +71,18 @@ public:
void drawParty(bool updateFlag);
+ /**
+ * Highlights the specified character in the party display at the bottom of the screen
+ * @param charId Character number
+ */
void highlightChar(int charId);
+ /**
+ * Highlights the specified character in the party display at the bottom of the screen
+ * @param c Character to highlight
+ */
+ void highlightChar(const Character *c);
+
void unhighlightChar();
void resetHighlight();
@@ -154,7 +164,6 @@ private:
void nextChar();
public:
Obscurity _obscurity;
- Common::String _interfaceText;
FallState _falling;
int _face1State, _face2State;
int _face1UIFrame, _face2UIFrame;
diff --git a/engines/xeen/interface_minimap.cpp b/engines/xeen/interface_minimap.cpp
index 5ab10696bc..5805047d9e 100644
--- a/engines/xeen/interface_minimap.cpp
+++ b/engines/xeen/interface_minimap.cpp
@@ -141,7 +141,7 @@ void InterfaceMinimap::drawIndoorsMinimap() {
}
// Draw the specific surface type for each cell
- for (int yp = MINIMAP_YSTART + (TILE_HEIGHT / 2), mazeY = pt.y + MINIMAP_DIFF;
+ for (int yp = MINIMAP_YSTART + (TILE_HEIGHT / 2) + 1, mazeY = pt.y + MINIMAP_DIFF;
mazeY >= (pt.y - MINIMAP_DIFF); yp += TILE_HEIGHT, --mazeY) {
for (int xp = MINIMAP_XSTART + (TILE_WIDTH / 2), mazeX = pt.x - MINIMAP_DIFF;
mazeX <= (pt.x + MINIMAP_DIFF); xp += TILE_WIDTH, ++mazeX) {
@@ -161,13 +161,13 @@ void InterfaceMinimap::drawIndoorsMinimap() {
(map._currentSteppedOn || party._wizardEyeActive)) {
map._tileSprites.draw(1,
map.mazeData()._surfaceTypes[map._currentSurfaceId] + 36,
- Common::Point(MINIMAP_XSTART - (TILE_WIDTH / 2),
+ Common::Point(MINIMAP_XSTART - (TILE_WIDTH / 2),
MINIMAP_YSTART - (TILE_HEIGHT / 2) + 1));
}
// Handle drawing surface sprites partially clipped at the left edge
- for (int yp = MINIMAP_YSTART, mazeY = pt.y + MINIMAP_DIFF; mazeY >= (pt.y - MINIMAP_DIFF);
- yp += TILE_HEIGHT, --mazeY) {
+ for (int yp = MINIMAP_YSTART + (TILE_HEIGHT / 2) + 1, mazeY = pt.y + MINIMAP_DIFF;
+ mazeY >= (pt.y - MINIMAP_DIFF); yp += TILE_HEIGHT, --mazeY) {
v = map.mazeLookup(Common::Point(pt.x - MINIMAP_DIFF - 1, mazeY), 0, 0xffff);
if (v != INVALID_CELL && map._currentSurfaceId &&
@@ -192,7 +192,7 @@ void InterfaceMinimap::drawIndoorsMinimap() {
}
// Handle drawing partially clip top row and left column
- for (int xp = MINIMAP_XSTART, yp = MINIMAP_YSTART + (MINIMAP_SIZE - 1) * TILE_HEIGHT,
+ for (int xp = MINIMAP_XSTART, yp = MINIMAP_YSTART + (MINIMAP_SIZE - 1) * TILE_HEIGHT,
mazeX = pt.x - MINIMAP_DIFF, mazeY = pt.y + MINIMAP_DIFF;
mazeX <= (pt.x - MINIMAP_DIFF);
xp += TILE_WIDTH, yp -= TILE_HEIGHT, ++mazeX, --mazeY) {
diff --git a/engines/xeen/interface_scene.cpp b/engines/xeen/interface_scene.cpp
index 51cb6d8b13..0fdf867448 100644
--- a/engines/xeen/interface_scene.cpp
+++ b/engines/xeen/interface_scene.cpp
@@ -63,11 +63,11 @@ OutdoorDrawList::OutdoorDrawList() : _sky1(_data[0]), _sky2(_data[1]),
_data[25] = DrawStruct(0, 8, 109);
_data[26] = DrawStruct(0, 201, 109);
_data[27] = DrawStruct(0, 8, 109);
- _data[28] = DrawStruct(1, -64, 61, 14, SPRFLAG_SCENE_CLIPPED);
+ _data[28] = DrawStruct(1, -64, 61, 14);
_data[29] = DrawStruct(1, -40, 61, 14, 0);
_data[30] = DrawStruct(1, -16, 61, 14, 0);
_data[31] = DrawStruct(1, 8, 61, 14, 0);
- _data[32] = DrawStruct(1, 128, 61, 14, SPRFLAG_HORIZ_FLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[32] = DrawStruct(1, 128, 61, 14, SPRFLAG_HORIZ_FLIPPED);
_data[33] = DrawStruct(1, 104, 61, 14, SPRFLAG_HORIZ_FLIPPED);
_data[34] = DrawStruct(1, 80, 61, 14, SPRFLAG_HORIZ_FLIPPED);
_data[35] = DrawStruct(1, 56, 61, 14, SPRFLAG_HORIZ_FLIPPED);
@@ -123,10 +123,10 @@ OutdoorDrawList::OutdoorDrawList() : _sky1(_data[0]), _sky2(_data[1]),
_data[85] = DrawStruct(2, 146, 40, 0, SPRFLAG_HORIZ_FLIPPED);
_data[86] = DrawStruct(1, 32, 40, 6, 0);
_data[87] = DrawStruct(0, -7, 30, 7, 0);
- _data[88] = DrawStruct(0, -112, 30, 7, SPRFLAG_SCENE_CLIPPED);
- _data[89] = DrawStruct(0, 98, 30, 7, SPRFLAG_SCENE_CLIPPED);
- _data[90] = DrawStruct(0, -112, 30, 8, SPRFLAG_SCENE_CLIPPED);
- _data[91] = DrawStruct(0, 98, 30, 8, SPRFLAG_SCENE_CLIPPED);
+ _data[88] = DrawStruct(0, -112, 30, 7);
+ _data[89] = DrawStruct(0, 98, 30, 7);
+ _data[90] = DrawStruct(0, -112, 30, 8);
+ _data[91] = DrawStruct(0, 98, 30, 8);
_data[92] = DrawStruct(0, -38, 30, 8, 0);
_data[93] = DrawStruct(0, 25, 30, 8, 0);
_data[94] = DrawStruct(0, -7, 30, 8, 0);
@@ -141,22 +141,22 @@ OutdoorDrawList::OutdoorDrawList() : _sky1(_data[0]), _sky2(_data[1]),
_data[103] = DrawStruct(0, 8, 24);
_data[104] = DrawStruct(0, 169, 24, 0, SPRFLAG_HORIZ_FLIPPED);
_data[105] = DrawStruct(1, 32, 24);
- _data[106] = DrawStruct(0, -23, 40, 0, SPRFLAG_SCENE_CLIPPED);
- _data[107] = DrawStruct(0, 200, 40, 0, SPRFLAG_HORIZ_FLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[106] = DrawStruct(0, -23, 40, 0);
+ _data[107] = DrawStruct(0, 200, 40, 0, SPRFLAG_HORIZ_FLIPPED);
_data[108] = DrawStruct(0, 8, 47);
_data[109] = DrawStruct(0, 169, 47, 0, SPRFLAG_HORIZ_FLIPPED);
- _data[110] = DrawStruct(1, -56, -4, SCALE_ENLARGE, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
- _data[111] = DrawStruct(0, -5, 2, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
- _data[112] = DrawStruct(0, -67, 2, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[110] = DrawStruct(1, -56, -4, SCALE_ENLARGE, SPRFLAG_BOTTOM_CLIPPED);
+ _data[111] = DrawStruct(0, -5, 2, 0, SPRFLAG_BOTTOM_CLIPPED);
+ _data[112] = DrawStruct(0, -67, 2, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[113] = DrawStruct(0, 44, 73);
_data[114] = DrawStruct(0, 44, 73);
- _data[115] = DrawStruct(0, 58, 14, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[115] = DrawStruct(0, 58, 14, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[116] = DrawStruct(0, 169, 73);
_data[117] = DrawStruct(0, 169, 73);
- _data[118] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[118] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[119] = DrawStruct(0, 110, 73);
_data[120] = DrawStruct(0, 110, 73);
- _data[121] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[121] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[122] = DrawStruct(0, 110, 73);
_data[123] = DrawStruct(0, 110, 73);
_data[124] = DrawStruct(0, 72, 43);
@@ -167,6 +167,18 @@ OutdoorDrawList::OutdoorDrawList() : _sky1(_data[0]), _sky2(_data[1]),
_data[129] = DrawStruct(0, 47, 36, 0, SPRFLAG_HORIZ_FLIPPED);
_data[130] = DrawStruct(0, 118, 42);
_data[131] = DrawStruct(0, 26, 42, 0, SPRFLAG_HORIZ_FLIPPED);
+
+ for (int idx = 0; idx < 132; ++idx)
+ _data[idx]._flags |= SPRFLAG_SCENE_CLIPPED;
+}
+
+void OutdoorDrawList::draw() {
+ // Mark all items to be drawn as being clipped to the scene area
+ for (int idx = 0; idx < size(); ++idx)
+ _data[idx]._flags |= SPRFLAG_SCENE_CLIPPED;
+
+ // Draw the list
+ (*g_vm->_windows)[3].drawList(_data, size());
}
/*------------------------------------------------------------------------*/
@@ -283,16 +295,16 @@ IndoorDrawList::IndoorDrawList() :
_data[84] = DrawStruct(0, 71, 53, 12, SPRFLAG_HORIZ_FLIPPED);
_data[85] = DrawStruct(0, 80, 57, 12, 0);
_data[86] = DrawStruct(0, 64, 57, 12, SPRFLAG_HORIZ_FLIPPED);
- _data[87] = DrawStruct(7, -24, 52, 0, SPRFLAG_SCENE_CLIPPED);
+ _data[87] = DrawStruct(7, -24, 52, 0);
_data[88] = DrawStruct(7, 32, 52);
_data[89] = DrawStruct(7, 88, 52);
_data[90] = DrawStruct(0, 144, 52);
- _data[91] = DrawStruct(0, 200, 52, 0, SPRFLAG_SCENE_CLIPPED);
- _data[92] = DrawStruct(0, -79, 52, 11, SPRFLAG_SCENE_CLIPPED);
+ _data[91] = DrawStruct(0, 200, 52, 0);
+ _data[92] = DrawStruct(0, -79, 52, 11);
_data[93] = DrawStruct(0, -27, 52, 11, 0);
_data[94] = DrawStruct(0, 32, 52, 11, 0);
_data[95] = DrawStruct(0, 89, 52, 11, 0);
- _data[96] = DrawStruct(0, 145, 52, 11, SPRFLAG_SCENE_CLIPPED);
+ _data[96] = DrawStruct(0, 145, 52, 11);
_data[97] = DrawStruct(0, -8, 50, 12, 0);
_data[98] = DrawStruct(0, -65, 50, 12, 0);
_data[99] = DrawStruct(0, 49, 50, 12, 0);
@@ -315,17 +327,17 @@ IndoorDrawList::IndoorDrawList() :
_data[116] = DrawStruct(0, 63, 47, 8, SPRFLAG_HORIZ_FLIPPED);
_data[117] = DrawStruct(0, 94, 52, 8, 0);
_data[118] = DrawStruct(0, 50, 52, 8, SPRFLAG_HORIZ_FLIPPED);
- _data[119] = DrawStruct(6, -40, 40, 0, SPRFLAG_SCENE_CLIPPED);
+ _data[119] = DrawStruct(6, -40, 40, 0);
_data[120] = DrawStruct(6, 64, 40);
- _data[121] = DrawStruct(0, 168, 40, 0, SPRFLAG_SCENE_CLIPPED);
- _data[122] = DrawStruct(0, -72, 40, 6, SPRFLAG_SCENE_CLIPPED);
+ _data[121] = DrawStruct(0, 168, 40, 0);
+ _data[122] = DrawStruct(0, -72, 40, 6);
_data[123] = DrawStruct(0, 32, 40, 6, 0);
- _data[124] = DrawStruct(0, 137, 40, 6, SPRFLAG_SCENE_CLIPPED);
+ _data[124] = DrawStruct(0, 137, 40, 6);
_data[125] = DrawStruct(0, -7, 25, 7, 0);
- _data[126] = DrawStruct(0, -112, 25, 7, SPRFLAG_SCENE_CLIPPED);
- _data[127] = DrawStruct(0, 98, 25, 7, SPRFLAG_SCENE_CLIPPED);
- _data[128] = DrawStruct(0, -112, 29, 8, SPRFLAG_SCENE_CLIPPED);
- _data[129] = DrawStruct(0, 98, 29, 8, SPRFLAG_SCENE_CLIPPED);
+ _data[126] = DrawStruct(0, -112, 25, 7);
+ _data[127] = DrawStruct(0, 98, 25, 7);
+ _data[128] = DrawStruct(0, -112, 29, 8);
+ _data[129] = DrawStruct(0, 98, 29, 8);
_data[130] = DrawStruct(0, -38, 29, 8, 0);
_data[131] = DrawStruct(0, 25, 29, 8, 0);
_data[132] = DrawStruct(0, -7, 29, 8, 0);
@@ -339,23 +351,23 @@ IndoorDrawList::IndoorDrawList() :
_data[140] = DrawStruct(0, 55, 41, 4, SPRFLAG_HORIZ_FLIPPED);
_data[141] = DrawStruct(0, 106, 47, 4, 0);
_data[142] = DrawStruct(0, 38, 47, 4, SPRFLAG_HORIZ_FLIPPED);
- _data[143] = DrawStruct(0, -136, 24, 0, SPRFLAG_SCENE_CLIPPED);
+ _data[143] = DrawStruct(0, -136, 24, 0);
_data[144] = DrawStruct(0, 8, 12);
_data[145] = DrawStruct(0, 32, 24);
_data[146] = DrawStruct(0, 200, 12, 0, SPRFLAG_HORIZ_FLIPPED);
- _data[147] = DrawStruct(0, 200, 24, 0, SPRFLAG_SCENE_CLIPPED);
+ _data[147] = DrawStruct(0, 200, 24, 0);
_data[148] = DrawStruct(0, 32, 24);
- _data[149] = DrawStruct(0, -5, 2, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
- _data[150] = DrawStruct(0, -67, 10, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[149] = DrawStruct(0, -5, 2, 0, SPRFLAG_BOTTOM_CLIPPED);
+ _data[150] = DrawStruct(0, -67, 10, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[151] = DrawStruct(0, 44, 73);
_data[152] = DrawStruct(0, 44, 73);
- _data[153] = DrawStruct(0, 58, 14, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[153] = DrawStruct(0, 58, 14, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[154] = DrawStruct(0, 169, 73);
_data[155] = DrawStruct(0, 169, 73);
- _data[156] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[156] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[157] = DrawStruct(0, 110, 73);
_data[158] = DrawStruct(0, 110, 73);
- _data[159] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED | SPRFLAG_SCENE_CLIPPED);
+ _data[159] = DrawStruct(0, -5, 14, 0, SPRFLAG_BOTTOM_CLIPPED);
_data[160] = DrawStruct(0, 110, 73);
_data[161] = DrawStruct(0, 110, 73);
_data[162] = DrawStruct(0, 72, 43);
@@ -368,6 +380,15 @@ IndoorDrawList::IndoorDrawList() :
_data[169] = DrawStruct(0, 26, 42, 0, SPRFLAG_HORIZ_FLIPPED);
}
+void IndoorDrawList::draw() {
+ // Mark all items to be drawn as being clipped to the scene area
+ for (int idx = 0; idx < size(); ++idx)
+ _data[idx]._flags |= SPRFLAG_SCENE_CLIPPED;
+
+ // Draw the list
+ (*g_vm->_windows)[3].drawList(_data, size());
+}
+
/*------------------------------------------------------------------------*/
InterfaceScene::InterfaceScene(XeenEngine *vm): _vm(vm) {
@@ -380,7 +401,7 @@ InterfaceScene::InterfaceScene(XeenEngine *vm): _vm(vm) {
_flipDefaultGround = false;
_isAttacking = false;
_charsShooting = false;
- _objNumber = 0;
+ _objNumber = -1;
_combatFloatCounter = 0;
_thinWall = false;
_isAnimReset = false;
@@ -392,9 +413,8 @@ void InterfaceScene::drawScene() {
Map &map = *_vm->_map;
Scripts &scripts = *_vm->_scripts;
- MazeObject &objObject = map._mobData._objects[_objNumber];
+ MazeObject *obj = (_objNumber == -1) ? nullptr : &map._mobData._objects[_objNumber];
Direction partyDirection = _vm->_party->_mazeDirection;
- int objNum = _objNumber - 1;
// Loop to update the frame numbers for each maze object, applying the animation frame
// limits as specified by the map's _animationInfo listing
@@ -407,9 +427,9 @@ void InterfaceScene::drawScene() {
mazeObject._frame = animEntry._frame1._frames[directionIndex];
} else {
++mazeObject._frame;
- if ((int)idx == objNum && scripts._animCounter > 0 && (
- objObject._spriteId == (_vm->_files->_isDarkCc ? 15 : 16) ||
- objObject._spriteId == 58 || objObject._spriteId == 73)) {
+ if ((int)idx == _objNumber && scripts._animCounter > 0 && (
+ obj->_spriteId == (_vm->_files->_ccNum ? 15 : 16) ||
+ obj->_spriteId == 58 || obj->_spriteId == 73)) {
if (mazeObject._frame > 4 || mazeObject._spriteId == 58)
mazeObject._frame = 1;
} else if (mazeObject._frame >= animEntry._frame2._frames[directionIndex]) {
@@ -570,7 +590,7 @@ void InterfaceScene::drawIndoorsScene() {
_indoorList[idx]._frame = -1;
if (combat._monstersAttacking) {
- for (int idx = 0; idx < 96; ++idx) {
+ for (int idx = 0; idx < 8; ++idx) {
if (_indoorList[79 + idx]._sprites != nullptr) {
_indoorList[79 + idx]._frame = 0;
} else if (_indoorList[111 + idx]._sprites != nullptr) {
@@ -599,7 +619,7 @@ void InterfaceScene::drawIndoorsScene() {
_isAnimReset = false;
// Code in the original that's not being used
- //MazeObject &objObject = map._mobData._objects[_objNumber - 1];
+ //MazeObject &objObject = map._mobData._objects[_objNumber];
// Only the front rank of pow points result in a Pow splatter effect
for (int idx = 0; idx < 3; ++idx) {
@@ -2652,7 +2672,7 @@ void InterfaceScene::setIndoorsObjects() {
Common::Point mazePos = _vm->_party->_mazePosition;
Direction dir = _vm->_party->_mazeDirection;
Common::Point pt;
- _objNumber = 0;
+ _objNumber = -1;
Common::Array<MazeObject> &objects = _vm->_map->_mobData._objects;
for (uint idx = 0; idx < objects.size(); ++idx) {
@@ -2660,7 +2680,7 @@ void InterfaceScene::setIndoorsObjects() {
// Determine which half of the X/Y lists to use
int listOffset;
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
listOffset = mazeObject._spriteId == 47 ? 1 : 0;
} else {
listOffset = mazeObject._spriteId == 113 ? 1 : 0;
@@ -3361,11 +3381,12 @@ void InterfaceScene::setOutdoorsObjects() {
const Common::Point &pt = party._mazePosition;
Direction dir = party._mazeDirection;
int posIndex;
+ _objNumber = -1;
for (uint idx = 0; idx < map._mobData._objects.size(); ++idx) {
MazeObject &obj = map._mobData._objects[idx];
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
posIndex = obj._spriteId == 47 ? 1 : 0;
} else {
posIndex = obj._spriteId == 113 ? 1 : 0;
@@ -3544,7 +3565,6 @@ void InterfaceScene::setOutdoorsObjects() {
void InterfaceScene::drawIndoors() {
Map &map = *_vm->_map;
- Windows &windows = *_vm->_windows;
int surfaceId;
// Draw any surface tiles on top of the default ground
@@ -3667,8 +3687,9 @@ void InterfaceScene::drawIndoors() {
_indoorList._fwl_4F4R._frame = 9;
else if (_wo[35])
_indoorList._fwl_4F4R._frame = 0;
+ /* TODO: Duplicated switch in the original executable.. original bug meant to check some other index?
else if (_wo[79])
- _indoorList._fwl_4F4R._frame = 15;
+ _indoorList._fwl_4F4R._frame = 15;*/
else if (_wo[213])
_indoorList._fwl_4F4R._frame = 14;
else if (_wo[233])
@@ -3930,7 +3951,9 @@ void InterfaceScene::drawIndoors() {
_indoorList._fwl_4F1R._frame = 13;
}
- if (_wo[27] || _wo[22] || _wo[15] || _wo[96]) {
+ if (_wo[27] || _wo[22] || _wo[15]) {
+ } else if (_wo[96]) {
+ _indoorList._fwl_4F._frame = 7;
} else if (_wo[50]) {
_indoorList._fwl_4F._frame = 16;
} else if (_wo[156]) {
@@ -4377,7 +4400,7 @@ void InterfaceScene::drawIndoors() {
_indoorList._horizon._frame = 7;
// Finally draw the darn indoor scene
- windows[3].drawList(&_indoorList[0], _indoorList.size());
+ _indoorList.draw();
// Check for any character shooting
_isAttacking = false;
@@ -4392,7 +4415,6 @@ void InterfaceScene::drawIndoors() {
void InterfaceScene::drawOutdoors() {
Map &map = *_vm->_map;
Party &party = *_vm->_party;
- Windows &windows = *_vm->_windows;
int surfaceId;
// Draw any surface tiles on top of the default ground
@@ -4458,7 +4480,7 @@ void InterfaceScene::drawOutdoors() {
_outdoorList._groundSprite._flags = _flipWater ? SPRFLAG_HORIZ_FLIPPED : 0;
// Finally render the outdoor scene
- windows[3].drawList(&_outdoorList[0], _outdoorList.size());
+ _outdoorList.draw();
// Check for any character shooting
_isAttacking = false;
diff --git a/engines/xeen/interface_scene.h b/engines/xeen/interface_scene.h
index 0c181522bb..18f1f58a36 100644
--- a/engines/xeen/interface_scene.h
+++ b/engines/xeen/interface_scene.h
@@ -42,14 +42,28 @@ public:
DrawStruct * const _attackImgs3;
DrawStruct * const _attackImgs4;
public:
+ /**
+ * Constructor
+ */
OutdoorDrawList();
+ /**
+ * Get a draw list entry
+ */
DrawStruct &operator[](int idx) {
assert(idx < size());
return _data[idx];
}
+ /**
+ * Return the size of the list
+ */
int size() const { return 132; }
+
+ /**
+ * Draw the list to the scene
+ */
+ void draw();
};
class IndoorDrawList {
@@ -80,12 +94,23 @@ public:
public:
IndoorDrawList();
+ /**
+ * Get a draw list entry
+ */
DrawStruct &operator[](int idx) {
assert(idx < size());
return _data[idx];
}
+ /**
+ * Return the size of the list
+ */
int size() const { return 170; }
+
+ /**
+ * Draw the list to the scene
+ */
+ void draw();
};
class InterfaceScene {
diff --git a/engines/xeen/item.cpp b/engines/xeen/item.cpp
index 7a4b459d41..a364dad928 100644
--- a/engines/xeen/item.cpp
+++ b/engines/xeen/item.cpp
@@ -27,25 +27,50 @@
namespace Xeen {
+void ItemState::synchronize(Common::Serializer &s) {
+ byte b = _counter | (_cursed ? 0x40 : 0) | (_broken ? 0x80 : 0);
+ s.syncAsByte(b);
+
+ if (s.isLoading()) {
+ _counter = b & 63;
+ _cursed = (b & 0x40) != 0;
+ _broken = (b & 0x80) != 0;
+ }
+}
+
+void ItemState::operator=(byte val) {
+ _counter = val & 63;
+ _cursed = (val & 0x40) != 0;
+ _broken = (val & 0x80) != 0;
+}
+
+/*------------------------------------------------------------------------*/
+
XeenItem::XeenItem() {
clear();
}
void XeenItem::clear() {
- _material = _id = _bonusFlags = 0;
+ _material = _id = 0;
+ _state.clear();
_frame = 0;
}
void XeenItem::synchronize(Common::Serializer &s) {
s.syncAsByte(_material);
s.syncAsByte(_id);
- s.syncAsByte(_bonusFlags);
+ _state.synchronize(s);
s.syncAsByte(_frame);
}
ElementalCategory XeenItem::getElementalCategory() const {
+ assert(_material < 36);
+ return getElementalCategory(_material);
+}
+
+ElementalCategory XeenItem::getElementalCategory(int material) {
int idx;
- for (idx = 0; Res.ELEMENTAL_CATEGORIES[idx] < _material; ++idx)
+ for (idx = 0; Res.ELEMENTAL_CATEGORIES[idx] < material; ++idx)
;
return (ElementalCategory)idx;
@@ -61,21 +86,36 @@ AttributeCategory XeenItem::getAttributeCategory() const {
}
const char *XeenItem::getItemName(ItemCategory category, uint id) {
- if (id < 82)
- return Res.ITEM_NAMES[category][id];
-
- switch (category) {
- case CATEGORY_WEAPON:
- return Res.QUEST_ITEM_NAMES[id - 82];
-
- case CATEGORY_ARMOR:
- return Res.QUEST_ITEM_NAMES[id - 82 + 35];
-
- case CATEGORY_ACCESSORY:
- return Res.QUEST_ITEM_NAMES[id - 82 + 35 + 14];
-
- default:
- return Res.QUEST_ITEM_NAMES[id - 82 + 35 + 14 + 11];
+ const char **questItems = (g_vm->getGameID() == GType_Swords) ? Res.QUEST_ITEM_NAMES_SWORDS : Res.QUEST_ITEM_NAMES;
+ const uint QUEST_OFFSET = g_vm->getGameID() == GType_Swords ? 88 : 82;
+
+ if (id < QUEST_OFFSET) {
+ switch (category) {
+ case CATEGORY_WEAPON:
+ assert(id < 41);
+ return Res.WEAPON_NAMES[id];
+ case CATEGORY_ARMOR:
+ assert(id < 14);
+ return Res.ARMOR_NAMES[id];
+ case CATEGORY_ACCESSORY:
+ assert(id < 11);
+ return Res.ACCESSORY_NAMES[id];
+ default:
+ assert(id < 22);
+ return Res.MISC_NAMES[id];
+ }
+ } else {
+ switch (category) {
+ case CATEGORY_WEAPON:
+ return questItems[id - QUEST_OFFSET];
+ case CATEGORY_ARMOR:
+ return questItems[id - QUEST_OFFSET + 35];
+ case CATEGORY_ACCESSORY:
+ return questItems[id - QUEST_OFFSET + 35 + 14];
+ default:
+ assert(g_vm->getGameID() != GType_Swords);
+ return questItems[id - QUEST_OFFSET + 35 + 14 + 11];
+ }
}
}
@@ -93,6 +133,14 @@ void InventoryItems::clear() {
operator[](idx).clear();
}
+InventoryItems &InventoryItems::operator=(const InventoryItems &src) {
+ Common::Array<XeenItem>::clear();
+ assert(src.size() == INV_ITEMS_TOTAL);
+ for (uint idx = 0; idx < INV_ITEMS_TOTAL; ++idx)
+ push_back(src[idx]);
+ return *this;
+}
+
bool InventoryItems::passRestrictions(int itemId, bool suppressError) const {
CharacterClass charClass = _character->_class;
@@ -156,7 +204,7 @@ bool InventoryItems::discardItem(int itemIndex) {
XeenItem &item = operator[](itemIndex);
XeenEngine *vm = Party::_vm;
- if (item._bonusFlags & ITEMFLAG_CURSED) {
+ if (item._state._cursed) {
ErrorScroll::show(vm, Res.CANNOT_DISCARD_CURSED_ITEM);
} else {
Common::String itemDesc = getFullDescription(itemIndex, 4);
@@ -175,7 +223,7 @@ bool InventoryItems::discardItem(int itemIndex) {
void InventoryItems::sort() {
for (uint idx = 0; idx < size(); ++idx) {
- if (operator[](idx)._id == 0) {
+ if (operator[](idx).empty()) {
// Found empty slot
operator[](idx).clear();
@@ -196,7 +244,7 @@ void InventoryItems::removeItem(int itemIndex) {
XeenItem &item = operator[](itemIndex);
XeenEngine *vm = Party::_vm;
- if (item._bonusFlags & ITEMFLAG_CURSED)
+ if (item._state._cursed)
ErrorScroll::show(vm, Res.CANNOT_REMOVE_CURSED_ITEM);
else
item._frame = 0;
@@ -215,7 +263,7 @@ void InventoryItems::equipError(int itemIndex1, ItemCategory category1, int item
Common::String itemName2 = _character->_items[category2].getName(itemIndex2);
MessageDialog::show(vm, Common::String::format(Res.REMOVE_X_TO_EQUIP_Y,
- itemName1.c_str(), itemName2.c_str()));
+ itemName2.c_str(), itemName1.c_str()));
} else {
MessageDialog::show(vm, Common::String::format(Res.EQUIPPED_ALL_YOU_CAN,
(itemIndex1 == -1) ? Res.RING : Res.MEDAL));
@@ -230,7 +278,14 @@ void InventoryItems::enchantItem(int itemIndex, int amount) {
bool InventoryItems::isFull() const {
assert(size() == INV_ITEMS_TOTAL);
- return operator[](size() - 1)._id != 0;
+ return !operator[](size() - 1).empty();
+}
+
+void InventoryItems::capitalizeItem(Common::String &name) {
+ if (name[3] == '\f')
+ name.setChar(toupper(name[6]), 6);
+ else
+ name.setChar(toupper(name[3]), 3);
}
/*------------------------------------------------------------------------*/
@@ -289,16 +344,17 @@ Common::String WeaponItems::getFullDescription(int itemIndex, int displayNum) {
XeenItem &i = operator[](itemIndex);
Resources &res = *getVm()->_resources;
- return Common::String::format("\f%02u%s%s%s\f%02u%s%s%s", displayNum,
- !i._bonusFlags ? res._maeNames[i._material].c_str() : "",
- (i._bonusFlags & ITEMFLAG_BROKEN) ? Res.ITEM_BROKEN : "",
- (i._bonusFlags & ITEMFLAG_CURSED) ? Res.ITEM_CURSED : "",
+ Common::String desc = Common::String::format("\f%02u%s%s%s\f%02u%s%s%s", displayNum,
+ i._state._cursed || i._state._broken ? "" : res._maeNames[i._material].c_str(),
+ i._state._broken ? Res.ITEM_BROKEN : "",
+ i._state._cursed ? Res.ITEM_CURSED : "",
displayNum,
Res.WEAPON_NAMES[i._id],
- !i._bonusFlags ? "" : Res.BONUS_NAMES[i._bonusFlags & ITEMFLAG_BONUS_MASK],
- (i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED)) ||
- !i._bonusFlags ? "\b " : ""
+ !i._state._counter ? "" : Res.BONUS_NAMES[i._state._counter],
+ (i._state._cursed || i._state._broken) || !i._id ? "\b " : ""
);
+ capitalizeItem(desc);
+ return desc;
}
void WeaponItems::enchantItem(int itemIndex, int amount) {
@@ -306,12 +362,12 @@ void WeaponItems::enchantItem(int itemIndex, int amount) {
XeenItem &item = operator[](itemIndex);
Character tempCharacter;
- if (item._material == 0 && item._bonusFlags == 0 && item._id != 34) {
+ if (item._material == 0 && item._state.empty() && item._id < XEEN_SLAYER_SWORD) {
tempCharacter.makeItem(amount, 0, 1);
XeenItem &tempItem = tempCharacter._weapons[0];
item._material = tempItem._material;
- item._bonusFlags = tempItem._bonusFlags;
+ item._state = tempItem._state;
sound.playFX(19);
} else {
InventoryItems::enchantItem(itemIndex, amount);
@@ -350,10 +406,9 @@ Common::String WeaponItems::getAttributes(XeenItem &item, const Common::String &
}
// Handle weapon effective against
- int effective = item._bonusFlags & ITEMFLAG_BONUS_MASK;
+ Effectiveness effective = (Effectiveness)item._state._counter;
if (effective) {
- specialPower = Common::String::format(Res.EFFECTIVE_AGAINST,
- Res.EFFECTIVENESS_NAMES[effective]);
+ specialPower = Common::String::format(Res.EFFECTIVE_AGAINST, Res.EFFECTIVENESS_NAMES[effective]);
}
return Common::String::format(Res.ITEM_DETAILS, classes.c_str(),
@@ -362,6 +417,17 @@ Common::String WeaponItems::getAttributes(XeenItem &item, const Common::String &
);
}
+bool WeaponItems::hasElderWeapon() const {
+ if (g_vm->getGameID() == GType_Swords) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ if ((*this)[idx]._id >= 34)
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*------------------------------------------------------------------------*/
void ArmorItems::equipItem(int itemIndex) {
@@ -371,7 +437,7 @@ void ArmorItems::equipItem(int itemIndex) {
if (passRestrictions(item._id)) {
for (uint idx = 0; idx < size(); ++idx) {
XeenItem &i = operator[](idx);
- if (i._frame == 9) {
+ if (i._frame == 3) {
equipError(itemIndex, CATEGORY_ARMOR, idx, CATEGORY_ARMOR);
return;
}
@@ -446,15 +512,16 @@ Common::String ArmorItems::getFullDescription(int itemIndex, int displayNum) {
XeenItem &i = operator[](itemIndex);
Resources &res = *getVm()->_resources;
- return Common::String::format("\f%02u%s%s%s\f%02u%s%s", displayNum,
- !i._bonusFlags ? "" : res._maeNames[i._material].c_str(),
- (i._bonusFlags & ITEMFLAG_BROKEN) ? Res.ITEM_BROKEN : "",
- (i._bonusFlags & ITEMFLAG_CURSED) ? Res.ITEM_CURSED : "",
+ Common::String desc = Common::String::format("\f%02u%s%s%s\f%02u%s%s", displayNum,
+ i._state._cursed || i._state._broken ? "" : res._maeNames[i._material].c_str(),
+ i._state._broken ? Res.ITEM_BROKEN : "",
+ i._state._cursed ? Res.ITEM_CURSED : "",
displayNum,
Res.ARMOR_NAMES[i._id],
- (i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED)) ||
- !i._bonusFlags ? "\b " : ""
+ (i._state._cursed || i._state._broken) || !i._id ? "\b " : ""
);
+ capitalizeItem(desc);
+ return desc;
}
void ArmorItems::enchantItem(int itemIndex, int amount) {
@@ -462,12 +529,12 @@ void ArmorItems::enchantItem(int itemIndex, int amount) {
XeenItem &item = operator[](itemIndex);
Character tempCharacter;
- if (item._material == 0 && item._bonusFlags == 0) {
+ if (item._material == 0 && item._state.empty()) {
tempCharacter.makeItem(amount, 0, 2);
XeenItem &tempItem = tempCharacter._armor[0];
item._material = tempItem._material;
- item._bonusFlags = tempItem._bonusFlags;
+ item._state = tempItem._state;
sound.playFX(19);
} else {
InventoryItems::enchantItem(itemIndex, amount);
@@ -529,6 +596,8 @@ void AccessoryItems::equipItem(int itemIndex) {
return;
}
}
+
+ item._frame = 12;
} else if (item._id <= 7) {
int count = 0;
for (uint idx = 0; idx < size(); ++idx) {
@@ -558,15 +627,16 @@ Common::String AccessoryItems::getFullDescription(int itemIndex, int displayNum)
XeenItem &i = operator[](itemIndex);
Resources &res = *getVm()->_resources;
- return Common::String::format("\f%02u%s%s%s\f%02u%s%s", displayNum,
- !i._bonusFlags ? "" : res._maeNames[i._material].c_str(),
- (i._bonusFlags & ITEMFLAG_BROKEN) ? Res.ITEM_BROKEN : "",
- (i._bonusFlags & ITEMFLAG_CURSED) ? Res.ITEM_CURSED : "",
+ Common::String desc = Common::String::format("\f%02u%s%s%s\f%02u%s%s", displayNum,
+ i._state._cursed || i._state._broken ? "" : res._maeNames[i._material].c_str(),
+ i._state._broken ? Res.ITEM_BROKEN : "",
+ i._state._cursed ? Res.ITEM_CURSED : "",
displayNum,
- Res.ARMOR_NAMES[i._id],
- (i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED)) ||
- !i._bonusFlags ? "\b " : ""
+ Res.ACCESSORY_NAMES[i._id],
+ (i._state._cursed || i._state._broken) || !i._id ? "\b " : ""
);
+ capitalizeItem(desc);
+ return desc;
}
/*
@@ -602,17 +672,18 @@ Common::String AccessoryItems::getAttributes(XeenItem &item, const Common::Strin
Common::String MiscItems::getFullDescription(int itemIndex, int displayNum) {
XeenItem &i = operator[](itemIndex);
- Resources &res = *getVm()->_resources;
- return Common::String::format("\f%02u%s%s%s\f%02u%s%s", displayNum,
- !i._bonusFlags ? "" : res._maeNames[i._material].c_str(),
- (i._bonusFlags & ITEMFLAG_BROKEN) ? Res.ITEM_BROKEN : "",
- (i._bonusFlags & ITEMFLAG_CURSED) ? Res.ITEM_CURSED : "",
+ Common::String desc = Common::String::format("\f%02u%s%s\f%02u%s%s%s%s", displayNum,
+ i._state._broken ? Res.ITEM_BROKEN : "",
+ i._state._cursed ? Res.ITEM_CURSED : "",
displayNum,
- Res.ARMOR_NAMES[i._id],
- (i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED)) ||
- !i._id ? "\b " : ""
+ Res.MISC_NAMES[i._material],
+ (i._state._cursed || i._state._broken) || !i._id ? "" : Res.ITEM_OF,
+ (i._state._cursed || i._state._broken) ? "" : Res.SPECIAL_NAMES[i._id],
+ (i._state._cursed || i._state._broken) || !i._id ? "\b " : ""
);
+ capitalizeItem(desc);
+ return desc;
}
Common::String MiscItems::getAttributes(XeenItem &item, const Common::String &classes) {
@@ -629,31 +700,65 @@ Common::String MiscItems::getAttributes(XeenItem &item, const Common::String &cl
}
/*------------------------------------------------------------------------*/
-InventoryItemsGroup::InventoryItemsGroup(InventoryItems &weapons, InventoryItems &armor,
- InventoryItems &accessories, InventoryItems &misc) {
- _itemSets[0] = &weapons;
- _itemSets[1] = &armor;
- _itemSets[2] = &accessories;
- _itemSets[3] = &misc;
+InventoryItems &InventoryItemsGroup::operator[](ItemCategory category) {
+ switch (category) {
+ case CATEGORY_WEAPON:
+ return _owner->_weapons;
+ case CATEGORY_ARMOR:
+ return _owner->_armor;
+ case CATEGORY_ACCESSORY:
+ return _owner->_accessories;
+ default:
+ return _owner->_misc;
+ }
}
-InventoryItems &InventoryItemsGroup::operator[](ItemCategory category) {
- return *_itemSets[category];
+const InventoryItems &InventoryItemsGroup::operator[](ItemCategory category) const {
+ switch (category) {
+ case CATEGORY_WEAPON:
+ return _owner->_weapons;
+ case CATEGORY_ARMOR:
+ return _owner->_armor;
+ case CATEGORY_ACCESSORY:
+ return _owner->_accessories;
+ default:
+ return _owner->_misc;
+ }
}
void InventoryItemsGroup::breakAllItems() {
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
- if ((*_itemSets[0])[idx]._id != 34) {
- (*_itemSets[0])[idx]._bonusFlags |= ITEMFLAG_BROKEN;
- (*_itemSets[0])[idx]._frame = 0;
+ if (_owner->_weapons[idx]._id < XEEN_SLAYER_SWORD) {
+ _owner->_weapons[idx]._state._broken = true;
+ _owner->_weapons[idx]._frame = 0;
}
- (*_itemSets[1])[idx]._bonusFlags |= ITEMFLAG_BROKEN;
- (*_itemSets[2])[idx]._bonusFlags |= ITEMFLAG_BROKEN;
- (*_itemSets[3])[idx]._bonusFlags |= ITEMFLAG_BROKEN;
- (*_itemSets[1])[idx]._frame = 0;
- (*_itemSets[2])[idx]._frame = 0;
+ _owner->_armor[idx]._state._broken = true;
+ _owner->_accessories[idx]._state._broken = true;
+ _owner->_misc[idx]._state._broken = true;
+ _owner->_armor[idx]._frame = 0;
+ _owner->_accessories[idx]._frame = 0;
+ }
+}
+
+void InventoryItemsGroup::curseUncurse(bool curse) {
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ _owner->_weapons[idx]._state._cursed = curse && _owner->_weapons[idx]._id < XEEN_SLAYER_SWORD;
+ _owner->_armor[idx]._state._cursed = curse;
+ _owner->_accessories[idx]._state._cursed = curse;
+ _owner->_misc[idx]._state._cursed = curse;
}
}
+bool InventoryItemsGroup::hasCursedItems() const {
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ for (ItemCategory cat = CATEGORY_WEAPON; cat <= CATEGORY_MISC; cat = (ItemCategory)((int)cat + 1)) {
+ if ((*this)[cat][idx]._state._cursed)
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/item.h b/engines/xeen/item.h
index 871bd1c919..df13456cd7 100644
--- a/engines/xeen/item.h
+++ b/engines/xeen/item.h
@@ -52,11 +52,54 @@ enum ElementalCategory {
ELEM_ENERGY = 4, ELEM_MAGIC = 5
};
+enum WeaponId {
+ XEEN_SLAYER_SWORD = 34
+};
+
+enum Effectiveness {
+ EFFECTIVE_NONE = 0, EFFECTIVE_DRAGON = 1, EFFECTIVE_UNDEAD = 2, EFFECTIVE_GOLEM = 3,
+ EFFECTIVE_INSECT = 4, EFFEctIVE_MONSTERS = 5, EFFECTIVE_ANIMAL = 6
+};
+
+struct ItemState {
+ byte _counter : 6; // Stores charges for Misc items, and the effective against for weapons
+ bool _cursed : 1;
+ bool _broken : 1;
+
+ /**
+ * Constructor
+ */
+ ItemState() : _counter(0), _cursed(false), _broken(false) {}
+
+ /**
+ * Clear the state
+ */
+ void clear() {
+ _counter = 0;
+ _cursed = _broken = false;
+ }
+
+ /**
+ * Returns true if the state is empty
+ */
+ bool empty() const { return !_counter && !_cursed && !_broken; }
+
+ /**
+ * Synchronizes the item's state
+ */
+ void synchronize(Common::Serializer &s);
+
+ /**
+ * Set the entire state value
+ */
+ void operator=(byte val);
+};
+
class XeenItem {
public:
int _material;
uint _id;
- int _bonusFlags;
+ ItemState _state;
int _frame;
public:
/**
@@ -64,6 +107,9 @@ public:
*/
static const char *getItemName(ItemCategory category, uint id);
public:
+ /**
+ * Constructor
+ */
XeenItem();
/**
@@ -77,6 +123,16 @@ public:
bool empty() const { return _id == 0; }
/**
+ * Returns true if the item is cursed or broken
+ */
+ bool isBad() const { return _state._cursed || _state._broken; }
+
+ /**
+ * Returns true for weapons if it's equipped
+ */
+ bool isEquipped() const { return _frame != 0; }
+
+ /**
* Synchronizes the data for the item
*/
void synchronize(Common::Serializer &s);
@@ -87,6 +143,11 @@ public:
ElementalCategory getElementalCategory() const;
/**
+ * Gets the elemental category for a given material
+ */
+ static ElementalCategory getElementalCategory(int material);
+
+ /**
* Gets the attribute category for the item
*/
AttributeCategory getAttributeCategory() const;
@@ -106,6 +167,11 @@ protected:
* Returns a text string listing all the stats/attributes of a given item
*/
virtual Common::String getAttributes(XeenItem &item, const Common::String &classes) = 0;
+
+ /**
+ * Capitalizes a passed description string that includes embedded formatting for the Items dialog
+ */
+ void capitalizeItem(Common::String &name);
public:
InventoryItems(Character *character, ItemCategory category);
virtual ~InventoryItems() {}
@@ -116,6 +182,11 @@ public:
void clear();
/**
+ * Handles copying items from one character to another
+ */
+ InventoryItems &operator=(const InventoryItems &src);
+
+ /**
* Return whether a given item passes class-based usage restrictions
* @param itemId Item Index
* @param suppressError If true, no dialog is shown if the item doesn't pass restrictions
@@ -190,6 +261,11 @@ public:
* Enchants a weapon
*/
virtual void enchantItem(int itemIndex, int amount);
+
+ /**
+ * Returns true if the character has an Elder weapon in Swords of Xeen
+ */
+ bool hasElderWeapon() const;
};
class ArmorItems : public InventoryItems {
@@ -259,10 +335,9 @@ public:
class InventoryItemsGroup {
private:
- InventoryItems *_itemSets[4];
+ Character *_owner;
public:
- InventoryItemsGroup(InventoryItems &weapons, InventoryItems &armor,
- InventoryItems &accessories, InventoryItems &misc);
+ InventoryItemsGroup(Character *owner) : _owner(owner) {}
/**
* Returns the inventory items for a given category
@@ -270,9 +345,24 @@ public:
InventoryItems &operator[](ItemCategory category);
/**
+ * Returns the inventory items for a given category
+ */
+ const InventoryItems &operator[](ItemCategory category) const;
+
+ /**
* Breaks all the items in a given character's inventory
*/
void breakAllItems();
+
+ /**
+ * Curses or curses all the items
+ */
+ void curseUncurse(bool curse);
+
+ /**
+ * Returns true if the character has any cursed items
+ */
+ bool hasCursedItems() const;
};
} // End of namespace Xeen
diff --git a/engines/xeen/locations.cpp b/engines/xeen/locations.cpp
index 2690bf1ebc..7cbfc2bab3 100644
--- a/engines/xeen/locations.cpp
+++ b/engines/xeen/locations.cpp
@@ -35,12 +35,12 @@ namespace Xeen {
namespace Locations {
BaseLocation::BaseLocation(LocationAction action) : ButtonContainer(g_vm),
- _locationActionId(action), _isDarkCc(g_vm->_files->_isDarkCc),
+ _locationActionId(action), _ccNum(g_vm->_files->_ccNum),
_vocName("hello1.voc"), _exitToUi(false) {
- _townMaxId = (action >= SPHINX) ? 0 : Res.TOWN_MAXES[_isDarkCc][action];
+ _townMaxId = (action >= SPHINX) ? 0 : Res.TOWN_MAXES[_ccNum][action];
if (action < NO_ACTION) {
- _songName = Res.TOWN_ACTION_MUSIC[_isDarkCc][action];
- _townSprites.resize(Res.TOWN_ACTION_FILES[_isDarkCc][action]);
+ _songName = Res.TOWN_ACTION_MUSIC[_ccNum][action];
+ _townSprites.resize(Res.TOWN_ACTION_FILES[_ccNum][action]);
}
_animFrame = 0;
@@ -149,7 +149,7 @@ void BaseLocation::drawAnim(bool flag) {
// TODO: Figure out a clean way to split method into individual location classes
if (_locationActionId == BLACKSMITH) {
if (sound.isSoundPlaying()) {
- if (_isDarkCc) {
+ if (_ccNum) {
_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _animPos);
_townSprites[2].draw(0, _vm->getRandomNumber(11) == 1 ? 9 : 10,
Common::Point(34, 33));
@@ -158,20 +158,20 @@ void BaseLocation::drawAnim(bool flag) {
}
} else {
_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _animPos);
- if (_isDarkCc) {
+ if (_ccNum) {
_townSprites[2].draw(0, _vm->getRandomNumber(11) == 1 ? 9 : 10,
Common::Point(34, 33));
}
}
- } else if (!_isDarkCc || _locationActionId != TRAINING) {
+ } else if (!_ccNum || _locationActionId != TRAINING) {
if (!_townSprites[_drawFrameIndex / 8].empty())
_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _animPos);
}
switch (_locationActionId) {
case BANK:
- if (sound.isSoundPlaying() || (_isDarkCc && _animFrame)) {
- if (_isDarkCc) {
+ if (sound.isSoundPlaying() || (_ccNum && _animFrame)) {
+ if (_ccNum) {
if (sound.isSoundPlaying() || _animFrame == 1) {
_townSprites[4].draw(0, _vm->getRandomNumber(13, 18),
Common::Point(8, 30));
@@ -189,7 +189,7 @@ void BaseLocation::drawAnim(bool flag) {
case GUILD:
if (!sound.isSoundPlaying()) {
- if (_isDarkCc) {
+ if (_ccNum) {
if (_animFrame) {
_animFrame ^= 1;
_townSprites[6].draw(0, _animFrame, Common::Point(8, 106));
@@ -201,7 +201,7 @@ void BaseLocation::drawAnim(bool flag) {
break;
case TAVERN:
- if (sound.isSoundPlaying() && _isDarkCc) {
+ if (sound.isSoundPlaying() && _ccNum) {
_townSprites[4].draw(0, _vm->getRandomNumber(7), Common::Point(153, 49));
}
break;
@@ -215,11 +215,11 @@ void BaseLocation::drawAnim(bool flag) {
case TRAINING:
if (sound.isSoundPlaying()) {
- if (_isDarkCc) {
+ if (_ccNum) {
_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _animPos);
}
} else {
- if (_isDarkCc) {
+ if (_ccNum) {
_townSprites[0].draw(0, ++_animFrame % 8, Common::Point(8, 8));
_townSprites[5].draw(0, _vm->getRandomNumber(5), Common::Point(61, 74));
} else {
@@ -257,7 +257,7 @@ void BaseLocation::drawAnim(bool flag) {
_drawFrameIndex = (_drawFrameIndex + 1) % _townMaxId;
}
- if (_isDarkCc) {
+ if (_ccNum) {
if (_locationActionId == BLACKSMITH && (_drawFrameIndex == 4 || _drawFrameIndex == 13))
sound.playFX(45);
@@ -307,7 +307,7 @@ BankLocation::BankLocation() : BaseLocation(BANK) {
addButton(Common::Rect(288, 108, 312, 128), Common::KEYCODE_ESCAPE, &_icons1);
_animFrame = 1;
- _vocName = _isDarkCc ? "bank1.voc" : "banker.voc";
+ _vocName = _ccNum ? "bank1.voc" : "banker.voc";
}
Common::String BankLocation::createLocationText(Character &ch) {
@@ -320,7 +320,7 @@ Common::String BankLocation::createLocationText(Character &ch) {
}
void BankLocation::drawBackground() {
- if (_isDarkCc) {
+ if (_ccNum) {
_townSprites[4].draw(0, _vm->getRandomNumber(13, 18),
Common::Point(8, 30));
}
@@ -342,6 +342,7 @@ void BankLocation::depositWithdrawl(PartyBank whereId) {
Party &party = *g_vm->_party;
Sound &sound = *g_vm->_sound;
Windows &windows = *g_vm->_windows;
+ Window &w = windows[35];
int gold, gems;
if (whereId == WHERE_BANK) {
@@ -363,26 +364,24 @@ void BankLocation::depositWithdrawl(PartyBank whereId) {
XeenEngine::printMil(gold).c_str(),
XeenEngine::printMil(gems).c_str());
- windows[35].open();
- windows[35].writeString(msg);
- drawButtons(&windows[35]);
- windows[35].update();
+ w.open();
+ w.writeString(msg);
+ drawButtons(&w);
+ w.update();
sound.stopSound();
File voc("coina.voc");
ConsumableType consType = CONS_GOLD;
do {
- switch (wait()) {
- case Common::KEYCODE_o:
+ wait();
+ if (_buttonValue == Common::KEYCODE_o) {
consType = CONS_GOLD;
- break;
- case Common::KEYCODE_e:
+ } else if (_buttonValue == Common::KEYCODE_e) {
consType = CONS_GEMS;
+ } else if (_buttonValue == Common::KEYCODE_ESCAPE) {
break;
- case Common::KEYCODE_ESCAPE:
- break;
- default:
+ } else {
continue;
}
@@ -392,7 +391,7 @@ void BankLocation::depositWithdrawl(PartyBank whereId) {
(whereId == WHERE_PARTY && !party._gold && consType == CONS_GOLD)) {
party.notEnough(consType, whereId, WHERE_BANK, WT_LOC_WAIT);
} else {
- windows[35].writeString(Res.AMOUNT);
+ w.writeString(Res.AMOUNT);
int amount = NumericInput::show(_vm, 35, 10, 77);
if (amount) {
@@ -426,16 +425,19 @@ void BankLocation::depositWithdrawl(PartyBank whereId) {
sound.playSound(voc);
msg = Common::String::format(Res.GOLD_GEMS_2, Res.DEPOSIT_WITHDRAWL[whereId],
XeenEngine::printMil(gold).c_str(), XeenEngine::printMil(gems).c_str());
- windows[35].writeString(msg);
- windows[35].update();
+ w.writeString(msg);
+ w.update();
}
- } while (!g_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
+ } while (!g_vm->shouldExit());
for (uint idx = 0; idx < _buttons.size(); ++idx)
_buttons[idx]._sprites = &_icons1;
_buttons[0]._value = Common::KEYCODE_d;
_buttons[1]._value = Common::KEYCODE_w;
_buttons[2]._value = Common::KEYCODE_ESCAPE;
+
+ w.close();
+ clearEvents();
}
/*------------------------------------------------------------------------*/
@@ -448,7 +450,7 @@ BlacksmithLocation::BlacksmithLocation() : BaseLocation(BLACKSMITH) {
addButton(Common::Rect(234, 74, 308, 82), 0);
addButton(Common::Rect(234, 84, 308, 92), 0);
- _vocName = _isDarkCc ? "see2.voc" : "whaddayo.voc";
+ _vocName = _ccNum ? "see2.voc" : "whaddayo.voc";
}
Common::String BlacksmithLocation::createLocationText(Character &ch) {
@@ -469,7 +471,7 @@ Character *BlacksmithLocation::doOptions(Character *c) {
intf.highlightChar(_buttonValue);
}
} else if (_buttonValue == Common::KEYCODE_b) {
- c = ItemsDialog::show(_vm, c, ITEMMODE_BLACKSMITH);
+ c = ItemsDialog::show(_vm, c, ITEMMODE_BUY);
_buttonValue = 0;
}
@@ -479,7 +481,7 @@ Character *BlacksmithLocation::doOptions(Character *c) {
void BlacksmithLocation::farewell() {
Sound &sound = *g_vm->_sound;
- if (_isDarkCc) {
+ if (_ccNum) {
sound.stopSound();
sound.playVoice("come1.voc", 1);
}
@@ -495,9 +497,9 @@ GuildLocation::GuildLocation() : BaseLocation(GUILD) {
addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_b);
addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_s);
addButton(Common::Rect(234, 84, 308, 92), 0);
- g_vm->_mode = MODE_17;
+ g_vm->_mode = MODE_INTERACTIVE7;
- _vocName = _isDarkCc ? "parrot1.voc" : "guild10.voc";
+ _vocName = _ccNum ? "parrot1.voc" : "guild10.voc";
}
Common::String GuildLocation::createLocationText(Character &ch) {
@@ -524,17 +526,17 @@ Character *GuildLocation::doOptions(Character *c) {
if (!c->guildMember()) {
sound.stopSound();
_animFrame = 5;
- sound.playSound(_isDarkCc ? "skull1.voc" : "guild11.voc", 1);
+ sound.playSound(_ccNum ? "skull1.voc" : "guild11.voc", 1);
}
}
} else if (_buttonValue == Common::KEYCODE_s) {
if (c->guildMember())
- c = SpellsDialog::show(_vm, nullptr, c, 0x80);
+ c = SpellsDialog::show(_vm, this, c, SPELLS_DIALOG_INFO);
_buttonValue = 0;
- } else if (_buttonValue == Common::KEYCODE_c) {
+ } else if (_buttonValue == Common::KEYCODE_b) {
if (!c->noActions()) {
if (c->guildMember())
- c = SpellsDialog::show(_vm, nullptr, c, 0);
+ c = SpellsDialog::show(_vm, this, c, SPELLS_DIALOG_BUY);
_buttonValue = 0;
}
}
@@ -558,9 +560,9 @@ TavernLocation::TavernLocation() : BaseLocation(TAVERN) {
addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_f);
addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_t);
addButton(Common::Rect(234, 84, 308, 92), Common::KEYCODE_r);
- g_vm->_mode = MODE_17;
+ g_vm->_mode = MODE_INTERACTIVE7;
- _vocName = _isDarkCc ? "hello1.voc" : "hello.voc";
+ _vocName = _ccNum ? "hello1.voc" : "hello.voc";
}
Common::String TavernLocation::createLocationText(Character &ch) {
@@ -570,6 +572,7 @@ Common::String TavernLocation::createLocationText(Character &ch) {
}
Character *TavernLocation::doOptions(Character *c) {
+ EventsManager &events = *g_vm->_events;
Interface &intf = *g_vm->_interface;
Map &map = *g_vm->_map;
Party &party = *g_vm->_party;
@@ -620,19 +623,19 @@ Character *TavernLocation::doOptions(Character *c) {
case Common::KEYCODE_f: {
// Food
- if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+ if (party._mazeId == (_ccNum ? 29 : 28)) {
_v22 = party._activeParty.size() * 15;
_v23 = 10;
idx = 0;
- } else if (_isDarkCc && party._mazeId == 31) {
+ } else if (_ccNum && party._mazeId == 31) {
_v22 = party._activeParty.size() * 60;
_v23 = 100;
idx = 1;
- } else if (!_isDarkCc && party._mazeId == 30) {
+ } else if (!_ccNum && party._mazeId == 30) {
_v22 = party._activeParty.size() * 50;
_v23 = 50;
idx = 1;
- } else if (_isDarkCc) {
+ } else if (_ccNum) {
_v22 = party._activeParty.size() * 120;
_v23 = 250;
idx = 2;
@@ -646,7 +649,7 @@ Character *TavernLocation::doOptions(Character *c) {
idx = 0;
}
- Common::String msg = _textStrings[(_isDarkCc ? 60 : 75) + idx];
+ Common::String msg = _textStrings[(_ccNum ? 60 : 75) + idx];
windows[10].close();
windows[12].open();
windows[12].writeString(msg);
@@ -658,7 +661,7 @@ Character *TavernLocation::doOptions(Character *c) {
} else if (party.subtract(CONS_GOLD, _v23, WHERE_PARTY, WT_LOC_WAIT)) {
party._food = _v22;
sound.stopSound();
- sound.playSound(_isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
+ sound.playSound(_ccNum ? "thanks2.voc" : "thankyou.voc", 1);
}
}
@@ -670,11 +673,11 @@ Character *TavernLocation::doOptions(Character *c) {
case Common::KEYCODE_r: {
// Rumors
- if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+ if (party._mazeId == (_ccNum ? 29 : 28)) {
idx = 0;
- } else if (party._mazeId == (_isDarkCc ? 31 : 30)) {
+ } else if (party._mazeId == (_ccNum ? 31 : 30)) {
idx = 10;
- } else if (_isDarkCc || party._mazeId == 49) {
+ } else if (_ccNum || party._mazeId == 49) {
idx = 20;
}
@@ -693,12 +696,12 @@ Character *TavernLocation::doOptions(Character *c) {
case Common::KEYCODE_s: {
// Sign In
// Set location and position for afterwards
- idx = _isDarkCc ? (party._mazeId - 29) >> 1 : party._mazeId - 28;
+ idx = _ccNum ? (party._mazeId - 29) >> 1 : party._mazeId - 28;
assert(idx >= 0);
- party._mazePosition.x = Res.TAVERN_EXIT_LIST[_isDarkCc ? 1 : 0][_locationActionId][idx][0];
- party._mazePosition.y = Res.TAVERN_EXIT_LIST[_isDarkCc ? 1 : 0][_locationActionId][idx][1];
+ party._mazePosition.x = Res.TAVERN_EXIT_LIST[_ccNum][_locationActionId][idx][0];
+ party._mazePosition.y = Res.TAVERN_EXIT_LIST[_ccNum][_locationActionId][idx][1];
- if (!_isDarkCc || party._mazeId == 29)
+ if (!_ccNum || party._mazeId == 29)
party._mazeDirection = DIR_WEST;
else if (party._mazeId == 31)
party._mazeDirection = DIR_EAST;
@@ -708,13 +711,22 @@ Character *TavernLocation::doOptions(Character *c) {
party._priorMazeId = party._mazeId;
for (idx = 0; idx < (int)party._activeParty.size(); ++idx) {
party._activeParty[idx]._savedMazeId = party._mazeId;
- party._activeParty[idx]._xeenSide = map._loadDarkSide;
+ party._activeParty[idx]._xeenSide = map._loadCcNum;
}
- g_vm->_mode = MODE_17;
+ g_vm->_mode = MODE_INTERACTIVE7;
party.addTime(1440);
party._mazeId = 0;
+ // Say farewell
+ farewell();
+ while (sound.isSoundPlaying())
+ events.wait(1);
+
+ // Animate closing a scroll
+ doScroll(true, false);
+ sound.stopAllAudio();
+
// Show the party dialog
PartyDialog::show(g_vm);
@@ -744,23 +756,23 @@ Character *TavernLocation::doOptions(Character *c) {
wait();
} else if (party.subtract(CONS_GOLD, 1, WHERE_PARTY, WT_LOC_WAIT)) {
sound.stopSound();
- sound.playSound(_isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
+ sound.playSound(_ccNum ? "thanks2.voc" : "thankyou.voc", 1);
- if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+ if (party._mazeId == (_ccNum ? 29 : 28)) {
_v24 = 30;
- } else if (_isDarkCc && party._mazeId == 31) {
+ } else if (_ccNum && party._mazeId == 31) {
_v24 = 40;
- } else if (!_isDarkCc && party._mazeId == 45) {
+ } else if (!_ccNum && party._mazeId == 45) {
_v24 = 45;
- } else if (!_isDarkCc && party._mazeId == 49) {
+ } else if (!_ccNum && party._mazeId == 49) {
_v24 = 60;
- } else if (_isDarkCc) {
+ } else if (_ccNum) {
_v24 = 50;
}
Common::String msg = _textStrings[map.mazeData()._tavernTips + _v24];
map.mazeData()._tavernTips = (map.mazeData()._tavernTips + 1) /
- (_isDarkCc ? 10 : 15);
+ (_ccNum ? 10 : 15);
Window &w = windows[12];
w.open();
@@ -786,7 +798,7 @@ void TavernLocation::farewell() {
Sound &sound = *g_vm->_sound;
sound.stopSound();
- sound.playVoice(_isDarkCc ? "gdluck1.voc" : "goodbye.voc", 1);
+ sound.playVoice(_ccNum ? "gdluck1.voc" : "goodbye.voc");
map.mazeData()._mazeNumber = party._mazeId;
}
@@ -802,7 +814,7 @@ TempleLocation::TempleLocation() : BaseLocation(TEMPLE) {
_v10 = _v11 = 0;
_v12 = _v13 = 0;
_v14 = 0;
- _flag1 = false;
+ _blessed = false;
_v5 = _v6 = 0;
_icons1.load("esc.icn");
@@ -812,28 +824,32 @@ TempleLocation::TempleLocation() : BaseLocation(TEMPLE) {
addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_u);
addButton(Common::Rect(234, 84, 308, 92), 0);
- _vocName = _isDarkCc ? "help2.voc" : "maywe2.voc";
+ _vocName = _ccNum ? "help2.voc" : "maywe2.voc";
}
Common::String TempleLocation::createLocationText(Character &ch) {
Party &party = *g_vm->_party;
+ _donation = 0;
+ _uncurseCost = 0;
+ _healCost = 0;
+ _v5 = _v6 = 0;
- if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+ if (party._mazeId == (_ccNum ? 29 : 28)) {
_v10 = _v11 = _v12 = _v13 = 0;
_v14 = 10;
- } else if (party._mazeId == (_isDarkCc ? 31 : 30)) {
+ } else if (party._mazeId == (_ccNum ? 31 : 30)) {
_v13 = 10;
_v12 = 50;
_v11 = 500;
_v10 = 100;
_v14 = 25;
- } else if (party._mazeId == (_isDarkCc ? 37 : 73)) {
+ } else if (party._mazeId == (_ccNum ? 37 : 73)) {
_v13 = 20;
_v12 = 100;
_v11 = 1000;
_v10 = 200;
_v14 = 50;
- } else if (_isDarkCc || party._mazeId == 49) {
+ } else if (_ccNum || party._mazeId == 49) {
_v13 = 100;
_v12 = 500;
_v11 = 5000;
@@ -862,17 +878,11 @@ Common::String TempleLocation::createLocationText(Character &ch) {
_v5 = (_currentCharLevel * 1000) + (ch._conditions[ERADICATED] * 500) + _v11;
}
- for (int idx = 0; idx < 9; ++idx) {
- _uncurseCost |= ch._weapons[idx]._bonusFlags & 0x40;
- _uncurseCost |= ch._armor[idx]._bonusFlags & 0x40;
- _uncurseCost |= ch._accessories[idx]._bonusFlags & 0x40;
- _uncurseCost |= ch._misc[idx]._bonusFlags & 0x40;
- }
-
- if (_uncurseCost || ch._conditions[CURSED])
- _v5 = (_currentCharLevel * 20) + _v10;
+ bool isCursed = ch._items.hasCursedItems();
+ if (isCursed || ch._conditions[CURSED])
+ _uncurseCost = (_currentCharLevel * 20) + _v10;
- _donation = _flag1 ? 0 : _v14;
+ _donation = _blessed ? 0 : _v14;
_healCost += _v6 + _v5;
return Common::String::format(Res.TEMPLE_TEXT, ch._name.c_str(),
@@ -905,9 +915,9 @@ Character *TempleLocation::doOptions(Character *c) {
if (_donation && party.subtract(CONS_GOLD, _donation, WHERE_PARTY, WT_LOC_WAIT)) {
sound.stopSound();
sound.playSound("coina.voc", 1);
- _dayOfWeek = (_dayOfWeek + 1) / 10;
+ _dayOfWeek = (_dayOfWeek + 1) % 10;
- if (_dayOfWeek == (party._day / 10)) {
+ if (_dayOfWeek == (party._day % 10)) {
party._clairvoyanceActive = true;
party._lightCount = 1;
@@ -920,7 +930,7 @@ Character *TempleLocation::doOptions(Character *c) {
intf.drawParty(true);
sound.stopSound();
sound.playSound("ahh.voc");
- _flag1 = true;
+ _blessed = true;
_donation = 0;
}
}
@@ -955,13 +965,8 @@ Character *TempleLocation::doOptions(Character *c) {
case Common::KEYCODE_u:
if (_uncurseCost && party.subtract(CONS_GOLD, _uncurseCost, WHERE_PARTY, WT_LOC_WAIT)) {
- for (int idx = 0; idx < 9; ++idx) {
- c->_weapons[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
- c->_armor[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
- c->_accessories[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
- c->_misc[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
- }
-
+ c->_items.curseUncurse(false);
+ c->_conditions[CURSED] = 0;
_farewellTime = 1440;
intf.drawParty(true);
sound.stopSound();
@@ -988,12 +993,12 @@ TrainingLocation::TrainingLocation() : BaseLocation(TRAINING) {
addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_ESCAPE, &_icons1);
addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_t, &_icons1);
- _vocName = _isDarkCc ? "youtrn1.voc" : "training.voc";
+ _vocName = _ccNum ? "youtrn1.voc" : "training.voc";
}
Common::String TrainingLocation::createLocationText(Character &ch) {
Party &party = *g_vm->_party;
- if (_isDarkCc) {
+ if (_ccNum) {
switch (party._mazeId) {
case 29:
// Castleview
@@ -1040,11 +1045,12 @@ Common::String TrainingLocation::createLocationText(Character &ch) {
} else if (ch._level._permanent >= _maxLevel) {
// At maximum level
_experienceToNextLevel = 1;
- msg = Common::String::format(Res.LEARNED_ALL, ch._name.c_str());
+ msg = Common::String::format(Res.TRAINING_LEARNED_ALL, ch._name.c_str());
} else {
// Eligble for level increase
+ uint cost = ch._level._permanent * ch._level._permanent * 10;
msg = Common::String::format(Res.ELIGIBLE_FOR_LEVEL,
- ch._name.c_str(), ch._level._permanent + 1);
+ ch._name.c_str(), ch._level._permanent + 1, cost);
}
return Common::String::format(Res.TRAINING_TEXT, msg.c_str(),
@@ -1079,9 +1085,9 @@ Character *TrainingLocation::doOptions(Character *c) {
Common::String name;
if (c->_level._permanent >= _maxLevel) {
- name = _isDarkCc ? "gtlost.voc" : "trainin1.voc";
+ name = _ccNum ? "gtlost.voc" : "trainin1.voc";
} else {
- name = _isDarkCc ? "gtlost.voc" : "trainin0.voc";
+ name = _ccNum ? "gtlost.voc" : "trainin0.voc";
}
sound.playSound(name);
@@ -1090,7 +1096,7 @@ Character *TrainingLocation::doOptions(Character *c) {
if (party.subtract(CONS_GOLD, (c->_level._permanent * c->_level._permanent) * 10, WHERE_PARTY, WT_LOC_WAIT)) {
_drawFrameIndex = 0;
sound.stopSound();
- sound.playSound(_isDarkCc ? "prtygd.voc" : "trainin2.voc", 1);
+ sound.playSound(_ccNum ? "prtygd.voc" : "trainin2.voc", 1);
c->_experience -= c->nextExperienceLevel() -
(c->getCurrentExperience() - c->_experience);
@@ -1147,10 +1153,10 @@ int ArenaLocation::show() {
}
Common::String format = map._events._text[3];
- Common::String count = Common::String::format("%05u", party._activeParty[0]._awards[WARZONE_AWARD]);
- int numIdx = count[3] == '1' ? 0 : count[4] - '0';
- Common::String msg = Common::String::format(format.c_str(), count.c_str(), SUFFIXES[numIdx]);
-
+ int count = party._activeParty[0]._awards[WARZONE_AWARD];
+ int suffixNum = (count < 10) ? count : 0;
+ Common::String msg = Common::String::format(format.c_str(), count, SUFFIXES[suffixNum]);
+
LocationMessage::show(27, Res.WARZONE_BATTLE_MASTER, msg, 1);
map.load(28);
@@ -1165,8 +1171,7 @@ int ArenaLocation::show() {
}
}
- check = LocationMessage::show(27, Res.WARZONE_BATTLE_MASTER,
- map._events._text[0].c_str(), 300);
+ check = LocationMessage::show(27, Res.WARZONE_BATTLE_MASTER, map._events._text[0].c_str(), 0);
if (!check) {
LocationMessage::show(27, Res.WARZONE_BATTLE_MASTER,
map._events._text[1].c_str(), 300);
@@ -1191,7 +1196,7 @@ int ArenaLocation::show() {
if (howMany == 0)
goto exit;
- LocationMessage::show(27, Res.WARZONE_BATTLE_MASTER, map._events._text[2], 300);
+ LocationMessage::show(27, Res.WARZONE_BATTLE_MASTER, map._events._text[2], 1);
// Clear monsters array
party._mazeDirection = DIR_EAST;
@@ -1236,7 +1241,7 @@ exit:
/*------------------------------------------------------------------------*/
-CutsceneLocation::CutsceneLocation(LocationAction action) : BaseLocation(action), _mazeFlag(false) {
+CutsceneLocation::CutsceneLocation(LocationAction action) : BaseLocation(action), _keyFound(false) {
Party &party = *g_vm->_party;
_mazeId = party._mazeId;
_mazePos = party._mazePosition;
@@ -1279,16 +1284,17 @@ int ReaperCutscene::show() {
Sound &sound = *g_vm->_sound;
Windows &windows = *g_vm->_windows;
- SpriteResource sprites1(_isDarkCc ? "tower1.zom" : "tower.vga", _isDarkCc);
- SpriteResource sprites2(_isDarkCc ? "tower2.zom" : "freap.vga", _isDarkCc);
+ SpriteResource sprites1(_ccNum ? "tower1.zom" : "tower.vga", _ccNum);
+ SpriteResource sprites2(_ccNum ? "tower2.zom" : "freap.vga", _ccNum);
Graphics::ManagedSurface savedBg;
savedBg.copyFrom(screen);
+ getNewLocation();
for (int idx = 13; idx >= 0; --idx) {
events.updateGameCounter();
- sprites1.draw(0, 0, Common::Point(REAPER_X1[_isDarkCc][idx], REAPER_Y1[_isDarkCc][idx]), 0, idx);
- if (_isDarkCc) {
+ sprites1.draw(0, 0, Common::Point(REAPER_X1[_ccNum][idx], REAPER_Y1[_ccNum][idx]), 0, idx);
+ if (_ccNum) {
sprites1.draw(0, 1, Common::Point(REAPER_X2[idx], REAPER_Y1[1][idx]), 0, idx);
sprites1.draw(0, party._isNight ? 3 : 2, Common::Point(REAPER_X3[idx], REAPER_Y1[1][idx]), 0, idx);
}
@@ -1296,7 +1302,7 @@ int ReaperCutscene::show() {
WAIT(1);
}
- if (_isDarkCc) {
+ if (_ccNum) {
for (int idx = -200; idx < 0; idx += 16) {
events.updateGameCounter();
sprites1.draw(0, 0, Common::Point(0, 0));
@@ -1319,18 +1325,23 @@ int ReaperCutscene::show() {
sound.setMusicPercent(38);
sprites1.draw(0, 0, Common::Point(0, 0));
- if (_isDarkCc) {
+ if (_ccNum) {
sprites1.draw(0, 1, Common::Point(160, 0));
sprites1.draw(0, party._isNight ? 3 : 2);
}
- _subtitles.setLine(_mazeFlag ? 5 : 6);
- sound.playVoice(_mazeFlag ? "reaper12.voc" : "reaper14.voc");
+ if (!_ccNum) {
+ _subtitles.setLine(_keyFound ? 5 : 6);
+ sound.playVoice(_keyFound ? "reaper12.voc" : "reaper14.voc");
+ } else if (_keyFound) {
+ _subtitles.setLine(2);
+ sound.playVoice("howdid1.voc");
+ }
do {
events.updateGameCounter();
int frame = g_vm->getRandomNumber(4);
- if (_isDarkCc) {
+ if (_ccNum) {
sprites2.draw(0, frame);
sprites2.draw(0, frame + 5, Common::Point(160, 0));
} else {
@@ -1344,21 +1355,23 @@ int ReaperCutscene::show() {
} while (sound.isSoundPlaying());
sprites2.draw(0, 0, Common::Point(0, 0));
- if (_isDarkCc)
+ if (_ccNum)
sprites2.draw(0, 5, Common::Point(160, 0));
windows[0].update();
WAIT(7);
- sound.playVoice(_mazeFlag ? "reaper12.voc" : "reaper14.voc");
- if (_mazeFlag)
- sound.playVoice(_isDarkCc ? "goin1.voc" : "reaper13.voc");
- else
- sound.playVoice(_isDarkCc ? "needkey1.voc" : "reaper15.voc");
+ if (_keyFound) {
+ sound.playVoice(_ccNum ? "goin1.voc" : "reaper13.voc");
+ } else {
+ if (_ccNum)
+ _subtitles.setLine(3);
+ sound.playVoice(_ccNum ? "needkey1.voc" : "reaper15.voc");
+ }
do {
events.updateGameCounter();
int frame = g_vm->getRandomNumber(4);
- if (_isDarkCc) {
+ if (_ccNum) {
sprites2.draw(0, frame, Common::Point(0, 0));
sprites2.draw(0, frame + 5, Common::Point(160, 0));
} else {
@@ -1370,18 +1383,18 @@ int ReaperCutscene::show() {
} while (_subtitles.lineActive());
sprites2.draw(0, 0, Common::Point(0, 0));
- if (_isDarkCc)
+ if (_ccNum)
sprites2.draw(0, 5, Common::Point(160, 0));
windows[0].update();
WAIT(1);
- if (_mazeFlag) {
+ if (_keyFound) {
for (int idx = 0; idx < 14; ++idx) {
events.updateGameCounter();
screen.blitFrom(savedBg);
- sprites1.draw(0, 0, Common::Point(REAPER_X1[_isDarkCc][idx], REAPER_Y1[_isDarkCc][idx]), 0, idx);
-
- if (_isDarkCc) {
+ sprites1.draw(0, 0, Common::Point(REAPER_X1[_ccNum][idx], REAPER_Y1[_ccNum][idx]), 0, idx);
+
+ if (_ccNum) {
sprites1.draw(0, 1, Common::Point(REAPER_X2[idx], REAPER_Y1[1][idx]), 0, idx);
sprites1.draw(0, party._isNight ? 3 : 2, Common::Point(REAPER_X3[idx], REAPER_Y1[1][idx]), 0, idx);
}
@@ -1415,14 +1428,14 @@ void ReaperCutscene::getNewLocation() {
Map &map = *g_vm->_map;
Party &party = *g_vm->_party;
- if (_isDarkCc) {
+ if (_ccNum) {
switch (party._mazeId) {
case 3:
if (party._questItems[40]) {
_mazeId = 57;
_mazePos = Common::Point(11, 8);
_mazeDir = DIR_WEST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1431,7 +1444,7 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 55;
_mazePos = Common::Point(3, 8);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1440,7 +1453,16 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 69;
_mazePos = Common::Point(7, 4);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
+ }
+ break;
+
+ case 16:
+ if (party._questItems[41]) {
+ _mazeId = 61;
+ _mazePos = Common::Point(7, 12);
+ _mazeDir = DIR_SOUTH;
+ _keyFound = true;
}
break;
@@ -1449,7 +1471,7 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 65;
_mazePos = Common::Point(3, 8);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1458,7 +1480,7 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 53;
_mazePos = Common::Point(11, 8);
_mazeDir = DIR_WEST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1468,12 +1490,12 @@ void ReaperCutscene::getNewLocation() {
} else {
switch (party._mazeId) {
case 7:
- if (party._questItems[30]) {
- map._loadDarkSide = true;
+ if (party._questItems[46]) {
+ map._loadCcNum = 1;
_mazeId = 113;
_mazePos = Common::Point(7, 4);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1482,17 +1504,17 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 55;
_mazePos = Common::Point(3, 8);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
case 13:
- if (party._questItems[29]) {
- map._loadDarkSide = true;
+ if (party._questItems[45]) {
+ map._loadCcNum = 1;
_mazeId = 117;
_mazePos = Common::Point(7, 4);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1501,7 +1523,7 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 59;
_mazePos = Common::Point(11, 8);
_mazeDir = DIR_WEST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1510,7 +1532,7 @@ void ReaperCutscene::getNewLocation() {
_mazeId = 51;
_mazePos = Common::Point(7, 12);
_mazeDir = DIR_SOUTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1545,28 +1567,29 @@ int GolemCutscene::show() {
Sound &sound = *g_vm->_sound;
Windows &windows = *g_vm->_windows;
SpriteResource sprites1, sprites2[2];
- sprites1.load(_isDarkCc ? "dung1.zom" : "golmback.vga");
- sprites2[0].load(_isDarkCc ? "dung2.zom" : "golem.vga");
- if (_isDarkCc)
+ sprites1.load(_ccNum ? "dung1.zom" : "golmback.vga");
+ sprites2[0].load(_ccNum ? "dung2.zom" : "golem.vga");
+ if (_ccNum)
sprites2[1].load("dung3.zom");
// Save the screen
Graphics::ManagedSurface savedBg;
savedBg.copyFrom(screen);
+ getNewLocation();
- for (int idx = (_isDarkCc ? 8 : 11); idx >= 0; --idx) {
+ for (int idx = (_ccNum ? 8 : 11); idx >= 0; --idx) {
events.updateGameCounter();
screen.blitFrom(savedBg);
sprites1.draw(0, 0,
- Common::Point(GOLEM_X1[_isDarkCc][idx], GOLEM_Y1[_isDarkCc][idx]), 0, idx);
+ Common::Point(GOLEM_X1[_ccNum][idx], GOLEM_Y1[_ccNum][idx]), 0, idx);
sprites1.draw(0, 1,
- Common::Point(GOLEM_X2[_isDarkCc][idx], GOLEM_Y1[_isDarkCc][idx]), 0, idx);
+ Common::Point(GOLEM_X2[_ccNum][idx], GOLEM_Y1[_ccNum][idx]), 0, idx);
windows[0].update();
WAIT(1);
}
- if (_isDarkCc)
+ if (!_ccNum)
sound.playSound("ogre.voc");
for (int idx = -200; idx < 0; idx += 16) {
@@ -1574,13 +1597,13 @@ int GolemCutscene::show() {
sprites1.draw(0, 0, Common::Point(0, 0));
sprites1.draw(0, 1, Common::Point(160, 0));
sprites2[0].draw(0, 0, Common::Point(idx, 0), SPRFLAG_800);
- sprites2[_isDarkCc].draw(0, 1, Common::Point(idx + 160, 0), SPRFLAG_800);
+ sprites2[_ccNum].draw(0, 1, Common::Point(idx + 160, 0), SPRFLAG_800);
- if (!_isDarkCc)
+ if (!_ccNum)
sprites2[0].draw(0, 2, Common::Point(idx + g_vm->getRandomNumber(9) - 5,
g_vm->getRandomNumber(9) - 5), SPRFLAG_800);
-
- if (!_isDarkCc && !sound.isSoundPlaying())
+
+ if (!_ccNum && !sound.isSoundPlaying())
sound.playSound("ogre.voc");
WAIT(1);
@@ -1589,28 +1612,34 @@ int GolemCutscene::show() {
sprites1.draw(0, 0, Common::Point(0, 0));
sprites1.draw(0, 1, Common::Point(160, 0));
sprites2[0].draw(0, 0, Common::Point(0, 0));
- sprites2[_isDarkCc].draw(0, _isDarkCc ? 0 : 1, Common::Point(160, 0));
- if (!_isDarkCc)
+ sprites2[_ccNum].draw(0, 1 - _ccNum, Common::Point(160, 0));
+ if (!_ccNum)
sprites2[0].draw(0, 2);
windows[0].update();
while (sound.isSoundPlaying()) {
+ _subtitles.show();
WAIT(1);
}
sound.setMusicPercent(38);
- _subtitles.setLine(_mazeFlag ? 8 : 7);
- sound.playVoice(_mazeFlag ? "golem15.voc" : "golem13.voc");
+ if (_ccNum) {
+ _subtitles.setLine(_keyFound ? 5 : 4);
+ sound.playVoice("what2.voc");
+ } else {
+ _subtitles.setLine(_keyFound ? 8 : 7);
+ sound.playVoice(_keyFound ? "golem15.voc" : "golem13.voc");
+ }
do {
events.updateGameCounter();
sprites1.draw(0, 0, Common::Point(0, 0));
sprites1.draw(0, 1, Common::Point(160, 0));
- if (_isDarkCc) {
+ if (_ccNum) {
int frame = g_vm->getRandomNumber(6);
sprites2[0].draw(0, frame, Common::Point(0, 0));
- sprites2[1].draw(1, frame, Common::Point(160, 0));
+ sprites2[1].draw(0, frame, Common::Point(160, 0));
} else {
sprites2[0].draw(0, 0, Common::Point(0, 0));
sprites2[0].draw(0, 1, Common::Point(160, 0));
@@ -1618,28 +1647,30 @@ int GolemCutscene::show() {
g_vm->getRandomNumber(9) - 3));
}
+ _subtitles.show();
WAIT(1);
} while (sound.isSoundPlaying());
sprites1.draw(0, 0, Common::Point(0, 0));
sprites1.draw(0, 1, Common::Point(160, 0));
sprites2[0].draw(0, 0, Common::Point(0, 0));
- sprites2[_isDarkCc].draw(0, _isDarkCc ? 0 : 1, Common::Point(160, 0));
- if (!_isDarkCc)
+ sprites2[_ccNum].draw(0, 1 - _ccNum, Common::Point(160, 0));
+ if (!_ccNum)
sprites2[0].draw(0, 2);
windows[0].update();
events.updateGameCounter();
- events.wait(_isDarkCc ? 10 : 1);
+ if (_subtitles.wait(_ccNum ? 10 : 1))
+ goto exit;
- if (!_isDarkCc) {
+ if (_ccNum) {
+ sound.playVoice(_keyFound ? "go2.voc" : "key2.voc");
+ } else {
sound.playVoice("ogre.voc");
while (sound.isSoundPlaying())
events.pollEventsAndWait();
- sound.playVoice(_mazeFlag ? "golem16.voc" : "golem14.voc");
- } else {
- sound.playVoice(_mazeFlag ? "go2.voc" : "key2.voc");
+ sound.playVoice(_keyFound ? "golem16.voc" : "golem14.voc");
}
do {
@@ -1647,10 +1678,10 @@ int GolemCutscene::show() {
sprites1.draw(0, 0, Common::Point(0, 0));
sprites1.draw(0, 1, Common::Point(160, 0));
- if (_isDarkCc) {
+ if (_ccNum) {
int frame = g_vm->getRandomNumber(6);
sprites2[0].draw(0, frame, Common::Point(0, 0));
- sprites2[1].draw(1, frame, Common::Point(160, 0));
+ sprites2[1].draw(0, frame, Common::Point(160, 0));
} else {
sprites2[0].draw(0, 0, Common::Point(0, 0));
sprites2[0].draw(0, 1, Common::Point(160, 0));
@@ -1659,31 +1690,28 @@ int GolemCutscene::show() {
}
windows[0].update();
+ _subtitles.show();
WAIT(1);
- } while (sound.isSoundPlaying());
+ } while (_subtitles.lineActive());
sprites1.draw(0, 0, Common::Point(0, 0));
sprites1.draw(0, 1, Common::Point(160, 0));
sprites2[0].draw(0, 0, Common::Point(0, 0));
- sprites2[_isDarkCc].draw(0, _isDarkCc ? 0 : 1, Common::Point(160, 0));
- if (!_isDarkCc)
+ sprites2[_ccNum].draw(0, 1 - _ccNum, Common::Point(160, 0));
+ if (!_ccNum)
sprites2[0].draw(0, 2);
-
windows[0].update();
- while (_subtitles.lineActive()) {
- WAIT(1);
- }
sound.setMusicPercent(75);
- if (!_mazeFlag) {
- for (int idx = 0; !g_vm->shouldExit() && idx < (_isDarkCc ? 9 : 12); ++idx) {
+ if (!_keyFound) {
+ for (int idx = 0; !g_vm->shouldExit() && idx < (_ccNum ? 9 : 12); ++idx) {
events.updateGameCounter();
screen.blitFrom(savedBg);
sprites1.draw(0, 0,
- Common::Point(GOLEM_X1[_isDarkCc][idx], GOLEM_Y1[_isDarkCc][idx]), 0, idx);
+ Common::Point(GOLEM_X1[_ccNum][idx], GOLEM_Y1[_ccNum][idx]), 0, idx);
sprites1.draw(0, 1,
- Common::Point(GOLEM_X2[_isDarkCc][idx], GOLEM_Y1[_isDarkCc][idx]), 0, idx);
+ Common::Point(GOLEM_X2[_ccNum][idx], GOLEM_Y1[_ccNum][idx]), 0, idx);
windows[0].update();
WAIT(1);
@@ -1712,14 +1740,14 @@ void GolemCutscene::getNewLocation() {
Map &map = *g_vm->_map;
Party &party = *g_vm->_party;
- if (_isDarkCc) {
+ if (_ccNum) {
switch (party._mazeId) {
case 12:
if (party._questItems[47]) {
_mazeId = 73;
_mazePos = Common::Point(0, 7);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1728,7 +1756,7 @@ void GolemCutscene::getNewLocation() {
_mazeId = 83;
_mazePos = Common::Point(11, 1);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1737,7 +1765,7 @@ void GolemCutscene::getNewLocation() {
_mazeId = 121;
_mazePos = Common::Point(18, 0);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1746,7 +1774,7 @@ void GolemCutscene::getNewLocation() {
_mazeId = 78;
_mazePos = Common::Point(8, 14);
_mazeDir = DIR_SOUTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1760,7 +1788,7 @@ void GolemCutscene::getNewLocation() {
_mazeId = 81;
_mazePos = Common::Point(1, 17);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1769,17 +1797,17 @@ void GolemCutscene::getNewLocation() {
_mazeId = 80;
_mazePos = Common::Point(29, 16);
_mazeDir = DIR_WEST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
case 19:
if (party._questItems[50]) {
- map._loadDarkSide = true;
+ map._loadCcNum = 1;
_mazeId = 121;
_mazePos = Common::Point(18, 0);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1788,7 +1816,7 @@ void GolemCutscene::getNewLocation() {
_mazeId = 79;
_mazePos = Common::Point(5, 16);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1833,9 +1861,9 @@ int DwarfCutscene::show() {
Sound &sound = *g_vm->_sound;
Windows &windows = *g_vm->_windows;
- SpriteResource sprites1(_isDarkCc ? "town1.zom" : "dwarf1.vga");
- SpriteResource sprites2(_isDarkCc ? "town2.zom" : "dwarf3.vga");
- SpriteResource sprites3(_isDarkCc ? "town3.zom" : "dwarf2.vga");
+ SpriteResource sprites1(_ccNum ? "town1.zom" : "dwarf1.vga");
+ SpriteResource sprites2(_ccNum ? "town2.zom" : "dwarf3.vga");
+ SpriteResource sprites3(_ccNum ? "town3.zom" : "dwarf2.vga");
getNewLocation();
// Save the screen contents
@@ -1843,17 +1871,17 @@ int DwarfCutscene::show() {
savedBg.copyFrom(screen);
// Zoom in on the mine entrance
- for (int idx = (_isDarkCc ? 10 : 12); idx >= 0; --idx) {
+ for (int idx = (_ccNum ? 10 : 12); idx >= 0; --idx) {
events.updateGameCounter();
screen.blitFrom(savedBg);
sprites1.draw(0, 0,
- Common::Point(DWARF_X0[_isDarkCc][idx], DWARF_Y[_isDarkCc][idx]), 0, idx);
+ Common::Point(DWARF_X0[_ccNum][idx], DWARF_Y[_ccNum][idx]), 0, idx);
sprites1.draw(0, 1,
- Common::Point(DWARF_X1[_isDarkCc][idx], DWARF_Y[_isDarkCc][idx]), 0, idx);
- if (_isDarkCc)
+ Common::Point(DWARF_X1[_ccNum][idx], DWARF_Y[_ccNum][idx]), 0, idx);
+ if (_ccNum)
sprites1.draw(0, 2,
- Common::Point(DWARF_X2[idx], DWARF_Y[_isDarkCc][idx]), 0, idx);
+ Common::Point(DWARF_X2[idx], DWARF_Y[_ccNum][idx]), 0, idx);
windows[0].update();
WAIT(1);
@@ -1867,7 +1895,7 @@ int DwarfCutscene::show() {
events.updateGameCounter();
screen.blitFrom(savedBg);
- sprites2.draw(0, 0, Common::Point(DWARF2_X[_isDarkCc][idx], DWARF2_Y[_isDarkCc][idx]), 0, idx);
+ sprites2.draw(0, 0, Common::Point(DWARF2_X[_ccNum][idx], DWARF2_Y[_ccNum][idx]), 0, idx);
windows[0].update();
WAIT(1);
}
@@ -1876,16 +1904,19 @@ int DwarfCutscene::show() {
screen.blitFrom(savedBg);
sprites2.draw(0, 0);
windows[0].update();
- _subtitles.setLine(_isDarkCc ? 0 : 4);
+ if (_ccNum)
+ _subtitles.setLine(_keyFound ? 7 : 8);
+ else
+ _subtitles.setLine(4);
- for (int idx = 0; idx < (_isDarkCc ? 2 : 3); ++idx) {
+ for (int idx = 0; idx < (_ccNum ? 2 : 3); ++idx) {
switch (idx) {
case 0:
- sound.playSound(_isDarkCc ? "pass2.voc" : "dwarf10.voc");
+ sound.playSound(_ccNum ? "pass2.voc" : "dwarf10.voc");
break;
case 1:
- if (_isDarkCc) {
+ if (_ccNum) {
sprites2.draw(0, 0);
sprites3.draw(0, 0);
_subtitles.show();
@@ -1895,7 +1926,7 @@ int DwarfCutscene::show() {
WAIT(1);
}
- sound.playSound(_mazeFlag ? "ok2.voc" : "back2.voc");
+ sound.playSound(_keyFound ? "ok2.voc" : "back2.voc");
} else {
sound.playSound("dwarf11.voc");
}
@@ -1909,7 +1940,7 @@ int DwarfCutscene::show() {
events.updateGameCounter();
do {
sprites2.draw(0, 0);
- sprites3.draw(0, g_vm->getRandomNumber(_isDarkCc ? 8 : 9));
+ sprites3.draw(0, g_vm->getRandomNumber(_ccNum ? 8 : 9));
_subtitles.show();
events.timeMark5();
@@ -1923,7 +1954,7 @@ int DwarfCutscene::show() {
exit:
sprites2.draw(0, 0);
- if (!_isDarkCc)
+ if (!_ccNum)
sprites3.draw(0, 1);
windows[0].update();
@@ -1944,14 +1975,37 @@ exit:
void DwarfCutscene::getNewLocation() {
Party &party = *g_vm->_party;
- if (_isDarkCc) {
+ if (g_vm->getGameID() == GType_Swords) {
+ switch (party._mazeId) {
+ case 1:
+ if (party._questItems[0]) {
+ _mazeId = 53;
+ _mazePos = Common::Point(8, 1);
+ _mazeDir = DIR_NORTH;
+ _keyFound = true;
+ }
+ break;
+
+ case 7:
+ if (party._questItems[1]) {
+ _mazeId = 92;
+ _mazePos = Common::Point(8, 1);
+ _mazeDir = DIR_NORTH;
+ _keyFound = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_ccNum) {
switch (party._mazeId) {
case 4:
if (party._questItems[35]) {
_mazeId = 29;
_mazePos = Common::Point(15, 31);
_mazeDir = DIR_SOUTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1960,7 +2014,7 @@ void DwarfCutscene::getNewLocation() {
_mazeId = 35;
_mazePos = Common::Point(15, 8);
_mazeDir = DIR_WEST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1969,7 +2023,7 @@ void DwarfCutscene::getNewLocation() {
_mazeId = 31;
_mazePos = Common::Point(31, 16);
_mazeDir = DIR_WEST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1978,7 +2032,7 @@ void DwarfCutscene::getNewLocation() {
_mazeId = 33;
_mazePos = Common::Point(0, 3);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -1987,7 +2041,7 @@ void DwarfCutscene::getNewLocation() {
_mazeId = 37;
_mazePos = Common::Point(7, 0);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -2000,7 +2054,7 @@ void DwarfCutscene::getNewLocation() {
_mazeId = 37;
_mazePos = Common::Point(1, 4);
_mazeDir = DIR_EAST;
- _mazeFlag = true;
+ _keyFound = true;
break;
case 18:
@@ -2013,7 +2067,7 @@ void DwarfCutscene::getNewLocation() {
_mazePos = Common::Point(7, 1);
_mazeDir = DIR_NORTH;
}
- _mazeFlag = true;
+ _keyFound = true;
break;
case 23:
@@ -2026,7 +2080,7 @@ void DwarfCutscene::getNewLocation() {
_mazePos = Common::Point(7, 30);
_mazeDir = DIR_SOUTH;
}
- _mazeFlag = true;
+ _keyFound = true;
break;
default:
@@ -2057,7 +2111,7 @@ int SphinxCutscene::show() {
// Save background
Graphics::ManagedSurface bgSurface;
bgSurface.copyFrom(screen);
-
+
for (int idx = 8; idx >= 0; --idx) {
events.updateGameCounter();
screen.blitFrom(bgSurface);
@@ -2069,14 +2123,14 @@ int SphinxCutscene::show() {
sound.setMusicPercent(38);
- for (int idx = 0; idx < (_mazeFlag ? 3 : 2); ++idx) {
+ for (int idx = 0; idx < (_keyFound ? 3 : 2); ++idx) {
switch (idx) {
case 0:
- _subtitles.setLine(_mazeFlag ? 9 : 10);
- sound.playSound(_mazeFlag ? "sphinx10.voc" : "sphinx13.voc");
+ _subtitles.setLine(_keyFound ? 9 : 10);
+ sound.playSound(_keyFound ? "sphinx10.voc" : "sphinx13.voc");
break;
case 1:
- sound.playSound(_mazeFlag ? "sphinx11.voc" : "sphinx14.voc");
+ sound.playSound(_keyFound ? "sphinx11.voc" : "sphinx14.voc");
break;
case 2:
sound.playSound("sphinx12.voc");
@@ -2100,7 +2154,7 @@ int SphinxCutscene::show() {
sound.setMusicPercent(75);
- if (!_mazeFlag) {
+ if (!_keyFound) {
for (int idx = 0; idx < 8; ++idx) {
screen.blitFrom(bgSurface);
sprites1.draw(0, 0, Common::Point(SPHINX_X1[idx], SPHINX_Y1[idx]), 0, idx);
@@ -2135,11 +2189,11 @@ void SphinxCutscene::getNewLocation() {
switch (party._mazeId) {
case 2:
if (party._questItems[51]) {
- map._loadDarkSide = true;
+ map._loadCcNum = 1;
_mazeId = 125;
_mazePos = Common::Point(7, 6);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -2148,7 +2202,7 @@ void SphinxCutscene::getNewLocation() {
_mazeId = 82;
_mazePos = Common::Point(7, 5);
_mazeDir = DIR_NORTH;
- _mazeFlag = true;
+ _keyFound = true;
}
break;
@@ -2172,7 +2226,7 @@ int PyramidLocation::show() {
Common::Point pt;
if (g_vm->getGameID() == GType_WorldOfXeen) {
- if (_isDarkCc) {
+ if (_ccNum) {
if (party._mazeId == 52) {
mapId = 49;
pt = Common::Point(7, 14);
@@ -2192,7 +2246,7 @@ int PyramidLocation::show() {
}
// Load the destination map and set position and direction
- map._loadDarkSide = !_isDarkCc;
+ map._loadCcNum = _ccNum ? 0 : 1;
map.load(mapId);
party._mazePosition = pt;
party._mazeDirection = dir;
@@ -2200,7 +2254,7 @@ int PyramidLocation::show() {
// Playing Clouds or Dark Side on it's own, so can't switch sides
Window &win = windows[12];
Common::String msg = Common::String::format(Res.MOONS_NOT_ALIGNED,
- _isDarkCc ? "Clouds" : "Darkside");
+ _ccNum ? "Clouds" : "Darkside");
win.open();
win.writeString(msg);
win.update();
@@ -2219,9 +2273,12 @@ int PyramidLocation::show() {
LocationManager::LocationManager() : _location(nullptr) {
}
-int LocationManager::doAction(LocationAction actionId) {
+int LocationManager::doAction(int actionId) {
+ LocationAction action = (g_vm->getGameID() == GType_Swords && actionId > 13 && actionId < 18) ?
+ BLACKSMITH : (LocationAction)actionId;
+
// Create the desired location
- switch (actionId) {
+ switch (action) {
case BANK:
_location = new Locations::BankLocation();
break;
@@ -2264,6 +2321,7 @@ int LocationManager::doAction(LocationAction actionId) {
}
// Show the location
+ g_vm->_events->clearEvents();
int result = _location->show();
delete _location;
_location = nullptr;
@@ -2355,21 +2413,18 @@ bool LocationMessage::execute(int portrait, const Common::String &name, const Co
do {
events.clearEvents();
- events.updateGameCounter();
- if (msgEnd)
- clearButtons();
+ clearEvents();
do {
- events.pollEventsAndWait();
- checkEvents(_vm);
-
- if (_vm->shouldExit())
- return false;
-
- while (events.timeElapsed() >= 3) {
- drawAnim(false);
- events.updateGameCounter();
+ events.updateGameCounter();
+ while (!_buttonValue && events.timeElapsed() < 3) {
+ events.pollEventsAndWait();
+ checkEvents(_vm);
+ if (g_vm->shouldExit())
+ return false;
}
+
+ drawAnim(false);
} while (!_buttonValue);
if (msgEnd)
diff --git a/engines/xeen/locations.h b/engines/xeen/locations.h
index 9b3e36eed7..ad0a8e2cee 100644
--- a/engines/xeen/locations.h
+++ b/engines/xeen/locations.h
@@ -47,7 +47,7 @@ protected:
Common::Array<SpriteResource> _townSprites;
SpriteResource _icons1, _icons2;
int _townMaxId;
- const bool &_isDarkCc;
+ const int &_ccNum;
int _animFrame;
Common::String _vocName, _songName;
Common::Point _animPos;
@@ -198,7 +198,7 @@ private:
int _dayOfWeek;
int _v10, _v11, _v12;
int _v13, _v14;
- bool _flag1;
+ bool _blessed;
int _v5, _v6;
protected:
/**
@@ -253,7 +253,7 @@ protected:
int _mazeId;
Direction _mazeDir;
Common::Point _mazePos;
- bool _mazeFlag;
+ bool _keyFound;
protected:
/**
* Sets the new location
@@ -364,7 +364,7 @@ public:
/**
* Show a given location, and return any result
*/
- int doAction(LocationAction actionId);
+ int doAction(int actionId);
/**
* Returns true if a town location (bank, blacksmith, etc.) is currently active
diff --git a/engines/xeen/map.cpp b/engines/xeen/map.cpp
index d8afa4d2a3..9d384c7c8f 100644
--- a/engines/xeen/map.cpp
+++ b/engines/xeen/map.cpp
@@ -52,7 +52,7 @@ MonsterStruct::MonsterStruct() {
_specialAttack = SA_NONE;
_hitChance = 0;
_rangeAttack = 0;
- _monsterType = MONSTER_0;
+ _monsterType = MONSTER_MONSTERS;
_fireResistence = 0;
_electricityResistence = 0;
_coldResistence = 0;
@@ -463,8 +463,6 @@ void MonsterObjectData::synchronize(XeenSerializer &s, MonsterData &monsterData)
if (obj._id < (int)_objectSprites.size()) {
obj._spriteId = _objectSprites[obj._id]._spriteId;
obj._sprites = &_objectSprites[obj._id]._sprites;
- } else {
- assert(!obj._id);
}
_objects.push_back(obj);
@@ -525,7 +523,8 @@ void MonsterObjectData::clearMonsterSprites() {
void MonsterObjectData::addMonsterSprites(MazeMonster &monster) {
Map &map = *g_vm->_map;
- int imgNumber = map._monsterData[monster._spriteId]._imageNumber;
+ monster._monsterData = &map._monsterData[monster._spriteId];
+ int imgNumber = monster._monsterData->_imageNumber;
uint idx;
// Find the sprites for the monster, loading them in if necessary
@@ -604,12 +603,11 @@ void AnimationInfo::load(const Common::String &name) {
/*------------------------------------------------------------------------*/
Map::Map(XeenEngine *vm) : _vm(vm), _mobData(vm) {
- _loadDarkSide = false;
+ _loadCcNum = 0;
_sideTownPortal = 0;
_sideObjects = 0;
_sideMonsters = 0;
_sidePictures = 0;
- _sideMusic = 0;
_isOutdoors = false;
_mazeDataIndex = 0;
_currentSteppedOn = false;
@@ -629,6 +627,7 @@ void Map::load(int mapId) {
FileManager &files = *g_vm->_files;
Interface &intf = *g_vm->_interface;
Party &party = *g_vm->_party;
+ Patcher &patcher = *g_vm->_patcher;
Sound &sound = *g_vm->_sound;
IndoorDrawList &indoorList = intf._indoorList;
OutdoorDrawList &outdoorList = intf._outdoorList;
@@ -636,7 +635,7 @@ void Map::load(int mapId) {
PleaseWait waitMsg(intf._falling);
waitMsg.show();
- intf._objNumber = 0;
+ intf._objNumber = -1;
party._stepped = true;
party._mazeId = mapId;
saveMaze();
@@ -648,12 +647,12 @@ void Map::load(int mapId) {
if (mapId >= 113 && mapId <= 127) {
_sideTownPortal = 0;
} else {
- _sideTownPortal = _loadDarkSide ? 1 : 0;
+ _sideTownPortal = _loadCcNum;
}
if (_vm->getGameID() == GType_Swords || _vm->getGameID() == GType_DarkSide) {
_animationInfo.load("dark.dat");
- _monsterData.load("dark.mon");
+ _monsterData.load((_vm->getGameID() == GType_Swords) ? "monsters.swd" : "dark.mon");
_wallPicSprites.load("darkpic.dat");
} else if (_vm->getGameID() == GType_Clouds) {
_animationInfo.load("animinfo.cld");
@@ -662,7 +661,7 @@ void Map::load(int mapId) {
} else if (_vm->getGameID() == GType_WorldOfXeen) {
files.setGameCc(1);
- if (!_loadDarkSide) {
+ if (!_loadCcNum) {
_animationInfo.load("clouds.dat");
_monsterData.load("xeen.mon");
_wallPicSprites.load("xeenpic.dat");
@@ -709,15 +708,15 @@ void Map::load(int mapId) {
}
}
- files.setGameCc(_loadDarkSide);
+ files.setGameCc(_loadCcNum);
}
// Load any events for the new map
- loadEvents(mapId);
+ loadEvents(mapId, _loadCcNum);
// Iterate through loading the given maze as well as the two successive
// mazes in each of the four cardinal directions
- bool isDarkCc = files._isDarkCc;
+ int ccNum = files._ccNum;
MazeData *mazeDataP = &_mazeData[0];
bool textLoaded = false;
@@ -735,9 +734,9 @@ void Map::load(int mapId) {
mazeDataP->synchronize(datSer);
datFile.close();
- if (isDarkCc && mapId == 50)
+ if (ccNum && mapId == 50)
mazeDataP->setAllTilesStepped();
- if (!isDarkCc && party._gameFlags[0][25] &&
+ if (!ccNum && party._gameFlags[0][25] &&
(mapId == 42 || mapId == 43 || mapId == 4)) {
mazeDataP->clearCellSurfaces();
}
@@ -747,20 +746,7 @@ void Map::load(int mapId) {
// Handle loading text data
if (!textLoaded) {
textLoaded = true;
-
- if (g_vm->getGameID() == GType_Clouds) {
- _mazeName = Res._cloudsMapNames[mapId];
- } else {
- Common::String txtName = Common::String::format("%s%c%03d.txt",
- isDarkCc ? "dark" : "xeen", mapId >= 100 ? 'x' : '0', mapId);
- File fText(txtName, 1);
- char mazeName[33];
- fText.read(mazeName, 33);
- mazeName[32] = '\0';
-
- _mazeName = Common::String(mazeName);
- fText.close();
- }
+ _mazeName = getMazeName(mapId, ccNum);
// Load the monster/object data
Common::String mobName = Common::String::format("maze%c%03d.mob",
@@ -776,7 +762,7 @@ void Map::load(int mapId) {
_headData.synchronize(headFile);
headFile.close();
- if (!isDarkCc && mapId == 15) {
+ if (!ccNum && mapId == 15) {
if ((_mobData._monsters[0]._position.x > 31 || _mobData._monsters[0]._position.y > 31) &&
(_mobData._monsters[1]._position.x > 31 || _mobData._monsters[1]._position.y > 31) &&
(_mobData._monsters[2]._position.x > 31 || _mobData._monsters[2]._position.y > 31)) {
@@ -808,13 +794,13 @@ void Map::load(int mapId) {
for (uint i = 0; i < _mobData._objectSprites.size(); ++i) {
files.setGameCc(_sideObjects);
- if (party._cloudsEnd && _mobData._objectSprites[i]._spriteId == 85 &&
- mapId == 27 && isDarkCc) {
+ if (party._cloudsCompleted && _mobData._objectSprites[i]._spriteId == 85 &&
+ mapId == 27 && ccNum) {
_mobData._objects[29]._spriteId = 0;
_mobData._objects[29]._id = 8;
_mobData._objectSprites[i]._sprites.clear();
} else if (mapId == 12 && party._gameFlags[0][43] &&
- _mobData._objectSprites[i]._spriteId == 118 && !isDarkCc) {
+ _mobData._objectSprites[i]._spriteId == 118 && !ccNum) {
filename = "085.obj";
_mobData._objectSprites[0]._spriteId = 85;
} else {
@@ -847,15 +833,15 @@ void Map::load(int mapId) {
_mobData._wallItemSprites[i]._sprites.load(filename, _sidePictures);
}
- files.setGameCc(isDarkCc);
+ files.setGameCc(ccNum);
// Handle loading miscellaneous sprites for the map
if (_isOutdoors) {
// Start playing relevant music
- sound._musicSide = isDarkCc;
+ sound._musicSide = ccNum;
Common::String musName;
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
int randIndex = _vm->getRandomNumber(6);
musName = Res.MUSIC_FILES2[_mazeData->_wallKind][randIndex];
} else {
@@ -884,16 +870,15 @@ void Map::load(int mapId) {
_surfaceSprites[i].load(Res.SURFACE_NAMES[_mazeData[0]._surfaceTypes[i]]);
}
} else {
- if (files._isDarkCc && (mapId == 125 || mapId == 126 || mapId == 127))
+ if (files._ccNum && (mapId == 125 || mapId == 126 || mapId == 127))
files.setGameCc(0);
- sound._musicSide = files._isDarkCc;
+ sound._musicSide = files._ccNum;
// Start playing relevant music
const int MUS_INDEXES[] = { 1, 2, 3, 4, 3, 5 };
Common::String musName;
- _sideMusic = isDarkCc;
- if (isDarkCc) {
+ if (files._ccNum) {
int randIndex = _vm->getRandomNumber(6);
musName = Res.MUSIC_FILES2[MUS_INDEXES[_mazeData->_wallKind]][randIndex];
} else {
@@ -987,7 +972,7 @@ void Map::load(int mapId) {
indoorList._ground._sprites = &_groundSprites;
// Don't show horizon for certain maps
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
if ((mapId >= 89 && mapId <= 112) || mapId == 128 || mapId == 129)
indoorList._horizon._sprites = nullptr;
} else {
@@ -996,9 +981,10 @@ void Map::load(int mapId) {
}
}
+ patcher.patch();
loadSky();
- files.setGameCc(isDarkCc);
+ files.setGameCc(ccNum);
}
void Map::findMap(int mapId) {
@@ -1066,7 +1052,8 @@ int Map::mazeLookup(const Common::Point &pt, int layerShift, int wallMask) {
_currentSurfaceId = _mazeData[_mazeDataIndex]._cells[pos.y][pos.x]._surfaceId;
}
- if (_currentSurfaceId == SURFTYPE_SPACE || _currentSurfaceId == SURFTYPE_SKY) {
+ if (mazeData()._surfaceTypes[_currentSurfaceId] == SURFTYPE_SPACE ||
+ mazeData()._surfaceTypes[_currentSurfaceId] == SURFTYPE_SKY) {
_currentSteppedOn = true;
} else {
_currentSteppedOn = _mazeData[_mazeDataIndex]._steppedOnTiles[pos.y][pos.x];
@@ -1080,11 +1067,11 @@ int Map::mazeLookup(const Common::Point &pt, int layerShift, int wallMask) {
}
}
-void Map::loadEvents(int mapId) {
+void Map::loadEvents(int mapId, int ccNum) {
// Load events
Common::String filename = Common::String::format("maze%c%03d.evt",
(mapId >= 100) ? 'x' : '0', mapId);
- File fEvents(filename);
+ File fEvents(filename, ccNum);
XeenSerializer sEvents(&fEvents, nullptr);
_events.synchronize(sEvents);
fEvents.close();
@@ -1092,7 +1079,7 @@ void Map::loadEvents(int mapId) {
// Load text data
filename = Common::String::format("aaze%c%03d.txt",
(mapId >= 100) ? 'x' : '0', mapId);
- File fText(filename);
+ File fText(filename, ccNum);
_events._text.clear();
while (fText.pos() < fText.size())
_events._text.push_back(fText.readString());
@@ -1114,7 +1101,7 @@ void Map::saveMap() {
FileManager &files = *g_vm->_files;
Party &party = *g_vm->_party;
int mapId = _mazeData[0]._mazeId;
- if (!files._isDarkCc && mapId == 85)
+ if (!files._ccNum && mapId == 85)
return;
// Save the primary maze
@@ -1124,7 +1111,7 @@ void Map::saveMap() {
_mazeData[0].synchronize(datSer);
datFile.finalize();
- if (!files._isDarkCc && mapId == 15) {
+ if (!files._ccNum && mapId == 15) {
for (uint idx = 0; idx < MIN(_mobData._monsters.size(), (uint)3); ++idx) {
MazeMonster &mon = _mobData._monsters[idx];
if (mon._position.x > 31 || mon._position.y > 31) {
@@ -1162,7 +1149,7 @@ void Map::saveMonsters() {
void Map::saveMaze() {
int mazeNum = _mazeData[0]._mazeNumber;
- if (!mazeNum || (mazeNum == 85 && !_vm->_files->_isDarkCc))
+ if (!mazeNum || (mazeNum == 85 && !_vm->_files->_ccNum))
return;
saveEvents();
@@ -1236,7 +1223,8 @@ void Map::setWall(const Common::Point &pt, Direction dir, int v) {
}
int Map::getCell(int idx) {
- int mapId = _vm->_party->_mazeId;
+ Party &party = *g_vm->_party;
+ int mapId = party._mazeId;
Direction dir = _vm->_party->_mazeDirection;
Common::Point pt(
_vm->_party->_mazePosition.x + Res.SCREEN_POSITIONING_X[_vm->_party->_mazeDirection][idx],
@@ -1244,7 +1232,7 @@ int Map::getCell(int idx) {
);
if (pt.x > 31 || pt.y > 31) {
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
if ((mapId >= 53 && mapId <= 88 && mapId != 73) || (mapId >= 74 && mapId <= 120) ||
mapId == 125 || mapId == 126 || mapId == 128 || mapId == 129) {
_currentSurfaceId = SURFTYPE_DESERT;
@@ -1270,12 +1258,14 @@ int Map::getCell(int idx) {
}
if (!mapId) {
+ mapId = party._mazeId;
+
if (_isOutdoors) {
_currentSurfaceId = SURFTYPE_SPACE;
_currentWall = 0;
return 0;
} else {
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
if ((mapId >= 53 && mapId <= 88 && mapId != 73) || (mapId >= 74 && mapId <= 120) ||
mapId == 125 || mapId == 126 || mapId == 128 || mapId == 129) {
_currentSurfaceId = 6;
@@ -1304,12 +1294,14 @@ int Map::getCell(int idx) {
}
if (!mapId) {
+ mapId = party._mazeId;
+
if (_isOutdoors) {
_currentSurfaceId = SURFTYPE_SPACE;
_currentWall = 0;
return 0;
} else {
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
if ((mapId >= 53 && mapId <= 88 && mapId != 73) || (mapId >= 74 && mapId <= 120) ||
mapId == 125 || mapId == 126 || mapId == 128 || mapId == 129) {
_currentSurfaceId = 6;
@@ -1404,4 +1396,24 @@ void Map::getNewMaze() {
load(mapId);
}
+Common::String Map::getMazeName(int mapId, int ccNum) {
+ if (ccNum == -1)
+ ccNum = g_vm->_files->_ccNum;
+
+ if (g_vm->getGameID() == GType_Clouds) {
+ return Res._cloudsMapNames[mapId];
+ } else {
+ Common::String txtName = Common::String::format("%s%c%03d.txt",
+ ccNum ? "dark" : "xeen", mapId >= 100 ? 'x' : '0', mapId);
+ File fText(txtName, 1);
+ char mazeName[33];
+ fText.read(mazeName, 33);
+ mazeName[32] = '\0';
+
+ Common::String name = Common::String(mazeName);
+ fText.close();
+ return name;
+ }
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/map.h b/engines/xeen/map.h
index a0bc77a7ec..1c00e549c3 100644
--- a/engines/xeen/map.h
+++ b/engines/xeen/map.h
@@ -42,11 +42,15 @@ namespace Xeen {
class XeenEngine;
enum MonsterType {
- MONSTER_0 = 0, MONSTER_ANIMAL = 1, MONSTER_INSECT = 2,
+ MONSTER_MONSTERS = 0, MONSTER_ANIMAL = 1, MONSTER_INSECT = 2,
MONSTER_HUMANOID = 3, MONSTER_UNDEAD = 4, MONSTER_GOLEM = 5,
MONSTER_DRAGON = 6
};
+enum MapId {
+ XEEN_CASTLE1 = 75, XEEN_CASTLE4 = 78
+};
+
class MonsterStruct {
public:
Common::String _name;
@@ -165,16 +169,16 @@ enum SurfaceType {
union MazeWallLayers {
struct MazeWallIndoors {
- int _wallNorth : 4;
- int _wallEast : 4;
- int _wallSouth : 4;
- int _wallWest : 4;
+ uint _wallNorth : 4;
+ uint _wallEast : 4;
+ uint _wallSouth : 4;
+ uint _wallWest : 4;
} _indoors;
struct MazeWallOutdoors {
- SurfaceType _surfaceId : 4;
- int _iMiddle : 4;
- int _iTop : 4;
- int _iOverlay : 4;
+ uint _surfaceId : 4; // SurfaceType, but needs to be unsigned
+ uint _iMiddle : 4;
+ uint _iTop : 4;
+ uint _iOverlay : 4;
} _outdoors;
uint16 _data;
};
@@ -318,7 +322,6 @@ public:
};
private:
XeenEngine *_vm;
- Common::Array<SpriteResourceEntry> _objectSprites;
Common::Array<SpriteResourceEntry> _monsterSprites;
Common::Array<SpriteResourceEntry> _monsterAttackSprites;
Common::Array<SpriteResourceEntry> _wallItemSprites;
@@ -326,6 +329,7 @@ public:
Common::Array<MazeObject> _objects;
Common::Array<MazeMonster> _monsters;
Common::Array<MazeWallItem> _wallItems;
+ Common::Array<SpriteResourceEntry> _objectSprites;
public:
MonsterObjectData(XeenEngine *vm);
@@ -403,13 +407,12 @@ private:
int _sidePictures;
int _sideObjects;
int _sideMonsters;
- int _sideMusic;
int _mazeDataIndex;
/**
* Load the events for a new map
*/
- void loadEvents(int mapId);
+ void loadEvents(int mapId, int ccNum);
/**
* Save the events for a map
@@ -454,7 +457,7 @@ public:
int _currentTile;
int _currentSurfaceId;
bool _currentSteppedOn;
- bool _loadDarkSide;
+ int _loadCcNum;
int _sideTownPortal;
public:
Map(XeenEngine *vm);
@@ -516,6 +519,13 @@ public:
* position to the relative position on the new map
*/
void getNewMaze();
+
+ /**
+ * Return the name of a specified maze
+ * @param mapId Map Id
+ * @param ccNum Cc file number. If -1, uses the current C
+ */
+ static Common::String getMazeName(int mapId, int ccNum = -1);
};
} // End of namespace Xeen
diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk
index 0154b8533b..5b3f69710f 100644
--- a/engines/xeen/module.mk
+++ b/engines/xeen/module.mk
@@ -6,7 +6,6 @@ MODULE_OBJS := \
worldofxeen/worldofxeen_cutscenes.o \
worldofxeen/worldofxeen_menu.o \
worldofxeen/worldofxeen.o \
- worldofxeen/worldofxeen_resources.o \
swordsofxeen/swordsofxeen.o \
swordsofxeen/swordsofxeen_menu.o \
dialogs/credits_screen.o \
@@ -14,6 +13,7 @@ MODULE_OBJS := \
dialogs/dialogs_awards.o \
dialogs/dialogs_char_info.o \
dialogs/dialogs_control_panel.o \
+ dialogs/dialogs_copy_protection.o \
dialogs/dialogs_create_char.o \
dialogs/dialogs_difficulty.o \
dialogs/dialogs_dismiss.o \
@@ -46,6 +46,7 @@ MODULE_OBJS := \
locations.o \
map.o \
party.o \
+ patcher.o \
resources.o \
saves.o \
screen.o \
diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp
index 3f0cdf0433..1fee0980d2 100644
--- a/engines/xeen/party.cpp
+++ b/engines/xeen/party.cpp
@@ -54,6 +54,14 @@ Roster::Roster() {
}
void Roster::synchronize(Common::Serializer &s) {
+ Party &party = *g_vm->_party;
+
+ if (s.isSaving()) {
+ // Copy out the party's characters back to the roster
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx)
+ (*this)[party._activeParty[idx]._rosterId] = party._activeParty[idx];
+ }
+
for (uint i = 0; i < TOTAL_CHARACTERS; ++i)
(*this)[i].synchronize(s);
}
@@ -70,6 +78,21 @@ Treasure::Treasure() {
_categories[3] = &_misc[0];
}
+void Treasure::clear() {
+ for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
+ _weapons[idx].clear();
+ _armor[idx].clear();
+ _accessories[idx].clear();
+ _misc[idx].clear();
+ }
+}
+
+void Treasure::reset() {
+ clear();
+ _hasItems = false;
+ _gold = _gems = 0;
+}
+
/*------------------------------------------------------------------------*/
const int BLACKSMITH_DATA1[4][4] = {
@@ -104,9 +127,7 @@ void BlacksmithWares::regenerate() {
ItemCategory itemCat = tempChar.makeItem(idx2 + 1, 0, 0);
if (catCount[itemCat] < 8) {
XeenItem &item = (*this)[itemCat][0][slotNum][catCount[itemCat]];
- item._id = tempChar._weapons[0]._id;
- item._material = tempChar._weapons[0]._material;
- item._bonusFlags = tempChar._weapons[0]._bonusFlags;
+ item = tempChar._items[itemCat][0];
++catCount[itemCat];
}
@@ -123,9 +144,7 @@ void BlacksmithWares::regenerate() {
ItemCategory itemCat = tempChar.makeItem(idx2 + (slotNum >= 2 ? 3 : 1), 0, 0);
if (catCount[itemCat] < 8) {
XeenItem &item = (*this)[itemCat][1][slotNum][catCount[itemCat]];
- item._id = tempChar._misc[0]._id;
- item._material = tempChar._misc[0]._material;
- item._bonusFlags = tempChar._misc[0]._bonusFlags;
+ item = tempChar._items[itemCat][0];
++catCount[itemCat];
}
@@ -135,21 +154,21 @@ void BlacksmithWares::regenerate() {
}
void BlacksmithWares::blackData2CharData(Character &c) {
- bool isDarkCc = g_vm->_files->_isDarkCc;
+ int ccNum = g_vm->_files->_ccNum;
int slotIndex = getSlotIndex();
for (ItemCategory cat = CATEGORY_WEAPON; cat <= CATEGORY_MISC; cat = (ItemCategory)((int)cat + 1))
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx)
- c._items[cat][idx] = (*this)[cat][isDarkCc][slotIndex][idx];
+ c._items[cat][idx] = (*this)[cat][ccNum][slotIndex][idx];
}
void BlacksmithWares::charData2BlackData(Character &c) {
- bool isDarkCc = g_vm->_files->_isDarkCc;
+ int ccNum = g_vm->_files->_ccNum;
int slotIndex = getSlotIndex();
for (ItemCategory cat = CATEGORY_WEAPON; cat <= CATEGORY_MISC; cat = (ItemCategory)((int)cat + 1))
for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx)
- (*this)[cat][isDarkCc][slotIndex][idx] = c._items[cat][idx];
+ (*this)[cat][ccNum][slotIndex][idx] = c._items[cat][idx];
}
BlacksmithItems &BlacksmithWares::operator[](ItemCategory category) {
@@ -163,10 +182,10 @@ BlacksmithItems &BlacksmithWares::operator[](ItemCategory category) {
uint BlacksmithWares::getSlotIndex() const {
Party &party = *g_vm->_party;
- bool isDarkCc = g_vm->_files->_isDarkCc;
+ int ccNum = g_vm->_files->_ccNum;
int slotIndex = 0;
- while (slotIndex < 4 && party._mazeId != (int)Res.BLACKSMITH_MAP_IDS[isDarkCc][slotIndex])
+ while (slotIndex < 4 && party._mazeId != (int)Res.BLACKSMITH_MAP_IDS[ccNum][slotIndex])
++slotIndex;
if (slotIndex == 4)
slotIndex = 0;
@@ -199,9 +218,9 @@ Party::Party(XeenEngine *vm) {
_holyBonus = 0;
_heroism = 0;
_difficulty = ADVENTURER;
- _cloudsEnd = false;
- _darkSideEnd = false;
- _worldEnd = false;
+ _cloudsCompleted = false;
+ _darkSideCompleted = false;
+ _worldCompleted = false;
_ctr24 = 0;
_day = 0;
_year = 0;
@@ -226,14 +245,12 @@ Party::Party(XeenEngine *vm) {
Common::fill(&_gameFlags[0][0], &_gameFlags[0][256], false);
Common::fill(&_gameFlags[1][0], &_gameFlags[1][256], false);
Common::fill(&_worldFlags[0], &_worldFlags[128], false);
- Common::fill(&_questFlags[0][0], &_questFlags[0][30], false);
- Common::fill(&_questFlags[1][0], &_questFlags[1][30], false);
+ Common::fill(&_questFlags[0], &_questFlags[60], false);
Common::fill(&_questItems[0], &_questItems[85], 0);
for (int i = 0; i < TOTAL_CHARACTERS; ++i)
Common::fill(&_characterFlags[i][0], &_characterFlags[i][24], false);
- _partyDead = false;
_newDay = false;
_isNight = false;
_stepped = false;
@@ -287,9 +304,9 @@ void Party::synchronize(Common::Serializer &s) {
_blacksmithWares.synchronize(s, 0);
- s.syncAsUint16LE(_cloudsEnd);
- s.syncAsUint16LE(_darkSideEnd);
- s.syncAsUint16LE(_worldEnd);
+ s.syncAsUint16LE(_cloudsCompleted);
+ s.syncAsUint16LE(_darkSideCompleted);
+ s.syncAsUint16LE(_worldCompleted);
s.syncAsUint16LE(_ctr24);
s.syncAsUint16LE(_day);
s.syncAsUint16LE(_year);
@@ -313,8 +330,7 @@ void Party::synchronize(Common::Serializer &s) {
File::syncBitFlags(s, &_gameFlags[0][0], &_gameFlags[0][256]);
File::syncBitFlags(s, &_gameFlags[1][0], &_gameFlags[1][256]);
File::syncBitFlags(s, &_worldFlags[0], &_worldFlags[128]);
- File::syncBitFlags(s, &_questFlags[0][0], &_questFlags[0][30]);
- File::syncBitFlags(s, &_questFlags[1][0], &_questFlags[1][30]);
+ File::syncBitFlags(s, &_questFlags[0], &_questFlags[60]);
for (int i = 0; i < 85; ++i)
s.syncAsByte(_questItems[i]);
@@ -324,6 +340,10 @@ void Party::synchronize(Common::Serializer &s) {
for (int i = 0; i < TOTAL_CHARACTERS; ++i)
File::syncBitFlags(s, &_characterFlags[i][0], &_characterFlags[i][24]);
s.syncBytes(&dummy[0], 30);
+
+ if (s.isLoading())
+ _newDay = _minutes < 300;
+ _dead = false;
}
void Party::loadActiveParty() {
@@ -444,8 +464,12 @@ void Party::changeTime(int numMinutes) {
}
}
- player._conditions[WEAK] = player._conditions[DRUNK];
- player._conditions[DRUNK] = 0;
+ // WORKAROUND: Original incorrectly reset weakness (due to lack of sleep) even when party
+ // wasn't drunk. We now have any resetting drunkness add to, rather than replace, weakness
+ if (player._conditions[WEAK] != -1) {
+ player._conditions[WEAK] += player._conditions[DRUNK];
+ player._conditions[DRUNK] = 0;
+ }
if (player._conditions[DEPRESSED]) {
player._conditions[DEPRESSED] = (player._conditions[DEPRESSED] + 1) % 4;
@@ -502,7 +526,7 @@ void Party::addTime(int numMinutes) {
_newDay = true;
if (_newDay && _minutes >= 300) {
- if (_vm->_mode != MODE_RECORD_EVENTS && _vm->_mode != MODE_17) {
+ if (_vm->_mode != MODE_SCRIPT_IN_PROGRESS && _vm->_mode != MODE_INTERACTIVE7) {
resetTemps();
if (_rested || _vm->_mode == MODE_SLEEPING) {
_rested = false;
@@ -673,11 +697,8 @@ void Party::giveTreasure() {
if (!_treasure._hasItems && !_treasure._gold && !_treasure._gems)
return;
- bool monstersPresent = false;
- for (int idx = 0; idx < 26 && !monstersPresent; ++idx)
- monstersPresent = combat._attackMonsters[idx] != -1;
-
- if (_vm->_mode != MODE_RECORD_EVENTS && monstersPresent)
+ bool monstersPresent = combat.areMonstersPresent();
+ if (_vm->_mode != MODE_SCRIPT_IN_PROGRESS && monstersPresent)
return;
combat.clearShooting();
@@ -702,18 +723,13 @@ void Party::giveTreasure() {
for (int categoryNum = 0; categoryNum < NUM_ITEM_CATEGORIES; ++categoryNum) {
for (int itemNum = 0; itemNum < MAX_TREASURE_ITEMS; ++itemNum) {
if (arePacksFull()) {
- if (_treasure._weapons[itemNum]._id == 34) {
- // Important item, so clear a slot for it
+ if (_treasure._weapons[itemNum]._id >= XEEN_SLAYER_SWORD) {
+ // Xeen Slayer Sword, so clear a slot for it
_activeParty[0]._weapons[INV_ITEMS_TOTAL - 1].clear();
} else {
// Otherwise, clear all the remaining treasure items,
// since all the party's packs are full
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- _treasure._weapons[idx].clear();
- _treasure._armor[idx].clear();
- _treasure._accessories[idx].clear();
- _treasure._armor[idx].clear();
- }
+ _treasure.clear();
}
}
@@ -767,7 +783,7 @@ void Party::giveTreasure() {
events.clearEvents();
if (_vm->_mode != MODE_COMBAT)
- _vm->_mode = MODE_1;
+ _vm->_mode = MODE_INTERACTIVE;
w.close();
_gold += _treasure._gold;
@@ -776,13 +792,7 @@ void Party::giveTreasure() {
_treasure._gems = 0;
_treasure._hasItems = false;
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- _treasure._weapons[idx].clear();
- _treasure._armor[idx].clear();
- _treasure._accessories[idx].clear();
- _treasure._armor[idx].clear();
- }
-
+ _treasure.clear();
combat._combatTarget = 1;
}
@@ -790,10 +800,10 @@ bool Party::arePacksFull() const {
uint total = 0;
for (uint idx = 0; idx < _activeParty.size(); ++idx) {
const Character &c = _activeParty[idx];
- total += (c._weapons[INV_ITEMS_TOTAL - 1]._id != 0 ? 1 : 0)
- + (c._armor[INV_ITEMS_TOTAL - 1]._id != 0 ? 1 : 0)
- + (c._accessories[INV_ITEMS_TOTAL - 1]._id != 0 ? 1 : 0)
- + (c._misc[INV_ITEMS_TOTAL - 1]._id != 0 ? 1 : 0);
+ total += (c._weapons[INV_ITEMS_TOTAL - 1].empty() ? 0 : 1)
+ + (c._armor[INV_ITEMS_TOTAL - 1].empty() ? 0 : 1)
+ + (c._accessories[INV_ITEMS_TOTAL - 1].empty() ? 0 : 1)
+ + (c._misc[INV_ITEMS_TOTAL - 1].empty() ? 0 : 1);
}
return total == (_activeParty.size() * NUM_ITEM_CATEGORIES);
@@ -816,11 +826,20 @@ void Party::giveTreasureToCharacter(Character &c, ItemCategory category, int ite
w.update();
events.ipause(5);
- const char *itemName = XeenItem::getItemName(category, treasureItem._id);
- w.writeString(Common::String::format(Res.X_FOUND_Y, c._name.c_str(), itemName));
+ int index = (category == CATEGORY_MISC) ? treasureItem._material : treasureItem._id;
+ const char *itemName = XeenItem::getItemName(category, index);
+
+ if (index >= (_vm->getGameID() == GType_Swords ? 88 : 82)) {
+ // Quest item, give an extra '*' prefix
+ Common::String format = Common::String::format("\f04 * \fd%s", itemName);
+ w.writeString(Common::String::format(Res.X_FOUND_Y, c._name.c_str(), format.c_str()));
+ } else {
+ w.writeString(Common::String::format(Res.X_FOUND_Y, c._name.c_str(), itemName));
+ }
+
w.update();
c._items[category].sort();
- events.ipause(5);
+ events.ipause(8);
}
bool Party::canShoot() const {
@@ -880,7 +899,7 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
ps._tempAge -= takeVal;
break;
case 13:
- ps._skills[THIEVERY] = 0;
+ ps._skills[takeVal] = 0;
break;
case 15:
ps.setAward(takeVal, false);
@@ -895,26 +914,11 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
ps._conditions[takeVal] = 0;
break;
case 19: {
- int idx2 = 0;
- switch (ps._class) {
- case CLASS_PALADIN:
- case CLASS_CLERIC:
- idx2 = 0;
- break;
- case CLASS_ARCHER:
- case CLASS_SORCERER:
- idx2 = 1;
- break;
- case CLASS_DRUID:
- case CLASS_RANGER:
- idx2 = 2;
- break;
- default:
- break;
- }
+ SpellsCategory category = ps.getSpellsCategory();
+ assert(category != SPELLCAT_INVALID);
- for (int idx = 0; idx < 39; ++idx) {
- if (Res.SPELLS_ALLOWED[idx2][idx] == (int)takeVal) {
+ for (int idx = 0; idx < SPELLS_PER_CLASS; ++idx) {
+ if (Res.SPELLS_ALLOWED[category][idx] == (int)takeVal) {
ps._spells[idx] = false;
break;
}
@@ -922,45 +926,53 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
break;
}
case 20:
- _gameFlags[files._isDarkCc][takeVal] = false;
+ assert(takeVal < 256);
+ _gameFlags[_vm->getGameID() == GType_Swords ? 0 : files._ccNum][takeVal] = false;
break;
case 21: {
- bool found = false;
- for (int idx = 0; idx < 9; ++idx) {
- if (takeVal < 35) {
- if (ps._weapons[idx]._id == takeVal) {
- ps._weapons[idx].clear();
- ps._weapons.sort();
- found = true;
- break;
- }
- } else if (takeVal < 49) {
- if (ps._armor[idx]._id == (takeVal - 35)) {
- ps._armor[idx].clear();
- ps._armor.sort();
- found = true;
- break;
- }
- } else if (takeVal < 60) {
- if (ps._accessories[idx]._id == (takeVal - 49)) {
- ps._accessories[idx].clear();
- ps._accessories.sort();
- found = true;
- break;
- }
- } else if (takeVal < 82) {
- if (ps._misc[idx]._material == ((int)takeVal - 60)) {
- ps._misc[idx].clear();
- ps._misc.sort();
- found = true;
- break;
+ const uint WEAPONS_END = _vm->getGameID() != GType_Swords ? 35 : 41;
+ const uint ARMOR_END = _vm->getGameID() != GType_Swords ? 49 : 55;
+ const uint ACCESSORIES_END = _vm->getGameID() != GType_Swords ? 60 : 66;
+ const uint MISC_END = _vm->getGameID() != GType_Swords ? 82 : 88;
+
+ if (takeVal >= MISC_END) {
+ _questItems[takeVal - MISC_END]--;
+ } else {
+ bool found = false;
+ for (int idx = 0; idx < 9; ++idx) {
+ if (takeVal < WEAPONS_END) {
+ if (ps._weapons[idx]._id == takeVal) {
+ ps._weapons[idx].clear();
+ ps._weapons.sort();
+ found = true;
+ break;
+ }
+ } else if (takeVal < ARMOR_END) {
+ if (ps._armor[idx]._id == (takeVal - WEAPONS_END)) {
+ ps._armor[idx].clear();
+ ps._armor.sort();
+ found = true;
+ break;
+ }
+ } else if (takeVal < ACCESSORIES_END) {
+ if (ps._accessories[idx]._id == (takeVal - ARMOR_END)) {
+ ps._accessories[idx].clear();
+ ps._accessories.sort();
+ found = true;
+ break;
+ }
+ } else {
+ if (ps._misc[idx]._material == (int)(takeVal - ACCESSORIES_END)) {
+ ps._misc[idx].clear();
+ ps._misc.sort();
+ found = true;
+ break;
+ }
}
- } else {
- _questItems[takeVal - 82]--;
}
+ if (!found)
+ return true;
}
- if (!found)
- return true;
break;
}
case 25:
@@ -1099,7 +1111,7 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
_worldFlags[takeVal] = false;
break;
case 104:
- _questFlags[files._isDarkCc][takeVal] = false;
+ _questFlags[(_vm->getGameID() == GType_Swords ? 0 : files._ccNum * 30) + takeVal] = false;
break;
case 107:
_characterFlags[ps._rosterId][takeVal] = false;
@@ -1137,6 +1149,7 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
case 13:
assert(giveVal < 18);
ps._skills[giveVal]++;
+ intf.spellFX(&ps);
break;
case 15:
ps.setAward(giveVal, true);
@@ -1164,66 +1177,59 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
ps._currentHp = 0;
break;
case 19: {
- int idx2 = 0;
- switch (ps._class) {
- case CLASS_PALADIN:
- case CLASS_CLERIC:
- idx2 = 0;
- break;
- case CLASS_ARCHER:
- case CLASS_SORCERER:
- idx2 = 1;
- break;
- case CLASS_DRUID:
- case CLASS_RANGER:
- idx2 = 2;
- break;
- default:
- break;
- }
-
- for (int idx = 0; idx < 39; ++idx) {
- if (Res.SPELLS_ALLOWED[idx2][idx] == (int)giveVal) {
- ps._spells[idx] = true;
- intf.spellFX(&ps);
- break;
+ // Give spell to character
+ SpellsCategory category = ps.getSpellsCategory();
+
+ if (category != SPELLCAT_INVALID) {
+ for (int idx = 0; idx < SPELLS_PER_CLASS; ++idx) {
+ if (Res.SPELLS_ALLOWED[category][idx] == (int)giveVal) {
+ ps._spells[idx] = true;
+ intf.spellFX(&ps);
+ break;
+ }
}
}
break;
}
case 20:
- _gameFlags[files._isDarkCc][giveVal] = true;
+ assert(giveVal < 256);
+ _gameFlags[_vm->getGameID() == GType_Swords ? 0 : files._ccNum][giveVal] = true;
break;
case 21: {
+ const uint WEAPONS_END = _vm->getGameID() != GType_Swords ? 35 : 41;
+ const uint ARMOR_END = _vm->getGameID() != GType_Swords ? 49 : 55;
+ const uint ACCESSORIES_END = _vm->getGameID() != GType_Swords ? 60 : 66;
+ const uint MISC_END = _vm->getGameID() != GType_Swords ? 82 : 88;
+
int idx;
- if (giveVal >= 82) {
- _questItems[giveVal - 82]++;
+ if (giveVal >= MISC_END) {
+ _questItems[giveVal - MISC_END]++;
}
- if (giveVal < 35 || giveVal >= 82) {
- for (idx = 0; idx < 10 && _treasure._weapons[idx]._id; ++idx);
- if (idx < 10) {
+ if (giveVal < WEAPONS_END || giveVal >= MISC_END) {
+ for (idx = 0; idx < MAX_TREASURE_ITEMS && !_treasure._weapons[idx].empty(); ++idx) {}
+ if (idx < MAX_TREASURE_ITEMS) {
_treasure._weapons[idx]._id = giveVal;
_treasure._hasItems = true;
return false;
}
- } else if (giveVal < 49) {
- for (idx = 0; idx < 10 && _treasure._armor[idx]._id; ++idx);
- if (idx < 10) {
- _treasure._armor[idx]._id = giveVal - 35;
+ } else if (giveVal < ARMOR_END) {
+ for (idx = 0; idx < MAX_TREASURE_ITEMS && !_treasure._armor[idx].empty(); ++idx) {}
+ if (idx < MAX_TREASURE_ITEMS) {
+ _treasure._armor[idx]._id = giveVal - WEAPONS_END;
_treasure._hasItems = true;
return false;
}
- } else if (giveVal < 60) {
- for (idx = 0; idx < 10 && _treasure._accessories[idx]._id; ++idx);
- if (idx < 10) {
- _treasure._accessories[idx]._id = giveVal - 49;
+ } else if (giveVal < ACCESSORIES_END) {
+ for (idx = 0; idx < MAX_TREASURE_ITEMS && !_treasure._accessories[idx].empty(); ++idx) {}
+ if (idx < MAX_TREASURE_ITEMS) {
+ _treasure._accessories[idx]._id = giveVal - ARMOR_END;
_treasure._hasItems = true;
return false;
}
} else {
- for (idx = 0; idx < 10 && _treasure._misc[idx]._material; ++idx);
- if (idx < 10) {
- _treasure._accessories[idx]._material = giveVal - 60;
+ for (idx = 0; idx < MAX_TREASURE_ITEMS && _treasure._misc[idx]._material; ++idx) {}
+ if (idx < MAX_TREASURE_ITEMS) {
+ _treasure._accessories[idx]._material = giveVal - ACCESSORIES_END;
_treasure._hasItems = true;
return false;
}
@@ -1355,7 +1361,7 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
Character &tempChar = _itemsCharacter;
int idx = -1;
if (scripts._itemType != 0) {
- for (idx = 0; idx < 10 && _treasure._misc[idx]._material; ++idx);
+ for (idx = 0; idx < 10 && _treasure._misc[idx]._material; ++idx) {}
if (idx == 10)
return true;
}
@@ -1366,14 +1372,14 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
XeenItem *trItems = _treasure[itemCat];
// Check for a free treasure slot
- for (idx = 0; idx < 10 && trItems[idx]._id; ++idx);
+ for (idx = 0; idx < 10 && trItems[idx]._id; ++idx) {}
if (idx == 10)
return true;
// Found a free slot, so copy the created item into it
trItems[idx]._material = srcItem._material;
trItems[idx]._id = srcItem._id;
- trItems[idx]._bonusFlags = srcItem._bonusFlags;
+ trItems[idx]._state = srcItem._state;
_treasure._hasItems = true;
break;
}
@@ -1435,16 +1441,16 @@ bool Party::giveTake(int takeMode, uint takeVal, int giveMode, uint giveVal, int
_gold += _vm->getRandomNumber(1, giveVal);
break;
case 103:
- assert(takeVal < 128);
- _worldFlags[takeVal] = true;
+ assert(giveVal < (uint)(_vm->getGameID() == GType_Swords ? 49 : 128));
+ _worldFlags[giveVal] = true;
break;
case 104:
- assert(giveVal < 30);
- _questFlags[files._isDarkCc][giveVal] = true;
+ assert(giveVal < (uint)(_vm->getGameID() == GType_Swords ? 60 : 30));
+ _questFlags[(_vm->getGameID() == GType_Swords ? 0 : files._ccNum * 30) + giveVal] = true;
break;
case 107:
- assert(takeVal < 24);
- _characterFlags[ps._rosterId][takeVal] = true;
+ assert(giveVal < 24);
+ _characterFlags[ps._rosterId][giveVal] = true;
break;
default:
break;
@@ -1460,19 +1466,21 @@ bool Party::giveExt(int mode1, uint val1, int mode2, uint val2, int mode3, uint
Map &map = *g_vm->_map;
Scripts &scripts = *g_vm->_scripts;
Sound &sound = *g_vm->_sound;
- Character &c = _itemsCharacter;
- if (intf._objNumber && !scripts._animCounter) {
- MazeObject &obj = map._mobData._objects[intf._objNumber - 1];
+ // WORKAROUND: Ali Baba's chest in Dark Side requires the character in the first slot to have Lockpicking.
+ // This is obviously a mistake, since the chest is meant to be opened via a password
+ if (intf._objNumber != -1 && !scripts._animCounter && !(files._ccNum && _mazeId == 63 && intf._objNumber == 15)) {
+ MazeObject &obj = map._mobData._objects[intf._objNumber];
switch (obj._spriteId) {
case 15:
- if (!files._isDarkCc)
+ if (!files._ccNum)
break;
// Intentional fall-through
case 16:
case 58:
- case 73:
+ case 73: {
+ Character &c = _activeParty[charId];
obj._frame = 1;
if (obj._position.x != 20) {
@@ -1490,19 +1498,24 @@ bool Party::giveExt(int mode1, uint val1, int mode2, uint val2, int mode3, uint
sound.playFX(10);
intf.draw3d(true, false);
Common::String msg = Common::String::format(Res.PICKS_THE_LOCK, c._name.c_str());
- ErrorScroll::show(g_vm, msg);
+ ErrorScroll::show(g_vm, msg, WT_NONFREEZED_WAIT);
} else {
sound.playFX(21);
obj._frame = 0;
scripts._animCounter = 0;
Common::String msg = Common::String::format(Res.UNABLE_TO_PICK_LOCK, c._name.c_str());
- ErrorScroll::show(g_vm, msg);
+ ErrorScroll::show(g_vm, msg, WT_NONFREEZED_WAIT);
scripts._animCounter = 255;
return true;
}
}
+ break;
+ }
+
+ default:
+ break;
}
}
@@ -1520,7 +1533,7 @@ bool Party::giveExt(int mode1, uint val1, int mode2, uint val2, int mode3, uint
break;
case 66:
- c.clear();
+ _itemsCharacter.clear();
if (giveTake(0, 0, mode, val, charId))
return true;
@@ -1590,7 +1603,7 @@ uint Party::getScore() {
uint time = _vm->_events->playTime() / GAME_FRAME_RATE;
int minutes = (time % 3600) / 60;
int hours = time / 3600;
-
+
score += minutes + (hours * 100);
return score;
}
diff --git a/engines/xeen/party.h b/engines/xeen/party.h
index 881b1502c5..fde6defeee 100644
--- a/engines/xeen/party.h
+++ b/engines/xeen/party.h
@@ -53,6 +53,7 @@ enum PartyBank {
#define MAX_PARTY_COUNT 8
#define TOTAL_STATS 7
#define TOTAL_QUEST_ITEMS 85
+#define TOTAL_QUEST_ITEMS_SWORDS 51
#define TOTAL_QUEST_FLAGS 56
#define MAX_TREASURE_ITEMS 10
@@ -81,6 +82,16 @@ public:
* Returns a particular category's array
*/
XeenItem *operator[](int category) { return _categories[category]; }
+
+ /**
+ * Clears the treasure list
+ */
+ void clear();
+
+ /**
+ * Completely reset the treasure data
+ */
+ void reset();
};
/**
@@ -184,9 +195,9 @@ public:
int _heroism;
Difficulty _difficulty;
BlacksmithWares _blacksmithWares;
- bool _cloudsEnd;
- bool _darkSideEnd;
- bool _worldEnd;
+ bool _cloudsCompleted;
+ bool _darkSideCompleted;
+ bool _worldCompleted;
int _ctr24; // Unused counter
int _day;
uint _year;
@@ -209,14 +220,13 @@ public:
bool _rested;
bool _gameFlags[2][256];
bool _worldFlags[128];
- bool _questFlags[2][30];
+ bool _questFlags[60];
int _questItems[TOTAL_QUEST_ITEMS];
bool _characterFlags[30][24];
public:
// Other party related runtime data
Roster _roster;
- Common::Array<Character> _activeParty;
- bool _partyDead;
+ CharacterArray _activeParty;
bool _newDay;
bool _isNight;
bool _stepped;
diff --git a/engines/xeen/patcher.cpp b/engines/xeen/patcher.cpp
new file mode 100644
index 0000000000..10c8664776
--- /dev/null
+++ b/engines/xeen/patcher.cpp
@@ -0,0 +1,101 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "xeen/patcher.h"
+#include "xeen/xeen.h"
+#include "xeen/map.h"
+#include "xeen/party.h"
+#include "common/memstream.h"
+#include "common/serializer.h"
+
+namespace Xeen {
+
+struct ScriptEntry {
+ uint _gameId;
+ int _mapId;
+ const byte *_data;
+};
+
+const byte DS_MAP54_LINE8[] = { 8, 10, 10, DIR_EAST, 8, OP_MoveWallObj, 20, 100, 100 };
+const byte SW_MAP53_LINE8[] = { 5, 14, 6, DIR_EAST, 8, OP_Exit };
+const byte DS_MAP116[] = { 9, 10, 6, 4, 2, OP_TakeOrGive, 0, 0, 103, 127 };
+
+#define SCRIPT_PATCHES_COUNT 3
+static const ScriptEntry SCRIPT_PATCHES[] = {
+ { GType_DarkSide, 54, DS_MAP54_LINE8 }, // Fix curtain on level 2 of Ellinger's Tower
+ { GType_Swords, 53, SW_MAP53_LINE8 }, // Fix chest in Hart having gems, but saying "Nothing Here"
+ { GType_DarkSide, 116, DS_MAP116 } // Fix statue in Dark Tower setting invalid world flag
+};
+
+/*------------------------------------------------------------------------*/
+
+void Patcher::patch() {
+ patchScripts();
+ patchObjects();
+}
+
+void Patcher::patchScripts() {
+ FileManager &files = *g_vm->_files;
+ Map &map = *g_vm->_map;
+ Party &party = *g_vm->_party;
+
+ uint gameId = g_vm->getGameID();
+ if (gameId == GType_WorldOfXeen)
+ gameId = files._ccNum ? GType_DarkSide : GType_Clouds;
+
+ for (int patchIdx = 0; patchIdx < SCRIPT_PATCHES_COUNT; ++patchIdx) {
+ const ScriptEntry &se = SCRIPT_PATCHES[patchIdx];
+ if (se._gameId != gameId || se._mapId != party._mazeId)
+ continue;
+
+ MazeEvent evt;
+ Common::MemoryReadStream memStream(se._data, se._data[0] + 1);
+ Common::Serializer s(&memStream, nullptr);
+ evt.synchronize(s);
+
+ // Scan through the events to find a matching line
+ int idx = 0;
+ while (idx < (int)map._events.size() && (evt._position != map._events[idx]._position
+ || evt._direction != map._events[idx]._direction || evt._line != map._events[idx]._line))
+ ++idx;
+
+ // Set the event
+ if (idx == (int)map._events.size())
+ map._events.push_back(evt);
+ else
+ map._events[idx] = evt;
+ }
+}
+
+void Patcher::patchObjects() {
+ FileManager &files = *g_vm->_files;
+ Map &map = *g_vm->_map;
+ Party &party = *g_vm->_party;
+
+ if ((g_vm->getGameID() == GType_Clouds || (g_vm->getGameID() == GType_WorldOfXeen && !files._ccNum)) &&
+ party._mazeId == 24) {
+ // Remove floating statue in the distance off SE corner of Clouds of Xeen map
+ map._mobData._objects[15]._position = Common::Point(-128, -128);
+ }
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_resources.h b/engines/xeen/patcher.h
index e69f52028d..24d6cd5a8d 100644
--- a/engines/xeen/worldofxeen/worldofxeen_resources.h
+++ b/engines/xeen/patcher.h
@@ -20,29 +20,34 @@
*
*/
-#ifndef XEEN_WORLDOFXEEN_RESOURCES_H
-#define XEEN_WORLDOFXEEN_RESOURCES_H
-
-#include "xeen/resources.h"
+#ifndef XEEN_PATCHER_H
+#define XEEN_PATCHER_H
namespace Xeen {
-namespace WorldOfXeen {
-#ifdef Res
-#undef Res
-#endif
-#define Res (*(WorldOfXeenResources *)g_resources)
+class Patcher {
+private:
+ /**
+ * Patches incorrect script lines
+ */
+ void patchScripts();
-class WorldOfXeenResources : public Resources {
+ /**
+ * Patches incorrect map objects
+ */
+ void patchObjects();
public:
- static const char *const CLOUDS_INTRO1;
- static const char *const DARKSIDE_ENDING1;
- static const char *const DARKSIDE_ENDING2;
- static const char *const PHAROAH_ENDING_TEXT1;
- static const char *const PHAROAH_ENDING_TEXT2;
+ /**
+ * Constructor
+ */
+ Patcher() {}
+
+ /**
+ * Called after a map is loaded to patch any problems
+ */
+ void patch();
};
-} // End of namespace WorldOfXeen
} // End of namespace Xeen
-#endif /* XEEN_RESOURCES_H */
+#endif /* XEEN_PATCHER_H */
diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp
index c2732a9bf9..160c60a7a9 100644
--- a/engines/xeen/resources.cpp
+++ b/engines/xeen/resources.cpp
@@ -24,7 +24,6 @@
#include "xeen/resources.h"
#include "xeen/files.h"
#include "xeen/xeen.h"
-#include "xeen/worldofxeen/worldofxeen_resources.h"
namespace Xeen {
@@ -33,7 +32,7 @@ Resources *g_resources;
Resources::Resources() {
g_resources = this;
g_vm->_files->setGameCc(1);
-
+
_globalSprites.load("global.icn");
if (g_vm->getGameID() == GType_Swords)
_logoSprites.load("logo.int");
@@ -72,6 +71,7 @@ void Resources::loadData() {
file.syncString(WHO_WILL);
file.syncString(HOW_MUCH);
file.syncString(WHATS_THE_PASSWORD);
+ file.syncString(PASSWORD_INCORRECT);
file.syncString(IN_NO_CONDITION);
file.syncString(NOTHING_HERE);
file.syncStrings(TERRAIN_TYPES, 6);
@@ -165,7 +165,7 @@ void Resources::loadData() {
file.syncString(FOOD_AND_DRINK);
file.syncString(TEMPLE_TEXT);
file.syncString(EXPERIENCE_FOR_LEVEL);
- file.syncString(LEARNED_ALL);
+ file.syncString(TRAINING_LEARNED_ALL);
file.syncString(ELIGIBLE_FOR_LEVEL);
file.syncString(TRAINING_TEXT);
file.syncString(GOLD_GEMS);
@@ -182,18 +182,20 @@ void Resources::loadData() {
file.syncString(GUILD_OPTIONS);
file.syncNumbers((int *)MISC_SPELL_INDEX, 74);
file.syncNumbers((int *)SPELL_COSTS, 77);
- file.syncNumbers2D((int *)CLOUDS_SPELL_OFFSETS, 5, 20);
+ file.syncNumbers2D((int *)CLOUDS_GUILD_SPELLS, 5, 20);
file.syncNumbers2D((int *)DARK_SPELL_OFFSETS, 3, 39);
file.syncNumbers2D((int *)DARK_SPELL_RANGES, 12, 2);
+ file.syncNumbers2D((int *)SWORDS_SPELL_RANGES, 12, 2);
file.syncNumbers((int *)SPELL_GEM_COST, 77);
file.syncString(NOT_A_SPELL_CASTER);
+ file.syncString(SPELLS_LEARNED_ALL);
file.syncString(SPELLS_FOR);
file.syncString(SPELL_LINES_0_TO_9);
file.syncString(SPELLS_DIALOG_SPELLS);
file.syncString(SPELL_PTS);
file.syncString(GOLD);
- file.syncString(SPELLS_PRESS_A_KEY);
- file.syncString(SPELLS_PURCHASE);
+ file.syncString(SPELL_INFO);
+ file.syncString(SPELL_PURCHASE);
file.syncString(MAP_TEXT);
file.syncString(LIGHT_COUNT_TEXT);
file.syncString(FIRE_RESISTENCE_TEXT);
@@ -247,15 +249,18 @@ void Resources::loadData() {
file.syncString(BTN_GOLD);
file.syncString(ITEM_BROKEN);
file.syncString(ITEM_CURSED);
+ file.syncString(ITEM_OF);
file.syncStrings(BONUS_NAMES, 7);
- file.syncStrings(WEAPON_NAMES, 35);
+ file.syncStrings(WEAPON_NAMES, 41);
file.syncStrings(ARMOR_NAMES, 14);
file.syncStrings(ACCESSORY_NAMES, 11);
file.syncStrings(MISC_NAMES, 22);
+ file.syncStrings(SPECIAL_NAMES, 74);
file.syncStrings(ELEMENTAL_NAMES, 6);
file.syncStrings(ATTRIBUTE_NAMES, 10);
file.syncStrings(EFFECTIVENESS_NAMES, 7);
file.syncStrings(QUEST_ITEM_NAMES, 85);
+ file.syncStrings(QUEST_ITEM_NAMES_SWORDS, 51);
file.syncNumbers((int *)WEAPON_BASE_COSTS, 35);
file.syncNumbers((int *)ARMOR_BASE_COSTS, 14);
file.syncNumbers((int *)ACCESSORY_BASE_COSTS, 11);
@@ -310,6 +315,7 @@ void Resources::loadData() {
file.syncString(QUESTS_DIALOG_TEXT);
file.syncString(CLOUDS_OF_XEEN_LINE);
file.syncString(DARKSIDE_OF_XEEN_LINE);
+ file.syncString(SWORDS_OF_XEEN_LINE);
file.syncString(NO_QUEST_ITEMS);
file.syncString(NO_CURRENT_QUESTS);
file.syncString(NO_AUTO_NOTES);
@@ -322,6 +328,7 @@ void Resources::loadData() {
file.syncString(TOO_DANGEROUS_TO_REST);
file.syncString(SOME_CHARS_MAY_DIE);
file.syncString(CANT_DISMISS_LAST_CHAR);
+ file.syncString(DELETE_CHAR_WITH_ELDER_WEAPON);
file.syncStrings(REMOVE_DELETE, 2);
file.syncString(REMOVE_OR_DELETE_WHICH);
file.syncString(YOUR_PARTY_IS_FULL);
@@ -333,6 +340,7 @@ void Resources::loadData() {
file.syncString(SELECT_CLASS_BEFORE_SAVING);
file.syncString(EXCHANGE_ATTR_WITH);
file.syncNumbers((int *)NEW_CHAR_SKILLS, 10);
+ file.syncNumbers((int *)NEW_CHAR_SKILLS_OFFSET, 10);
file.syncNumbers((int *)NEW_CHAR_SKILLS_LEN, 10);
file.syncNumbers((int *)NEW_CHAR_RACE_SKILLS, 10);
file.syncNumbers((int *)RACE_MAGIC_RESISTENCES, 5);
@@ -358,7 +366,8 @@ void Resources::loadData() {
file.syncString(LLOYDS_BEACON);
file.syncString(HOW_MANY_SQUARES);
file.syncString(TOWN_PORTAL);
- file.syncNumbers2D((int *)TOWN_MAP_NUMBERS, 2, 5);
+ file.syncString(TOWN_PORTAL_SWORDS);
+ file.syncNumbers2D((int *)TOWN_MAP_NUMBERS, 3, 5);
file.syncString(MONSTER_DETAILS);
file.syncStrings(MONSTER_SPECIAL_ATTACKS, 23);
file.syncString(IDENTIFY_MONSTERS);
@@ -392,6 +401,12 @@ void Resources::loadData() {
file.syncStrings(MUSIC_FILES1, 5);
file.syncStrings2D(&MUSIC_FILES2[0][0], 6, 7);
file.syncString(DIFFICULTY_TEXT);
+ file.syncString(SAVE_OFF_LIMITS);
+ file.syncString(CLOUDS_INTRO1);
+ file.syncString(DARKSIDE_ENDING1);
+ file.syncString(DARKSIDE_ENDING2);
+ file.syncString(PHAROAH_ENDING_TEXT1);
+ file.syncString(PHAROAH_ENDING_TEXT2);
}
} // End of namespace Xeen
diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h
index 0659de45c9..55f0ed3413 100644
--- a/engines/xeen/resources.h
+++ b/engines/xeen/resources.h
@@ -126,6 +126,7 @@ public:
const char *WHO_WILL;
const char *HOW_MUCH;
const char *WHATS_THE_PASSWORD;
+ const char *PASSWORD_INCORRECT;
const char *IN_NO_CONDITION;
const char *NOTHING_HERE;
const char *TERRAIN_TYPES[6];
@@ -219,7 +220,7 @@ public:
const char *FOOD_AND_DRINK;
const char *TEMPLE_TEXT;
const char *EXPERIENCE_FOR_LEVEL;
- const char *LEARNED_ALL;
+ const char *TRAINING_LEARNED_ALL;
const char *ELIGIBLE_FOR_LEVEL;
const char *TRAINING_TEXT;
const char *GOLD_GEMS;
@@ -236,19 +237,20 @@ public:
const char *GUILD_OPTIONS;
int MISC_SPELL_INDEX[74];
int SPELL_COSTS[77];
- int CLOUDS_SPELL_OFFSETS[5][20];
+ int CLOUDS_GUILD_SPELLS[5][20];
int DARK_SPELL_OFFSETS[3][39];
int DARK_SPELL_RANGES[12][2];
- int SPELL_LEVEL_OFFSETS[3][39];
+ int SWORDS_SPELL_RANGES[12][2];
int SPELL_GEM_COST[77];
const char *NOT_A_SPELL_CASTER;
+ const char *SPELLS_LEARNED_ALL;
const char *SPELLS_FOR;
const char *SPELL_LINES_0_TO_9;
const char *SPELLS_DIALOG_SPELLS;
const char *SPELL_PTS;
const char *GOLD;
- const char *SPELLS_PRESS_A_KEY;
- const char *SPELLS_PURCHASE;
+ const char *SPELL_INFO;
+ const char *SPELL_PURCHASE;
const char *MAP_TEXT;
const char *LIGHT_COUNT_TEXT;
const char *FIRE_RESISTENCE_TEXT;
@@ -302,15 +304,18 @@ public:
const char *BTN_GOLD;
const char *ITEM_BROKEN;
const char *ITEM_CURSED;
+ const char *ITEM_OF;
const char *BONUS_NAMES[7];
- const char *WEAPON_NAMES[35];
+ const char *WEAPON_NAMES[41];
const char *ARMOR_NAMES[14];
const char *ACCESSORY_NAMES[11];
const char *MISC_NAMES[22];
+ const char *SPECIAL_NAMES[74];
const char *ELEMENTAL_NAMES[6];
const char *ATTRIBUTE_NAMES[10];
const char *EFFECTIVENESS_NAMES[7];
const char *QUEST_ITEM_NAMES[85];
+ const char *QUEST_ITEM_NAMES_SWORDS[51];
int WEAPON_BASE_COSTS[35];
int ARMOR_BASE_COSTS[14];
int ACCESSORY_BASE_COSTS[11];
@@ -365,6 +370,7 @@ public:
const char *QUESTS_DIALOG_TEXT;
const char *CLOUDS_OF_XEEN_LINE;
const char *DARKSIDE_OF_XEEN_LINE;
+ const char *SWORDS_OF_XEEN_LINE;
const char *NO_QUEST_ITEMS;
const char *NO_CURRENT_QUESTS;
const char *NO_AUTO_NOTES;
@@ -377,6 +383,7 @@ public:
const char *TOO_DANGEROUS_TO_REST;
const char *SOME_CHARS_MAY_DIE;
const char *CANT_DISMISS_LAST_CHAR;
+ const char *DELETE_CHAR_WITH_ELDER_WEAPON;
const char *REMOVE_DELETE[2];
const char *REMOVE_OR_DELETE_WHICH;
const char *YOUR_PARTY_IS_FULL;
@@ -388,6 +395,7 @@ public:
const char *SELECT_CLASS_BEFORE_SAVING;
const char *EXCHANGE_ATTR_WITH;
int NEW_CHAR_SKILLS[10];
+ int NEW_CHAR_SKILLS_OFFSET[10];
int NEW_CHAR_SKILLS_LEN[10];
int NEW_CHAR_RACE_SKILLS[10];
int RACE_MAGIC_RESISTENCES[5];
@@ -413,7 +421,8 @@ public:
const char *LLOYDS_BEACON;
const char *HOW_MANY_SQUARES;
const char *TOWN_PORTAL;
- int TOWN_MAP_NUMBERS[2][5];
+ const char *TOWN_PORTAL_SWORDS;
+ int TOWN_MAP_NUMBERS[3][5];
const char *MONSTER_DETAILS;
const char *MONSTER_SPECIAL_ATTACKS[23];
const char *IDENTIFY_MONSTERS;
@@ -447,6 +456,12 @@ public:
const char *MUSIC_FILES1[5];
const char *MUSIC_FILES2[6][7];
const char *DIFFICULTY_TEXT;
+ const char *SAVE_OFF_LIMITS;
+ const char *CLOUDS_INTRO1;
+ const char *DARKSIDE_ENDING1;
+ const char *DARKSIDE_ENDING2;
+ const char *PHAROAH_ENDING_TEXT1;
+ const char *PHAROAH_ENDING_TEXT2;
public:
/**
* Constructor
diff --git a/engines/xeen/saves.cpp b/engines/xeen/saves.cpp
index 7bd938180e..82e294921b 100644
--- a/engines/xeen/saves.cpp
+++ b/engines/xeen/saves.cpp
@@ -48,9 +48,8 @@ SavesManager::~SavesManager() {
const char *const SAVEGAME_STR = "XEEN";
#define SAVEGAME_STR_SIZE 6
-bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header) {
+WARN_UNUSED_RESULT bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header, bool skipThumbnail) {
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = nullptr;
// Validate the header Id
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
@@ -68,9 +67,9 @@ bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader
header._saveName += ch;
// Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
+ if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
header._year = in->readSint16LE();
@@ -153,6 +152,7 @@ Common::Error SavesManager::saveGameState(int slot, const Common::String &desc)
}
Common::Error SavesManager::loadGameState(int slot) {
+ Combat &combat = *g_vm->_combat;
EventsManager &events = *g_vm->_events;
FileManager &files = *g_vm->_files;
Map &map = *g_vm->_map;
@@ -168,11 +168,6 @@ Common::Error SavesManager::loadGameState(int slot) {
if (!readSavegameHeader(saveFile, header))
error("Invalid savegame");
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
// Set the total play time
events.setPlayTime(header._totalFrames);
@@ -182,9 +177,13 @@ Common::Error SavesManager::loadGameState(int slot) {
uint fileSize = saveFile->readUint32LE();
if (archives[idx]) {
- Common::SeekableSubReadStream arcStream(saveFile, saveFile->pos(),
- saveFile->pos() + fileSize);
- archives[idx]->load(arcStream);
+ if (fileSize) {
+ Common::SeekableSubReadStream arcStream(saveFile, saveFile->pos(),
+ saveFile->pos() + fileSize);
+ archives[idx]->load(arcStream);
+ } else {
+ archives[idx]->reset((idx == 1) ? File::_darkCc : File::_xeenCc);
+ }
} else {
assert(!fileSize);
}
@@ -193,9 +192,16 @@ Common::Error SavesManager::loadGameState(int slot) {
// Read in miscellaneous
files.load(*saveFile);
+ // Load the character roster and party
+ File::_currentSave->loadParty();
+
+ // Reset any combat information from the previous game
+ combat.reset();
+ party._treasure.reset();
+
// Load the new map
map.clearMaze();
- map._loadDarkSide = files._isDarkCc;
+ map._loadCcNum = files._ccNum;
map.load(party._mazeId);
delete saveFile;
@@ -212,6 +218,10 @@ void SavesManager::newGame() {
File::_xeenSave = nullptr;
File::_darkSave = nullptr;
+ // Reset any combat information from the previous game
+ g_vm->_combat->reset();
+
+ // Reset the game states
if (g_vm->getGameID() != GType_Clouds) {
File::_darkSave = new SaveArchive(g_vm->_party);
File::_darkSave->reset(File::_darkCc);
@@ -225,6 +235,9 @@ void SavesManager::newGame() {
File::_darkSave : File::_xeenSave;
assert(File::_currentSave);
+ // Load the character roster and party
+ File::_currentSave->loadParty();
+
// Set any final initial values
Party &party = *g_vm->_party;
party.resetBlacksmithWares();
@@ -245,32 +258,37 @@ void SavesManager::newGame() {
}
bool SavesManager::loadGame() {
- if (!g_vm->canLoadGameStateCurrently())
- return false;
-
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false);
int slotNum = dialog->runModalWithCurrentTarget();
delete dialog;
- if (slotNum != -1)
+ if (slotNum != -1) {
loadGameState(slotNum);
+ g_vm->_interface->drawParty(true);
+ }
return slotNum != -1;
}
bool SavesManager::saveGame() {
- if (!g_vm->canSaveGameStateCurrently())
- return false;
+ Map &map = *g_vm->_map;
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
- int slotNum = dialog->runModalWithCurrentTarget();
- Common::String saveName = dialog->getResultString();
- delete dialog;
+ if (map.mazeData()._mazeFlags & RESTRICTION_SAVE) {
+ ErrorScroll::show(g_vm, Res.SAVE_OFF_LIMITS, WT_NONFREEZED_WAIT);
+ return false;
+ } else if (!g_vm->canSaveGameStateCurrently()) {
+ return false;
+ } else {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+ int slotNum = dialog->runModalWithCurrentTarget();
+ Common::String saveName = dialog->getResultString();
+ delete dialog;
- if (slotNum != -1)
- saveGameState(slotNum, saveName);
+ if (slotNum != -1)
+ saveGameState(slotNum, saveName);
- return slotNum != -1;
+ return slotNum != -1;
+ }
}
} // End of namespace Xeen
diff --git a/engines/xeen/saves.h b/engines/xeen/saves.h
index b18e04a822..9b1bea62a3 100644
--- a/engines/xeen/saves.h
+++ b/engines/xeen/saves.h
@@ -65,7 +65,7 @@ public:
/**
* Read in a savegame header
*/
- static bool readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header);
+ WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header, bool skipThumbnail = true);
/**
* Write out a savegame header
diff --git a/engines/xeen/screen.cpp b/engines/xeen/screen.cpp
index c9781b3cf1..47735478ed 100644
--- a/engines/xeen/screen.cpp
+++ b/engines/xeen/screen.cpp
@@ -169,7 +169,7 @@ bool Screen::doScroll(bool rollUp, bool fadeInFlag) {
const int SCROLL_L[8] = { 29, 23, 15, -5, -11, -23, -49, -71 };
const int SCROLL_R[8] = { 165, 171, 198, 218, 228, 245, 264, 281 };
- if (_vm->_files->_isDarkCc) {
+ if (_vm->_files->_ccNum) {
if (fadeInFlag)
screen.fadeIn(2);
return _vm->shouldExit();
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index 8777cdc6e0..bc0b179d4c 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -21,7 +21,10 @@
*/
#include "common/config-manager.h"
+#include "common/textconsole.h"
+#include "backends/audiocd/audiocd.h"
#include "xeen/scripts.h"
+#include "xeen/dialogs/dialogs_copy_protection.h"
#include "xeen/dialogs/dialogs_input.h"
#include "xeen/dialogs/dialogs_whowill.h"
#include "xeen/dialogs/dialogs_query.h"
@@ -138,7 +141,7 @@ int Scripts::checkEvents() {
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
Windows &windows = *_vm->_windows;
- bool isDarkCc = files._isDarkCc;
+ int ccNum = files._ccNum;
_refreshIcons = false;
_itemType = 0;
@@ -182,10 +185,10 @@ int Scripts::checkEvents() {
for (eventIndex = 0; eventIndex < map._events.size() && !_vm->shouldExit(); ++eventIndex) {
MazeEvent &event = map._events[eventIndex];
- if (event._position == _currentPos && party._mazeDirection !=
- (_currentPos.x | _currentPos.y) && event._line == _lineNum) {
+ if (event._position == _currentPos && event._line == _lineNum &&
+ (party._mazeDirection | _currentPos.x | _currentPos.y)) {
if (event._direction == party._mazeDirection || event._direction == DIR_ALL) {
- _vm->_mode = MODE_RECORD_EVENTS;
+ _vm->_mode = MODE_SCRIPT_IN_PROGRESS;
_scriptExecuted = true;
doOpcode(event);
break;
@@ -209,24 +212,27 @@ int Scripts::checkEvents() {
if (party._treasure._hasItems || party._treasure._gold || party._treasure._gems)
party.giveTreasure();
- if (_animCounter > 0 && intf._objNumber) {
- MazeObject &selectedObj = map._mobData._objects[intf._objNumber - 1];
+ if (_animCounter > 0 && intf._objNumber != -1) {
+ MazeObject &selectedObj = map._mobData._objects[intf._objNumber];
- if (selectedObj._spriteId == (isDarkCc ? 15 : 16)) {
- for (uint idx = 0; idx < 16; ++idx) {
- MazeObject &obj = map._mobData._objects[idx];
- if (obj._spriteId == (isDarkCc ? 62 : 57)) {
+ if (selectedObj._spriteId == (ccNum ? 15 : 16)) {
+ // Treasure chests that were opened will be set to be in an open, empty state
+ for (uint idx = 0; idx < map._mobData._objectSprites.size(); ++idx) {
+ MonsterObjectData::SpriteResourceEntry &e = map._mobData._objectSprites[idx];
+ if (e._spriteId == (ccNum ? 57 : 62)) {
selectedObj._id = idx;
- selectedObj._spriteId = isDarkCc ? 62 : 57;
+ selectedObj._spriteId = ccNum ? 57 : 62;
+ selectedObj._sprites = &e._sprites;
break;
}
}
} else if (selectedObj._spriteId == 73) {
- for (uint idx = 0; idx < 16; ++idx) {
- MazeObject &obj = map._mobData._objects[idx];
- if (obj._spriteId == 119) {
+ for (uint idx = 0; idx < map._mobData._objectSprites.size(); ++idx) {
+ MonsterObjectData::SpriteResourceEntry &e = map._mobData._objectSprites[idx];
+ if (e._spriteId == 119) {
selectedObj._id = idx;
selectedObj._spriteId = 119;
+ selectedObj._sprites = &e._sprites;
break;
}
}
@@ -237,8 +243,17 @@ int Scripts::checkEvents() {
_vm->_mode = oldMode;
windows.closeAll();
- if (_scriptExecuted || !intf._objNumber || _dirFlag) {
- if (_dirFlag && !_scriptExecuted && intf._objNumber && !map._currentIsEvent) {
+ if (g_vm->getIsCD() && g_system->getAudioCDManager()->isPlaying())
+ // Stop any playing voice
+ g_system->getAudioCDManager()->stop();
+
+ if (g_vm->shouldExit())
+ return g_vm->_gameMode;
+
+ if (_scriptExecuted)
+ intf.clearEvents();
+ if (_scriptExecuted || intf._objNumber == -1 || _dirFlag) {
+ if (_dirFlag && !_scriptExecuted && intf._objNumber != -1 && !map._currentIsEvent) {
sound.playFX(21);
}
} else {
@@ -269,69 +284,71 @@ int Scripts::checkEvents() {
return _scriptResult;
}
-void Scripts::openGrate(int wallVal, int action) {
+bool Scripts::openGrate(int wallVal, int action) {
Combat &combat = *_vm->_combat;
FileManager &files = *_vm->_files;
Interface &intf = *_vm->_interface;
Map &map = *_vm->_map;
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
- bool isDarkCc = files._isDarkCc;
-
- if ((wallVal != 13 || map._currentGrateUnlocked) && (!isDarkCc || wallVal != 9 ||
- map.mazeData()._wallKind != 2)) {
- if (wallVal != 9 && !map._currentGrateUnlocked) {
- int charIndex = WhoWill::show(_vm, 13, action, false) - 1;
- if (charIndex < 0) {
- intf.draw3d(true);
- return;
- }
+ int ccNum = files._ccNum;
- // There is a 1 in 4 chance the character will receive damage
- if (_vm->getRandomNumber(1, 4) == 1) {
- combat.giveCharDamage(map.mazeData()._trapDamage,
- (DamageType)_vm->getRandomNumber(0, 6), charIndex);
- }
+ if (!((wallVal != 13 || map._currentGrateUnlocked) && (!ccNum || wallVal != 9 ||
+ map.mazeData()._wallKind != 2)))
+ return false;
- // Check whether character can unlock the door
- Character &c = party._activeParty[charIndex];
- if ((c.getThievery() + _vm->getRandomNumber(1, 20)) <
- map.mazeData()._difficulties._unlockDoor)
- return;
+ if (wallVal != 9 && !map._currentGrateUnlocked) {
+ int charIndex = WhoWill::show(_vm, 13, action, false) - 1;
+ if (charIndex < 0) {
+ intf.draw3d(true);
+ return true;
+ }
- c._experience += map.mazeData()._difficulties._unlockDoor * c.getCurrentLevel();
+ // There is a 1 in 4 chance the character will receive damage
+ if (_vm->getRandomNumber(1, 4) == 1) {
+ combat.giveCharDamage(map.mazeData()._trapDamage,
+ (DamageType)_vm->getRandomNumber(0, 6), charIndex);
}
- // Flag the grate as unlocked, and the wall the grate is on
- map.setCellSurfaceFlags(party._mazePosition, 0x80);
- map.setWall(party._mazePosition, party._mazeDirection, wallVal);
+ // Check whether character can unlock the door
+ Character &c = party._activeParty[charIndex];
+ if ((c.getThievery() + _vm->getRandomNumber(1, 20)) <
+ map.mazeData()._difficulties._unlockDoor)
+ return true;
- // Set the grate as opened and the wall on the other side of the grate
- Common::Point pt = party._mazePosition;
- Direction dir = (Direction)((int)party._mazeDirection ^ 2);
- switch (party._mazeDirection) {
- case DIR_NORTH:
- pt.y++;
- break;
- case DIR_EAST:
- pt.x++;
- break;
- case DIR_SOUTH:
- pt.y--;
- break;
- case DIR_WEST:
- pt.x--;
- break;
- default:
- break;
- }
+ c._experience += map.mazeData()._difficulties._unlockDoor * c.getCurrentLevel();
+ }
- map.setCellSurfaceFlags(pt, 0x80);
- map.setWall(pt, dir, wallVal);
+ // Flag the grate as unlocked, and the wall the grate is on
+ map.setCellSurfaceFlags(party._mazePosition, 0x80);
+ map.setWall(party._mazePosition, party._mazeDirection, wallVal);
- sound.playFX(10);
- intf.draw3d(true);
+ // Set the grate as opened and the wall on the other side of the grate
+ Common::Point pt = party._mazePosition;
+ Direction dir = (Direction)((int)party._mazeDirection ^ 2);
+ switch (party._mazeDirection) {
+ case DIR_NORTH:
+ pt.y++;
+ break;
+ case DIR_EAST:
+ pt.x++;
+ break;
+ case DIR_SOUTH:
+ pt.y--;
+ break;
+ case DIR_WEST:
+ pt.x--;
+ break;
+ default:
+ break;
}
+
+ map.setCellSurfaceFlags(pt, 0x80);
+ map.setWall(pt, dir, wallVal);
+
+ sound.playFX(10);
+ intf.draw3d(true);
+ return true;
}
bool Scripts::doOpcode(MazeEvent &event) {
@@ -373,7 +390,7 @@ bool Scripts::doOpcode(MazeEvent &event) {
bool result = (this->*COMMAND_LIST[event._opcode])(params);
if (result)
// Move to next line
- _lineNum = _vm->_party->_partyDead ? -1 : _lineNum + 1;
+ _lineNum = _vm->_party->_dead ? SCRIPT_ABORT : _lineNum + 1;
return result;
}
@@ -465,7 +482,7 @@ bool Scripts::cmdTeleport(ParamsIterator &params) {
Sound &sound = *_vm->_sound;
windows.closeAll();
-
+
bool restartFlag = _event->_opcode == OP_TeleportAndContinue;
int mapId = params.readByte();
Common::Point pt;
@@ -491,8 +508,7 @@ bool Scripts::cmdTeleport(ParamsIterator &params) {
party._stepped = true;
if (mapId != party._mazeId) {
- int spriteId = (intf._objNumber == 0) ? -1 :
- map._mobData._objects[intf._objNumber - 1]._spriteId;
+ int spriteId = (intf._objNumber == -1) ? -1 : map._mobData._objects[intf._objNumber]._spriteId;
switch (spriteId) {
case 47:
@@ -519,7 +535,7 @@ bool Scripts::cmdTeleport(ParamsIterator &params) {
if (restartFlag) {
// Draw the new location and start any script at that location
- intf.draw3d(true);
+ events.ipause(2);
_lineNum = SCRIPT_RESET;
return false;
} else {
@@ -592,7 +608,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
Combat &combat = *_vm->_combat;
Party &party = *_vm->_party;
Windows &windows = *_vm->_windows;
- int mode1, mode2, mode3, param2;
+ int mode1, mode2, mode3;
uint32 val1, val2, val3;
_refreshIcons = true;
@@ -614,7 +630,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
break;
}
- param2 = mode2 = params.readByte();
+ mode2 = params.readByte();
switch (mode2) {
case 16:
case 34:
@@ -707,7 +723,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
if (_charIndex == 0 || _charIndex == 8) {
for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
if (_charIndex == 0 || (_charIndex == 8 && (int)idx != combat._combatTarget)) {
- party.giveTake(mode1, val1, mode2, val2, idx);
+ bool flag = party.giveTake(mode1, val1, mode2, val2, idx);
switch (mode1) {
case 8:
@@ -715,7 +731,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
// fall through
case 21:
case 66:
- if (param2) {
+ if (flag) {
switch (mode2) {
case 82:
mode1 = 0;
@@ -728,13 +744,18 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
case 100:
case 101:
case 106:
- if (param2)
+ if (flag)
continue;
// Break out of character loop
idx = party._activeParty.size();
break;
+ default:
+ break;
}
+ } else {
+ // Break out of character loop
+ idx = party._activeParty.size();
}
break;
@@ -744,7 +765,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
case 100:
case 101:
case 106:
- if (param2) {
+ if (flag) {
_lineNum = -1;
return false;
}
@@ -766,7 +787,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
case 100:
case 101:
case 106:
- if (param2)
+ if (flag)
continue;
// Break out of character loop
@@ -793,9 +814,9 @@ bool Scripts::cmdRemove(ParamsIterator &params) {
Interface &intf = *_vm->_interface;
Map &map = *_vm->_map;
- if (intf._objNumber) {
+ if (intf._objNumber != -1) {
// Give the active object a completely way out of bounds position
- MazeObject &obj = map._mobData._objects[intf._objNumber - 1];
+ MazeObject &obj = map._mobData._objects[intf._objNumber];
obj._position = Common::Point(128, 128);
}
@@ -845,7 +866,7 @@ bool Scripts::cmdSpawn(ParamsIterator &params) {
}
bool Scripts::cmdDoTownEvent(ParamsIterator &params) {
- _scriptResult = _vm->_locations->doAction((LocationAction)params.readByte());
+ _scriptResult = _vm->_locations->doAction(params.readByte());
_vm->_party->_stepped = true;
_refreshIcons = true;
@@ -930,40 +951,46 @@ bool Scripts::cmdConfirmWord(ParamsIterator &params) {
int param2 = params.readByte();
int param3 = params.readByte();
- Common::String msg1 = param2 ? map._events._text[param2] : _message;
- Common::String msg2;
+ Common::String expected2;
+ Common::String title;
if (_event->_opcode == OP_ConfirmWord_2) {
- msg2 = "";
+ title = "";
} else if (param3) {
- msg2 = map._events._text[param3];
+ title = map._events._text[param3];
} else {
- msg2 = Res.WHATS_THE_PASSWORD;
+ title = Res.WHATS_THE_PASSWORD;
}
- _mirrorId = StringInput::show(_vm, inputType, msg1, msg2, _event->_opcode);
+ if (!param2) {
+ expected2 = _message;
+ } else if (param2 < (int)map._events._text.size()) {
+ expected2 = map._events._text[param2];
+ }
+
+ _mirrorId = StringInput::show(_vm, inputType, expected2, title, _event->_opcode);
if (_mirrorId) {
- if (_mirrorId == 33 && files._isDarkCc) {
+ if (_mirrorId == 33 && files._ccNum) {
doDarkSideEnding();
- } else if (_mirrorId == 34 && files._isDarkCc) {
+ } else if (_mirrorId == 34 && files._ccNum) {
doWorldEnding();
- } else if (_mirrorId == 35 && files._isDarkCc &&
+ } else if (_mirrorId == 35 && files._ccNum &&
_vm->getGameID() == GType_WorldOfXeen) {
doCloudsEnding();
- } else if (_mirrorId == 40 && !files._isDarkCc) {
+ } else if (_mirrorId == 40 && !files._ccNum) {
doCloudsEnding();
- } else if (_mirrorId == 60 && !files._isDarkCc) {
+ } else if (_mirrorId == 60 && !files._ccNum) {
doDarkSideEnding();
- } else if (_mirrorId == 61 && !files._isDarkCc) {
+ } else if (_mirrorId == 61 && !files._ccNum) {
doWorldEnding();
} else {
- if (_mirrorId == 59 && !files._isDarkCc) {
+ if (_mirrorId == 59 && !files._ccNum) {
for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
XeenItem &item = party._treasure._weapons[idx];
if (!item._id) {
- item._id = 34;
+ item._id = XEEN_SLAYER_SWORD;
item._material = 0;
- item._bonusFlags = 0;
+ item._state.clear();
party._treasure._hasItems = true;
return cmdExit(params);
@@ -990,7 +1017,7 @@ bool Scripts::cmdDamage(ParamsIterator &params) {
int damage = params.readUint16LE();
DamageType damageType = (DamageType)params.readByte();
- combat.giveCharDamage(damage, damageType, _charIndex);
+ combat.giveCharDamage(damage, damageType, _charIndex - 1);
return true;
}
@@ -1033,11 +1060,16 @@ bool Scripts::cmdCallEvent(ParamsIterator &params) {
}
bool Scripts::cmdReturn(ParamsIterator &params) {
- StackEntry &se = _stack.top();
- _currentPos = se;
- _lineNum = se.line;
+ if (_stack.empty()) {
+ // WORKAROUND: Some scripts in Swords of Xeen use cmdReturn as a substitute for cmdExit
+ return cmdExit(params);
+ } else {
+ StackEntry se = _stack.pop();
+ _currentPos = se;
+ _lineNum = se.line;
- return true;
+ return true;
+ }
}
bool Scripts::cmdSetVar(ParamsIterator &params) {
@@ -1114,17 +1146,17 @@ bool Scripts::cmdRndDamage(ParamsIterator &params) {
DamageType dmgType = (DamageType)params.readByte();
int max = params.readByte();
- combat.giveCharDamage(_vm->getRandomNumber(1, max), dmgType, _charIndex);
+ combat.giveCharDamage(_vm->getRandomNumber(1, max), dmgType, _charIndex - 1);
return true;
}
bool Scripts::cmdMoveWallObj(ParamsIterator &params) {
Map &map = *_vm->_map;
- int itemNum = params.readByte();
+ int index = params.readByte();
int x = params.readShort();
int y = params.readShort();
- map._mobData._wallItems[itemNum]._position = Common::Point(x, y);
+ map._mobData._wallItems[index]._position = Common::Point(x, y);
return true;
}
@@ -1203,14 +1235,25 @@ bool Scripts::cmdDisplayBottom(ParamsIterator &params) {
bool Scripts::cmdIfMapFlag(ParamsIterator &params) {
Map &map = *_vm->_map;
- MazeMonster &monster = map._mobData._monsters[params.readByte()];
+ int monsterNum = params.readByte();
+ int lineNum = params.readByte();
- if (monster._position.x >= 32 || monster._position.y >= 32) {
- _lineNum = params.readByte();
- return false;
+ if (monsterNum == 0xff) {
+ for (monsterNum = 0; monsterNum < (int)map._mobData._monsters.size(); ++monsterNum) {
+ MazeMonster &monster = map._mobData._monsters[monsterNum];
+
+ if ((uint)monster._position.x < 32 && (uint)monster._position.y < 32)
+ return true;
+ }
+ } else {
+ MazeMonster &monster = map._mobData._monsters[monsterNum];
+
+ if ((uint)monster._position.x < 32 && (uint)monster._position.y < 32)
+ return true;
}
- return true;
+ _lineNum = lineNum;
+ return false;
}
bool Scripts::cmdSelectRandomChar(ParamsIterator &params) {
@@ -1220,64 +1263,47 @@ bool Scripts::cmdSelectRandomChar(ParamsIterator &params) {
bool Scripts::cmdGiveEnchanted(ParamsIterator &params) {
Party &party = *_vm->_party;
-
+ int itemOffset = _vm->getGameID() == GType_Swords ? 6 : 0;
+ XeenItem *item;
+ int invIndex;
int id = params.readByte();
- int material = params.readByte();
- int flags = params.readByte();
-
- if (id >= 35) {
- if (id < 49) {
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._armor[idx];
- if (!item.empty()) {
- item._id = id - 35;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
- }
- }
- return true;
- } else if (id < 60) {
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._accessories[idx];
- if (!item.empty()) {
- item._id = id - 49;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
- }
- }
+ // Get category of item to add
+ ItemCategory cat = CATEGORY_WEAPON;
+ if (id < (35 + itemOffset)) {
+ } else if (id < (49 + itemOffset)) {
+ cat = CATEGORY_ARMOR;
+ id -= 35 + itemOffset;
+ } else if (id < (60 + itemOffset)) {
+ cat = CATEGORY_ACCESSORY;
+ id -= 49 + itemOffset;
+ } else if (id < (82 + itemOffset)) {
+ cat = CATEGORY_MISC;
+ id -= 60 + itemOffset;
+ } else {
+ party._questItems[id - (82 + itemOffset)]++;
+ }
- return true;
- } else if (id < 82) {
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._misc[idx];
- if (!item.empty()) {
- item._id = id;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
- }
- }
+ // Check for an empty slot
+ for (invIndex = 0, item = party._treasure[cat]; invIndex < MAX_TREASURE_ITEMS && !item->empty(); ++invIndex, ++item)
+ ;
- return true;
- } else {
- party._questItems[id - 82]++;
- }
- }
+ if (invIndex == MAX_TREASURE_ITEMS) {
+ // Treasure category entirely full. Should never happen
+ warning("Treasure category was completely filled up");
+ } else {
+ party._treasure._hasItems = true;
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._weapons[idx];
- if (!item.empty()) {
- item._id = id;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
+ if (cat == CATEGORY_MISC) {
+ // Handling of misc items. Note that for them, id actually specifies the material field
+ item->_material = id;
+ item->_id = params.readByte();
+ item->_state._counter = (item->_material == 10 || item->_material == 11) ? 1 : _vm->getRandomNumber(3, 10);
+ } else {
+ // Weapons, armor, and accessories
+ item->_id = id;
+ item->_material = params.readByte();
+ item->_state = params.readByte();
}
}
@@ -1391,6 +1417,8 @@ bool Scripts::cmdFallToMap(ParamsIterator &params) {
}
bool Scripts::cmdDisplayMain(ParamsIterator &params) {
+ _windowIndex = 11;
+
display(false, 0);
return true;
}
@@ -1415,7 +1443,7 @@ bool Scripts::cmdCutsceneEndDarkside(ParamsIterator &params) {
Party &party = *_vm->_party;
_vm->_saves->_wonDarkSide = true;
party._questItems[53] = 1;
- party._darkSideEnd = true;
+ party._darkSideCompleted = true;
party._mazeId = 29;
party._mazeDirection = DIR_NORTH;
party._mazePosition = Common::Point(25, 21);
@@ -1436,24 +1464,55 @@ bool Scripts::cmdCutsceneEndWorld(ParamsIterator &params) {
g_vm->saveSettings();
_vm->_saves->_wonWorld = true;
- _vm->_party->_worldEnd = true;
+ _vm->_party->_worldCompleted = true;
doWorldEnding();
return false;
}
bool Scripts::cmdFlipWorld(ParamsIterator &params) {
- _vm->_map->_loadDarkSide = params.readByte() != 0;
+ _vm->_map->_loadCcNum = params.readByte();
+ return true;
+}
+
+bool Scripts::cmdPlayCD(ParamsIterator &params) {
+ int trackNum = params.readByte();
+ int start = params.readUint16LE();
+ int finish = params.readUint16LE();
+ debugC(3, kDebugScripts, "cmdPlayCD Track=%d start=%d finish=%d", trackNum, start, finish);
+
+ if (_vm->_files->_ccNum && trackNum < 31)
+ trackNum += 30;
+ assert(trackNum <= 60);
+
+ start = convertCDTime(start);
+ finish = convertCDTime(finish);
+
+ g_system->getAudioCDManager()->play(trackNum, 1, start, finish - start, false, Audio::Mixer::kSpeechSoundType);
return true;
}
-bool Scripts::cmdPlayCD(ParamsIterator &params) { error("TODO"); }
+#define CD_FRAME_RATE 75
+uint Scripts::convertCDTime(uint srcTime) {
+ // Times are encoded as MMSSCC - MM=Minutes, SS=Seconds, CC=Centiseconds (1/100th second)
+ uint mins = srcTime / 10000;
+ uint csec = srcTime % 10000;
+ return (mins * 6000 + csec) * CD_FRAME_RATE / 100;
+}
void Scripts::doCloudsEnding() {
+ g_vm->_party->_cloudsCompleted = true;
doEnding("ENDGAME");
+
+ g_vm->_mode = MODE_INTERACTIVE;
+ g_vm->_saves->saveGame();
+
+ g_vm->_gameMode = GMODE_MENU;
+ g_vm->_mode = MODE_STARTUP;
}
void Scripts::doDarkSideEnding() {
+ g_vm->_party->_darkSideCompleted = true;
doEnding("ENDGAME2");
}
@@ -1487,56 +1546,56 @@ void Scripts::doEnding(const Common::String &endStr) {
bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
FileManager &files = *_vm->_files;
Party &party = *_vm->_party;
- Character &ps = party._activeParty[charIndex];
+ Character *ps = (charIndex == -1) ? nullptr : &party._activeParty[charIndex];
uint v = 0;
switch (action) {
case 3:
// Player sex
- v = (uint)ps._sex;
+ v = (uint)ps->_sex;
break;
case 4:
// Player race
- v = (uint)ps._race;
+ v = (uint)ps->_race;
break;
case 5:
// Player class
- v = (uint)ps._class;
+ v = (uint)ps->_class;
break;
case 8:
// Current health points
- v = (uint)ps._currentHp;
+ v = (uint)ps->_currentHp;
break;
case 9:
// Current spell points
- v = (uint)ps._currentSp;
+ v = (uint)ps->_currentSp;
break;
case 10:
// Get armor class
- v = (uint)ps.getArmorClass(false);
+ v = (uint)ps->getArmorClass(false);
break;
case 11:
// Level bonus (extra beyond base)
- v = ps._level._temporary;
+ v = ps->_level._temporary;
break;
case 12:
// Current age, including unnatural aging
- v = ps.getAge(false);
+ v = ps->getAge(false);
break;
case 13:
assert(val < 18);
- if (ps._skills[val])
+ if (ps->_skills[val])
v = val;
break;
case 15:
// Award
assert(val < AWARDS_TOTAL);
- if (ps.hasAward(val))
+ if (ps->hasAward(val))
v = val;
break;
case 16:
// Experience
- v = ps._experience;
+ v = ps->_experience;
break;
case 17:
// Party poison resistence
@@ -1544,38 +1603,19 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 18:
// Condition
- assert(val < 16);
- if (!ps._conditions[val] && !(val & 0x10))
- v = val;
+ assert(val <= NO_CONDITION);
+ v = (ps->_conditions[val] || val == NO_CONDITION) ? val : 0xffffffff;
break;
case 19: {
// Can player cast a given spell
-
- // Get the type of character
- int category;
- switch (ps._class) {
- case CLASS_KNIGHT:
- case CLASS_ARCHER:
- category = 0;
- break;
- case CLASS_PALADIN:
- case CLASS_CLERIC:
- category = 1;
- break;
- case CLASS_BARBARIAN:
- case CLASS_DRUID:
- category = 2;
- break;
- default:
- category = 0;
- break;
- }
+ SpellsCategory category = ps->getSpellsCategory();
+ assert(category != SPELLCAT_INVALID);
// Check if the character class can cast the particular spell
- for (int idx = 0; idx < 39; ++idx) {
+ for (int idx = 0; idx < SPELLS_PER_CLASS; ++idx) {
if (Res.SPELLS_ALLOWED[category][idx] == (int)val) {
// Can cast it. Check if the player has it in their spellbook
- if (ps._spells[idx])
+ if (ps->_spells[idx])
v = val;
break;
}
@@ -1583,42 +1623,44 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
}
case 20:
- if (files._isDarkCc)
+ assert(val < 256);
+ if (files._ccNum && _vm->getGameID() != GType_Swords)
val += 256;
- assert(val < 512);
v = party._gameFlags[val / 256][val % 256] ? val : 0xffffffff;
break;
- case 21:
+ case 21: {
// Scans inventories for given item number
+ uint itemOffset = _vm->getGameID() == GType_Swords ? 6 : 0;
v = 0xFFFFFFFF;
- if (val < 82) {
- for (int idx = 0; idx < 9; ++idx) {
- if (val == 35) {
- if (ps._weapons[idx]._id == val) {
+ if (val < (82 + itemOffset)) {
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ if (val < (35 + itemOffset)) {
+ if (ps->_weapons[idx]._id == val) {
v = val;
break;
}
- } else if (val < 49) {
- if (ps._armor[idx]._id == (val - 35)) {
+ } else if (val < (49 + itemOffset)) {
+ if (ps->_armor[idx]._id == (val - 35)) {
v = val;
break;
}
- } else if (val < 60) {
- if (ps._accessories[idx]._id == (val - 49)) {
+ } else if (val < (60 + itemOffset)) {
+ if (ps->_accessories[idx]._id == (val - (49 + itemOffset))) {
v = val;
break;
}
} else {
- if (ps._misc[idx]._id == (val - 60)) {
+ if (ps->_misc[idx]._id == (val - (60 + itemOffset))) {
v = val;
break;
}
}
}
- } else if (party._questItems[val - 82]) {
+ } else if (party._questItems[val - (82 + itemOffset)]) {
v = val;
}
break;
+ }
case 25:
// Returns number of minutes elapsed in the day (0-1440)
v = party._minutes;
@@ -1632,32 +1674,32 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
v = party._gems;
break;
case 37:
- // Might bonus (extra beond base)
- v = ps._might._temporary;
+ // Might bonus (extra beyond base)
+ v = ps->_might._temporary;
break;
case 38:
// Intellect bonus (extra beyond base)
- v = ps._intellect._temporary;
+ v = ps->_intellect._temporary;
break;
case 39:
// Personality bonus (extra beyond base)
- v = ps._personality._temporary;
+ v = ps->_personality._temporary;
break;
case 40:
// Endurance bonus (extra beyond base)
- v = ps._endurance._temporary;
+ v = ps->_endurance._temporary;
break;
case 41:
// Speed bonus (extra beyond base)
- v = ps._speed._temporary;
+ v = ps->_speed._temporary;
break;
case 42:
// Accuracy bonus (extra beyond base)
- v = ps._accuracy._temporary;
+ v = ps->_accuracy._temporary;
break;
case 43:
// Luck bonus (extra beyond base)
- v = ps._luck._temporary;
+ v = ps->_luck._temporary;
break;
case 44:
v = YesNo::show(_vm, val);
@@ -1665,83 +1707,83 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 45:
// Might base (before bonus)
- v = ps._might._permanent;
+ v = ps->_might._permanent;
break;
case 46:
// Intellect base (before bonus)
- v = ps._intellect._permanent;
+ v = ps->_intellect._permanent;
break;
case 47:
// Personality base (before bonus)
- v = ps._personality._permanent;
+ v = ps->_personality._permanent;
break;
case 48:
// Endurance base (before bonus)
- v = ps._endurance._permanent;
+ v = ps->_endurance._permanent;
break;
case 49:
// Speed base (before bonus)
- v = ps._speed._permanent;
+ v = ps->_speed._permanent;
break;
case 50:
// Accuracy base (before bonus)
- v = ps._accuracy._permanent;
+ v = ps->_accuracy._permanent;
break;
case 51:
// Luck base (before bonus)
- v = ps._luck._permanent;
+ v = ps->_luck._permanent;
break;
case 52:
// Fire resistence (before bonus)
- v = ps._fireResistence._permanent;
+ v = ps->_fireResistence._permanent;
break;
case 53:
// Elecricity resistence (before bonus)
- v = ps._electricityResistence._permanent;
+ v = ps->_electricityResistence._permanent;
break;
case 54:
// Cold resistence (before bonus)
- v = ps._coldResistence._permanent;
+ v = ps->_coldResistence._permanent;
break;
case 55:
// Poison resistence (before bonus)
- v = ps._poisonResistence._permanent;
+ v = ps->_poisonResistence._permanent;
break;
case 56:
// Energy reistence (before bonus)
- v = ps._energyResistence._permanent;
+ v = ps->_energyResistence._permanent;
break;
case 57:
// Energy resistence (before bonus)
- v = ps._magicResistence._permanent;
+ v = ps->_magicResistence._permanent;
break;
case 58:
// Fire resistence (extra beyond base)
- v = ps._fireResistence._temporary;
+ v = ps->_fireResistence._temporary;
break;
case 59:
// Electricity resistence (extra beyond base)
- v = ps._electricityResistence._temporary;
+ v = ps->_electricityResistence._temporary;
break;
case 60:
// Cold resistence (extra beyond base)
- v = ps._coldResistence._temporary;
+ v = ps->_coldResistence._temporary;
break;
case 61:
// Poison resistence (extra beyod base)
- v = ps._poisonResistence._temporary;
+ v = ps->_poisonResistence._temporary;
break;
case 62:
// Energy resistence (extra beyond base)
- v = ps._energyResistence._temporary;
+ v = ps->_energyResistence._temporary;
break;
case 63:
// Magic resistence (extra beyond base)
- v = ps._magicResistence._temporary;
+ v = ps->_magicResistence._temporary;
break;
case 64:
// Level (before bonus)
- v = ps._level._permanent;
+ v = ps->_level._permanent;
break;
case 65:
// Total party food
@@ -1772,19 +1814,19 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 77:
// Armor class (extra beyond base)
- v = ps._ACTemp;
+ v = ps->_ACTemp;
break;
case 78:
- // Test whether current Hp is equal to or exceeds the max HP
- v = ps._currentHp >= ps.getMaxHP() ? 1 : 0;
+ // Test whether current Hp exceeds max HP or not
+ v = ps->_currentHp <= ps->getMaxHP() ? 1 : 0;
break;
case 79:
// Test for Wizard Eye being active
v = party._wizardEyeActive ? 1 : 0;
break;
case 81:
- // Test whether current Sp is equal to or exceeds the max SP
- v = ps._currentSp >= ps.getMaxSP() ? 1 : 0;
+ // Test whether current Sp exceeds the max SP or not
+ v = ps->_currentSp <= ps->getMaxSP() ? 1 : 0;
break;
case 84:
// Current facing direction
@@ -1802,7 +1844,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
case 91:
case 92:
// Get a player stat
- v = ps.getStat((Attribute)(action - 86), 0);
+ v = ps->getStat((Attribute)(action - 86), 0);
break;
case 93:
// Current day of the week (10 days per week)
@@ -1818,7 +1860,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 102:
// Thievery skill
- v = ps.getThievery();
+ v = ps->getThievery();
break;
case 103:
// Get value of world flag
@@ -1826,7 +1868,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 104:
// Get value of quest flag
- v = party._questFlags[files._isDarkCc][val] ? val : 0xffffffff;
+ v = party._questFlags[(_vm->getGameID() == GType_Swords ? 0 : files._ccNum * 30) + val] ? val : 0xffffffff;
break;
case 105:
// Test number of Megacredits in party. Only used by King's Engineer in Castle Burlock
@@ -1834,7 +1876,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 107:
// Get value of character flag
- error("Unused");
+ v = party._characterFlags[ps->_rosterId][val] ? val : 0xffffffff;
break;
default:
break;
@@ -1857,8 +1899,8 @@ bool Scripts::copyProtectionCheck() {
if (!ConfMan.getBool("copy_protection"))
return true;
- // Currently not implemented
- return true;
+ // Show the copy protection dialog
+ return CopyProtection::show(_vm);
}
void Scripts::display(bool justifyFlag, int var46) {
diff --git a/engines/xeen/scripts.h b/engines/xeen/scripts.h
index 40564f3dda..89b6bda250 100644
--- a/engines/xeen/scripts.h
+++ b/engines/xeen/scripts.h
@@ -220,7 +220,6 @@ private:
MazeEvent *_event;
Common::Point _currentPos;
Common::Stack<StackEntry> _stack;
- Common::String _message;
Common::String _displayMessage;
typedef EventParameters::Iterator ParamsIterator;
@@ -279,7 +278,7 @@ private:
* Moves the position of an object
*/
bool cmdMoveObj(ParamsIterator &params);
-
+
/**
* Take or give amounts from various character or party figures
*/
@@ -320,13 +319,13 @@ private:
* Gives up to three different item/amounts to various character and/or party properties
*/
bool cmdGiveMulti(ParamsIterator &params);
-
+
/**
* Prompts the user to enter a word for passwords or mirror
* teleport destinations
*/
bool cmdConfirmWord(ParamsIterator &params);
-
+
/**
* Deals damage to a character
*/
@@ -545,6 +544,11 @@ private:
* Displays a message
*/
void display(bool justifyFlag, int var46);
+
+ /**
+ * Convert a CD time from the World of Xeen playCD opcodes to ScummVM CD frame number (which is at 75Hz)
+ */
+ uint convertCDTime(uint srcTime);
public:
int _animCounter;
bool _eventSkipped;
@@ -552,6 +556,7 @@ public:
DamageType _nEdamageType;
int _itemType;
Common::Array<MirrorEntry> _mirror;
+ Common::String _message;
public:
Scripts(XeenEngine *vm);
@@ -563,8 +568,9 @@ public:
/**
* Handles opening grates
+ * @returns If true, no further event checking should be done
*/
- void openGrate(int wallVal, int action);
+ bool openGrate(int wallVal, int action);
};
} // End of namespace Xeen
diff --git a/engines/xeen/sound.cpp b/engines/xeen/sound.cpp
index be15028f42..ae70c1f5d8 100644
--- a/engines/xeen/sound.cpp
+++ b/engines/xeen/sound.cpp
@@ -29,7 +29,8 @@
namespace Xeen {
Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer), _fxOn(true), _musicOn(true), _subtitles(false),
- _songData(nullptr), _effectsData(nullptr), _musicSide(0), _musicPercent(100) {
+ _songData(nullptr), _effectsData(nullptr), _musicSide(0), _musicPercent(100),
+ _musicVolume(0), _sfxVolume(0) {
_SoundDriver = new AdlibSoundDriver();
}
@@ -106,44 +107,32 @@ void Sound::setFxOn(bool isOn) {
g_vm->syncSoundSettings();
}
-void Sound::updateSoundSettings() {
- _fxOn = !ConfMan.getBool("sfx_mute");
- if (!_fxOn)
- stopFX();
-
- _musicOn = !ConfMan.getBool("music_mute");
- if (!_musicOn)
- stopSong();
-
- _subtitles = ConfMan.hasKey("subtitles") ? ConfMan.getBool("subtitles") : true;
-}
-
void Sound::loadEffectsData() {
// Stop any prior FX
stopFX();
- delete[] _effectsData;
-
- // Load in an entire driver so we have quick access to the effects data
- // that's hardcoded within it
- File file("blastmus");
- byte *effectsData = new byte[file.size()];
- file.seek(0);
- file.read(effectsData, file.size());
- file.close();
- _effectsData = effectsData;
-
- // Locate the playFX routine
- const byte *fx = effectsData + READ_LE_UINT16(effectsData + 10) + 12;
- assert(READ_BE_UINT16(fx + 28) == 0x81FB);
- uint numEffects = READ_LE_UINT16(fx + 30);
- assert(READ_BE_UINT16(fx + 36) == 0x8B87);
- const byte *table = effectsData + READ_LE_UINT16(fx + 38);
-
- // Extract the effects offsets
- _effectsOffsets.resize(numEffects);
- for (uint idx = 0; idx < numEffects; ++idx)
- _effectsOffsets[idx] = READ_LE_UINT16(&table[idx * 2]);
+ if (!_effectsData) {
+ // Load in an entire driver so we have quick access to the effects data that's hardcoded within it
+ File file("blastmus");
+ byte *effectsData = new byte[file.size()];
+ file.seek(0);
+ file.read(effectsData, file.size());
+ file.close();
+ _effectsData = effectsData;
+
+ // Locate the playFX routine
+ const byte *fx = effectsData + READ_LE_UINT16(effectsData + 10) + 12;
+ assert(READ_BE_UINT16(fx + 28) == 0x81FB);
+ uint numEffects = READ_LE_UINT16(fx + 30);
+
+ assert(READ_BE_UINT16(fx + 36) == 0x8B87);
+ const byte *table = effectsData + READ_LE_UINT16(fx + 38);
+
+ // Extract the effects offsets
+ _effectsOffsets.resize(numEffects);
+ for (uint idx = 0; idx < numEffects; ++idx)
+ _effectsOffsets[idx] = READ_LE_UINT16(&table[idx * 2]);
+ }
}
void Sound::playFX(uint effectId) {
@@ -160,8 +149,8 @@ void Sound::stopFX() {
_SoundDriver->stopFX();
}
-int Sound::songCommand(uint commandId, byte volume) {
- int result = _SoundDriver->songCommand(commandId, volume);
+int Sound::songCommand(uint commandId, byte musicVolume, byte sfxVolume) {
+ int result = _SoundDriver->songCommand(commandId, musicVolume, sfxVolume);
if (commandId == STOP_SONG) {
delete[] _songData;
_songData = nullptr;
@@ -212,8 +201,26 @@ void Sound::setMusicPercent(byte percent) {
assert(percent <= 100);
_musicPercent = percent;
- songCommand(SET_VOLUME, (int)percent * 127 / 100);
+ updateVolume();
}
+void Sound::updateSoundSettings() {
+ _fxOn = !ConfMan.getBool("sfx_mute");
+ if (!_fxOn)
+ stopFX();
+
+ _musicOn = !ConfMan.getBool("music_mute");
+ if (!_musicOn)
+ stopSong();
+
+ _subtitles = ConfMan.hasKey("subtitles") ? ConfMan.getBool("subtitles") : true;
+ _musicVolume = CLIP(ConfMan.getInt("music_volume"), 0, 255);
+ _sfxVolume = CLIP(ConfMan.getInt("sfx_volume"), 0, 255);
+ updateVolume();
+}
+
+void Sound::updateVolume() {
+ songCommand(SET_VOLUME, _musicPercent * _musicVolume / 100, _sfxVolume);
+}
} // End of namespace Xeen
diff --git a/engines/xeen/sound.h b/engines/xeen/sound.h
index 86303f682f..613299c6dc 100644
--- a/engines/xeen/sound.h
+++ b/engines/xeen/sound.h
@@ -40,6 +40,7 @@ private:
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
byte _musicPercent;
+ int _musicVolume, _sfxVolume;
private:
/**
* Loads effects data that was embedded in the music driver
@@ -50,6 +51,11 @@ private:
* Updates any playing music
*/
void update();
+
+ /**
+ * Updates the music and sound effects playing volume
+ */
+ void updateVolume();
public:
bool _fxOn;
bool _musicOn;
@@ -73,7 +79,7 @@ public:
/**
* Executes special music command
*/
- int songCommand(uint commandId, byte volume = 0);
+ int songCommand(uint commandId, byte musicVolume = 0, byte sfxVolume = 0);
/**
* Stops any currently playing music
diff --git a/engines/xeen/sound_driver.cpp b/engines/xeen/sound_driver.cpp
index e79fcdd501..967f53ac49 100644
--- a/engines/xeen/sound_driver.cpp
+++ b/engines/xeen/sound_driver.cpp
@@ -225,7 +225,7 @@ void SoundDriver::playSong(const byte *data) {
debugC(1, kDebugSound, "Starting song");
}
-int SoundDriver::songCommand(uint commandId, byte volume) {
+int SoundDriver::songCommand(uint commandId, byte musicVolume, byte sfxVolume) {
if (commandId == STOP_SONG) {
_musicPlaying = false;
} else if (commandId == RESTART_SONG) {
@@ -262,7 +262,7 @@ const CommandFn SoundDriver::FX_COMMANDS[16] = {
/*------------------------------------------------------------------------*/
AdlibSoundDriver::AdlibSoundDriver() : _field180(0), _field181(0), _field182(0),
- _volume(127) {
+ _musicVolume(0), _sfxVolume(0) {
Common::fill(&_musInstrumentPtrs[0], &_musInstrumentPtrs[16], (const byte *)nullptr);
Common::fill(&_fxInstrumentPtrs[0], &_fxInstrumentPtrs[16], (const byte *)nullptr);
@@ -304,9 +304,9 @@ void AdlibSoundDriver::playSong(const byte *data) {
resetFrequencies();
}
-int AdlibSoundDriver::songCommand(uint commandId, byte volume) {
+int AdlibSoundDriver::songCommand(uint commandId, byte musicVolume, byte sfxVolume) {
Common::StackLock slock(_driverMutex);
- SoundDriver::songCommand(commandId, volume);
+ SoundDriver::songCommand(commandId, musicVolume, sfxVolume);
if (commandId == STOP_SONG) {
_field180 = 0;
@@ -320,7 +320,8 @@ int AdlibSoundDriver::songCommand(uint commandId, byte volume) {
_field182 = 63;
}
} else if (commandId == SET_VOLUME) {
- _volume = volume;
+ _musicVolume = musicVolume;
+ _sfxVolume = sfxVolume;
} else if (commandId == GET_STATUS) {
return _field180;
}
@@ -428,7 +429,7 @@ void AdlibSoundDriver::setOutputLevel(byte channelNum, uint level) {
(_channels[channelNum]._scalingValue & 0xC0));
}
-void AdlibSoundDriver::playInstrument(byte channelNum, const byte *data) {
+void AdlibSoundDriver::playInstrument(byte channelNum, const byte *data, byte volume) {
byte op1 = OPERATOR1_INDEXES[channelNum];
byte op2 = OPERATOR2_INDEXES[channelNum];
debugC(2, kDebugSound, "---START-playInstrument - %d", channelNum);
@@ -441,7 +442,7 @@ void AdlibSoundDriver::playInstrument(byte channelNum, const byte *data) {
int scalingVal = *data++;
_channels[channelNum]._scalingValue = scalingVal;
- scalingVal += (127 - _volume) / 2;
+ scalingVal += (127 - volume) / 2;
if (scalingVal > 63) {
scalingVal = 63;
@@ -535,7 +536,7 @@ bool AdlibSoundDriver::musPlayInstrument(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "musPlayInstrument %d, %d", param, instrument);
if (param < 7)
- playInstrument(param, _musInstrumentPtrs[instrument]);
+ playInstrument(param, _musInstrumentPtrs[instrument], _musicVolume);
return false;
}
@@ -633,7 +634,7 @@ bool AdlibSoundDriver::fxPlayInstrument(const byte *&srcP, byte param) {
debugC(3, kDebugSound, "fxPlayInstrument %d, %d", param, instrument);
if (!_exclude7 || param != 7)
- playInstrument(param, _fxInstrumentPtrs[instrument]);
+ playInstrument(param, _fxInstrumentPtrs[instrument], _sfxVolume);
return false;
}
diff --git a/engines/xeen/sound_driver.h b/engines/xeen/sound_driver.h
index c78408b047..d4edd49c05 100644
--- a/engines/xeen/sound_driver.h
+++ b/engines/xeen/sound_driver.h
@@ -40,8 +40,7 @@ namespace OPL {
namespace Xeen {
enum MusicCommand {
- STOP_SONG = 0, RESTART_SONG = 1, SET_VOLUME = 0x100,
- GET_STATUS = 0xFFE0
+ STOP_SONG = 0, RESTART_SONG = 1, SET_VOLUME = 0x100, GET_STATUS = 0xFFE0
};
class SoundDriver;
@@ -170,7 +169,7 @@ public:
/**
* Executes special music command
*/
- virtual int songCommand(uint commandId, byte volume = 0);
+ virtual int songCommand(uint commandId, byte musicVolume = 0, byte sfxVolume = 0);
/**
* Returns whether music is currently playing
@@ -200,7 +199,7 @@ private:
int _field180;
int _field181;
int _field182;
- int _volume;
+ int _musicVolume, _sfxVolume;
private:
/**
* Initializes the state of the Adlib OPL driver
@@ -246,7 +245,7 @@ private:
/**
* Starts playing an instrument
*/
- void playInstrument(byte channelNum, const byte *data);
+ void playInstrument(byte channelNum, const byte *data, byte volume);
protected:
virtual bool musSetInstrument(const byte *&srcP, byte param);
virtual bool musSetPitchWheel(const byte *&srcP, byte param);
@@ -301,7 +300,7 @@ public:
/**
* Executes special music command
*/
- virtual int songCommand(uint commandId, byte volume = 0);
+ virtual int songCommand(uint commandId, byte musicVolume = 0, byte sfxVolume = 0);
};
} // End of namespace Xeen
diff --git a/engines/xeen/spells.cpp b/engines/xeen/spells.cpp
index 9ba581249b..04d77e1f66 100644
--- a/engines/xeen/spells.cpp
+++ b/engines/xeen/spells.cpp
@@ -93,47 +93,49 @@ void Spells::spellFailed() {
}
void Spells::castItemSpell(int itemSpellId) {
+ assert(itemSpellId != 0);
+
switch (itemSpellId) {
- case 15:
+ case 16:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_Jump);
return;
}
break;
- case 20:
+ case 21:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_WizardEye);
return;
}
break;
- case 27:
+ case 28:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_LloydsBeacon);
return;
}
break;
- case 32:
+ case 33:
frostbite2();
break;
- case 41:
+ case 42:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_Teleport);
return;
}
break;
- case 47:
+ case 48:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_SuperShelter);
return;
}
break;
- case 54:
+ case 55:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_TownPortal);
return;
}
break;
- case 57:
+ case 58:
if (_vm->_mode == MODE_COMBAT) {
NotWhileEngaged::show(_vm, MS_Etheralize);
return;
@@ -143,8 +145,8 @@ void Spells::castItemSpell(int itemSpellId) {
break;
}
- static const MagicSpell spells[73] = {
- MS_Light, MS_Awaken, MS_MagicArrow, MS_FirstAid, MS_FlyingFist,
+ static const MagicSpell spells[74] = {
+ NO_SPELL, MS_Light, MS_Awaken, MS_MagicArrow, MS_FirstAid, MS_FlyingFist,
MS_EnergyBlast, MS_Sleep, MS_Revitalize, MS_CureWounds, MS_Sparks,
MS_Shrapmetal, MS_InsectSpray, MS_ToxicCloud, MS_ProtFromElements, MS_Pain,
MS_Jump, MS_BeastMaster, MS_Clairvoyance, MS_TurnUndead, MS_Levitate,
@@ -426,52 +428,7 @@ void Spells::deadlySwarm() {
}
void Spells::detectMonster() {
- EventsManager &events = *_vm->_events;
- Interface &intf = *_vm->_interface;
- Map &map = *_vm->_map;
- Party &party = *_vm->_party;
- Sound &sound = *_vm->_sound;
- Windows &windows = *_vm->_windows;
- Window &w = windows[19];
- bool isDarkCc = _vm->_files->_isDarkCc;
- int grid[7][7];
-
- SpriteResource sprites(isDarkCc ? "detectmn.icn" : "detctmon.icn");
- Common::fill(&grid[0][0], &grid[6][6], 0);
-
- w.open();
- w.writeString(Res.DETECT_MONSTERS);
- sprites.draw(w, 0, Common::Point(243, 80));
-
- for (int yDiff = 3; yDiff >= -3; --yDiff) {
- for (int xDiff = -3; xDiff <= 3; ++xDiff) {
- for (uint monIndex = 0; monIndex < map._mobData._monsters.size(); ++monIndex) {
- MazeMonster &monster = map._mobData._monsters[monIndex];
- Common::Point pt = party._mazePosition + Common::Point(xDiff, yDiff);
- if (monster._position == pt) {
- int &gridEntry = grid[yDiff + 3][xDiff + 3];
- if (++gridEntry > 3)
- gridEntry = 3;
-
- sprites.draw(w, gridEntry, Common::Point(xDiff * 9 + 244,
- yDiff * 7 + 81));
- }
- }
- }
- }
-
- sprites.draw(w, party._mazeDirection + 1, Common::Point(270, 101));
- sound.playFX(20);
- w.update();
-
- do {
- events.updateGameCounter();
- intf.draw3d(true);
-
- events.wait(1, false);
- } while (!events.isKeyMousePressed());
-
- w.close();
+ DetectMonsters::show(_vm);
}
void Spells::divineIntervention() {
@@ -520,8 +477,8 @@ void Spells::elementalStorm() {
combat._monsterDamage = 150;
combat._damageType = (DamageType)_vm->getRandomNumber(DT_FIRE, DT_POISON);
combat._rangeType = RT_ALL;
- sound.playFX(STORM_FX_LIST[combat._damageType]);
- combat.rangedAttack(STORM_MA_LIST[combat._damageType]);
+ sound.playFX(STORM_FX_LIST[combat._damageType - DT_FIRE]);
+ combat.rangedAttack(STORM_MA_LIST[combat._damageType - DT_FIRE]);
}
void Spells::enchantItem() {
@@ -1148,7 +1105,7 @@ void Spells::superShelter() {
spellFailed();
} else {
Mode oldMode = _vm->_mode;
- _vm->_mode = MODE_12;
+ _vm->_mode = MODE_INTERACTIVE2;
sound.playFX(30);
intf.rest();
_vm->_mode = oldMode;
@@ -1246,11 +1203,16 @@ void Spells::townPortal() {
return;
sound.playFX(51);
- map._loadDarkSide = map._sideTownPortal;
- _vm->_files->_isDarkCc = map._sideTownPortal > 0;
- map.load(Res.TOWN_MAP_NUMBERS[map._sideTownPortal][townNumber - 1]);
+ map._loadCcNum = map._sideTownPortal;
+ _vm->_files->_ccNum = map._sideTownPortal > 0;
+
+ int arrIndex = _vm->getGameID() == GType_Swords ? 2 : map._sideTownPortal;
+ map.load(Res.TOWN_MAP_NUMBERS[arrIndex][townNumber - 1]);
- if (!_vm->_files->_isDarkCc) {
+ if (_vm->getGameID() == GType_Swords) {
+ party._mazePosition = Common::Point(8, 3);
+ party._mazeDirection = DIR_NORTH;
+ } else if (!_vm->_files->_ccNum) {
party.moveToRunLocation();
} else {
switch (townNumber) {
diff --git a/engines/xeen/spells.h b/engines/xeen/spells.h
index a333ea2f5f..24e9dd1f57 100644
--- a/engines/xeen/spells.h
+++ b/engines/xeen/spells.h
@@ -56,7 +56,7 @@ enum MagicSpell {
MS_SuppressDisease = 67, MS_SuppressPoison = 68, MS_Teleport = 69,
MS_TimeDistortion = 70, MS_TownPortal = 71, MS_ToxicCloud = 72,
MS_TurnUndead = 73, MS_WalkOnWater = 74, MS_WizardEye = 75,
- NO_SPELL = 76
+ NO_SPELL = 76, TOTAL_SPELLS = 76
};
class Spells {
diff --git a/engines/xeen/sprites.cpp b/engines/xeen/sprites.cpp
index 4811f10628..7b484b53e3 100644
--- a/engines/xeen/sprites.cpp
+++ b/engines/xeen/sprites.cpp
@@ -146,6 +146,9 @@ void SpriteResource::drawOffset(XSurface &dest, uint16 offset, const Common::Poi
dest.create(xOffset + width, yOffset + height);
bounds = Common::Rect(0, 0, dest.w, dest.h);
}
+ if (flags & SPRFLAG_SCENE_CLIPPED) {
+ bounds.clip(Common::Rect(8, 8, 223, 141));
+ }
uint16 scaleMaskXCopy = scaleMaskX;
Common::Rect drawBounds;
@@ -281,17 +284,23 @@ void SpriteResource::drawOffset(XSurface &dest, uint16 offset, const Common::Poi
if (bit) {
// Check whether there's a pixel to write, and we're within the allowable bounds. Note that for
// the SPRFLAG_SCENE_CLIPPED or when enlarging, we also have an extra horizontal bounds check
- if (*lineP != -1 && xp >= bounds.left && xp < bounds.right &&
- ((!(flags & SPRFLAG_SCENE_CLIPPED) && !enlarge) || (xp >= SCENE_CLIP_LEFT && xp < SCENE_CLIP_RIGHT))) {
+ if (*lineP != -1 && xp >= bounds.left && xp < bounds.right) {
drawBounds.left = MIN(drawBounds.left, xp);
drawBounds.right = MAX((int)drawBounds.right, xp + 1);
*destP = (byte)*lineP;
- if (enlarge)
+ if (enlarge) {
*(destP + SCREEN_WIDTH) = (byte)*lineP;
+ *(destP + 1) = (byte)*lineP;
+ *(destP + 1 + SCREEN_WIDTH) = (byte)*lineP;
+ }
}
- ++destP;
++xp;
+ ++destP;
+ if (enlarge) {
+ ++destP;
+ ++xp;
+ }
}
}
diff --git a/engines/xeen/subtitles.cpp b/engines/xeen/subtitles.cpp
index 86dff2dac8..168ed1d4ea 100644
--- a/engines/xeen/subtitles.cpp
+++ b/engines/xeen/subtitles.cpp
@@ -40,7 +40,7 @@ Subtitles::~Subtitles() {
void Subtitles::loadSubtitles() {
File f("special.bin");
- if (!g_vm->_files->_isDarkCc) {
+ if (!g_vm->_files->_ccNum) {
// The first subtitle line contains all the text for the Clouds intro. Since ScummVM allows
// both voice and subtitles at the same time, unlike the original, we need to split up the
// first subtitle into separate lines to allow them to better interleave with the voice
diff --git a/engines/xeen/subtitles.h b/engines/xeen/subtitles.h
index 37148dbc92..55c5faaa26 100644
--- a/engines/xeen/subtitles.h
+++ b/engines/xeen/subtitles.h
@@ -65,7 +65,7 @@ public:
* Set which subtitle line to display
*/
void setLine(int line);
-
+
/**
* Resets subtitles, stopping any display
*/
diff --git a/engines/xeen/swordsofxeen/swordsofxeen.cpp b/engines/xeen/swordsofxeen/swordsofxeen.cpp
index bbe0a74c1c..6f3963e1d0 100644
--- a/engines/xeen/swordsofxeen/swordsofxeen.cpp
+++ b/engines/xeen/swordsofxeen/swordsofxeen.cpp
@@ -49,10 +49,10 @@ void SwordsOfXeenEngine::death() {
_sound->playSound("laff1.voc");
bool breakFlag = false;
- for (int idx = 0, idx2 = 0; idx < (_files->_isDarkCc ? 10 : 23); ++idx) {
+ for (int idx = 0, idx2 = 0; idx < (_files->_ccNum ? 10 : 23); ++idx) {
_events->updateGameCounter();
- if (_files->_isDarkCc) {
+ if (_files->_ccNum) {
breakFlag = _events->wait(2);
} else {
if (idx == 1 || idx == 11)
@@ -63,8 +63,8 @@ void SwordsOfXeenEngine::death() {
_sound->playFX(34);
}
- if ((_files->_isDarkCc ? 9 : 10) == idx) {
- if ((_files->_isDarkCc ? 2 : 1) > idx2) {
+ if ((_files->_ccNum ? 9 : 10) == idx) {
+ if ((_files->_ccNum ? 2 : 1) > idx2) {
// Restart loop
idx = -1;
++idx2;
@@ -82,12 +82,44 @@ void SwordsOfXeenEngine::death() {
_sound->stopAllAudio();
}
+bool SwordsOfXeenEngine::showEnding() {
+ Windows &windows = *_windows;
+ SpriteResource win("win.int");
+
+ _screen->loadBackground("blank.raw");
+ windows[28].setBounds(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+ _screen->fadeIn(0x81);
+ _screen->loadPalette("scr.pal");
+ _screen->fadeIn(0x81);
+
+ win.draw(0, 0, Common::Point(0, 0));
+ win.draw(0, 1, Common::Point(160, 0));
+ _sound->playSound("ch1.voc");
+ _events->waitForPress();
+
+ _screen->fadeOut();
+ _screen->loadBackground("blank.raw");
+ return true;
+}
+
void SwordsOfXeenEngine::dream() {
// Swords of Xeen doesn't have any dreams
}
void SwordsOfXeenEngine::showCutscene(const Common::String &name, int status, uint score) {
+ _sound->stopAllAudio();
+ _events->clearEvents();
+
+ if (name != "ENDGAME")
+ error("Unknown cutscene specified");
+
+ showEnding();
+
+ _screen->freePages();
+ _sound->stopAllAudio();
+ _events->clearEvents();
_gameMode = GMODE_MENU;
+
}
} // End of namespace SwordsOfXeen
diff --git a/engines/xeen/swordsofxeen/swordsofxeen.h b/engines/xeen/swordsofxeen/swordsofxeen.h
index d301423287..b19f4e1d53 100644
--- a/engines/xeen/swordsofxeen/swordsofxeen.h
+++ b/engines/xeen/swordsofxeen/swordsofxeen.h
@@ -34,6 +34,11 @@ namespace SwordsOfXeen {
* Swords of Xeen specific game code
*/
class SwordsOfXeenEngine: public XeenEngine {
+private:
+ /**
+ * Show the ending "You won" screen
+ */
+ bool showEnding();
protected:
/**
* Show the starting sequence/intro
diff --git a/engines/xeen/window.cpp b/engines/xeen/window.cpp
index 47732dc841..caa17b7563 100644
--- a/engines/xeen/window.cpp
+++ b/engines/xeen/window.cpp
@@ -41,21 +41,21 @@ Windows::Windows() {
Window windows[48] = {
Window(Common::Rect(0, 0, 320, 200), 0, 0, 0, 0, 320, 200),
Window(Common::Rect(237, 9, 317, 74), 0, 0, 237, 12, 307, 68),
- Window(Common::Rect(225, 1, 319, 73), 1, 8, 225, 1, 319, 73),
+ Window(Common::Rect(225, 1, 320, 73), 1, 8, 225, 1, 319, 73),
Window(Common::Rect(0, 0, 230, 149), 0, 0, 9, 8, 216, 140),
Window(Common::Rect(235, 148, 309, 189), 2, 8, 0, 0, 0, 0),
Window(Common::Rect(70, 20, 250, 183), 3, 8, 80, 38, 240, 166),
- Window(Common::Rect(52, 149, 268, 197), 4, 8, 0, 0, 0, 0),
+ Window(Common::Rect(52, 149, 268, 198), 4, 8, 0, 0, 0, 0),
Window(Common::Rect(108, 0, 200, 200), 5, 0, 0, 0, 0, 0),
Window(Common::Rect(232, 9, 312, 74), 0, 0, 0, 0, 0, 0),
Window(Common::Rect(103, 156, 217, 186), 6, 8, 0, 0, 0, 0),
- Window(Common::Rect(226, 0, 319, 146), 7, 8, 0, 0, 0, 0),
+ Window(Common::Rect(226, 0, 320, 146), 7, 8, 0, 0, 0, 0),
Window(Common::Rect(8, 8, 224, 140), 8, 8, 8, 8, 224, 200),
Window(Common::Rect(0, 143, 320, 199), 9, 8, 0, 0, 0, 0),
Window(Common::Rect(50, 103, 266, 139), 10, 8, 0, 0, 0, 0),
Window(Common::Rect(0, 7, 320, 138), 11, 8, 0, 0, 0, 0),
Window(Common::Rect(50, 71, 182, 129), 12, 8, 0, 0, 0, 0),
- Window(Common::Rect(228, 106, 319, 146), 13, 8, 0, 0, 0, 0),
+ Window(Common::Rect(228, 106, 320, 146), 13, 8, 0, 0, 0, 0),
Window(Common::Rect(20, 142, 290, 199), 14, 8, 0, 0, 0, 0),
Window(Common::Rect(0, 20, 320, 180), 15, 8, 0, 0, 0, 0),
Window(Common::Rect(231, 48, 317, 141), 16, 8, 0, 0, 0, 0),
@@ -74,10 +74,10 @@ Windows::Windows() {
Window(Common::Rect(12, 11, 164, 94), 0, 0, 0, 0, 52, 0),
Window(Common::Rect(8, 147, 224, 192), 0, 8, 0, 0, 0, 94),
Window(Common::Rect(232, 74, 312, 138), 29, 8, 0, 0, 0, 0),
- Window(Common::Rect(226, 26, 319, 146), 30, 8, 0, 0, 0, 0),
- Window(Common::Rect(225, 74, 319, 154), 31, 8, 0, 0, 0, 0),
+ Window(Common::Rect(226, 26, 320, 146), 30, 8, 0, 0, 0, 0),
+ Window(Common::Rect(225, 74, 320, 154), 31, 8, 0, 0, 0, 0),
Window(Common::Rect(27, 6, 195, 142), 0, 8, 0, 0, 0, 0),
- Window(Common::Rect(225, 140, 319, 199), 0, 8, 0, 0, 0, 0),
+ Window(Common::Rect(225, 140, 320, 199), 0, 8, 0, 0, 0, 0),
Window(Common::Rect(12, 8, 162, 198), 0, 0, 128, 0, 119, 0),
Window(Common::Rect(0, 0, 320, 200), 32, 8, 0, 0, 320, 190),
Window(Common::Rect(0, 0, 320, 200), 33, 8, 0, 0, 320, 200)
diff --git a/engines/xeen/worldofxeen/clouds_cutscenes.cpp b/engines/xeen/worldofxeen/clouds_cutscenes.cpp
index 0e8149e37e..2ae921cf19 100644
--- a/engines/xeen/worldofxeen/clouds_cutscenes.cpp
+++ b/engines/xeen/worldofxeen/clouds_cutscenes.cpp
@@ -21,7 +21,6 @@
*/
#include "xeen/worldofxeen/clouds_cutscenes.h"
-#include "xeen/worldofxeen/worldofxeen_resources.h"
#include "xeen/sound.h"
namespace Xeen {
@@ -40,8 +39,10 @@ bool CloudsCutscenes::showCloudsIntro() {
Screen &screen = *g_vm->_screen;
Sound &sound = *g_vm->_sound;
- bool darkCc = files._isDarkCc;
+ bool darkCc = files._ccNum;
files.setGameCc(0);
+ sound._musicSide = 0;
+ _subtitles.reset();
bool seenIntro = showCloudsTitle() && showCloudsIntroInner();
@@ -278,7 +279,7 @@ bool CloudsCutscenes::showCloudsIntroInner() {
sound.playVoice(_INTRO_VOCS[lineCtr]);
}
- for (int frameCtr = 0, lookup = 0; sound.isSoundPlaying() ||
+ for (int frameCtr = 0, lookup = 0; sound.isSoundPlaying() ||
(_subtitles.active() && (lineCtr == 0 || lineCtr == 4 || lineCtr == 10 || lineCtr == 13)); ) {
groupo.draw(0, 0);
groupo.draw(0, 1, Common::Point(160, 0));
@@ -332,7 +333,7 @@ bool CloudsCutscenes::showCloudsIntroInner() {
windows[0].writeString(Res.CLOUDS_INTRO1);
ctr5 = (ctr5 + 1) % 19;
-
+
WAIT(1);
continue;
}
@@ -379,8 +380,9 @@ void CloudsCutscenes::showCloudsEnding(uint finalScore) {
FileManager &files = *g_vm->_files;
Sound &sound = *g_vm->_sound;
- bool darkCc = files._isDarkCc;
+ bool darkCc = files._ccNum;
files.setGameCc(0);
+ _subtitles.reset();
_mirror.load("mirror.end");
_mirrBack.load("mirrback.end");
@@ -406,7 +408,7 @@ bool CloudsCutscenes::showCloudsEnding1() {
Screen &screen = *_vm->_screen;
Sound &sound = *_vm->_sound;
- files._isDarkCc = false;
+ files._ccNum = false;
files.setGameCc(0);
// Show the castle with swirling clouds and lightning
@@ -985,7 +987,7 @@ bool CloudsCutscenes::showCloudsEnding5() {
king.draw(0, 1, Common::Point(160, 0));
screen.fadeIn();
_subtitles.setLine(13);
-
+
sound.playVoice("king4.voc");
do {
king.draw(0, 0, Common::Point(0, 0));
diff --git a/engines/xeen/worldofxeen/darkside_cutscenes.cpp b/engines/xeen/worldofxeen/darkside_cutscenes.cpp
index 0e931ce9d7..c0ef2e98d7 100644
--- a/engines/xeen/worldofxeen/darkside_cutscenes.cpp
+++ b/engines/xeen/worldofxeen/darkside_cutscenes.cpp
@@ -24,7 +24,6 @@
#include "xeen/xeen.h"
#include "xeen/worldofxeen/darkside_cutscenes.h"
#include "xeen/worldofxeen/worldofxeen.h"
-#include "xeen/worldofxeen/worldofxeen_resources.h"
#define WAIT(TIME) if (_subtitles.wait(TIME)) return false
@@ -74,7 +73,8 @@ const int LEFT_CLAW_IDLE_Y[32] = {
bool DarkSideCutscenes::showDarkSideTitle(bool seenIntro) {
Screen &screen = *g_vm->_screen;
Sound &sound = *g_vm->_sound;
- g_vm->_files->_isDarkCc = true;
+ g_vm->_files->_ccNum = true;
+ _subtitles.reset();
screen.loadPalette("dark.pal");
SpriteResource nwc[4] = {
@@ -105,7 +105,7 @@ bool DarkSideCutscenes::showDarkSideTitle(bool seenIntro) {
// Render the next frame
screen.vertMerge(0);
nwc[nwcIndex].draw(0, nwcFrame);
-
+
switch (idx) {
case 17:
sound.playSound(voc[0]);
@@ -129,7 +129,7 @@ bool DarkSideCutscenes::showDarkSideTitle(bool seenIntro) {
for (int idx = 0; idx < 42 && !g_vm->shouldExit(); ++idx) {
screen.vertMerge(SCREEN_HEIGHT);
nwc[3].draw(0, idx);
-
+
switch (idx) {
case 3:
sound.playFX(40);
@@ -168,8 +168,9 @@ bool DarkSideCutscenes::showDarkSideIntro(bool seenIntro) {
Screen &screen = *g_vm->_screen;
Sound &sound = *g_vm->_sound;
- files._isDarkCc = true;
+ files._ccNum = true;
files.setGameCc(1);
+ _subtitles.reset();
if (showDarkSideTitle(seenIntro)) {
if (seenIntro) {
@@ -809,7 +810,7 @@ bool DarkSideCutscenes::showWorldOfXeenLogo() {
for (int idx = 0; idx < 21; ++idx) {
screen.restoreBackground();
wfire[6].draw(0, idx, Common::Point(0, 45));
-
+
switch (idx) {
case 0:
case 11:
@@ -837,6 +838,7 @@ void DarkSideCutscenes::showDarkSideEnding(uint endingScore) {
Sound &sound = *g_vm->_sound;
files.setGameCc(1);
+ _subtitles.reset();
sound._musicSide = 1;
screen.fadeOut();
@@ -1285,7 +1287,7 @@ bool DarkSideCutscenes::showDarkSideEnding3() {
screen.horizMerge(0);
sc16.draw(0, 0, Common::Point(7, 29));
_subtitles.show();
- sound.playSound("fail1.voc");
+ sound.playVoice("fail1.voc", 2);
for (int idx = 0; idx < 5; ++idx) {
screen.horizMerge(0);
@@ -1689,21 +1691,25 @@ void DarkSideCutscenes::showDarkSideScore(uint endingScore) {
sound.stopAllAudio();
- if (g_vm->shouldExit()) {
+ if (!g_vm->shouldExit()) {
sound.playSong("outday3.m");
Common::String str = Common::String::format(Res.DARKSIDE_ENDING1, endingScore);
showPharaohEndText(str.c_str(), Res.DARKSIDE_ENDING2);
+ g_vm->_mode = MODE_INTERACTIVE;
if (!g_vm->shouldExit())
saves.saveGame();
}
}
bool DarkSideCutscenes::showPharaohEndText(const char *msg1, const char *msg2, const char *msg3) {
+ Windows &windows = *g_vm->_windows;
_ball.load("ball.int");
_claw.load("claw.int");
_dragon1.load("dragon1.int");
+
+ windows[39].setBounds(Common::Rect(12, 8, 162, 198));
bool result = showPharaohEndTextInner(msg1, msg2, msg3);
_ball.clear();
diff --git a/engines/xeen/worldofxeen/worldofxeen.cpp b/engines/xeen/worldofxeen/worldofxeen.cpp
index 962bdfec6a..ecaae8303b 100644
--- a/engines/xeen/worldofxeen/worldofxeen.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen.cpp
@@ -71,7 +71,7 @@ void WorldOfXeenEngine::death() {
}
w.update();
- _events->wait(1);
+ _events->wait(1, false);
}
deathSprites.draw(0, 34, Common::Point(0, 0));
@@ -79,10 +79,10 @@ void WorldOfXeenEngine::death() {
w.update();
savedBg.blitFrom(*_screen);
- _sound->playSong(_files->_isDarkCc ? "laff1.voc" : "xeenlaff.voc");
+ _sound->playSound(_files->_ccNum ? "laff1.voc" : "xeenlaff.voc", _files->_ccNum, 0);
// Animation of Xeen or Alamar laughing
- for (int idx = 0, idx2 = 0; idx < (_files->_isDarkCc ? 10 : 23); ++idx) {
+ for (int idx = 0, idx2 = 0; idx < (_files->_ccNum ? 10 : 23); ++idx) {
_events->updateGameCounter();
_screen->blitFrom(savedBg);
@@ -90,18 +90,18 @@ void WorldOfXeenEngine::death() {
death1Sprites.draw(0, idx - 1);
w.update();
- if (_files->_isDarkCc) {
- _events->wait(2);
+ if (_files->_ccNum) {
+ _events->wait(2, false);
} else {
if (idx == 1 || idx == 11)
_sound->playFX(33);
- _events->wait(2);
+ _events->wait(2, false);
if (idx == 15)
_sound->playFX(34);
}
- if (idx == (_files->_isDarkCc ? 9 : 10)) {
- if (idx2 < (_files->_isDarkCc ? 2 : 1)) {
+ if (idx == (_files->_ccNum ? 9 : 10)) {
+ if (idx2 < (_files->_ccNum ? 2 : 1)) {
idx = -1;
++idx2;
}
@@ -111,6 +111,9 @@ void WorldOfXeenEngine::death() {
idx = 23;
}
+ while (_sound->isSoundPlaying())
+ _events->wait(1, false);
+
_screen->blitFrom(savedBg);
w.update();
}
@@ -131,11 +134,11 @@ void WorldOfXeenEngine::dream() {
while (!shouldExit() && _events->timeElapsed() < 7)
_events->pollEventsAndWait();
- _sound->playSound("dreams2.voc", 1);
+ _sound->playSound("dreams2.voc", 1, 0);
while (!shouldExit() && _sound->isSoundPlaying())
_events->pollEventsAndWait();
- _sound->playSound("laff1.voc", 1);
+ _sound->playSound("laff1.voc", 1, 0);
while (!shouldExit() && _sound->isSoundPlaying())
_events->pollEventsAndWait();
diff --git a/engines/xeen/worldofxeen/worldofxeen_cutscenes.cpp b/engines/xeen/worldofxeen/worldofxeen_cutscenes.cpp
index 9d35733de9..fafbb8ef8d 100644
--- a/engines/xeen/worldofxeen/worldofxeen_cutscenes.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_cutscenes.cpp
@@ -479,14 +479,14 @@ bool WorldOfXeenCutscenes::worldEnding2() {
if (idx == 2 || idx == 15 || idx == 21)
sound.playSound("photon.voc", 1, 0);
- screen.restoreBackground();
+ screen.blitFrom(savedBg);
sc24.draw(0, idx, Common::Point(103, 6));
WAIT(3);
}
for (int idx = 20; idx < 35; ++idx) {
- screen.restoreBackground();
+ screen.blitFrom(savedBg);
sc24.draw(0, idx, Common::Point(103, 6));
WAIT(3);
@@ -599,13 +599,13 @@ bool WorldOfXeenCutscenes::worldEnding3() {
SpriteResource sc30("sc30.eg2");
SpriteResource sc28[14] = {
- SpriteResource("sc28a.eg2"), SpriteResource("sc28b1.eg2"),
- SpriteResource("sc28c.eg2"), SpriteResource("sc28d.eg2"),
- SpriteResource("sc28e.eg2"), SpriteResource("sc28f.eg2"),
- SpriteResource("sc28g.eg2"), SpriteResource("sc28h.eg2"),
- SpriteResource("sc28i.eg2"), SpriteResource("sc28j.eg2"),
- SpriteResource("sc28k.eg2"), SpriteResource("sc28l.eg2"),
- SpriteResource("sc28m.eg2"), SpriteResource("sc28n.eg2"),
+ SpriteResource("sc28a.eg2", 2), SpriteResource("sc28b1.eg2", 2),
+ SpriteResource("sc28c.eg2", 2), SpriteResource("sc28d.eg2", 2),
+ SpriteResource("sc28e.eg2", 2), SpriteResource("sc28f.eg2", 2),
+ SpriteResource("sc28g.eg2", 2), SpriteResource("sc28h.eg2", 2),
+ SpriteResource("sc28i.eg2", 2), SpriteResource("sc28j.eg2", 2),
+ SpriteResource("sc28k.eg2", 2), SpriteResource("sc28l.eg2", 2),
+ SpriteResource("sc28m.eg2", 2), SpriteResource("sc28n.eg2", 2),
};
// Transformation of Xeen into a globe
@@ -652,7 +652,7 @@ bool WorldOfXeenCutscenes::worldEnding3() {
}
screen.fadeOut();
- while (sound.isMusicPlaying()) {
+ while (sound.isSoundPlaying()) {
WAIT(2);
}
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index 3e4e14455e..6d80e62806 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -41,7 +41,10 @@ void MainMenuContainer::show() {
menu = new DarkSideMainMenuContainer();
break;
case GType_WorldOfXeen:
- menu = new WorldOfXeenMainMenuContainer();
+ if (g_vm->getIsCD())
+ menu = new WorldOfXeenCDMainMenuContainer();
+ else
+ menu = new WorldOfXeenMainMenuContainer();
break;
default:
error("Invalid game");
@@ -51,9 +54,20 @@ void MainMenuContainer::show() {
delete menu;
}
-MainMenuContainer::MainMenuContainer(const Common::String &spritesName, uint frameCount) :
- _frameCount(frameCount), _animateCtr(0), _dialog(nullptr) {
- _backgroundSprites.load(spritesName);
+MainMenuContainer::MainMenuContainer(const char *spritesName1, const char *spritesName2, const char *spritesName3) :
+ _animateCtr(0), _dialog(nullptr) {
+ g_vm->_files->setGameCc(g_vm->getGameID() == GType_Clouds ? 0 : 1);
+
+ _backgroundSprites.resize(1 + (spritesName2 ? 1 : 0) + (spritesName3 ? 1 : 0));
+ _backgroundSprites[0].load(spritesName1);
+ if (spritesName2)
+ _backgroundSprites[1].load(spritesName2);
+ if (spritesName3)
+ _backgroundSprites[2].load(spritesName3);
+
+ _frameCount = 0;
+ for (uint idx = 0; idx < _backgroundSprites.size(); ++idx)
+ _frameCount += _backgroundSprites[idx].size();
}
MainMenuContainer::~MainMenuContainer() {
@@ -66,7 +80,17 @@ MainMenuContainer::~MainMenuContainer() {
void MainMenuContainer::draw() {
g_vm->_screen->restoreBackground();
_animateCtr = (_animateCtr + 1) % _frameCount;
- _backgroundSprites.draw(0, _animateCtr);
+
+ // Draw the next background frame
+ uint frameNum = _animateCtr;
+ for (uint idx = 0; idx < _backgroundSprites.size(); ++idx) {
+ if (frameNum < _backgroundSprites[idx].size()) {
+ _backgroundSprites[idx].draw(0, frameNum);
+ return;
+ } else {
+ frameNum -= _backgroundSprites[idx].size();
+ }
+ }
}
void MainMenuContainer::execute() {
@@ -96,7 +120,7 @@ void MainMenuContainer::execute() {
// Check for events
events.updateGameCounter();
-
+
if (events.wait(4, true)) {
if (_dialog) {
// There's a dialog active, so let it handle the event
@@ -109,11 +133,9 @@ void MainMenuContainer::execute() {
} else {
// No active dialog. If Escape pressed, exit game entirely. Otherwise,
// open up the main menu dialog
- if (events.isKeyPending()) {
- Common::KeyState key;
- if (events.getKey(key) && key.keycode == Common::KEYCODE_ESCAPE)
- g_vm->_gameMode = GMODE_QUIT;
- }
+ PendingEvent pe;
+ if (events.getEvent(pe) && pe._keyState.keycode == Common::KEYCODE_ESCAPE)
+ g_vm->_gameMode = GMODE_QUIT;
events.clearEvents();
showMenuDialog();
@@ -124,7 +146,7 @@ void MainMenuContainer::execute() {
/*------------------------------------------------------------------------*/
-CloudsMainMenuContainer::CloudsMainMenuContainer() : MainMenuContainer("intro.vga", 9) {
+CloudsMainMenuContainer::CloudsMainMenuContainer() : MainMenuContainer("intro.vga") {
}
void CloudsMainMenuContainer::display() {
@@ -149,7 +171,7 @@ void CloudsMainMenuContainer::showMenuDialog() {
/*------------------------------------------------------------------------*/
-DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("title2a.int", 10) {
+DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("title2a.int") {
Screen &screen = *g_vm->_screen;
Sound &sound = *g_vm->_sound;
screen.loadPalette("dark.pal");
@@ -185,7 +207,7 @@ void DarkSideMainMenuContainer::showMenuDialog() {
/*------------------------------------------------------------------------*/
-WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("world.int", 5) {
+WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("world.int") {
}
void WorldOfXeenMainMenuContainer::display() {
@@ -210,7 +232,33 @@ void WorldOfXeenMainMenuContainer::showMenuDialog() {
/*------------------------------------------------------------------------*/
+WorldOfXeenCDMainMenuContainer::WorldOfXeenCDMainMenuContainer() : MainMenuContainer("world0.int", "world1.int", "world2.int") {
+}
+
+void WorldOfXeenCDMainMenuContainer::display() {
+ FileManager &files = *g_vm->_files;
+ Screen &screen = *g_vm->_screen;
+ Sound &sound = *g_vm->_sound;
+
+ sound._musicSide = 1;
+ files.setGameCc(1);
+
+ screen.loadPalette("dark.pal");
+ screen.loadBackground("world.raw");
+ screen.saveBackground();
+
+ if (!sound.isMusicPlaying())
+ sound.playSong("newbrigh.m");
+}
+
+void WorldOfXeenCDMainMenuContainer::showMenuDialog() {
+ setOwner(new WorldMenuDialog(this));
+}
+
+/*------------------------------------------------------------------------*/
+
bool MainMenuDialog::handleEvents() {
+ FileManager &files = *g_vm->_files;
checkEvents(g_vm);
int difficulty;
@@ -227,14 +275,18 @@ bool MainMenuDialog::handleEvents() {
g_vm->_gameMode = GMODE_PLAY_GAME;
break;
- case Common::KEYCODE_l:
+ case Common::KEYCODE_l: {
// Load existing game
+ int ccNum = files._ccNum;
g_vm->_saves->newGame();
- if (!g_vm->_saves->loadGame())
+ if (!g_vm->_saves->loadGame()) {
+ files.setGameCc(ccNum);
return true;
+ }
g_vm->_gameMode = GMODE_PLAY_GAME;
break;
+ }
case Common::KEYCODE_c:
case Common::KEYCODE_v:
@@ -285,7 +337,7 @@ void CloudsMenuDialog::loadButtons() {
void CloudsMenuDialog::draw() {
Windows &windows = *g_vm->_windows;
Window &w = windows[GAME_WINDOW];
-
+
w.frame();
w.writeString(Common::String::format(Res.OPTIONS_MENU, Res.GAME_NAMES[0], g_vm->_gameWon[0] ? 117 : 92, 1992));
drawButtons(&w);
@@ -532,7 +584,7 @@ void OtherOptionsDialog::draw() {
w.frame();
w.writeString(Common::String::format(Res.OPTIONS_MENU,
- Res.GAME_NAMES[g_vm->getGameID() == GType_WorldOfXeen ? 2 : 1],
+ Res.GAME_NAMES[g_vm->getGameID() == GType_WorldOfXeen ? 2 : 1],
w.getBounds().height() - 33, 1993));
drawButtons(&w);
}
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.h b/engines/xeen/worldofxeen/worldofxeen_menu.h
index e753665f08..ba4a465047 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.h
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.h
@@ -25,6 +25,7 @@
#include "xeen/xeen.h"
#include "xeen/dialogs/dialogs.h"
+#include "common/array.h"
namespace Xeen {
namespace WorldOfXeen {
@@ -35,7 +36,7 @@ class MainMenuContainer {
private:
uint _animateCtr;
uint _frameCount;
- SpriteResource _backgroundSprites;
+ Common::Array<SpriteResource> _backgroundSprites;
MenuContainerDialog *_dialog;
protected:
/**
@@ -61,7 +62,7 @@ public:
/**
* Constructor
*/
- MainMenuContainer(const Common::String &spritesName, uint frameCount);
+ MainMenuContainer(const char *spritesName1, const char *spritesName2 = nullptr, const char *spritesName3 = nullptr);
/**
* Destructor
@@ -128,6 +129,21 @@ public:
WorldOfXeenMainMenuContainer();
};
+class WorldOfXeenCDMainMenuContainer : public MainMenuContainer {
+protected:
+ /**
+ * Called when the menu screen is first shown
+ */
+ virtual void display();
+
+ /**
+ * Shows the main menu dialog
+ */
+ virtual void showMenuDialog();
+public:
+ WorldOfXeenCDMainMenuContainer();
+};
+
class MenuContainerDialog : public ButtonContainer {
protected:
MainMenuContainer *_owner;
diff --git a/engines/xeen/worldofxeen/worldofxeen_resources.cpp b/engines/xeen/worldofxeen/worldofxeen_resources.cpp
deleted file mode 100644
index 5bd6247d08..0000000000
--- a/engines/xeen/worldofxeen/worldofxeen_resources.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "xeen/worldofxeen/worldofxeen_resources.h"
-
-namespace Xeen {
-namespace WorldOfXeen {
-
-const char *const WorldOfXeenResources::CLOUDS_INTRO1 = "\xC" "00\xB" "082\x9" "040\x3"
- "cKing Burlock\xB" "190\x9" "040Peasants\xB" "082\x9" "247"
- "Lord Xeen\xB" "190\x9" "258Xeen's Pet\xB" "179\x9" "150Crodo";
-
-const char *const WorldOfXeenResources::DARKSIDE_ENDING1 = "\n\x3" "cCongratulations\n"
- "\n"
- "Your Final Score is:\n"
- "\n"
- "%010lu\n"
- "\x3" "l\n"
- "Please send this score to the Ancient's Headquarters "
- "where you'll be added to the Hall of Legends!\n"
- "\n"
- "Ancient's Headquarters\n"
- "New World Computing, Inc.\n"
- "P.O. Box 4302\n"
- "Hollywood, CA 90078";
-
-const char *const WorldOfXeenResources::DARKSIDE_ENDING2 = "\n"
- "Adventurers,\n"
- "\n"
- "I will save your game in Castleview.\n"
- "\n"
- "The World of Xeen still needs you!\n"
- "\n"
- "Load your game afterwards and come visit me in the "
- "Great Pyramid for further instructions";
-
-const char *const WorldOfXeenResources::PHAROAH_ENDING_TEXT1 = "\xC" "d\xB"
- "001\x9" "001%s\x3" "c\x9" "000\xB" "180Press a Key!\x3" "l";
-const char *const WorldOfXeenResources::PHAROAH_ENDING_TEXT2 = "\xC" "04\xB"
- "000\x9" "000%s\x3" "c\x9" "000\xB" "180Press a Key!\x3" "l\xC" "d";
-
-} // End of namespace WorldOfXeen
-} // End of namespace Xeen
diff --git a/engines/xeen/xeen.cpp b/engines/xeen/xeen.cpp
index c8fb40d2a0..371f437172 100644
--- a/engines/xeen/xeen.cpp
+++ b/engines/xeen/xeen.cpp
@@ -49,6 +49,7 @@ XeenEngine::XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc)
_locations = nullptr;
_map = nullptr;
_party = nullptr;
+ _patcher = nullptr;
_resources = nullptr;
_saves = nullptr;
_screen = nullptr;
@@ -75,6 +76,7 @@ XeenEngine::~XeenEngine() {
delete _locations;
delete _map;
delete _party;
+ delete _patcher;
delete _saves;
delete _screen;
delete _scripts;
@@ -100,6 +102,7 @@ bool XeenEngine::initialize() {
_locations = new LocationManager();
_map = new Map(this);
_party = new Party(this);
+ _patcher = new Patcher();
_saves = new SavesManager(_targetName);
_screen = new Screen(this);
_scripts = new Scripts(this);
@@ -114,19 +117,26 @@ bool XeenEngine::initialize() {
syncSoundSettings();
// Load settings
+ loadSettings();
+
+ return true;
+}
+
+void XeenEngine::loadSettings() {
_gameWon[0] = ConfMan.hasKey("game_won") && ConfMan.getBool("game_won");
_gameWon[1] = ConfMan.hasKey("game_won2") && ConfMan.getBool("game_won2");
_gameWon[2] = ConfMan.hasKey("game_won3") && ConfMan.getBool("game_won3");
_finalScore = ConfMan.hasKey("final_score") ? ConfMan.getInt("final_score") : 0;
+ _extOptions._showItemCosts = ConfMan.hasKey("ShowItemCosts") && ConfMan.getBool("ShowItemCosts");
+ _extOptions._durableArmor = ConfMan.hasKey("DurableArmor") && ConfMan.getBool("DurableArmor");
+
// If requested, load a savegame instead of showing the intro
if (ConfMan.hasKey("save_slot")) {
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot >= 0 && saveSlot <= 999)
_loadSaveSlot = saveSlot;
}
-
- return true;
}
Common::Error XeenEngine::run() {
@@ -183,11 +193,12 @@ Common::Error XeenEngine::loadGameState(int slot) {
}
bool XeenEngine::canLoadGameStateCurrently() {
- return _mode != MODE_COMBAT;
+ return _mode != MODE_STARTUP;
}
bool XeenEngine::canSaveGameStateCurrently() {
- return _mode != MODE_COMBAT;
+ return _mode != MODE_COMBAT && _mode != MODE_STARTUP && _mode != MODE_SCRIPT_IN_PROGRESS
+ && (_map->mazeData()._mazeFlags & RESTRICTION_SAVE) == 0;
}
void XeenEngine::playGame() {
@@ -196,6 +207,7 @@ void XeenEngine::playGame() {
SpriteResource::setClippedBottom(140);
play();
+ _sound->stopAllAudio();
}
void XeenEngine::play() {
@@ -203,14 +215,15 @@ void XeenEngine::play() {
_screen->loadBackground("back.raw");
_screen->loadPalette("mm4.pal");
- if (getGameID() == GType_DarkSide && !_map->_loadDarkSide) {
- _map->_loadDarkSide = true;
+ if (getGameID() == GType_DarkSide && !_map->_loadCcNum) {
+ _map->_loadCcNum = 1;
_party->_mazeId = 29;
_party->_mazeDirection = DIR_NORTH;
_party->_mazePosition.x = 25;
_party->_mazePosition.y = 21;
}
+ _map->clearMaze();
if (_loadSaveSlot >= 0) {
_saves->newGame();
_saves->loadGameState(_loadSaveSlot);
@@ -231,7 +244,7 @@ void XeenEngine::play() {
_combat->_moveMonsters = true;
if (_mode == MODE_STARTUP) {
- _mode = MODE_1;
+ _mode = MODE_INTERACTIVE;
_screen->fadeIn();
}
@@ -243,22 +256,26 @@ void XeenEngine::play() {
death();
_mode = MODE_STARTUP;
+ _gameMode = GMODE_MENU;
}
void XeenEngine::gameLoop() {
// Main game loop
- while (!shouldExit()) {
- if (_loadSaveSlot >= 0) {
+ while (isLoadPending() || !shouldExit()) {
+ if (isLoadPending()) {
// Load any pending savegame
int saveSlot = _loadSaveSlot;
_loadSaveSlot = -1;
_saves->loadGameState(saveSlot);
+ _interface->drawParty(true);
}
_map->cellFlagLookup(_party->_mazePosition);
if (_map->_currentIsEvent) {
_gameMode = (GameMode)_scripts->checkEvents();
- if (shouldExit() || _gameMode)
+ if (isLoadPending())
+ continue;
+ if (shouldExit())
return;
}
_party->giveTreasure();
diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h
index c79b240388..98b09e7f23 100644
--- a/engines/xeen/xeen.h
+++ b/engines/xeen/xeen.h
@@ -39,6 +39,7 @@
#include "xeen/locations.h"
#include "xeen/map.h"
#include "xeen/party.h"
+#include "xeen/patcher.h"
#include "xeen/resources.h"
#include "xeen/saves.h"
#include "xeen/screen.h"
@@ -77,7 +78,7 @@ enum XeenDebugChannels {
enum Mode {
MODE_FF = -1,
MODE_STARTUP = 0,
- MODE_1 = 1,
+ MODE_INTERACTIVE = 1,
MODE_COMBAT = 2,
MODE_3 = 3,
MODE_4 = 4,
@@ -85,11 +86,11 @@ enum Mode {
MODE_6 = 6,
MODE_7 = 7,
MODE_8 = 8,
- MODE_RECORD_EVENTS = 9,
+ MODE_SCRIPT_IN_PROGRESS = 9,
MODE_CHARACTER_INFO = 10,
- MODE_12 = 12,
+ MODE_INTERACTIVE2 = 12,
MODE_DIALOG_123 = 13,
- MODE_17 = 17,
+ MODE_INTERACTIVE7 = 17,
MODE_86 = 86
};
@@ -106,6 +107,15 @@ struct XeenGameDescription;
#define XEEN_SAVEGAME_VERSION 1
class XeenEngine : public Engine {
+ /**
+ * Container to a set of options newly introduced under ScummVM
+ */
+ struct ExtendedOptions {
+ bool _showItemCosts;
+ bool _durableArmor;
+
+ ExtendedOptions() : _showItemCosts(false), _durableArmor(false) {}
+ };
private:
const XeenGameDescription *_gameDescription;
Common::RandomSource _randomSource;
@@ -115,6 +125,11 @@ private:
*/
bool initialize();
+ /**
+ * Load settings
+ */
+ void loadSettings();
+
// Engine APIs
virtual Common::Error run();
virtual bool hasFeature(EngineFeature f) const;
@@ -170,6 +185,7 @@ public:
LocationManager *_locations;
Map *_map;
Party *_party;
+ Patcher *_patcher;
Resources *_resources;
SavesManager *_saves;
Screen *_screen;
@@ -178,13 +194,13 @@ public:
Spells *_spells;
Windows *_windows;
Mode _mode;
- GameEvent _gameEvent;
GameMode _gameMode;
bool _noDirectionSense;
bool _startupWindowActive;
uint _endingScore;
bool _gameWon[3];
uint _finalScore;
+ ExtendedOptions _extOptions;
public:
XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc);
virtual ~XeenEngine();
@@ -195,6 +211,7 @@ public:
uint16 getVersion() const;
uint32 getGameID() const;
uint32 getGameFeatures() const;
+ bool getIsCD() const;
int getRandomNumber(int maxNumber);
@@ -206,9 +223,14 @@ public:
void GUIError(const char *msg, ...) GCC_PRINTF(2, 3);
/**
- * Returns true if the game should be exited (and likely return to game menu)
+ * Returns true if the game should be exited (either quitting, exiting to the main menu, or loading a savegame)
+ */
+ bool shouldExit() const { return _gameMode != GMODE_NONE || isLoadPending() || shouldQuit(); }
+
+ /**
+ * Returns true if a savegame load is pending
*/
- bool shouldExit() const { return _gameMode != GMODE_NONE || shouldQuit(); }
+ bool isLoadPending() const { return _loadSaveSlot != -1; }
/**
* Load a savegame
diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp
index 5e535a9954..f14263f012 100644
--- a/engines/zvision/detection.cpp
+++ b/engines/zvision/detection.cpp
@@ -88,8 +88,8 @@ bool ZVisionMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime) ||
(f == kSimpleSavesNames);
- //(f == kSavesSupportPlayTime);
}
bool ZVision::ZVision::hasFeature(EngineFeature f) const {
@@ -178,7 +178,7 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
// We only use readSaveGameHeader() here, which doesn't need an engine callback
ZVision::SaveManager *zvisionSaveMan = new ZVision::SaveManager(NULL);
- bool successfulRead = zvisionSaveMan->readSaveGameHeader(in, header);
+ bool successfulRead = zvisionSaveMan->readSaveGameHeader(in, header, false);
delete zvisionSaveMan;
delete in;
@@ -192,7 +192,7 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
desc.setThumbnail(header.thumbnail);
- if (header.version > 0) {
+ if (header.version >= 1) {
int day = header.saveDay;
int month = header.saveMonth;
int year = header.saveYear;
@@ -203,8 +203,10 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
int minutes = header.saveMinutes;
desc.setSaveTime(hour, minutes);
+ }
- //desc.setPlayTime(header.playTime * 1000);
+ if (header.version >= 2) {
+ desc.setPlayTime(header.playTime * 1000);
}
return desc;
diff --git a/engines/zvision/detection_tables.h b/engines/zvision/detection_tables.h
index 3df8f280ee..cb813e6d5b 100644
--- a/engines/zvision/detection_tables.h
+++ b/engines/zvision/detection_tables.h
@@ -49,7 +49,7 @@ static const ADExtraGuiOptionsMap optionsList[] = {
GAMEOPTION_ORIGINAL_SAVELOAD,
{
_s("Use original save/load screens"),
- _s("Use the original save/load screens instead of the ScummVM interface"),
+ _s("Use the original save/load screens instead of the ScummVM ones"),
"originalsaveload",
false
}
diff --git a/engines/zvision/file/save_manager.cpp b/engines/zvision/file/save_manager.cpp
index 4259937a3b..dd4425ae90 100644
--- a/engines/zvision/file/save_manager.cpp
+++ b/engines/zvision/file/save_manager.cpp
@@ -128,6 +128,8 @@ void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::S
file->writeSint16LE(td.tm_mday);
file->writeSint16LE(td.tm_hour);
file->writeSint16LE(td.tm_min);
+
+ file->writeUint32LE(g_engine->getTotalPlayTime() / 1000);
}
Common::Error SaveManager::loadGame(int slot) {
@@ -162,8 +164,6 @@ Common::Error SaveManager::loadGame(int slot) {
scriptManager->deserialize(saveFile);
delete saveFile;
- if (header.thumbnail)
- delete header.thumbnail;
if (_engine->getGameId() == GID_NEMESIS && scriptManager->getCurrentLocation() == "tv2f") {
// WORKAROUND for script bug #6793: location tv2f (stairs) has two states:
@@ -186,20 +186,26 @@ Common::Error SaveManager::loadGame(int slot) {
}
}
+ g_engine->setTotalPlayTime(header.playTime * 1000);
+
return Common::kNoError;
}
-bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) {
+bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail) {
+ header.saveYear = 0;
+ header.saveMonth = 0;
+ header.saveDay = 0;
+ header.saveHour = 0;
+ header.saveMinutes = 0;
+ header.playTime = 0;
+ header.saveName.clear();
+ header.thumbnail = nullptr;
+ header.version = 0;
+
uint32 tag = in->readUint32BE();
// Check if it's original savegame than fill header structure
if (tag == MKTAG('Z', 'N', 'S', 'G')) {
- header.saveYear = 0;
- header.saveMonth = 0;
- header.saveDay = 0;
- header.saveHour = 0;
- header.saveMinutes = 0;
header.saveName = "Original Save";
- header.thumbnail = NULL;
header.version = SAVE_ORIGINAL;
in->seek(-4, SEEK_CUR);
return true;
@@ -226,23 +232,26 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea
}
// Read in the save name
- header.saveName.clear();
char ch;
while ((ch = (char)in->readByte()) != '\0')
header.saveName += ch;
// Get the thumbnail
- header.thumbnail = Graphics::loadThumbnail(*in);
- if (!header.thumbnail)
+ if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return false;
+ }
// Read in save date/time
- header.saveYear = in->readSint16LE();
- header.saveMonth = in->readSint16LE();
- header.saveDay = in->readSint16LE();
- header.saveHour = in->readSint16LE();
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
header.saveMinutes = in->readSint16LE();
+ if (header.version >= 2) {
+ header.playTime = in->readUint32LE();
+ }
+
return true;
}
diff --git a/engines/zvision/file/save_manager.h b/engines/zvision/file/save_manager.h
index 9e816373ea..e5bf47b47b 100644
--- a/engines/zvision/file/save_manager.h
+++ b/engines/zvision/file/save_manager.h
@@ -42,8 +42,9 @@ struct SaveGameHeader {
byte version;
Common::String saveName;
Graphics::Surface *thumbnail;
- int saveYear, saveMonth, saveDay;
- int saveHour, saveMinutes;
+ int16 saveYear, saveMonth, saveDay;
+ int16 saveHour, saveMinutes;
+ uint32 playTime;
};
class SaveManager {
@@ -64,7 +65,7 @@ private:
enum {
SAVE_ORIGINAL = 0,
- SAVE_VERSION = 1
+ SAVE_VERSION = 2
};
Common::MemoryWriteStreamDynamic *_tempThumbnail;
@@ -94,7 +95,7 @@ public:
Common::Error loadGame(int slot);
Common::SeekableReadStream *getSlotFile(uint slot);
- bool readSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &header);
+ bool readSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &header, bool skipThumbnail = true);
void prepareSaveBuffer();
void flushSaveBuffer();