aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/advancedDetector.cpp2
-rw-r--r--engines/agos/midi.cpp4
-rw-r--r--engines/cge/cge.h6
-rw-r--r--engines/cge/detection.cpp113
-rw-r--r--engines/cge/fileio.cpp2
-rw-r--r--engines/cge/vga13h.cpp64
-rw-r--r--engines/cge/vga13h.h32
-rw-r--r--engines/cge2/bitmap.cpp458
-rw-r--r--engines/cge2/bitmap.h94
-rw-r--r--engines/cge2/cge2.cpp206
-rw-r--r--engines/cge2/cge2.h341
-rw-r--r--engines/cge2/cge2_main.cpp960
-rw-r--r--engines/cge2/cge2_main.h52
-rw-r--r--engines/cge2/configure.engine3
-rw-r--r--engines/cge2/console.cpp33
-rw-r--r--engines/cge2/console.h40
-rw-r--r--engines/cge2/detection.cpp245
-rw-r--r--engines/cge2/events.cpp293
-rw-r--r--engines/cge2/events.h116
-rw-r--r--engines/cge2/fileio.cpp272
-rw-r--r--engines/cge2/fileio.h133
-rw-r--r--engines/cge2/general.h45
-rw-r--r--engines/cge2/hero.cpp620
-rw-r--r--engines/cge2/hero.h114
-rw-r--r--engines/cge2/inventory.cpp104
-rw-r--r--engines/cge2/map.cpp92
-rw-r--r--engines/cge2/map.h55
-rw-r--r--engines/cge2/module.mk30
-rw-r--r--engines/cge2/saveload.cpp279
-rw-r--r--engines/cge2/snail.cpp865
-rw-r--r--engines/cge2/snail.h129
-rw-r--r--engines/cge2/sound.cpp273
-rw-r--r--engines/cge2/sound.h131
-rw-r--r--engines/cge2/spare.cpp128
-rw-r--r--engines/cge2/spare.h56
-rw-r--r--engines/cge2/talk.cpp312
-rw-r--r--engines/cge2/talk.h94
-rw-r--r--engines/cge2/text.cpp197
-rw-r--r--engines/cge2/text.h68
-rw-r--r--engines/cge2/toolbar.cpp225
-rw-r--r--engines/cge2/vga13h.cpp1218
-rw-r--r--engines/cge2/vga13h.h308
-rw-r--r--engines/cge2/vmenu.cpp162
-rw-r--r--engines/cge2/vmenu.h89
-rw-r--r--engines/composer/composer.cpp5
-rw-r--r--engines/composer/scripting.cpp1
-rw-r--r--engines/cruise/cruise.cpp3
-rw-r--r--engines/cruise/cruise.h2
-rw-r--r--engines/cruise/cruise_main.cpp36
-rw-r--r--engines/cruise/function.cpp5
-rw-r--r--engines/cruise/mainDraw.cpp4
-rw-r--r--engines/cruise/mainDraw.h2
-rw-r--r--engines/cruise/menu.cpp6
-rw-r--r--engines/cruise/saveload.cpp2
-rw-r--r--engines/cruise/sound.cpp8
-rw-r--r--engines/cruise/vars.cpp4
-rw-r--r--engines/cruise/vars.h4
-rw-r--r--engines/drascula/animation.cpp28
-rw-r--r--engines/drascula/drascula.cpp3
-rw-r--r--engines/fullpipe/configure.engine2
-rw-r--r--engines/fullpipe/fullpipe.cpp37
-rw-r--r--engines/fullpipe/fullpipe.h4
-rw-r--r--engines/fullpipe/gameloader.cpp35
-rw-r--r--engines/fullpipe/gfx.cpp425
-rw-r--r--engines/fullpipe/gfx.h25
-rw-r--r--engines/fullpipe/mgm.cpp719
-rw-r--r--engines/fullpipe/mgm.h95
-rw-r--r--engines/fullpipe/modal.cpp33
-rw-r--r--engines/fullpipe/modal.h4
-rw-r--r--engines/fullpipe/module.mk1
-rw-r--r--engines/fullpipe/motion.cpp727
-rw-r--r--engines/fullpipe/motion.h68
-rw-r--r--engines/fullpipe/scene.cpp12
-rw-r--r--engines/fullpipe/scenes/scene04.cpp4
-rw-r--r--engines/fullpipe/scenes/scene29.cpp2
-rw-r--r--engines/fullpipe/sound.cpp8
-rw-r--r--engines/fullpipe/stateloader.cpp38
-rw-r--r--engines/fullpipe/statics.cpp27
-rw-r--r--engines/gob/detection/tables_ween.h87
-rw-r--r--engines/kyra/items_lol.cpp2
-rw-r--r--engines/kyra/sound_adlib.cpp327
-rw-r--r--engines/lastexpress/debug.cpp12
-rw-r--r--engines/lastexpress/entities/abbot.cpp10
-rw-r--r--engines/lastexpress/entities/alexei.cpp2
-rw-r--r--engines/lastexpress/entities/anna.cpp14
-rw-r--r--engines/lastexpress/entities/august.cpp47
-rw-r--r--engines/lastexpress/entities/boutarel.cpp8
-rw-r--r--engines/lastexpress/entities/chapters.cpp35
-rw-r--r--engines/lastexpress/entities/chapters.h2
-rw-r--r--engines/lastexpress/entities/cooks.cpp43
-rw-r--r--engines/lastexpress/entities/cooks.h24
-rw-r--r--engines/lastexpress/entities/entity.cpp4
-rw-r--r--engines/lastexpress/entities/gendarmes.cpp111
-rw-r--r--engines/lastexpress/entities/gendarmes.h18
-rw-r--r--engines/lastexpress/entities/hadija.cpp62
-rw-r--r--engines/lastexpress/entities/hadija.h10
-rw-r--r--engines/lastexpress/entities/ivo.cpp64
-rw-r--r--engines/lastexpress/entities/ivo.h18
-rw-r--r--engines/lastexpress/entities/kahina.cpp94
-rw-r--r--engines/lastexpress/entities/kahina.h34
-rw-r--r--engines/lastexpress/entities/kronos.cpp74
-rw-r--r--engines/lastexpress/entities/kronos.h18
-rw-r--r--engines/lastexpress/entities/max.cpp38
-rw-r--r--engines/lastexpress/entities/max.h19
-rw-r--r--engines/lastexpress/entities/milos.cpp4
-rw-r--r--engines/lastexpress/entities/pascale.cpp82
-rw-r--r--engines/lastexpress/entities/pascale.h24
-rw-r--r--engines/lastexpress/entities/rebecca.cpp18
-rw-r--r--engines/lastexpress/entities/tatiana.cpp4
-rw-r--r--engines/lastexpress/entities/waiter1.cpp (renamed from engines/lastexpress/entities/servers0.cpp)343
-rw-r--r--engines/lastexpress/entities/waiter1.h (renamed from engines/lastexpress/entities/servers0.h)78
-rw-r--r--engines/lastexpress/entities/waiter2.cpp (renamed from engines/lastexpress/entities/servers1.cpp)268
-rw-r--r--engines/lastexpress/entities/waiter2.h (renamed from engines/lastexpress/entities/servers1.h)66
-rw-r--r--engines/lastexpress/game/action.cpp2
-rw-r--r--engines/lastexpress/game/entities.cpp16
-rw-r--r--engines/lastexpress/game/inventory.cpp19
-rw-r--r--engines/lastexpress/game/savepoint.cpp16
-rw-r--r--engines/lastexpress/game/savepoint.h4
-rw-r--r--engines/lastexpress/lastexpress.cpp2
-rw-r--r--engines/lastexpress/module.mk4
-rw-r--r--engines/lastexpress/shared.h8
-rw-r--r--engines/lastexpress/sound/entry.cpp9
-rw-r--r--engines/lastexpress/sound/sound.cpp10
-rw-r--r--engines/made/database.cpp2
-rw-r--r--engines/made/resource.cpp3
-rw-r--r--engines/made/screen.cpp3
-rw-r--r--engines/mads/debugger.cpp37
-rw-r--r--engines/mads/dialogs.h4
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.cpp31
-rw-r--r--engines/mads/dragonsphere/game_dragonsphere.cpp4
-rw-r--r--engines/mads/events.cpp13
-rw-r--r--engines/mads/events.h22
-rw-r--r--engines/mads/game.cpp36
-rw-r--r--engines/mads/game.h6
-rw-r--r--engines/mads/mads.cpp12
-rw-r--r--engines/mads/mads.h1
-rw-r--r--engines/mads/messages.cpp5
-rw-r--r--engines/mads/module.mk1
-rw-r--r--engines/mads/msurface.cpp5
-rw-r--r--engines/mads/msurface.h10
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp496
-rw-r--r--engines/mads/nebular/dialogs_nebular.h108
-rw-r--r--engines/mads/nebular/game_nebular.cpp14
-rw-r--r--engines/mads/nebular/menu_nebular.cpp986
-rw-r--r--engines/mads/nebular/menu_nebular.h287
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp2
-rw-r--r--engines/mads/nebular/nebular_scenes1.cpp2
-rw-r--r--engines/mads/nebular/nebular_scenes8.cpp2
-rw-r--r--engines/mads/nebular/sound_nebular.cpp331
-rw-r--r--engines/mads/nebular/sound_nebular.h79
-rw-r--r--engines/mads/palette.h2
-rw-r--r--engines/mads/phantom/game_phantom.cpp4
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp31
-rw-r--r--engines/mads/scene.cpp40
-rw-r--r--engines/mads/scene.h2
-rw-r--r--engines/mads/scene_data.cpp83
-rw-r--r--engines/mads/scene_data.h3
-rw-r--r--engines/mads/screen.cpp65
-rw-r--r--engines/mads/screen.h24
-rw-r--r--engines/mads/sound.cpp22
-rw-r--r--engines/mads/sound.h3
-rw-r--r--engines/mohawk/detection_tables.h20
-rw-r--r--engines/mohawk/myst_stacks/stoneship.cpp1
-rw-r--r--engines/mohawk/myst_state.cpp3
-rw-r--r--engines/mortevielle/detection_tables.h30
-rw-r--r--engines/neverhood/graphics.cpp10
-rw-r--r--engines/neverhood/modules/module1400.cpp7
-rw-r--r--engines/neverhood/modules/module1400_sprites.cpp5
-rw-r--r--engines/neverhood/modules/module1400_sprites.h2
-rw-r--r--engines/neverhood/modules/module1600_sprites.cpp3
-rw-r--r--engines/neverhood/sprite.cpp14
-rw-r--r--engines/pegasus/energymonitor.cpp4
-rw-r--r--engines/pegasus/interaction.cpp38
-rw-r--r--engines/pegasus/interaction.h6
-rw-r--r--engines/pegasus/module.mk1
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria.cpp146
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp42
-rw-r--r--engines/pegasus/neighborhood/mars/shuttlehud.cpp42
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp4
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp118
-rw-r--r--engines/pegasus/neighborhood/norad/delta/globegame.cpp30
-rw-r--r--engines/pegasus/neighborhood/norad/subcontrolroom.cpp191
-rw-r--r--engines/pegasus/neighborhood/tsa/fulltsa.cpp845
-rw-r--r--engines/pegasus/neighborhood/tsa/tinytsa.cpp124
-rw-r--r--engines/pegasus/neighborhood/wsc/wsc.cpp698
-rw-r--r--engines/pegasus/pegasus.cpp2
-rw-r--r--engines/saga/console.cpp46
-rw-r--r--engines/saga/console.h4
-rw-r--r--engines/saga/detection_tables.h24
-rw-r--r--engines/saga/events.cpp12
-rw-r--r--engines/saga/events.h9
-rw-r--r--engines/saga/interface.cpp5
-rw-r--r--engines/saga/introproc_ite.cpp626
-rw-r--r--engines/saga/introproc_saga2.cpp6
-rw-r--r--engines/saga/itedata.cpp486
-rw-r--r--engines/saga/itedata.h37
-rw-r--r--engines/saga/music.cpp24
-rw-r--r--engines/saga/music.h5
-rw-r--r--engines/saga/resource.cpp14
-rw-r--r--engines/saga/resource.h16
-rw-r--r--engines/saga/resource_hrs.cpp45
-rw-r--r--engines/saga/saga.cpp1
-rw-r--r--engines/saga/scene.cpp8
-rw-r--r--engines/saga/scene.h35
-rw-r--r--engines/saga/sfuncs_ihnm.cpp9
-rw-r--r--engines/saga/shorten.cpp60
-rw-r--r--engines/saga/sndres.h1
-rw-r--r--engines/savestate.h2
-rw-r--r--engines/sci/detection_tables.h19
-rw-r--r--engines/sci/engine/features.cpp6
-rw-r--r--engines/sci/engine/kernel_tables.h3
-rw-r--r--engines/sci/engine/seg_manager.cpp2
-rw-r--r--engines/sci/engine/workarounds.cpp3
-rw-r--r--engines/sci/graphics/frameout.cpp6
-rw-r--r--engines/sci/parser/said.cpp35
-rw-r--r--engines/sci/parser/vocabulary.cpp15
-rw-r--r--engines/sci/sound/drivers/midi.cpp5
-rw-r--r--engines/scumm/cdda.cpp120
-rw-r--r--engines/scumm/cdda.h57
-rw-r--r--engines/scumm/charset.cpp95
-rw-r--r--engines/scumm/charset.h29
-rw-r--r--engines/scumm/detection.cpp48
-rw-r--r--engines/scumm/detection.h2
-rw-r--r--engines/scumm/detection_tables.h22
-rw-r--r--engines/scumm/dialogs.cpp4
-rw-r--r--engines/scumm/file.cpp24
-rw-r--r--engines/scumm/file.h27
-rw-r--r--engines/scumm/he/sprite_he.cpp14
-rw-r--r--engines/scumm/input.cpp5
-rw-r--r--engines/scumm/module.mk1
-rw-r--r--engines/scumm/nut_renderer.cpp55
-rw-r--r--engines/scumm/players/player_ad.cpp84
-rw-r--r--engines/scumm/saveload.cpp2
-rw-r--r--engines/scumm/script.cpp12
-rw-r--r--engines/scumm/script_v5.cpp2
-rw-r--r--engines/scumm/scumm-md5.h11
-rw-r--r--engines/scumm/scumm.cpp55
-rw-r--r--engines/scumm/scumm.h4
-rw-r--r--engines/scumm/smush/smush_font.cpp66
-rw-r--r--engines/scumm/sound.cpp75
-rw-r--r--engines/scumm/sound.h7
-rw-r--r--engines/scumm/vars.cpp1
-rw-r--r--engines/sword1/animation.cpp4
-rw-r--r--engines/sword1/console.cpp23
-rw-r--r--engines/sword1/console.h1
-rw-r--r--engines/sword1/sound.cpp55
-rw-r--r--engines/sword1/sound.h1
-rw-r--r--engines/sword1/sword1.h1
-rw-r--r--engines/sword2/animation.cpp2
-rw-r--r--engines/sword25/gfx/animation.cpp8
-rw-r--r--engines/sword25/gfx/bitmapresource.h18
-rw-r--r--engines/sword25/gfx/dynamicbitmap.cpp8
-rw-r--r--engines/sword25/gfx/graphicengine.cpp10
-rw-r--r--engines/sword25/gfx/image/image.h22
-rw-r--r--engines/sword25/gfx/image/imgloader.cpp4
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp292
-rw-r--r--engines/sword25/gfx/image/renderedimage.h11
-rw-r--r--engines/sword25/gfx/image/swimage.h2
-rw-r--r--engines/sword25/gfx/image/vectorimage.h2
-rw-r--r--engines/sword25/gfx/image/vectorimagerenderer.cpp10
-rw-r--r--engines/sword25/gfx/staticbitmap.cpp8
-rw-r--r--engines/sword25/gfx/text.cpp6
-rw-r--r--engines/sword25/sword25.cpp2
-rw-r--r--engines/testbed/sound.cpp2
-rw-r--r--engines/toltecs/detection.cpp14
-rw-r--r--engines/toon/toon.cpp22
-rw-r--r--engines/tsage/ringworld/ringworld_scenes10.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_logic.h2
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes3.cpp15
-rw-r--r--engines/tsage/sound.cpp7
-rw-r--r--engines/voyeur/configure.engine2
-rw-r--r--engines/voyeur/files_threads.cpp9
-rw-r--r--engines/voyeur/voyeur.cpp4
-rw-r--r--engines/wintermute/base/base_file_manager.cpp9
-rw-r--r--engines/wintermute/base/base_file_manager.h1
-rw-r--r--engines/wintermute/base/base_frame.cpp2
-rw-r--r--engines/wintermute/base/base_frame.h3
-rw-r--r--engines/wintermute/base/base_game.cpp4
-rw-r--r--engines/wintermute/base/base_game_settings.cpp4
-rw-r--r--engines/wintermute/base/base_game_settings.h3
-rw-r--r--engines/wintermute/base/base_object.cpp8
-rw-r--r--engines/wintermute/base/base_object.h3
-rw-r--r--engines/wintermute/base/base_persistence_manager.cpp4
-rw-r--r--engines/wintermute/base/base_sprite.cpp2
-rw-r--r--engines/wintermute/base/base_sprite.h10
-rw-r--r--engines/wintermute/base/base_string_table.cpp25
-rw-r--r--engines/wintermute/base/base_string_table.h4
-rw-r--r--engines/wintermute/base/base_sub_frame.cpp36
-rw-r--r--engines/wintermute/base/base_sub_frame.h3
-rw-r--r--engines/wintermute/base/font/base_font_truetype.cpp2
-rw-r--r--engines/wintermute/base/gfx/base_image.cpp6
-rw-r--r--engines/wintermute/base/gfx/base_renderer.h1
-rw-r--r--engines/wintermute/base/gfx/base_surface.cpp2
-rw-r--r--engines/wintermute/base/gfx/base_surface.h14
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.cpp6
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.h4
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp58
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.h20
-rw-r--r--engines/wintermute/base/gfx/osystem/render_ticket.cpp18
-rw-r--r--engines/wintermute/base/gfx/osystem/render_ticket.h8
-rw-r--r--engines/wintermute/base/sound/base_sound_manager.cpp1
-rw-r--r--engines/wintermute/dcgf.h4
-rw-r--r--engines/wintermute/dctypes.h8
-rw-r--r--engines/wintermute/detection_tables.h111
-rw-r--r--engines/wintermute/graphics/transform_struct.cpp119
-rw-r--r--engines/wintermute/graphics/transform_struct.h89
-rw-r--r--engines/wintermute/graphics/transform_tools.cpp87
-rw-r--r--engines/wintermute/graphics/transform_tools.h53
-rw-r--r--engines/wintermute/graphics/transparent_surface.cpp950
-rw-r--r--engines/wintermute/graphics/transparent_surface.h176
-rw-r--r--engines/wintermute/module.mk3
-rw-r--r--engines/wintermute/utils/utils.cpp5
-rw-r--r--engines/zvision/scripting/actions.cpp12
-rw-r--r--engines/zvision/scripting/controls/input_control.cpp2
315 files changed, 16917 insertions, 6688 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index fa23f5fa1a..72629a833e 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -122,7 +122,7 @@ bool cleanupPirated(ADGameDescList &matched) {
// We ruled out all variants and now have nothing
if (matched.empty()) {
- warning("Illegitimate game copy detected. We give no support in such cases %d", matched.size());
+ warning("Illegitimate game copy detected. We provide no support in such cases");
return true;
}
}
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 392ee08ea1..c26fbe3331 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -235,10 +235,6 @@ void MidiPlayer::startTrack(int track) {
_music.parser = parser; // That plugs the power cord into the wall
} else if (_music.parser) {
if (!_music.parser->setTrack(track)) {
- // The Roland MT32 music in Simon the Sorcerer 2
- // is missing the extra tracks in many scenes,
- // like the introduction sequence.
- stop();
return;
}
_currentTrack = (byte)track;
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index a65069ff46..c43358f252 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -80,12 +80,6 @@ class Talk;
#define kSayTheEnd 41
-enum GameType {
- kGameTypeNone = 0,
- kGameTypeSoltys,
- kGameTypeSfinx
-};
-
// our engine debug channels
enum {
kCGEDebugBitmap = 1 << 0,
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 4c2f81c1ae..022ff4df95 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -33,7 +33,6 @@ namespace CGE {
struct CgeGameDescription {
ADGameDescription desc;
- GameType gameType;
};
#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1
@@ -42,117 +41,81 @@ struct CgeGameDescription {
static const PlainGameDescriptor CGEGames[] = {
{ "soltys", "Soltys" },
- { "sfinx", "Sfinx" },
{ 0, 0 }
};
namespace CGE {
-static const CgeGameDescription gameDescriptions[] = {
-
- {
- {
- "soltys", "",
- {
- {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
- {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0()
- },
- kGameTypeSoltys
- },
+static const ADGameDescription gameDescriptions[] = {
{
+ "soltys", "",
{
- "soltys", "Soltys Freeware",
- {
- {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
- {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0()
},
{
+ "soltys", "Freeware",
{
- "soltys", "Soltys Demo (not supported)",
- {
- {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
- {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
- AD_LISTEND
- },
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Demo (not supported)",
{
- "soltys", "Soltys Demo (not supported)",
- {
- {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
- {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
+ {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Demo (not supported)",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176},
- {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868},
- AD_LISTEND
- },
- Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
+ {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176},
- {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176},
+ {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176},
- {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151},
- AD_LISTEND
- },
- Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176},
+ {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Freeware v1.0",
{
- // Polish version, provided by Strangerke
- "sfinx", "Sfinx Freeware",
- {
- {"vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024},
- {"vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176},
+ {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151},
+ AD_LISTEND
},
- kGameTypeSfinx
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
- {AD_TABLE_END_MARKER, kGameTypeNone}
+ AD_TABLE_END_MARKER
};
static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0].desc, { "vol.cat", "vol.dat", 0 } },
+ { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
{ 0, { 0 } }
};
} // End of namespace CGE
diff --git a/engines/cge/fileio.cpp b/engines/cge/fileio.cpp
index 2b1f74db02..d910e275eb 100644
--- a/engines/cge/fileio.cpp
+++ b/engines/cge/fileio.cpp
@@ -228,7 +228,7 @@ uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) {
}
bool EncryptedStream::err() {
- return (_error & _readStream->err());
+ return (_error || _readStream->err());
}
bool EncryptedStream::eos() {
diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp
index d7dccd2c65..babcb7e667 100644
--- a/engines/cge/vga13h.cpp
+++ b/engines/cge/vga13h.cpp
@@ -482,39 +482,39 @@ void Sprite::sync(Common::Serializer &s) {
uint16 flags = 0;
if (s.isLoading()) {
s.syncAsUint16LE(flags);
- _flags._hide = flags & 0x0001 ? true : false;
- _flags._near = flags & 0x0002 ? true : false;
- _flags._drag = flags & 0x0004 ? true : false;
- _flags._hold = flags & 0x0008 ? true : false;
- _flags._dummy = flags & 0x0010 ? true : false;
- _flags._slav = flags & 0x0020 ? true : false;
- _flags._syst = flags & 0x0040 ? true : false;
- _flags._kill = flags & 0x0080 ? true : false;
- _flags._xlat = flags & 0x0100 ? true : false;
- _flags._port = flags & 0x0200 ? true : false;
- _flags._kept = flags & 0x0400 ? true : false;
- _flags._east = flags & 0x0800 ? true : false;
- _flags._shad = flags & 0x1000 ? true : false;
- _flags._back = flags & 0x2000 ? true : false;
- _flags._bDel = flags & 0x4000 ? true : false;
- _flags._tran = flags & 0x8000 ? true : false;
+ _flags._hide = flags & 0x0001;
+ _flags._near = flags & 0x0002;
+ _flags._drag = flags & 0x0004;
+ _flags._hold = flags & 0x0008;
+ _flags._dummy = flags & 0x0010;
+ _flags._slav = flags & 0x0020;
+ _flags._syst = flags & 0x0040;
+ _flags._kill = flags & 0x0080;
+ _flags._xlat = flags & 0x0100;
+ _flags._port = flags & 0x0200;
+ _flags._kept = flags & 0x0400;
+ _flags._east = flags & 0x0800;
+ _flags._shad = flags & 0x1000;
+ _flags._back = flags & 0x2000;
+ _flags._bDel = flags & 0x4000;
+ _flags._tran = flags & 0x8000;
} else {
- flags = (flags << 1) | _flags._tran;
- flags = (flags << 1) | _flags._bDel;
- flags = (flags << 1) | _flags._back;
- flags = (flags << 1) | _flags._shad;
- flags = (flags << 1) | _flags._east;
- flags = (flags << 1) | _flags._kept;
- flags = (flags << 1) | _flags._port;
- flags = (flags << 1) | _flags._xlat;
- flags = (flags << 1) | _flags._kill;
- flags = (flags << 1) | _flags._syst;
- flags = (flags << 1) | _flags._slav;
- flags = (flags << 1) | _flags._dummy;
- flags = (flags << 1) | _flags._hold;
- flags = (flags << 1) | _flags._drag;
- flags = (flags << 1) | _flags._near;
- flags = (flags << 1) | _flags._hide;
+ flags = (flags << 1) | (_flags._tran ? 1 : 0);
+ flags = (flags << 1) | (_flags._bDel ? 1 : 0);
+ flags = (flags << 1) | (_flags._back ? 1 : 0);
+ flags = (flags << 1) | (_flags._shad ? 1 : 0);
+ flags = (flags << 1) | (_flags._east ? 1 : 0);
+ flags = (flags << 1) | (_flags._kept ? 1 : 0);
+ flags = (flags << 1) | (_flags._port ? 1 : 0);
+ flags = (flags << 1) | (_flags._xlat ? 1 : 0);
+ flags = (flags << 1) | (_flags._kill ? 1 : 0);
+ flags = (flags << 1) | (_flags._syst ? 1 : 0);
+ flags = (flags << 1) | (_flags._slav ? 1 : 0);
+ flags = (flags << 1) | (_flags._dummy ? 1 : 0);
+ flags = (flags << 1) | (_flags._hold ? 1 : 0);
+ flags = (flags << 1) | (_flags._drag ? 1 : 0);
+ flags = (flags << 1) | (_flags._near ? 1 : 0);
+ flags = (flags << 1) | (_flags._hide ? 1 : 0);
s.syncAsUint16LE(flags);
}
diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h
index 9511559df0..a976d7078c 100644
--- a/engines/cge/vga13h.h
+++ b/engines/cge/vga13h.h
@@ -88,22 +88,22 @@ public:
int _ref;
signed char _scene;
struct Flags {
- uint16 _hide : 1; // general visibility switch
- uint16 _near : 1; // Near action lock
- uint16 _drag : 1; // sprite is moveable
- uint16 _hold : 1; // sprite is held with mouse
- uint16 _dummy : 1; // intrrupt driven animation
- uint16 _slav : 1; // slave object
- uint16 _syst : 1; // system object
- uint16 _kill : 1; // dispose memory after remove
- uint16 _xlat : 1; // 2nd way display: xlat table
- uint16 _port : 1; // portable
- uint16 _kept : 1; // kept in pocket
- uint16 _east : 1; // talk to east (in opposite to west)
- uint16 _shad : 1; // shadow
- uint16 _back : 1; // 'send to background' request
- uint16 _bDel : 1; // delete bitmaps in ~SPRITE
- uint16 _tran : 1; // transparent (untouchable)
+ bool _hide; // general visibility switch
+ bool _near; // Near action lock
+ bool _drag; // sprite is moveable
+ bool _hold; // sprite is held with mouse
+ bool _dummy; // interrupt driven animation
+ bool _slav; // slave object
+ bool _syst; // system object
+ bool _kill; // dispose memory after remove
+ bool _xlat; // 2nd way display: xlat table
+ bool _port; // portable
+ bool _kept; // kept in pocket
+ bool _east; // talk to east (in opposite to west)
+ bool _shad; // shadow
+ bool _back; // 'send to background' request
+ bool _bDel; // delete bitmaps in ~SPRITE
+ bool _tran; // transparent (untouchable)
} _flags;
int _x;
int _y;
diff --git a/engines/cge2/bitmap.cpp b/engines/cge2/bitmap.cpp
new file mode 100644
index 0000000000..0f442b8c77
--- /dev/null
+++ b/engines/cge2/bitmap.cpp
@@ -0,0 +1,458 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/bitmap.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/talk.h"
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+
+namespace CGE2 {
+
+Bitmap::Bitmap() : _w(0), _h(0), _v(nullptr), _b(nullptr), _map(0), _vm(nullptr) {
+}
+
+void Bitmap::setVM(CGE2Engine *vm) {
+ _vm = vm;
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, const char *fname) : _w(0), _h(0), _v(nullptr), _b(nullptr), _map(0), _vm(vm) {
+ Common::String path;
+
+ if (!strcmp(fname, "04tal201")) {
+ path = "04tal202";
+ warning("Workaround for missing VBM: 04tal201");
+ } else if (!strcmp(fname, "11oqlist-")) {
+ path = "11oqlist";
+ warning("Workaround for wrong VBM name: 11oqlist-");
+ } else
+ path = fname;
+
+ path = setExtension(path, ".VBM");
+
+ if (_vm->_resman->exist(path.c_str())) {
+ EncryptedStream file(_vm, path.c_str());
+ if (file.err())
+ error("Unable to find VBM [%s]", fname);
+ if (!loadVBM(&file))
+ error("Bad VBM [%s]", fname);
+ } else {
+ warning("Missing VBM [%s]", path.c_str());
+ }
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _v(nullptr), _map(0), _b(nullptr), _vm(vm) {
+ if (map)
+ code(map);
+}
+
+// following routine creates filled rectangle
+// immediately as VGA video chunks, in near memory as fast as possible,
+// especially for text line real time display
+Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill)
+ : _w((w + 3) & ~3), // only full uint32 allowed!
+ _h(h), _map(0), _b(nullptr), _vm(vm) {
+
+ uint16 dsiz = _w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = _h * lsiz; // - last gape, but + plane trailer
+ uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes
+ // + room for wash table
+
+ WRITE_LE_UINT16(v, (kBmpCPY | dsiz)); // data chunk hader
+ memset(v + 2, fill, dsiz); // data bytes
+ WRITE_LE_UINT16(v + lsiz - 2, (kBmpSKP | ((kScrWidth / 4) - dsiz))); // gap
+
+ // Replicate lines
+ byte *destP;
+ for (destP = v + lsiz; destP < (v + psiz); destP += lsiz)
+ Common::copy(v, v + lsiz, destP);
+
+ WRITE_LE_UINT16(v + psiz - 2, kBmpEOI); // plane trailer uint16
+
+ // Replicate planes
+ for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz)
+ Common::copy(v, v + psiz, destP);
+
+ HideDesc *b = (HideDesc *)(v + 4 * psiz);
+ b->_skip = (kScrWidth - _w) >> 2;
+ b->_hide = _w >> 2;
+
+ // Replicate across the entire table
+ for (HideDesc *hdP = b + 1; hdP < (b + _h); hdP++)
+ *hdP = *b;
+
+ b->_skip = 0; // fix the first entry
+ _v = v;
+ _b = b;
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _v(nullptr), _map(0), _b(nullptr), _vm(vm) {
+ uint8 *v0 = bmp._v;
+ if (!v0)
+ return;
+
+ uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0);
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = new uint8[siz];
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+}
+
+Bitmap::~Bitmap() {
+ release();
+}
+
+void Bitmap::release() {
+ if (_v != nullptr)
+ delete[] _v;
+ _v = nullptr;
+}
+
+Bitmap &Bitmap::operator=(const Bitmap &bmp) {
+ if (this == &bmp)
+ return *this;
+
+ uint8 *v0 = bmp._v;
+ _w = bmp._w;
+ _h = bmp._h;
+ _map = 0;
+ _vm = bmp._vm;
+ delete[] _v;
+ _v = nullptr;
+
+ if (v0) {
+ uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0;
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = new uint8[siz];
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+ }
+ return *this;
+}
+
+// Blatant rip from hopkins engine where it's ripped from gob engine. Hi DrMcCoy, hi Strangerke! ;>
+Common::String Bitmap::setExtension(const Common::String &str, const Common::String &ext) {
+ if (str.empty())
+ return str;
+
+ const char *dot = strrchr(str.c_str(), '.');
+ if (dot)
+ return Common::String(str.c_str(), dot - str.c_str()) + ext;
+
+ return str + ext;
+}
+
+BitmapPtr Bitmap::code(uint8 *map) {
+ if (!map)
+ return nullptr;
+
+ uint16 cnt;
+
+ if (_v) { // old X-map exists, so remove it
+ delete[] _v;
+ _v = nullptr;
+ }
+
+ while (true) { // at most 2 times: for (V == NULL) & for allocated block;
+ uint8 *im = _v + 2;
+ uint16 *cp = (uint16 *) _v;
+
+ if (_v) { // 2nd pass - fill the hide table
+ for (uint i = 0; i < _h; i++) {
+ _b[i]._skip = 0xFFFF;
+ _b[i]._hide = 0x0000;
+ }
+ }
+ for (int bpl = 0; bpl < 4; bpl++) { // once per each bitplane
+ uint8 *bm = map;
+ bool skip = (bm[bpl] == kPixelTransp);
+ uint16 j;
+
+ cnt = 0;
+ for (uint i = 0; i < _h; i++) { // once per each line
+ uint8 pix;
+ for (j = bpl; j < _w; j += 4) {
+ pix = bm[j];
+ if (_v && (pix != kPixelTransp)) {
+ if (j < _b[i]._skip)
+ _b[i]._skip = j;
+
+ if (j >= _b[i]._hide)
+ _b[i]._hide = j + 1;
+ }
+ if (((pix == kPixelTransp) != skip) || (cnt >= 0x3FF0)) { // end of block
+ cnt |= (skip) ? kBmpSKP : kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt); // store block description uint16
+
+ cp = (uint16 *) im;
+ im += 2;
+ skip = (pix == kPixelTransp);
+ cnt = 0;
+ }
+ if (!skip) {
+ if (_v)
+ *im = pix;
+ im++;
+ }
+ cnt++;
+ }
+
+ bm += _w;
+ if (_w < kScrWidth) {
+ if (skip)
+ cnt += (kScrWidth - j + 3) / 4;
+ else {
+ cnt |= kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt);
+
+ cp = (uint16 *) im;
+ im += 2;
+ skip = true;
+ cnt = (kScrWidth - j + 3) / 4;
+ }
+ }
+ }
+ if (cnt && ! skip) {
+ cnt |= kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt);
+
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ WRITE_LE_UINT16(cp, kBmpEOI);
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ break;
+
+ uint16 sizV = (uint16)(im - 2 - _v);
+ _v = new uint8[sizV + _h * sizeof(*_b)];
+ _b = (HideDesc *)(_v + sizV);
+ }
+ cnt = 0;
+ for (uint i = 0; i < _h; i++) {
+ if (_b[i]._skip == 0xFFFF) { // whole line is skipped
+ _b[i]._skip = (cnt + kScrWidth) >> 2;
+ cnt = 0;
+ } else {
+ uint16 s = _b[i]._skip & ~3;
+ uint16 h = (_b[i]._hide + 3) & ~3;
+ _b[i]._skip = (cnt + s) >> 2;
+ _b[i]._hide = (h - s) >> 2;
+ cnt = kScrWidth - h;
+ }
+ }
+
+ return this;
+}
+
+bool Bitmap::solidAt(V2D pos) {
+ pos.x += _w >> 1;
+ pos.y = _h - pos.y;
+
+ if (!pos.limited(V2D(_vm, _w, _h)))
+ return false;
+
+ uint8 *m = _v;
+ uint16 r = static_cast<uint16>(pos.x) % 4;
+ uint16 n0 = (kScrWidth * pos.y + pos.x) / 4;
+ uint16 n = 0;
+
+ while (r) {
+ uint16 w, t;
+
+ w = READ_LE_UINT16(m);
+ m += 2;
+ t = w & 0xC000;
+ w &= 0x3FFF;
+
+ switch (t) {
+ case kBmpEOI:
+ r--;
+ // No break on purpose
+ case kBmpSKP:
+ w = 0;
+ break;
+ case kBmpREP:
+ w = 1;
+ break;
+ }
+ m += w;
+ }
+
+ while (true) {
+ uint16 w, t;
+
+ w = READ_LE_UINT16(m);
+ m += 2;
+ t = w & 0xC000;
+ w &= 0x3FFF;
+
+ if (n > n0)
+ return false;
+
+ n += w;
+ switch (t) {
+ case kBmpEOI:
+ return false;
+ case kBmpSKP:
+ w = 0;
+ break;
+ case kBmpREP:
+ case kBmpCPY:
+ if ((n - w <= n0) && (n > n0))
+ return true;
+ break;
+ }
+ m += ((t == kBmpREP) ? 1 : w);
+ }
+}
+
+bool Bitmap::loadVBM(EncryptedStream *f) {
+ uint16 p = 0, n = 0;
+ if (!f->err())
+ f->read((uint8 *)&p, sizeof(p));
+ p = FROM_LE_16(p);
+
+ if (!f->err())
+ f->read((uint8 *)&n, sizeof(n));
+ n = FROM_LE_16(n);
+
+ if (!f->err())
+ f->read((uint8 *)&_w, sizeof(_w));
+ _w = FROM_LE_16(_w);
+
+ if (!f->err())
+ f->read((uint8 *)&_h, sizeof(_h));
+ _h = FROM_LE_16(_h);
+
+ if (!f->err()) {
+ if (p) {
+ if (_vm->_bitmapPalette) {
+ // Read in the palette
+ byte palData[kPalSize];
+ f->read(palData, kPalSize);
+
+ const byte *srcP = palData;
+ for (int idx = 0; idx < kPalCount; idx++, srcP += 3) {
+ _vm->_bitmapPalette[idx]._r = *srcP;
+ _vm->_bitmapPalette[idx]._g = *(srcP + 1);
+ _vm->_bitmapPalette[idx]._b = *(srcP + 2);
+ }
+ } else
+ f->seek(f->pos() + kPalSize);
+ }
+ }
+ _v = new uint8[n];
+
+ if (!f->err())
+ f->read(_v, n);
+
+ _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc));
+ return (!f->err());
+}
+
+void Bitmap::xLatPos(V2D& p) {
+ p.x -= (_w >> 1);
+ p.y = kWorldHeight - p.y - _h;
+}
+
+#define _ kPixelTransp,
+#define L 1,
+#define G 2,
+#define D 3,
+#define kDesignSize 240
+
+uint8 *Bitmap::makeSpeechBubbleTail(int which, uint8 colorSet[][4]) {
+ static const uint8 kSLDesign[kDesignSize] = {
+ G G G G G G G G G _ _ _ _ _ _
+ L G G G G G G G G D _ _ _ _ _
+ _ L G G G G G G G D _ _ _ _ _
+ _ _ L G G G G G G G D _ _ _ _
+ _ _ _ L G G G G G G D _ _ _ _
+ _ _ _ _ L G G G G G D _ _ _ _
+ _ _ _ _ _ L G G G G G D _ _ _
+ _ _ _ _ _ _ L G G G G D _ _ _
+ _ _ _ _ _ _ _ L G G G D _ _ _
+ _ _ _ _ _ _ _ _ L G G G D _ _
+ _ _ _ _ _ _ _ _ _ L G G D _ _
+ _ _ _ _ _ _ _ _ _ _ L G D _ _
+ _ _ _ _ _ _ _ _ _ _ _ L G D _
+ _ _ _ _ _ _ _ _ _ _ _ _ L D _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ L D
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D
+ };
+
+ static const uint8 kSRDesign[kDesignSize] = {
+ _ _ _ _ _ _ G G G G G G G G G
+ _ _ _ _ _ L G G G G G G G G D
+ _ _ _ _ _ L G G G G G G G D _
+ _ _ _ _ L G G G G G G G D _ _
+ _ _ _ _ L G G G G G G D _ _ _
+ _ _ _ _ L G G G G G D _ _ _ _
+ _ _ _ L G G G G G D _ _ _ _ _
+ _ _ _ L G G G G D _ _ _ _ _ _
+ _ _ _ L G G G D _ _ _ _ _ _ _
+ _ _ L G G G D _ _ _ _ _ _ _ _
+ _ _ L G G D _ _ _ _ _ _ _ _ _
+ _ _ L G D _ _ _ _ _ _ _ _ _ _
+ _ L G D _ _ _ _ _ _ _ _ _ _ _
+ _ L D _ _ _ _ _ _ _ _ _ _ _ _
+ L D _ _ _ _ _ _ _ _ _ _ _ _ _
+ D _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ };
+
+ uint8 *des = new uint8[kDesignSize];
+ switch (which) {
+ case 0:
+ memcpy(des, kSLDesign, sizeof(kSLDesign));
+ break;
+ case 1:
+ memcpy(des, kSRDesign, sizeof(kSRDesign));
+ break;
+ default:
+ error("Wrong parameter in Bitmap::makeSpeechBubbleTail!");
+ break;
+ }
+
+ for (int i = 0; i < kDesignSize; i++) {
+ if ((des[i] >= 1) && (des[i] <= 3))
+ des[i] = colorSet[kCBSay][des[i]];
+ }
+
+ return des;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/bitmap.h b/engines/cge2/bitmap.h
new file mode 100644
index 0000000000..613222fc6e
--- /dev/null
+++ b/engines/cge2/bitmap.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_BITMAP_H
+#define CGE2_BITMAP_H
+
+#include "cge2/general.h"
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+class EncryptedStream;
+class V2D;
+
+#define kMaxPath 128
+
+enum {
+ kBmpEOI = 0x0000,
+ kBmpSKP = 0x4000,
+ kBmpREP = 0x8000,
+ kBmpCPY = 0xC000
+};
+
+#include "common/pack-start.h"
+
+struct HideDesc {
+ uint16 _skip;
+ uint16 _hide;
+};
+
+#include "common/pack-end.h"
+
+class Bitmap {
+ CGE2Engine *_vm;
+
+ Common::String setExtension(const Common::String &str, const Common::String &ext);
+ bool loadVBM(EncryptedStream *f);
+public:
+ uint16 _w;
+ uint16 _h;
+ uint8 *_v;
+ int32 _map;
+ HideDesc *_b;
+
+ Bitmap();
+ Bitmap(CGE2Engine *vm, const char *fname);
+ Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map);
+ Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill);
+ Bitmap(CGE2Engine *vm, const Bitmap &bmp);
+ ~Bitmap();
+
+ void setVM(CGE2Engine *vm);
+ Bitmap *code(uint8 *map);
+ Bitmap &operator=(const Bitmap &bmp);
+ void release();
+ void hide(V2D pos);
+ void show(V2D pos);
+ bool solidAt(V2D pos);
+ void xLatPos(V2D &p);
+
+ static uint8 *makeSpeechBubbleTail(int des, uint8 colorSet[][4]);
+};
+
+
+typedef Bitmap *BitmapPtr;
+
+} // End of namespace CGE2
+
+#endif // CGE2_BITMAP_H
diff --git a/engines/cge2/cge2.cpp b/engines/cge2/cge2.cpp
new file mode 100644
index 0000000000..852b7afb22
--- /dev/null
+++ b/engines/cge2/cge2.cpp
@@ -0,0 +1,206 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "engines/util.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "cge2/cge2.h"
+#include "cge2/bitmap.h"
+#include "cge2/vga13h.h"
+#include "cge2/sound.h"
+#include "cge2/text.h"
+#include "cge2/hero.h"
+#include "cge2/general.h"
+#include "cge2/spare.h"
+#include "cge2/talk.h"
+#include "cge2/cge2_main.h"
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+CGE2Engine::CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription)
+ : Engine(syst), _gameDescription(gameDescription), _randomSource("cge2") {
+
+ // Debug/console setup
+ DebugMan.addDebugChannel(kCGE2DebugOpcode, "opcode", "CGE2 opcode debug channel");
+
+ _resman = nullptr;
+ _vga = nullptr;
+ _midiPlayer = nullptr;
+ _fx = nullptr;
+ _sound = nullptr;
+ _text = nullptr;
+ for (int i = 0; i < 2; i++)
+ _heroTab[i] = nullptr;
+ _eye = nullptr;
+ for (int i = 0; i < kSceneMax; i++)
+ _eyeTab[i] = nullptr;
+ _spare = nullptr;
+ _commandHandler = nullptr;
+ _commandHandlerTurbo = nullptr;
+ _font = nullptr;
+ _infoLine = nullptr;
+ _mouse = nullptr;
+ _keyboard = nullptr;
+ _talk = nullptr;
+ for (int i = 0; i < kMaxPoint; i++)
+ _point[i] = nullptr;
+ _sys = nullptr;
+ _busyPtr = nullptr;
+ for (int i = 0; i < 2; i++)
+ _vol[i] = nullptr;
+ _eventManager = nullptr;
+ _map = nullptr;
+ _quitFlag = false;
+ _bitmapPalette = nullptr;
+ _gamePhase = kPhaseIntro;
+ _now = 1;
+ _sex = 1;
+ _mouseTop = kWorldHeight / 3;
+ _dark = false;
+ _lastFrame = 0;
+ _lastTick = 0;
+ _waitSeq = 0;
+ _waitRef = 0;
+ _soundStat._wait = nullptr;
+ _soundStat._ref[0] = 0;
+ _soundStat._ref[1] = 0;
+ _taken = false;
+ _endGame = false;
+ _req = 1;
+ _midiNotify = nullptr;
+ _spriteNotify = nullptr;
+ _startGameSlot = 0;
+
+ _sayCap = ConfMan.getBool("subtitles");
+ _sayVox = !ConfMan.getBool("speech_mute");
+ _muteAll = ConfMan.getBool("mute");
+ if (_muteAll) {
+ _oldMusicVolume = _oldSfxVolume = 0;
+ _music = _sayVox = false;
+ } else {
+ _oldMusicVolume = ConfMan.getInt("music_volume");
+ _oldSfxVolume = ConfMan.getInt("sfx_volume");
+ _music = _oldMusicVolume != 0;
+ }
+}
+
+void CGE2Engine::init() {
+ // Create debugger console
+ _console = new CGE2Console(this);
+ _resman = new ResourceManager();
+ _vga = new Vga(this);
+ _fx = new Fx(this, 16);
+ _sound = new Sound(this);
+ _midiPlayer = new MusicPlayer(this);
+ _text = new Text(this, "CGE");
+
+ for (int i = 0; i < 2; i++)
+ _heroTab[i] = new HeroTab(this);
+
+ _eye = new V3D();
+ for (int i = 0; i < kSceneMax; i++)
+ _eyeTab[i] = new V3D();
+
+ _spare = new Spare(this);
+ _commandHandler = new CommandHandler(this, false);
+ _commandHandlerTurbo = new CommandHandler(this, true);
+ _font = new Font(this);
+ _infoLine = new InfoLine(this, kInfoW);
+ _mouse = new Mouse(this);
+ _keyboard = new Keyboard(this);
+
+ for (int i = 0; i < kMaxPoint; i++)
+ _point[i] = new V3D();
+
+ _sys = new System(this);
+ _eventManager = new EventManager(this);
+ _map = new Map(this);
+ _startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+}
+
+void CGE2Engine::deinit() {
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+
+ delete _console;
+
+ delete _spare;
+ delete _resman;
+ delete _vga;
+ delete _fx;
+ delete _sound;
+ delete _midiPlayer;
+ delete _text;
+
+ for (int i = 0; i < 2; i++)
+ delete _heroTab[i];
+
+ for (int i = 0; i < kSceneMax; i++)
+ delete _eyeTab[i];
+
+ delete _eye;
+ delete _commandHandler;
+ delete _commandHandlerTurbo;
+ delete _font;
+ delete _infoLine;
+ delete _mouse;
+ delete _keyboard;
+
+ if (_talk != nullptr)
+ delete _talk;
+
+ for (int i = 0; i < kMaxPoint; i++)
+ delete _point[i];
+
+ delete _sys;
+ delete _eventManager;
+ delete _map;
+}
+
+bool CGE2Engine::hasFeature(EngineFeature f) const {
+ return (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime)
+ || (f == kSupportsRTL);
+}
+
+Common::Error CGE2Engine::run() {
+ syncSoundSettings();
+ initGraphics(kScrWidth, kScrHeight, false);
+
+ init();
+ cge2_main();
+ deinit();
+
+ ConfMan.setBool("subtitles", _sayCap);
+ ConfMan.setBool("speech_mute", !_sayVox);
+ ConfMan.flushToDisk();
+
+ return Common::kNoError;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h
new file mode 100644
index 0000000000..1f1cb17b48
--- /dev/null
+++ b/engines/cge2/cge2.h
@@ -0,0 +1,341 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_H
+#define CGE2_H
+
+#include "common/random.h"
+#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"
+
+namespace CGE2 {
+
+class Vga;
+class Sprite;
+class MusicPlayer;
+class Fx;
+class Sound;
+class Text;
+struct HeroTab;
+class FXP;
+class V3D;
+class V2D;
+struct Dac;
+class Spare;
+class CommandHandler;
+class InfoLine;
+class Mouse;
+class Keyboard;
+class Talk;
+class Hero;
+class Bitmap;
+class System;
+class EventManager;
+class Font;
+class Map;
+struct SavegameHeader;
+
+#define kScrWidth 320
+#define kScrHeight 240
+#define kScrDepth 480
+#define kPanHeight 40
+#define kWorldHeight (kScrHeight - kPanHeight)
+#define kMaxFile 128
+#define kPathMax 128
+#define kDimMax 8
+#define kWayMax 10
+#define kPocketMax 4
+#define kSceneMax 100
+#define kMaxPoint 4
+#define kInfoX 160
+#define kInfoY -11
+#define kInfoW 180
+#define kPocketsWidth 59
+#define kLineMax 512
+
+#define kIntroExt ".I80"
+#define kTabName "CGE.TAB"
+#define kPocketFull 170
+#define kGameFrameDelay (750 / 50)
+#define kGameTickDelay (750 / 62)
+
+#define kMusicRef 122
+#define kPowerRef 123
+#define kDvolRef 124
+#define kMvolRef 125
+#define kRef 126
+#define kBusyRef 127
+#define kCapRef 128
+#define kVoxRef 129
+
+#define kOffUseCount 130
+#define kOffUseText 131
+
+#define kSysTimeRate 6 // 12 Hz
+#define kBlinkRate 4 // 3 Hz
+
+#define kQuitTitle 200
+#define kQuitText 201
+#define kNoQuitText 202
+
+#define kSavegameVersion 1
+#define kSavegameStrSize 12
+#define kSavegameStr "SCUMMVM_CGE2"
+
+#define kColorNum 6
+
+struct SavegameHeader {
+ uint8 version;
+ Common::String saveName;
+ Graphics::Surface *thumbnail;
+ int saveYear, saveMonth, saveDay;
+ int saveHour, saveMinutes;
+};
+
+enum ColorBank { kCBRel, kCBStd, kCBSay, kCBInf, kCBMnu, kCBWar };
+
+enum GamePhase { kPhaseInGame, kPhaseIntro, kPhaseOver };
+
+// our engine debug channels
+enum {
+ kCGE2DebugOpcode = 1 << 0
+};
+
+enum CallbackType {
+ kNullCB = 0, kQGame, kXScene
+};
+
+enum Action { kNear, kMTake, kFTake, kActions };
+
+typedef void (CGE2Engine::*NotifyFunctionType)();
+
+class CGE2Engine : public Engine {
+private:
+ uint32 _lastFrame, _lastTick;
+ void tick();
+
+ CGE2Console *_console;
+ void init();
+ void deinit();
+
+ Common::String generateSaveName(int slot);
+ void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
+ void saveGame(int slotNumber, const Common::String &desc);
+ bool loadGame(int slotNumber);
+ void syncHeader(Common::Serializer &s);
+ void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
+ void resetGame();
+public:
+ CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription);
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual bool canSaveGameStateCurrently();
+ virtual bool canLoadGameStateCurrently();
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual Common::Error loadGameState(int slot);
+ virtual Common::Error run();
+
+ static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+
+ GUI::Debugger *getDebugger() {
+ return _console;
+ }
+
+ bool showTitle(const char *name);
+ void cge2_main();
+ char *mergeExt(char *buf, const char *name, const char *ext);
+ void inf(const char *text, ColorBank col = kCBInf);
+ void movie(const char *ext);
+ void runGame();
+ void loadHeroes();
+ void loadScript(const char *fname, bool onlyToolbar = false);
+ Sprite *loadSprite(const char *fname, int ref, int scene, V3D &pos);
+ void badLab(const char *fn);
+ void sceneUp(int cav);
+ void sceneDown();
+ void closePocket();
+ void switchScene(int scene);
+ void storeHeroPos();
+ void showBak(int ref);
+ void loadTab();
+ int newRandom(int range);
+ void openPocket();
+ void selectPocket(int n);
+ void busy(bool on);
+ void feedSnail(Sprite *spr, Action snq, Hero *hero);
+ int freePockets(int sx);
+ int findActivePocket(int ref);
+ void pocFul();
+ void killText();
+ void mainLoop();
+ void handleFrame();
+ Sprite *locate(int ref);
+ bool isHero(Sprite *spr);
+ void loadUser();
+ void loadPos();
+ void releasePocket(Sprite *spr);
+ void switchHero(int sex);
+ void offUse();
+ void setAutoColors();
+ bool cross(const V2D &a, const V2D &b, const V2D &c, const V2D &d);
+ bool contain(const V2D &a, const V2D &b, const V2D &p);
+ long det(const V2D &a, const V2D &b, const V2D &c);
+ int sgn(long n);
+ int mapCross(const V2D &a, const V2D &b);
+ Sprite *spriteAt(V2D pos);
+ void keyClick();
+ void swapInPocket(Sprite *spr, Sprite *xspr);
+ void busyStep();
+
+ void optionTouch(int opt, uint16 mask);
+ void switchColorMode();
+ void switchMusic();
+ void quit();
+ void setVolume(int idx, int cnt);
+ void checkVolumeSwitches();
+ void switchCap();
+ void switchVox();
+ void switchSay();
+ void initToolbar();
+ void initVolumeSwitch(Sprite *volSwitch, int val);
+ void checkMute();
+
+ void checkSounds();
+
+ void setEye(const V3D &e);
+ void setEye(const V2D& e2, int z = -kScrWidth);
+ void setEye(const char *s);
+
+ int number(char *s);
+ char *token(char *s);
+ char *tail(char *s);
+ int takeEnum(const char **tab, const char *text);
+ ID ident(const char *s);
+ bool testBool(char *s);
+
+ void snKill(Sprite *spr);
+ void snHide(Sprite *spr, int val);
+ void snMidi(int val);
+ void snSeq(Sprite *spr, int val);
+ void snRSeq(Sprite *spr, int val);
+ void snSend(Sprite *spr, int val);
+ void snSwap(Sprite *spr, int val);
+ void snCover(Sprite *spr, int val);
+ void snUncover(Sprite *spr, Sprite *spr2);
+ void snKeep(Sprite *spr, int val);
+ void snGive(Sprite *spr, int val);
+ void snGoto(Sprite *spr, int val);
+ void snPort(Sprite *spr, int port);
+ void snMouse(bool on);
+ void snNNext(Sprite *spr, Action act, int val);
+ void snRNNext(Sprite *spr, int val);
+ void snRMTNext(Sprite *spr, int val);
+ void snRFTNext(Sprite *spr, int val);
+ void snRmNear(Sprite *spr);
+ void snRmMTake(Sprite *spr);
+ void snRmFTake(Sprite *spr);
+ void snSetRef(Sprite *spr, int val);
+ void snFlash(bool on);
+ void snCycle(int cnt);
+ void snWalk(Sprite *spr, int val);
+ void snReach(Sprite *spr, int val);
+ void snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
+ void snRoom(Sprite *spr, bool on);
+ void snGhost(Bitmap *bmp);
+ void snSay(Sprite *spr, int val);
+
+ void hide1(Sprite *spr);
+ Sprite *expandSprite(Sprite *spr);
+ void qGame();
+ void xScene();
+
+ const ADGameDescription *_gameDescription;
+
+ Common::RandomSource _randomSource;
+
+ bool _quitFlag;
+ Dac *_bitmapPalette;
+ GamePhase _gamePhase; // Original name: startupmode
+ int _now;
+ int _sex;
+ int _mouseTop;
+ bool _dark;
+ int _waitSeq;
+ int _waitRef;
+
+ struct {
+ int *_wait;
+ int _ref[2];
+ } _soundStat;
+
+ bool _taken;
+ bool _endGame;
+ int _req;
+ NotifyFunctionType _midiNotify;
+ NotifyFunctionType _spriteNotify;
+ int _startGameSlot;
+
+ bool _sayCap;
+ bool _sayVox;
+ int _oldMusicVolume;
+ int _oldSfxVolume;
+ bool _music;
+ bool _muteAll;
+
+ ResourceManager *_resman;
+ Vga *_vga;
+ MusicPlayer *_midiPlayer;
+ Fx *_fx;
+ Sound *_sound;
+ Text *_text;
+ HeroTab *_heroTab[2];
+ V3D *_eye;
+ V3D *_eyeTab[kSceneMax];
+ Spare *_spare;
+ CommandHandler *_commandHandler;
+ CommandHandler *_commandHandlerTurbo;
+ Font *_font;
+ InfoLine *_infoLine;
+ Mouse *_mouse;
+ Keyboard *_keyboard;
+ Talk *_talk;
+ V3D *_point[kMaxPoint];
+ System *_sys;
+ Sprite *_busyPtr;
+ Sprite *_vol[2];
+ EventManager *_eventManager;
+ Map *_map;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_H
diff --git a/engines/cge2/cge2_main.cpp b/engines/cge2/cge2_main.cpp
new file mode 100644
index 0000000000..1057b00089
--- /dev/null
+++ b/engines/cge2/cge2_main.cpp
@@ -0,0 +1,960 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "sound.h"
+#include "cge2/cge2_main.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/text.h"
+#include "cge2/snail.h"
+#include "cge2/hero.h"
+#include "cge2/spare.h"
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+System::System(CGE2Engine *vm) : Sprite(vm), _vm(vm) {
+ _blinkCounter = 0;
+ _blinkSprite = nullptr;
+ tick();
+}
+
+void System::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
+ if (mask & kEventKeyb) {
+ if (keyCode == Common::KEYCODE_ESCAPE) {
+ // The original was calling keyClick()
+ // The sound is uselessly annoying and noisy, so it has been removed
+ _vm->killText();
+ if (_vm->_gamePhase == kPhaseIntro) {
+ _vm->_commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ return;
+ }
+ }
+ } else {
+ if (_vm->_gamePhase != kPhaseInGame)
+ return;
+ _vm->_infoLine->setText(nullptr);
+
+ if (mask & kMouseLeftUp) {
+ if (pos.y >= 0) { // world
+ if (!_vm->_talk && pos.y < _vm->_mouseTop)
+ _vm->_heroTab[_vm->_sex]->_ptr->walkTo(pos);
+ } else { // panel
+ if (_vm->_commandHandler->idle()) {
+ int sex = pos.x < kPocketsWidth;
+ if (sex || pos.x >= kScrWidth - kPocketsWidth) {
+ _vm->switchHero(sex);
+ if (_vm->_sex == sex) {
+ int dx = kPocketsWidth >> 1,
+ dy = 1 - (kPanHeight >> 1);
+ Sprite *s;
+ if (!sex)
+ pos.x -= kScrWidth - kPocketsWidth;
+ dx -= pos.x;
+ dy -= pos.y;
+ if (dx * dx + dy * dy > 10 * 10) {
+ int n = 0;
+ if (1 - pos.y >= (kPanHeight >> 1))
+ n += 2;
+ if (pos.x >= (kPocketsWidth >> 1))
+ ++n;
+ s = _vm->_heroTab[_vm->_sex]->_pocket[n];
+ if (_vm->_sys->_blinkSprite)
+ _vm->_sys->_blinkSprite->_flags._hide = false;
+ if (_vm->_sys->_blinkSprite == s)
+ _vm->_sys->_blinkSprite = nullptr;
+ else
+ _vm->_sys->_blinkSprite = s;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void System::tick() {
+ _time = kSysTimeRate;
+
+ if (_blinkCounter)
+ --_blinkCounter;
+ else {
+ if (_blinkSprite)
+ _blinkSprite->_flags._hide ^= 1;
+ _blinkCounter = kBlinkRate;
+ }
+}
+
+int CGE2Engine::number(char *str) {
+ char *s = token(str);
+ if (s == nullptr)
+ error("Wrong input for CGE2Engine::number()");
+ int r = atoi(s);
+ char *pp = strchr(s, ':');
+ if (pp)
+ r = (r << 8) + atoi(pp + 1);
+ return r;
+}
+
+char *CGE2Engine::token(char *s) {
+ return strtok(s, " =\t,;/()");
+}
+
+char *CGE2Engine::tail(char *s) {
+ if (s && (*s == '='))
+ s++;
+ return s;
+}
+
+int CGE2Engine::takeEnum(const char **tab, const char *text) {
+ if (text) {
+ for (const char **e = tab; *e; e++) {
+ if (scumm_stricmp(text, *e) == 0)
+ return e - tab;
+ }
+ }
+ return -1;
+}
+
+ID CGE2Engine::ident(const char *s) {
+ return ID(takeEnum(EncryptedStream::kIdTab, s));
+}
+
+bool CGE2Engine::testBool(char *s) {
+ return number(s) != 0;
+}
+
+void CGE2Engine::badLab(const char *fn) {
+ error("Misplaced label in %s!", fn);
+}
+
+Sprite *CGE2Engine::loadSprite(const char *fname, int ref, int scene, V3D &pos) {
+ int shpcnt = 0;
+ int seqcnt = 0;
+ int cnt[kActions];
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ ID section = kIdPhase;
+ bool frnt = true;
+ bool east = false;
+ bool port = false;
+ bool tran = false;
+ Hero *h;
+ ID id;
+
+ char tmpStr[kLineMax + 1];
+ mergeExt(tmpStr, fname, kSprExt);
+
+ if (_resman->exist(tmpStr)) { // sprite description file exist
+ EncryptedStream sprf(this, tmpStr);
+ if (sprf.err())
+ error("Bad SPR [%s]", tmpStr);
+
+ int label = kNoByte;
+ Common::String line;
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()){
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = token(tmpStr);
+ if (*p == '@') {
+ if (label != kNoByte)
+ badLab(fname);
+ label = atoi(p + 1);
+ continue;
+ }
+
+ id = ident(p);
+ switch (id) {
+ case kIdName: // will be taken in Expand routine
+ if (label != kNoByte)
+ badLab(fname);
+ break;
+ case kIdType:
+ if (label != kNoByte)
+ badLab(fname);
+ break;
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ if (label != kNoByte)
+ badLab(fname);
+ section = id;
+ break;
+ case kIdFront:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ frnt = testBool(p);
+ break;
+ case kIdEast:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ east = testBool(p);
+ break;
+ case kIdPortable:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ port = testBool(p);
+ break;
+ case kIdTransparent:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ tran = testBool(p);
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ if (_commandHandler->getComId(p) >= 0)
+ ++cnt[section];
+ else
+ error("Bad line %d [%s]", sprf.getLineCount(), tmpStr);
+ break;
+ case kIdPhase:
+ if (label != kNoByte)
+ badLab(fname);
+ ++shpcnt;
+ break;
+ case kIdSeq:
+ if (label != kNoByte)
+ badLab(fname);
+ ++seqcnt;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ label = kNoByte;
+ }
+
+ if (!shpcnt)
+ error("No shapes - %s", fname);
+ } else // No sprite description: mono-shaped sprite with only .BMP file.
+ ++shpcnt;
+
+ // Make sprite of chosen type:
+ Sprite *sprite = nullptr;
+ char c = *fname | 0x20;
+ if (c >= 'a' && c <= 'z' && fname[1] == '0' && fname[2] == '\0') {
+ h = new Hero(this);
+ h->gotoxyz(pos);
+ sprite = h;
+ } else {
+ sprite = new Sprite(this);
+ sprite->gotoxyz(pos);
+ }
+
+ if (sprite) {
+ sprite->_ref = ref;
+ sprite->_scene = scene;
+
+ sprite->_flags._frnt = frnt;
+ sprite->_flags._east = east;
+ sprite->_flags._port = port;
+ sprite->_flags._tran = tran;
+ sprite->_flags._kill = true;
+
+ // Extract the filename, without the extension
+ Common::strlcpy(sprite->_file, fname, sizeof(sprite->_file));
+ char *p = strchr(sprite->_file, '.');
+ if (p)
+ *p = '\0';
+
+ sprite->_shpCnt = shpcnt;
+ sprite->_seqCnt = seqcnt;
+
+ for (int i = 0; i < kActions; i++)
+ sprite->_actionCtrl[i]._cnt = cnt[i];
+ }
+
+ return sprite;
+}
+
+void CGE2Engine::loadScript(const char *fname, bool onlyToolbar) {
+ EncryptedStream scrf(this, fname);
+
+ if (scrf.err())
+ return;
+
+ bool ok = true;
+ int lcnt = 0;
+
+ char tmpStr[kLineMax + 1];
+ Common::String line;
+
+ for (line = scrf.readLine(); !scrf.eos(); line = scrf.readLine()) {
+ if (line.empty())
+ continue;
+
+ lcnt++;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ ok = false; // not OK if break
+
+ V3D P;
+
+ // sprite ident number
+ int SpI = number(tmpStr);
+
+ if (onlyToolbar && SpI >= 141)
+ return;
+
+ // sprite file name
+ char *SpN;
+ if ((SpN = token(nullptr)) == nullptr)
+ break;
+
+ // sprite scene
+ int SpA = number(nullptr);
+
+ // sprite column
+ P._x = number(nullptr);
+
+ // sprite row
+ P._y = number(nullptr);
+
+ // sprite Z pos
+ P._z = number(nullptr);
+
+ // sprite life
+ bool BkG = number(nullptr) == 0;
+
+ ok = true; // no break: OK
+
+ Sprite *sprite = loadSprite(SpN, SpI, SpA, P);
+ if (sprite) {
+ if (BkG)
+ sprite->_flags._back = true;
+
+ int n = _spare->count();
+ if (_spare->locate(sprite->_ref) == nullptr)
+ _spare->dispose(sprite);
+ else
+ delete sprite;
+
+ if (_spare->count() == n)
+ error("Duplicate reference! %s", SpN);
+ }
+ }
+
+ if (!ok)
+ error("Bad INI line %d [%s]", scrf.getLineCount(), fname);
+}
+
+void CGE2Engine::movie(const char *ext) {
+ assert(ext);
+
+ if (_quitFlag)
+ return;
+
+ char fn[12];
+ snprintf(fn, 12, "CGE%s", ext);
+
+ if (_resman->exist(fn)) {
+ int now = _now;
+ _now = atoi(ext + 2);
+ loadScript(fn);
+ sceneUp(_now);
+ _keyboard->setClient(_sys);
+
+ while (!_commandHandler->idle() && !_quitFlag)
+ mainLoop();
+
+ _keyboard->setClient(nullptr);
+ _commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
+ _spare->clear();
+ _vga->_showQ->clear();
+ _now = now;
+ }
+}
+
+void CGE2Engine::sceneUp(int cav) {
+ _now = cav;
+ int bakRef = _now << 8;
+ if (_music)
+ _midiPlayer->loadMidi(bakRef);
+ showBak(bakRef);
+ *_eye = *(_eyeTab[_now]);
+ _mouseTop = V2D(this, V3D(0, 1, kScrDepth)).y;
+ _map->load(_now);
+ _spare->takeScene(_now);
+ openPocket();
+
+ for (int i = 0; i < 2; i++) {
+ Hero *h = _heroTab[i]->_ptr;
+ if (h && h->_scene == _now) {
+ V2D p = *_heroTab[i]->_posTab[_now];
+ h->gotoxyz(V3D(p.x, 0, p.y));
+ h->clrHide();
+ _vga->_showQ->insert(h);
+ h->park();
+ h->setCurrent();
+ h->setContact();
+ }
+ }
+
+ _sound->stop();
+ _fx->clear();
+
+ selectPocket(-1);
+ _infoLine->setText(nullptr);
+ busy(false);
+
+ if (!_dark)
+ _vga->sunset();
+
+ _vga->show();
+ _vga->copyPage(1, 0);
+ _vga->show();
+ _vga->sunrise(_vga->_sysPal);
+
+ _dark = false;
+
+ if (_gamePhase == kPhaseInGame)
+ _mouse->on();
+
+ feedSnail(_vga->_showQ->locate(bakRef + 255), kNear, _heroTab[_sex]->_ptr);
+}
+
+void CGE2Engine::sceneDown() {
+ busy(true);
+ _soundStat._wait = nullptr; // unlock snail
+ Sprite *spr = _vga->_showQ->locate((_now << 8) | 254);
+
+ if (spr)
+ feedSnail(spr, kNear, _heroTab[_sex]->_ptr);
+
+ while (!(_commandHandler->idle() && _commandHandlerTurbo->idle())) {
+ _commandHandlerTurbo->runCommand();
+ _commandHandler->runCommand();
+ }
+
+ closePocket();
+ for (int i = 0; i < 2; i++)
+ _spare->update(_vga->_showQ->remove(_heroTab[i]->_ptr));
+ _spare->dispose();
+}
+
+void CGE2Engine::switchScene(int scene) {
+ if (scene == _now)
+ return;
+
+ _req = scene;
+ storeHeroPos();
+ *(_eyeTab[_now]) = *_eye;
+
+ if (scene < 0)
+ _commandHandler->addCallback(kCmdExec, -1, 0, kQGame); // quit game
+ else {
+ if (_heroTab[_sex]->_ptr->_scene == _now) {
+ _heroTab[_sex]->_ptr->setScene(scene);
+ if (_heroTab[!_sex]->_ptr->_scene == _now)
+ _heroTab[!_sex]->_ptr->setScene(scene);
+ }
+ _mouse->off();
+ if (_heroTab[_sex]->_ptr)
+ _heroTab[_sex]->_ptr->park();
+ killText();
+ _commandHandler->addCallback(kCmdExec, -1, 0, kXScene); // switch scene
+ }
+}
+
+void CGE2Engine::storeHeroPos() {
+ for (int i = 0; i < 2; i++) {
+ Hero *h = _heroTab[i]->_ptr;
+ if (h->_scene == _now) {
+ delete _heroTab[i]->_posTab[_now];
+ V2D *temp = new V2D(this, h->_pos3D._x.trunc(), h->_pos3D._z.trunc());
+ _heroTab[i]->_posTab[_now] = temp;
+ }
+ }
+}
+
+void CGE2Engine::showBak(int ref) {
+ Sprite *spr = _spare->locate(ref);
+ if (spr != nullptr) {
+ _bitmapPalette = _vga->_sysPal;
+ spr->expand();
+ _bitmapPalette = nullptr;
+ spr->show(2);
+ _vga->copyPage(1, 2);
+ }
+}
+
+void CGE2Engine::mainLoop() {
+ if (_gamePhase == kPhaseInGame)
+ checkSounds();
+
+ _vga->show();
+ _commandHandlerTurbo->runCommand();
+ _commandHandler->runCommand();
+
+ // Handle a delay between game frames
+ handleFrame();
+
+ // Handle any pending events
+ _eventManager->poll();
+
+ // Check shouldQuit()
+ _quitFlag = shouldQuit();
+}
+
+void CGE2Engine::checkSounds() {
+ checkMute();
+ _sound->checkSoundHandles();
+ checkVolumeSwitches();
+ _midiPlayer->syncVolume();
+ syncSoundSettings();
+}
+
+void CGE2Engine::handleFrame() {
+ // Game frame delay
+ uint32 millis = g_system->getMillis();
+ while (!_quitFlag && (millis < (_lastFrame + kGameFrameDelay))) {
+ // Handle any pending events
+ _eventManager->poll();
+
+ if (millis >= (_lastTick + kGameTickDelay)) {
+ // Dispatch the tick to any active objects
+ tick();
+ _lastTick = millis;
+ }
+
+ // Slight delay
+ g_system->delayMillis(5);
+ millis = g_system->getMillis();
+ }
+ _lastFrame = millis;
+
+ if (millis >= (_lastTick + kGameTickDelay)) {
+ // Dispatch the tick to any active objects
+ tick();
+ _lastTick = millis;
+ }
+}
+
+Sprite *CGE2Engine::locate(int ref) {
+ _taken = false;
+ Sprite *spr = _vga->_showQ->locate(ref);
+ if (!spr) {
+ spr = _spare->locate(ref);
+ if (spr)
+ _taken = true;
+ }
+ return spr;
+}
+
+bool CGE2Engine::isHero(Sprite *spr) {
+ return spr && spr->_ref / 10 == 14;
+}
+
+void CGE2Engine::tick() {
+ // system pseudo-sprite
+ if (_sys && _sys->_time && (--_sys->_time == 0))
+ _sys->tick();
+
+ for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) {
+ if (spr->_time && (--spr->_time == 0))
+ spr->tick();
+
+ if (_waitRef && (_waitRef == spr->_ref) && spr->seqTest(_waitSeq))
+ _waitRef = 0;
+ }
+
+ _mouse->tick();
+}
+
+void CGE2Engine::busy(bool on) {
+ if (on) {
+ _spriteNotify = _midiNotify = &CGE2::CGE2Engine::busyStep;
+ busyStep();
+ } else {
+ if (_busyPtr)
+ _busyPtr->step(0);
+ _spriteNotify = _midiNotify = nullptr;
+ }
+}
+
+void CGE2Engine::busyStep() {
+ if (_busyPtr) {
+ _busyPtr->step((_busyPtr->_seqPtr) ? -1 : 1);
+ _busyPtr->show(0);
+ }
+}
+
+void CGE2Engine::runGame() {
+ if (_quitFlag)
+ return;
+
+ loadUser();
+ sceneUp(_now);
+ initToolbar();
+
+ // main loop
+ while (!_endGame && !_quitFlag)
+ mainLoop();
+
+ // If leaving the game (close window, return to launcher, etc.
+ // - except finishing the game), explicitly save it's state:
+ if (!_endGame && canSaveGameStateCurrently())
+ qGame();
+
+ _keyboard->setClient(nullptr);
+ _commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
+ _mouse->off();
+}
+
+void CGE2Engine::loadUser() {
+ loadPos();
+
+ if (_startGameSlot != -1)
+ loadGame(_startGameSlot);
+ else {
+ loadScript("CGE.INI");
+ loadHeroes();
+ }
+}
+
+void CGE2Engine::loadHeroes() { // Original name: loadGame()
+ // load sprites & pocket
+
+ Sprite *s;
+ Hero *h = nullptr;
+
+ // initialize Andzia/Anna
+ s = _spare->take(142);
+ if (s) {
+ h = new Hero(this);
+ *(Sprite*)h = *s;
+ delete s;
+ h->expand();
+ _spare->update(h);
+ }
+ _heroTab[0]->_ptr = h;
+ s = _spare->locate(152);
+ _vga->_showQ->insert(s);
+ _heroTab[0]->_face = s;
+
+ // initialize Wacek/Vincent
+ s = _spare->take(141);
+ if (s) {
+ h = new Hero(this);
+ *(Sprite*)h = *s;
+ delete s;
+ h->expand();
+ _spare->update(h);
+ }
+ _heroTab[1]->_ptr = h;
+ s = _spare->locate(151);
+ _vga->_showQ->insert(s);
+ _heroTab[1]->_face = s;
+
+ //--- start!
+ switchHero(_sex);
+}
+
+void CGE2Engine::loadPos() {
+ if (_resman->exist("CGE.HXY")) {
+ for (int cav = 0; cav < kSceneMax; cav++)
+ _heroTab[1]->_posTab[cav] = new V2D(this, 180, 10);
+
+ EncryptedStream file(this, "CGE.HXY");
+
+ for (int cav = 0; cav < kSceneMax; cav++) {
+ _heroTab[0]->_posTab[cav] = new V2D(this);
+ _heroTab[0]->_posTab[cav]->x = file.readSint16LE();
+ _heroTab[0]->_posTab[cav]->y = file.readSint16LE();
+ }
+
+ for (int cav = 0; cav < 41; cav++) { // (564 - 400) / 4 = 41
+ _heroTab[1]->_posTab[cav]->x = file.readSint16LE();
+ _heroTab[1]->_posTab[cav]->y = file.readSint16LE();
+ }
+ } else
+ error("Missing file: CGE.HXY");
+}
+
+void CGE2Engine::loadTab() {
+ setEye(_text->getText(240));
+ for (int i = 0; i < kSceneMax; i++)
+ *(_eyeTab[i]) = *_eye;
+
+ if (_resman->exist(kTabName)) {
+ EncryptedStream f(this, kTabName);
+ uint32 v;
+
+ for (int i = 0; i < kSceneMax; i++) {
+ v = f.readUint32LE();
+ _eyeTab[i]->_x = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
+
+ v = f.readUint32LE();
+ _eyeTab[i]->_y = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
+
+ v = f.readUint32LE();
+ _eyeTab[i]->_z = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
+ }
+ }
+}
+
+void CGE2Engine::cge2_main() {
+ loadTab();
+
+ if (_startGameSlot != -1) {
+ // Starting up a savegame from the launcher
+ runGame();
+ return;
+ }
+
+ if (showTitle("WELCOME")) {
+ movie(kIntroExt);
+
+ if (_text->getText(255) != nullptr) {
+ runGame();
+ _gamePhase = kPhaseOver;
+ }
+
+ _vga->sunset();
+ } else
+ _vga->sunset();
+}
+
+char *CGE2Engine::mergeExt(char *buf, const char *name, const char *ext) {
+ strcpy(buf, name);
+ char *dot = strrchr(buf, '.');
+ if (!dot)
+ strcat(buf, ext);
+
+ return buf;
+}
+
+void CGE2Engine::setEye(const V3D &e) {
+ *_eye = e;
+}
+
+void CGE2Engine::setEye(const V2D& e2, int z) {
+ _eye->_x = e2.x;
+ _eye->_y = e2.y;
+ _eye->_z = z;
+}
+
+void CGE2Engine::setEye(const char *s) {
+ char *tempStr = new char[strlen(s) + 1];
+ strcpy(tempStr, s);
+ _eye->_x = atoi(token(tempStr));
+ _eye->_y = atoi(token(nullptr));
+ _eye->_z = atoi(token(nullptr));
+ delete[] tempStr;
+}
+
+int CGE2Engine::newRandom(int range) {
+ if (!range)
+ return 0;
+
+ return _randomSource.getRandomNumber(range - 1);
+}
+
+bool CGE2Engine::showTitle(const char *name) {
+ if (_quitFlag)
+ return false;
+
+ _bitmapPalette = _vga->_sysPal;
+ BitmapPtr LB = new Bitmap[1];
+ LB[0] = Bitmap(this, name);
+ _bitmapPalette = nullptr;
+
+ Sprite D(this, LB, 1);
+ D._flags._kill = true;
+ D.gotoxyz(kScrWidth >> 1, -(kPanHeight >> 1));
+
+ _vga->sunset();
+ D.show(2);
+ _vga->copyPage(1, 2);
+ _vga->copyPage(0, 1);
+ _vga->sunrise(_vga->_sysPal);
+ _vga->update();
+
+ g_system->delayMillis(2500);
+
+ return true;
+}
+
+void CGE2Engine::killText() {
+ if (!_talk)
+ return;
+
+ _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, _talk);
+ _talk = nullptr;
+}
+
+void CGE2Engine::switchHero(int sex) {
+ if (sex != _sex) {
+ int scene = _heroTab[sex]->_ptr->_scene;
+ if (_sys->_blinkSprite) {
+ _sys->_blinkSprite->_flags._hide = false;
+ _sys->_blinkSprite = nullptr;
+ }
+
+ if (scene >= 0) {
+ _commandHandler->addCommand(kCmdSeq, -1, 2, _heroTab[_sex]->_face);
+ _sex ^= 1;
+ switchScene(scene);
+ }
+ }
+ Sprite *face = _heroTab[_sex]->_face;
+ if (face->_seqPtr == 0)
+ _commandHandler->addCommand(kCmdSeq, -1, 1, face);
+}
+
+void Sprite::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
+ if ((mask & kEventAttn) != 0)
+ return;
+
+ if (_vm->_gamePhase == kPhaseInGame)
+ _vm->_infoLine->setText(name());
+
+ if (_ref < 0)
+ return; // cannot access system sprites
+
+ if (_ref / 10 == 12) {
+ _vm->optionTouch(_ref % 10, mask);
+ return;
+ }
+
+ if ((mask & kMouseLeftUp) && _vm->_commandHandler->idle()) {
+ if (_vm->isHero(this) && !_vm->_sys->_blinkSprite) {
+ _vm->switchHero((this == _vm->_heroTab[1]->_ptr) ? 1 : 0);
+ } else if (_flags._kept) { // sprite in pocket
+ for (int sex = 0; sex < 2; ++sex) {
+ for (int p = 0; p < kPocketMax; ++p) {
+ if (_vm->_heroTab[sex]->_pocket[p] == this) {
+ _vm->switchHero(sex);
+ if (_vm->_sex == sex) {
+ if (_vm->_sys->_blinkSprite)
+ _vm->_sys->_blinkSprite->_flags._hide = false;
+
+ if (_vm->_sys->_blinkSprite == this)
+ _vm->_sys->_blinkSprite = nullptr;
+ else
+ _vm->_sys->_blinkSprite = this;
+ }
+ }
+ }
+ }
+ } else { // sprite NOT in pocket
+ Hero *h = _vm->_heroTab[_vm->_sex]->_ptr;
+ if (!_vm->_talk) {
+ // the "+3" is a hack used to work around a script issue in scene 5
+ if ((_ref & 0xFF) < 200 && h->distance(this) > (h->_maxDist << 1) + 3)
+ h->walkTo(this);
+ else if (_vm->_sys->_blinkSprite) {
+ if (works(_vm->_sys->_blinkSprite)) {
+ _vm->feedSnail(_vm->_sys->_blinkSprite, (_vm->_sex) ? kMTake : kFTake, _vm->_heroTab[_vm->_sex]->_ptr);
+ _vm->_sys->_blinkSprite->_flags._hide = false;
+ _vm->_sys->_blinkSprite = nullptr;
+ } else
+ _vm->offUse();
+
+ _vm->selectPocket(-1);
+ // else, no pocket sprite selected
+ } else if (_flags._port) { // portable
+ if (_vm->findActivePocket(-1) < 0)
+ _vm->pocFul();
+ else {
+ _vm->_commandHandler->addCommand(kCmdReach, -2, _ref, nullptr);
+ _vm->_commandHandler->addCommand(kCmdKeep, -1, -1, this);
+ _flags._port = false;
+ }
+ } else { // non-portable
+ Action a = h->action();
+ if (_actionCtrl[a]._cnt) {
+ CommandHandler::Command *cmdList = snList(a);
+ if (cmdList[_actionCtrl[a]._ptr]._commandType == kCmdNext)
+ _vm->offUse();
+ else
+ _vm->feedSnail(this, a, h);
+ } else
+ _vm->offUse();
+ }
+ }
+ }
+ }
+}
+
+void CGE2Engine::keyClick() {
+ _commandHandlerTurbo->addCommand(kCmdSound, -1, 5, nullptr);
+}
+
+void CGE2Engine::offUse() {
+ int seq = 0;
+ int offUseCount = atoi(_text->getText(kOffUseCount));
+
+ // This fixes the issue of empty speech bubbles in the original.
+ // Now we only let this cycle pass if it randoms a valid value for getText().
+ int txt = 0;
+ do {
+ txt = kOffUseText + _sex * offUseCount + newRandom(offUseCount);
+ } while (_text->getText(txt) == nullptr);
+
+ Hero *h = _heroTab[_sex]->_ptr;
+ h->park();
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSeq, -1, seq, h);
+ if (!_sayVox)
+ _commandHandler->addCommand(kCmdSound, -1, 6 + _sex, h);
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSay, -1, txt, h);
+}
+
+Sprite *CGE2Engine::spriteAt(V2D pos) {
+ Sprite *spr;
+
+ for (spr = _vga->_showQ->last(); spr; spr = spr->_prev) {
+ if (!spr->_flags._hide && !spr->_flags._tran && (spr->getShp()->solidAt(pos - spr->_pos2D)))
+ break;
+ }
+
+ return spr;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/cge2_main.h b/engines/cge2/cge2_main.h
new file mode 100644
index 0000000000..88cca1cc1e
--- /dev/null
+++ b/engines/cge2/cge2_main.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_MAIN_H
+#define CGE2_MAIN_H
+
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+#define kShowScummVMVersion 15
+
+class System : public Sprite {
+public:
+ int _blinkCounter;
+ Sprite *_blinkSprite;
+
+ System(CGE2Engine *vm);
+
+ virtual void touch(uint16 mask, V2D pos, Common::KeyCode keyCode);
+ void tick();
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_MAIN_H
diff --git a/engines/cge2/configure.engine b/engines/cge2/configure.engine
new file mode 100644
index 0000000000..6ccbfee088
--- /dev/null
+++ b/engines/cge2/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 cge2 "CGE2" no
diff --git a/engines/cge2/console.cpp b/engines/cge2/console.cpp
new file mode 100644
index 0000000000..c67c7ab788
--- /dev/null
+++ b/engines/cge2/console.cpp
@@ -0,0 +1,33 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "cge2/console.h"
+
+namespace CGE2 {
+
+CGE2Console::CGE2Console(CGE2Engine *vm) : GUI::Debugger() {
+}
+
+CGE2Console::~CGE2Console() {
+}
+
+} // End of namespace CGE
diff --git a/engines/cge2/console.h b/engines/cge2/console.h
new file mode 100644
index 0000000000..15956bf728
--- /dev/null
+++ b/engines/cge2/console.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 CGE2_CONSOLE_H
+#define CGE2_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+class CGE2Console : public GUI::Debugger {
+public:
+ CGE2Console(CGE2Engine *vm);
+ virtual ~CGE2Console();
+};
+
+} // End of namespace CGE
+
+#endif // CGE2_CONSOLE_H
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
new file mode 100644
index 0000000000..605a3fe377
--- /dev/null
+++ b/engines/cge2/detection.cpp
@@ -0,0 +1,245 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/cge2.h"
+#include "engines/advancedDetector.h"
+#include "common/translation.h"
+#include "graphics/surface.h"
+
+namespace CGE2 {
+
+#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1
+
+static const PlainGameDescriptor CGE2Games[] = {
+ { "sfinx", "Sfinx" },
+ { 0, 0 }
+};
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "sfinx", "Freeware",
+ {
+ { "vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024 },
+ { "vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844 },
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ {
+ "sfinx", "Freeware v1.0",
+ {
+ {"vol.cat", 0, "aa402aed24a72c53a4d1211c456b79dd", 129024},
+ {"vol.dat", 0, "5966ac26d91d664714349669f9dd09b5", 34180164},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_COLOR_BLIND_DEFAULT_OFF,
+ {
+ _s("Color Blind Mode"),
+ _s("Enable Color Blind Mode by default"),
+ "enable_color_blind",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+class CGE2MetaEngine : public AdvancedMetaEngine {
+public:
+ CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games, optionsList) {
+ _singleid = "sfinx";
+ }
+
+ virtual const char *getName() const {
+ return "CGE2";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
+ }
+
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+
+ const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+};
+
+bool CGE2MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc)
+ *engine = new CGE2::CGE2Engine(syst, desc);
+
+ return desc != 0;
+}
+
+bool CGE2MetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup);
+}
+
+const ADGameDescription *CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ static ADGameDescription desc;
+
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (file->isDirectory())
+ continue;
+
+ if (file->getName().equalsIgnoreCase("lang.eng")) {
+ Common::File dataFile;
+ if (!dataFile.open(*file))
+ continue;
+
+ desc.gameid = "sfinx";
+ desc.extra = "Translation Alpha v0.3";
+ desc.language = Common::EN_ANY;
+ desc.platform = Common::kPlatformDOS;
+ desc.flags = ADGF_NO_FLAGS;
+ desc.guioptions = GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF);
+
+ return (const ADGameDescription *)&desc;
+ }
+ }
+ return 0;
+}
+
+int CGE2MetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+
+SaveStateList CGE2MetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ 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) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(filename->c_str() + filename->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ CGE2::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ file->read(buffer, kSavegameStrSize + 1);
+
+ if (!strncmp(buffer, kSavegameStr, kSavegameStrSize + 1)) {
+ // 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
+ saveList.push_back(SaveStateDescriptor(slotNum, "Unknown"));
+ }
+
+ delete file;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (f) {
+ CGE2::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ f->read(buffer, kSavegameStrSize + 1);
+
+ bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) &&
+ CGE2::CGE2Engine::readSavegameHeader(f, header);
+ delete f;
+
+ if (!hasHeader) {
+ // Original savegame perhaps?
+ SaveStateDescriptor desc(slot, "Unknown");
+ return desc;
+ } else {
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header.saveName);
+ desc.setThumbnail(header.thumbnail);
+ desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
+ desc.setSaveTime(header.saveHour, header.saveMinutes);
+
+ // 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);
+ desc.setWriteProtectedFlag(slot == 0);
+
+ return desc;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+void CGE2MetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+} // End of namespace CGE2
+
+#if PLUGIN_ENABLED_DYNAMIC(CGE2)
+ REGISTER_PLUGIN_DYNAMIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine);
+#endif
diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp
new file mode 100644
index 0000000000..ed1ec66bb1
--- /dev/null
+++ b/engines/cge2/events.cpp
@@ -0,0 +1,293 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "gui/saveload.h"
+#include "gui/about.h"
+#include "gui/message.h"
+#include "common/config-manager.h"
+#include "common/events.h"
+#include "engines/advancedDetector.h"
+#include "cge2/events.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+Keyboard::Keyboard(CGE2Engine *vm) : _client(nullptr), _vm(vm) {
+}
+
+Keyboard::~Keyboard() {
+}
+
+Sprite *Keyboard::setClient(Sprite *spr) {
+ SWAP(_client, spr);
+ return spr;
+}
+
+bool Keyboard::getKey(Common::Event &event) {
+ Common::KeyCode keycode = event.kbd.keycode;
+
+ switch (keycode) {
+ case Common::KEYCODE_F1:
+ if (event.type == Common::EVENT_KEYUP)
+ return false;
+ // Display ScummVM version and translation strings
+ for (int i = 0; i < 3; i++)
+ _vm->_commandHandler->addCommand(kCmdInf, 1, kShowScummVMVersion + i, NULL);
+ return false;
+ case Common::KEYCODE_F5:
+ if (_vm->canSaveGameStateCurrently()) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ Common::String savegameDescription = dialog->getResultString();
+ delete dialog;
+
+ if (savegameId != -1)
+ _vm->saveGameState(savegameId, savegameDescription);
+ }
+ return false;
+ case Common::KEYCODE_F7:
+ if (_vm->canLoadGameStateCurrently()) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ delete dialog;
+
+ if (savegameId != -1)
+ _vm->loadGameState(savegameId);
+ }
+ return false;
+ case Common::KEYCODE_d:
+ if (event.kbd.flags & Common::KBD_CTRL) {
+ // Start the debugger
+ _vm->getDebugger()->attach();
+ _vm->getDebugger()->onFrame();
+ return false;
+ }
+ break;
+ case Common::KEYCODE_x:
+ if (event.kbd.flags & Common::KBD_ALT) {
+ _vm->quit();
+ return false;
+ }
+ break;
+ case Common::KEYCODE_F10:
+ if (_vm->_commandHandler->idle())
+ _vm->switchScene(-1); // Exits the game.
+ return false;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+void Keyboard::newKeyboard(Common::Event &event) {
+ if (!getKey(event))
+ return;
+
+ if ((event.type == Common::EVENT_KEYDOWN) && _client) {
+ CGE2Event &evt = _vm->_eventManager->getNextEvent();
+ evt._x = 0;
+ evt._y = 0;
+ evt._keyCode = event.kbd.keycode; // Keycode
+ evt._mask = kEventKeyb; // Event mask
+ evt._spritePtr = _client; // Sprite pointer
+ }
+}
+
+/*----------------- MOUSE interface -----------------*/
+
+Mouse::Mouse(CGE2Engine *vm) : Sprite(vm), _busy(nullptr), _hold(nullptr), _hx(0), _point(vm), _vm(vm) {
+ _hold = nullptr;
+ _hx = 0;
+ _hy = 0;
+ _exist = true;
+ _buttons = 0;
+ _busy = nullptr;
+ _active = false;
+ _flags._kill = false;
+
+ setSeq(_stdSeq8);
+
+ BitmapPtr MC = new Bitmap[2];
+ MC[0] = Bitmap(_vm, "MOUSE");
+ MC[1] = Bitmap(_vm, "DUMMY");
+ setShapeList(MC, 2);
+
+ step(1);
+ on();
+ off();
+}
+
+Mouse::~Mouse() {
+ off();
+}
+
+void Mouse::on() {
+ if (_seqPtr && _exist) {
+ _active = true;
+ step(0);
+ if (_busy)
+ _busy->step(0);
+ }
+}
+
+void Mouse::off() {
+ if (_seqPtr == 0) {
+ if (_exist)
+ _active = false;
+
+ step(1);
+ if (_busy)
+ _busy->step(1);
+ }
+}
+
+void Mouse::newMouse(Common::Event &event) {
+ if (!_active)
+ return;
+
+ CGE2Event &evt = _vm->_eventManager->getNextEvent();
+ evt._x = event.mouse.x;
+ evt._y = event.mouse.y;
+ evt._keyCode = Common::KEYCODE_INVALID;
+ evt._spritePtr = _vm->spriteAt(V2D(_vm, evt._x, evt._y));
+
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ evt._mask = kMouseRoll;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ evt._mask = kMouseLeftDown;
+ _buttons |= 1;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ evt._mask = kMouseLeftUp;
+ _buttons &= ~1;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ evt._mask = kMouseRightDown;
+ _buttons |= 2;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ evt._mask = kMouseRightUp;
+ _buttons &= ~2;
+ break;
+ default:
+ break;
+ }
+}
+
+/*----------------- EventManager interface -----------------*/
+
+EventManager::EventManager(CGE2Engine *vm) : _vm(vm) {
+ _eventQueueHead = 0;
+ _eventQueueTail = 0;
+ memset(&_eventQueue, 0, kEventMax * sizeof(CGE2Event));
+ memset(&_event, 0, sizeof(Common::Event));
+}
+
+void EventManager::poll() {
+ while (g_system->getEventManager()->pollEvent(_event)) {
+ _event.mouse.y = kWorldHeight - _event.mouse.y;
+ switch (_event.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ // Handle keyboard events
+ _vm->_keyboard->newKeyboard(_event);
+ handleEvents();
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ // Handle mouse events
+ _vm->_mouse->newMouse(_event);
+ handleEvents();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void EventManager::handleEvents() {
+ while (_eventQueueTail != _eventQueueHead) {
+ CGE2Event e = _eventQueue[_eventQueueTail];
+ _vm->_mouse->_point = V2D(_vm, e._x, e._y);
+ if (e._mask) {
+ if (e._mask & kMouseMask) {
+ e._spritePtr = _vm->spriteAt(_vm->_mouse->_point);
+ e._x += (_vm->_mouse->_siz.x >> 1);
+ e._y -= _vm->_mouse->_siz.y;
+ if (_vm->_mouse->_hold && (e._spritePtr != _vm->_mouse->_hold)) {
+ _vm->_mouse->_hold->touch(e._mask | kEventAttn,
+ V2D(_vm, e._x - _vm->_mouse->_hold->_pos2D.x, e._y - _vm->_mouse->_hold->_pos2D.y), e._keyCode);
+ }
+ // update mouse cursor position
+ if (e._mask & kMouseRoll)
+ _vm->_mouse->gotoxyz(V2D(_vm, e._x, e._y));
+ }
+
+ // activate current touched SPRITE
+ if (e._spritePtr) {
+ if (e._mask & kEventKeyb)
+ e._spritePtr->touch(e._mask, _vm->_mouse->_point, e._keyCode);
+ else
+ e._spritePtr->touch(e._mask, _vm->_mouse->_point - e._spritePtr->_pos2D, e._keyCode);
+ } else if (_vm->_sys)
+ _vm->_sys->touch(e._mask, _vm->_mouse->_point, e._keyCode);
+
+ // discard Text if button released
+ if (e._mask & (kMouseLeftUp | kMouseRightUp))
+ _vm->killText();
+ }
+ _eventQueueTail = (_eventQueueTail + 1) % kEventMax;
+ }
+}
+
+void EventManager::clearEvent(Sprite *spr) {
+ if (spr) {
+ for (uint16 e = _eventQueueTail; e != _eventQueueHead; e = (e + 1) % kEventMax) {
+ if (_eventQueue[e]._spritePtr == spr)
+ _eventQueue[e]._mask = 0;
+ }
+ } else
+ _eventQueueTail = _eventQueueHead;
+}
+
+CGE2Event &EventManager::getNextEvent() {
+ CGE2Event &evt = _eventQueue[_eventQueueHead];
+ _eventQueueHead = (_eventQueueHead + 1) % kEventMax;
+
+ return evt;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/events.h b/engines/cge2/events.h
new file mode 100644
index 0000000000..d1aaca2ded
--- /dev/null
+++ b/engines/cge2/events.h
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_EVENTS_H
+#define CGE2_EVENTS_H
+
+#include "common/events.h"
+#include "cge2/talk.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+#define kEventMax 256
+
+enum EventMask {
+ kMouseRoll = 1 << 0,
+ kMouseLeftDown = 1 << 1,
+ kMouseLeftUp = 1 << 2,
+ kMouseRightDown = 1 << 3,
+ kMouseRightUp = 1 << 4,
+ kEventAttn = 1 << 5,
+ kMouseMask = (kMouseRoll | kMouseLeftDown | kMouseLeftUp | kMouseRightDown | kMouseRightUp),
+ kEventKeyb = 1 << 7
+};
+
+class Keyboard {
+private:
+ bool getKey(Common::Event &event);
+ CGE2Engine *_vm;
+public:
+ Sprite *_client;
+
+ void newKeyboard(Common::Event &event);
+ Sprite *setClient(Sprite *spr);
+
+ Keyboard(CGE2Engine *vm);
+ ~Keyboard();
+};
+
+/*----------------- MOUSE interface -----------------*/
+
+struct CGE2Event {
+ uint16 _mask;
+ uint16 _x;
+ uint16 _y;
+ Common::KeyCode _keyCode;
+ Sprite *_spritePtr;
+};
+
+class Mouse : public Sprite {
+public:
+ V2D _point;
+ Sprite *_hold;
+ bool _active;
+ int _hx;
+ int _hy;
+ bool _exist;
+ int _buttons;
+ Sprite *_busy;
+ Mouse(CGE2Engine *vm);
+ ~Mouse();
+ void on();
+ void off();
+ void newMouse(Common::Event &event);
+private:
+ CGE2Engine *_vm;
+};
+
+/*----------------- EventManager interface -----------------*/
+
+class EventManager {
+private:
+ CGE2Engine *_vm;
+ Common::Event _event;
+ CGE2Event _eventQueue[kEventMax];
+ uint16 _eventQueueHead;
+ uint16 _eventQueueTail;
+
+ void handleEvents();
+public:
+ EventManager(CGE2Engine *vm);
+ void poll();
+ void clearEvent(Sprite *spr);
+
+ CGE2Event &getNextEvent();
+};
+
+} // End of namespace CGE
+
+#endif // #define CGE2_EVENTS_H
diff --git a/engines/cge2/fileio.cpp b/engines/cge2/fileio.cpp
new file mode 100644
index 0000000000..6f8009716b
--- /dev/null
+++ b/engines/cge2/fileio.cpp
@@ -0,0 +1,272 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/memstream.h"
+#include "cge2/cge2.h"
+#include "cge2/fileio.h"
+
+namespace CGE2 {
+
+/*-----------------------------------------------------------------------
+ * BtPage
+ *-----------------------------------------------------------------------*/
+void BtPage::readBTree(Common::ReadStream &s) {
+ _header._count = s.readUint16LE();
+ _header._down = s.readUint16LE();
+
+ if (_header._down == kBtValNone) {
+ // Leaf list
+ for (int i = 0; i < kBtLeafCount; ++i) {
+ s.read(_leaf[i]._key, kBtKeySize);
+ _leaf[i]._pos = s.readUint32LE();
+ _leaf[i]._size = s.readUint32LE();
+ }
+ } else {
+ // Root index
+ for (int i = 0; i < kBtInnerCount; ++i) {
+ s.read(_inner[i]._key, kBtKeySize);
+ _inner[i]._down = s.readUint16LE();
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ * ResourceManager
+ *-----------------------------------------------------------------------*/
+ResourceManager::ResourceManager() {
+ _datFile = new Common::File();
+ _datFile->open(kDatName);
+
+ _catFile = new Common::File();
+ _catFile->open(kCatName);
+
+ if (!_datFile->isOpen() || !_catFile->isOpen())
+ error("Unable to open data files");
+
+ for (int i = 0; i < kBtLevel; i++) {
+ _buff[i]._page = new BtPage;
+ _buff[i]._pageNo = kBtValNone;
+ _buff[i]._index = -1;
+ assert(_buff[i]._page != nullptr);
+ }
+}
+
+ResourceManager::~ResourceManager() {
+ _datFile->close();
+ delete _datFile;
+
+ _catFile->close();
+ delete _catFile;
+
+ for (int i = 0; i < kBtLevel; i++)
+ delete _buff[i]._page;
+}
+
+void ResourceManager::xCrypt(byte *buf, uint16 length) {
+ byte *b = buf;
+
+ for (uint16 i = 0; i < length; i++)
+ *b++ ^= kCryptSeed;
+}
+
+bool ResourceManager::seek(int32 offs, int whence) {
+ return _datFile->seek(offs, whence);
+}
+
+uint16 ResourceManager::read(byte *buf, uint16 length) {
+ if (!_datFile->isOpen())
+ return 0;
+
+ uint16 bytesRead = _datFile->read(buf, length);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _datFile->getName(), length);
+ xCrypt(buf, length);
+ return bytesRead;
+}
+
+BtPage *ResourceManager::getPage(int level, uint16 pageId) {
+ if (_buff[level]._pageNo != pageId) {
+ int32 pos = pageId * kBtSize;
+ _buff[level]._pageNo = pageId;
+ assert(_catFile->size() > pos);
+ // In the original, there was a check verifying if the
+ // purpose was to write a new file. This should only be
+ // to create a new file, thus it was removed.
+ _catFile->seek(pageId * kBtSize, SEEK_SET);
+
+ // Read in the page
+ byte buffer[kBtSize];
+ int bytesRead = catRead(buffer, kBtSize);
+
+ // Unpack it into the page structure
+ Common::MemoryReadStream stream(buffer, bytesRead, DisposeAfterUse::NO);
+ _buff[level]._page->readBTree(stream);
+ _buff[level]._index = -1;
+ }
+ return _buff[level]._page;
+}
+
+BtKeypack *ResourceManager::find(const char *key) {
+ int lev = 0;
+ uint16 nxt = kBtValRoot;
+ while (!_catFile->eos()) {
+ BtPage *pg = getPage(lev, nxt);
+ // search
+ if (pg->_header._down != kBtValNone) {
+ int i;
+ for (i = 0; i < pg->_header._count; i++) {
+ // Does this work, or does it have to compare the entire buffer?
+ if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0)
+ break;
+ }
+ nxt = (i) ? pg->_inner[i - 1]._down : pg->_header._down;
+ _buff[lev]._index = i - 1;
+ lev++;
+ } else {
+ int i;
+ for (i = 0; i < pg->_header._count - 1; i++) {
+ if (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) <= 0)
+ break;
+ }
+
+ // Hack to work around a mix between 24piram_ and 24pirami
+ if (!strcmp(key, "24piram_.SPR") && (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) < 0))
+ ++i;
+ //
+
+ _buff[lev]._index = i;
+ return &pg->_leaf[i];
+ }
+ }
+ return nullptr;
+}
+
+bool ResourceManager::exist(const char *name) {
+ return scumm_stricmp(find(name)->_key, name) == 0;
+}
+
+uint16 ResourceManager::catRead(byte *buf, uint16 length) {
+ if (!_catFile->isOpen())
+ return 0;
+
+ uint16 bytesRead = _catFile->read(buf, length);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _catFile->getName(), length);
+ xCrypt(buf, length);
+ return bytesRead;
+}
+
+/*-----------------------------------------------------------------------
+ * EncryptedStream
+ *-----------------------------------------------------------------------*/
+EncryptedStream::EncryptedStream(CGE2Engine *vm, const char *name) : _vm(vm), _lineCount(0) {
+ _error = false;
+ BtKeypack *kp = _vm->_resman->find(name);
+ if (scumm_stricmp(kp->_key, name) != 0)
+ _error = true;
+
+ _vm->_resman->seek(kp->_pos);
+ byte *dataBuffer;
+ int bufSize;
+
+ if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) {
+ // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others
+ // do not have a carriage return at the end of the last line
+ // Therefore, we remove this ending 0x1A and add extra new lines.
+ // This fixes bug #3537527
+ dataBuffer = (byte *)malloc(kp->_size + 2);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ if (dataBuffer[kp->_size - 1] == 0x1A)
+ dataBuffer[kp->_size - 1] = '\n';
+ dataBuffer[kp->_size] = '\n';
+ dataBuffer[kp->_size + 1] = '\n';
+ bufSize = kp->_size + 2;
+ } else {
+ dataBuffer = (byte *)malloc(kp->_size);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ bufSize = kp->_size;
+ }
+
+ _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES);
+}
+
+uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) {
+ return _readStream->read(dataPtr, dataSize);
+}
+
+int16 EncryptedStream::readSint16LE() {
+ return _readStream->readSint16LE();
+}
+
+uint32 EncryptedStream::readUint32LE() {
+ return _readStream->readUint32LE();
+}
+
+bool EncryptedStream::err() {
+ return (_error || _readStream->err());
+}
+
+bool EncryptedStream::eos() {
+ return _readStream->eos();
+}
+
+bool EncryptedStream::seek(int32 offset) {
+ return _readStream->seek(offset);
+}
+
+Common::String EncryptedStream::readLine() {
+ _lineCount++;
+ Common::String line = _readStream->readLine();
+ if (!line.empty() && (line[0] == ';' || line[0] == '.' || line[0] == '*'))
+ line.clear(); // Returns an empty string, if the line is invalid.
+ return line;
+}
+
+int32 EncryptedStream::size() {
+ return _readStream->size();
+}
+
+int32 EncryptedStream::pos() {
+ return _readStream->pos();
+}
+
+EncryptedStream::~EncryptedStream() {
+ delete _readStream;
+}
+
+const char *EncryptedStream::kIdTab[] = {
+ "[near]", "[mtake]", "[ftake]", "[phase]", "[seq]",
+ "Name", "Type", "Front", "East",
+ "Portable", "Transparent",
+ nullptr
+};
+
+} // End of namespace CGE2
diff --git a/engines/cge2/fileio.h b/engines/cge2/fileio.h
new file mode 100644
index 0000000000..e236c73b49
--- /dev/null
+++ b/engines/cge2/fileio.h
@@ -0,0 +1,133 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_FILEIO_H
+#define CGE2_FILEIO_H
+
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+#define kBtSize 2048
+#define kBtKeySize 13
+#define kBtLevel 2
+#define kBtInnerCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 2 /*sizeof(Inner) */))
+#define kBtLeafCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 4 + 4 /*sizeof(BtKeypack) */))
+#define kBtValNone 0xFFFF
+#define kBtValRoot 0
+#define kCatName "VOL.CAT"
+#define kDatName "VOL.DAT"
+#define kCryptSeed 0xA5
+
+enum ID {
+ kIdNear, kIdMTake, kIdFTake, kIdPhase, kIdSeq,
+ kIdName, kIdType, kIdFront, kIdEast,
+ kIdPortable, kIdTransparent,
+ kIdNone = -1
+};
+
+struct BtKeypack {
+ char _key[kBtKeySize];
+ uint32 _pos;
+ uint32 _size;
+};
+
+struct Inner {
+ uint8 _key[kBtKeySize];
+ uint16 _down;
+};
+
+struct Header {
+ uint16 _count;
+ uint16 _down;
+};
+
+struct BtPage {
+ Header _header;
+ union {
+ // dummy filler to make proper size of union
+ uint8 _data[kBtSize - 4]; /* 4 is the size of struct Header */
+ // inner version of data: key + word-sized page link
+ Inner _inner[kBtInnerCount];
+ // leaf version of data: key + all user data
+ BtKeypack _leaf[kBtLeafCount];
+ };
+
+ void readBTree(Common::ReadStream &s);
+};
+
+class ResourceManager {
+private:
+ struct {
+ BtPage *_page;
+ uint16 _pageNo;
+ int _index;
+ } _buff[kBtLevel];
+
+ BtPage *getPage(int level, uint16 pageId);
+ uint16 catRead(byte *buf, uint16 length);
+ Common::File *_catFile;
+ Common::File *_datFile;
+ void xCrypt(byte *buf, uint16 length);
+public:
+ ResourceManager();
+ ~ResourceManager();
+ uint16 read(byte *buf, uint16 length);
+ bool seek(int32 offs, int whence = SEEK_SET);
+
+ BtKeypack *find(const char *key);
+ bool exist(const char *name);
+};
+
+class EncryptedStream {
+private:
+ CGE2Engine *_vm;
+ Common::SeekableReadStream *_readStream;
+ int _lineCount;
+ bool _error;
+public:
+ EncryptedStream(CGE2Engine *vm, const char *name);
+ ~EncryptedStream();
+ bool err();
+ bool eos();
+ bool seek(int32 offset);
+ int32 pos();
+ int32 size();
+ uint32 read(byte *dataPtr, uint32 dataSize);
+ int16 readSint16LE();
+ uint32 readUint32LE();
+ Common::String readLine();
+ int getLineCount() { return _lineCount; }
+
+ static const char *kIdTab[];
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_FILEIO_H
diff --git a/engines/cge2/general.h b/engines/cge2/general.h
new file mode 100644
index 0000000000..7213c2e24d
--- /dev/null
+++ b/engines/cge2/general.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_GENERAL_H
+#define CGE2_GENERAL_H
+
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+struct Dac {
+ uint8 _r;
+ uint8 _g;
+ uint8 _b;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_GENERAL_H
diff --git a/engines/cge2/hero.cpp b/engines/cge2/hero.cpp
new file mode 100644
index 0000000000..86bd7ac953
--- /dev/null
+++ b/engines/cge2/hero.cpp
@@ -0,0 +1,620 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+Hero::Hero(CGE2Engine *vm)
+ : Sprite(vm), _contact(nullptr), _dir(kNoDir),
+ _curDim(0), _tracePtr(-1), _ignoreMap(false), _maxDist(0) {
+
+ for (int i = 0; i < kDimMax; i++) {
+ _dim[i] = nullptr;
+ }
+}
+
+Hero::~Hero() {
+ contract();
+}
+
+Sprite *Hero::expand() {
+ if (_ext)
+ return this;
+
+ char fname[kMaxPath];
+ _vm->mergeExt(fname, _file, kSprExt);
+
+ if (_ext != nullptr)
+ delete _ext;
+
+ _ext = new SprExt(_vm);
+
+ if (!*_file)
+ return this;
+
+ for (int i = 0; i < kDimMax; i++) {
+ if (_dim[i] != nullptr) {
+ delete[] _dim[i];
+ _dim[i] = nullptr;
+ }
+ }
+ for (int i = 0; i < kDimMax; i++) {
+ _dim[i] = new Bitmap[_shpCnt];
+ for (int j = 0; j < _shpCnt; j++)
+ _dim[i][j].setVM(_vm);
+ }
+
+ int cnt[kActions];
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ for (int i = 0; i < kActions; i++) {
+ byte n = _actionCtrl[i]._cnt;
+ if (n)
+ _ext->_actions[i] = new CommandHandler::Command[n];
+ else
+ _ext->_actions[i] = nullptr;
+ }
+
+ Seq *curSeq = nullptr;
+ if (_seqCnt)
+ curSeq = new Seq[_seqCnt];
+
+ if (_vm->_resman->exist(fname)) { // sprite description file exist
+ EncryptedStream sprf(_vm, fname);
+ if (sprf.err())
+ error("Bad SPR [%s]", fname);
+
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+ int shpcnt = 0;
+ int seqcnt = 0;
+ int maxnow = 0;
+ int maxnxt = 0;
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) {
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = _vm->token(tmpStr);
+
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ case kIdName:
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ for (p = tmpStr; *p != '='; p++); // We search for the =
+ setName(_vm->tail(p));
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ Seq *s;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ id = (ID)_vm->_commandHandler->getComId(p);
+ if (_actionCtrl[section]._cnt) {
+ CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++];
+ c->_commandType = CommandType(id);
+ c->_ref = _vm->number(nullptr);
+ c->_val = _vm->number(nullptr);
+ c->_spritePtr = nullptr;
+ }
+ break;
+ case kIdSeq:
+ s = &curSeq[seqcnt++];
+ s->_now = atoi(p);
+ if (s->_now > maxnow)
+ maxnow = s->_now;
+ s->_next = _vm->number(nullptr);
+ switch (s->_next) {
+ case 0xFF:
+ s->_next = seqcnt;
+ break;
+ case 0xFE:
+ s->_next = seqcnt - 1;
+ break;
+ }
+ if (s->_next > maxnxt)
+ maxnxt = s->_next;
+ s->_dx = _vm->number(nullptr);
+ s->_dy = _vm->number(nullptr);
+ s->_dz = _vm->number(nullptr);
+ s->_dly = _vm->number(nullptr);
+ break;
+ case kIdPhase:
+ for (int i = 0; i < kDimMax; i++) {
+ char *q = p;
+ q[1] = '0' + i;
+ Bitmap b(_vm, q);
+ _dim[i][shpcnt] = b;
+ if (!shpcnt)
+ _hig[i] = b._h;
+ }
+ ++shpcnt;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (curSeq) {
+ if (maxnow >= shpcnt)
+ error("Bad PHASE in SEQ %s", fname);
+ if (maxnxt >= seqcnt)
+ error("Bad JUMP in SEQ %s", fname);
+ setSeq(curSeq);
+ } else
+ setSeq(_stdSeq8);
+
+ setShapeList(_dim[0], shpcnt);
+ }
+
+ char *tempStr = _vm->_text->getText(_ref + 100);
+ char *text = new char[strlen(tempStr) + 1];
+ strcpy(text, tempStr);
+ _reachStart = atoi(_vm->token(text));
+ _reachCycle = atoi(_vm->token(nullptr));
+ _sayStart = atoi(_vm->token(nullptr));
+ _funStart = atoi(_vm->token(nullptr));
+ _funDel = _funDel0 = (72 / _ext->_seq[0]._dly) * atoi(_vm->token(nullptr));
+ delete[] text;
+
+ int i = stepSize() / 2;
+ _maxDist = sqrt(double(i * i * 2));
+ setCurrent();
+
+ return this;
+}
+
+Sprite *Hero::contract() {
+ for (int i = 0; i < kDimMax; i++) {
+ if (_dim[i] != nullptr) {
+ delete[] _dim[i];
+ if (_ext->_shpList == _dim[i])
+ _ext->_shpList = nullptr;
+ _dim[i] = nullptr;
+ }
+ }
+ Sprite::contract();
+ return this;
+}
+
+void Hero::setCurrent() {
+ FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z);
+ FXP tmp = m * _siz.y;
+ int h = -(tmp.trunc());
+
+ int i = 0;
+ for (; i < kDimMax - 1; i++) {
+ if (h >= (_hig[i] + _hig[i + 1]) / 2)
+ break;
+ }
+
+ _ext->_shpList = _dim[_curDim = i];
+}
+
+void Hero::hStep() {
+ if (!_ignoreMap && _ext) {
+ Seq *seq = _ext->_seq;
+ int ptr = seq[_seqPtr]._next;
+ seq += ptr;
+ if (seq->_dx | seq->_dz) {
+ V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round());
+ V2D p1(_vm, p0.x + seq->_dx, p0.y + seq->_dz);
+ if (mapCross(p0, p1)) {
+ park();
+ return;
+ }
+ }
+ }
+ step();
+}
+
+Sprite *Hero::setContact() {
+ Sprite *spr;
+ int md = _maxDist << 1;
+ for (spr = _vm->_vga->_showQ->first(); spr; spr = spr->_next) {
+ if (spr->_actionCtrl[kNear]._cnt && ((spr->_ref & 255) != 255) && (distance(spr) <= md)) {
+ if (spr == _contact)
+ return nullptr;
+ else
+ break;
+ }
+ }
+ return (_contact = spr);
+}
+
+void Hero::tick() {
+ int z = _pos3D._z.trunc();
+ //-- maybe not exactly wid/2, but wid/3 ?
+ int d = ((_siz.x / 2) * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+
+ if (_dir != kNoDir) { // just walking...
+ if (_flags._hold || _tracePtr < 0)
+ park();
+ else {
+ Sprite *spr = setContact();
+ if (spr)
+ _vm->feedSnail(spr, kNear, this);
+ }
+ }
+ //---------------------------------------------------------------
+ if (_tracePtr >= 0) {
+ if (distance(_trace[_tracePtr]) <= _maxDist)
+ --_tracePtr;
+
+ if (_tracePtr < 0)
+ park();
+ else {
+ int stp = stepSize() / 2;
+ int dx = _trace[_tracePtr]._x.round() - _pos3D._x.round();
+ int dz = _trace[_tracePtr]._z.round() - _pos3D._z.round();
+ Dir dir = (dx > stp) ? kEE : ((-dx > stp) ? kWW : ((dz > stp) ? kNN : kSS));
+ turn(dir);
+ }
+ }
+
+ //---------------------------------------------------------------
+ hStep();
+ setCurrent();
+ switch (_dir) {
+ case kSS:
+ if (_pos3D._z < stepSize() / 2)
+ park();
+ break;
+ case kWW:
+ if (_pos2D.x <= d)
+ park();
+ break;
+ case kNN:
+ if (_pos3D._z > kScrDepth)
+ park();
+ break;
+ case kEE:
+ if (_pos2D.x >= kScrWidth - 1 - d)
+ park();
+ break;
+ default:
+ break;
+ }
+ if (_flags._trim)
+ gotoxyz_(_pos2D);
+
+ if (_pos3D._z.trunc() != z)
+ _flags._zmov = true;
+
+ if (--_funDel == 0)
+ fun();
+}
+
+int Hero::distance(V3D pos) {
+ V3D di = _pos3D - pos;
+ int x = di._x.round();
+ int z = di._z.round();
+ int retval = (int)sqrt((double)x * x + z * z);
+ return retval;
+}
+
+int Hero::distance(Sprite *spr) {
+ V3D pos = spr->_pos3D;
+ int mdx = (spr->_siz.x >> 1) + (_siz.x >> 1);
+ int dx = (_pos3D._x - spr->_pos3D._x).round();
+ if (dx < 0) {
+ mdx = -mdx;
+ if (dx > mdx)
+ pos._x = _pos3D._x;
+ else
+ pos._x += mdx;
+ } else if (dx < mdx)
+ pos._x = _pos3D._x;
+ else
+ pos._x += mdx;
+
+ return distance(pos);
+}
+
+void Hero::turn(Dir d) {
+ Dir dir = (_dir == kNoDir) ? kSS : _dir;
+ if (d != _dir) {
+ step((d == dir) ? 57 : (8 + 4 * dir + d));
+ _dir = d;
+ }
+ resetFun();
+}
+
+void Hero::park() {
+ if (_dir != kNoDir) {
+ step(8 + 5 * _dir);
+ _dir = kNoDir;
+ _trace[0] = _pos3D;
+ _tracePtr = -1;
+ setCurrent();
+ _flags._zmov = true;
+ }
+ _ignoreMap = false;
+ if (_time == 0)
+ ++_time;
+}
+
+bool Hero::lower(Sprite * spr) {
+ return (spr->_pos3D._y + (spr->_siz.y >> 2) < 10);
+}
+
+void Hero::reach(int mode) {
+ Sprite *spr = nullptr;
+ if (mode >= 4) {
+ spr = _vm->_vga->_showQ->locate(mode);
+ if (spr) {
+ mode = !spr->_flags._east; // 0-1
+ if (lower(spr)) // 2-3
+ mode += 2;
+ }
+ }
+ // note: insert SNAIL commands in reverse order
+ _vm->_commandHandler->insertCommand(kCmdPause, -1, 24, nullptr);
+ _vm->_commandHandler->insertCommand(kCmdSeq, -1, _reachStart + _reachCycle * mode, this);
+ if (spr) {
+ _vm->_commandHandler->insertCommand(kCmdWait, -1, -1, this);
+ _vm->_commandHandler->insertCommand(kCmdWalk, -1, spr->_ref, this);
+ }
+ // sequence is not finished,
+ // now it is just at sprite appear (disappear) point
+ resetFun();
+}
+
+void Hero::fun() {
+ if (_vm->_commandHandler->idle()) {
+ park();
+ _vm->_commandHandler->addCommand(kCmdWait, -1, -1, this);
+ _vm->_commandHandler->addCommand(kCmdSeq, -1, _funStart, this);
+ }
+ _funDel = _funDel0 >> 2;
+}
+
+int Hero::len(V2D v) {
+ return sqrt(double(v.x * v.x + v.y * v.y));
+}
+
+bool Hero::findWay(){
+ V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round());
+ V2D p1(_vm, _trace[_tracePtr]._x.round(), _trace[_tracePtr]._z.round());
+ V2D ph(_vm, p1.x, p0.y);
+ V2D pv(_vm, p0.x, p1.y);
+ bool pvOk = (!mapCross(p0, pv) && !mapCross(pv, p1));
+ bool phOk = (!mapCross(p0, ph) && !mapCross(ph, p1));
+ int md = (_maxDist >> 1);
+ if (pvOk && (len(ph - p0) <= md || len(p1 - ph) <= md))
+ return true;
+
+ if (phOk && (len(pv - p0) <= md || len(p1 - pv) <= md))
+ return true;
+
+ if (pvOk) {
+ _trace[++_tracePtr] = V3D(pv.x, 0, pv.y);
+ return true;
+ }
+
+ if (phOk) {
+ _trace[++_tracePtr] = V3D(ph.x, 0, ph.y);
+ return true;
+ }
+
+ return false;
+}
+
+int Hero::snap(int p, int q, int grid) {
+ int d = abs(q - p) % grid;
+ if (d > (grid >> 1))
+ d -= grid;
+ return (q >= p) ? (q - d) : (q + d);
+}
+
+void Hero::walkTo(V3D pos) {
+ if (distance(pos) <= _maxDist)
+ return;
+
+ int stp = stepSize();
+ pos._x = snap(_pos3D._x.round(), pos._x.round(), stp);
+ pos._y = 0;
+ pos._z = snap(_pos3D._z.round(), pos._z.round(), stp);
+
+ V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round());
+ V2D p1(_vm, pos._x.round(), pos._z.round());
+ resetFun();
+ int cnt = mapCross(p0, p1);
+ if ((cnt & 1) == 0) { // even == way exists
+ _trace[_tracePtr = 0] = pos;
+ if (!findWay()) {
+ int i;
+ ++_tracePtr;
+ for (i = stp; i < kMaxTry; i += stp) {
+ _trace[_tracePtr] = pos + V3D(i, 0, 0);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+
+ _trace[_tracePtr] = pos + V3D(-i, 0, 0);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+
+ _trace[_tracePtr] = pos + V3D(0, 0, i);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+
+ _trace[_tracePtr] = pos + V3D(0, 0, -i);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+ }
+ if (i >= kMaxTry)
+ _trace[_tracePtr] = V3D(_pos3D._x, 0, pos._z); // not found
+ }
+ }
+}
+
+void Hero::walkTo(Sprite *spr) {
+ int mdx = _siz.x >> 1;
+ int stp = (stepSize() + 1) / 2;
+ if (!spr->_flags._east)
+ mdx = -mdx;
+ walkTo(spr->_pos3D + V3D(mdx, 0, (!spr->_flags._frnt || spr->_pos3D._z < 8) ? stp : -stp));
+}
+
+V3D Hero::screenToGround(V2D pos) {
+ FXP z = _vm->_eye->_z + (_vm->_eye->_y * _vm->_eye->_z) / (FXP(pos.y) - _vm->_eye->_y);
+ FXP x = _vm->_eye->_x - ((FXP(pos.x) - _vm->_eye->_x) * (z - _vm->_eye->_z)) / _vm->_eye->_z;
+ return V3D(x.round(), 0, z.round());
+}
+
+int Hero::cross(const V2D &a, const V2D &b) {
+ int x = _pos3D._x.trunc();
+ int z = _pos3D._z.trunc();
+ int r = ((_siz.x / 3) * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+ return _vm->cross(a, b, V2D(_vm, x - r, z), V2D(_vm, x + r, z)) << 1;
+}
+
+bool CGE2Engine::cross(const V2D &a, const V2D &b, const V2D &c, const V2D &d) {
+ if (contain(a, b, c) || contain(a, b, d) || contain(c, d, a) || contain(c, d, b))
+ return true;
+
+ return sgn(det(a, b, c)) != sgn(det(a, b, d)) && sgn(det(c, d, a)) != sgn(det(c, d, b));
+}
+
+bool CGE2Engine::contain(const V2D &a, const V2D &b, const V2D &p) {
+ if (det(a, b, p))
+ return false;
+
+ return ((long)(a.x - p.x) * (p.x - b.x) >= 0 && (long)(a.y - p.y) * (p.y - b.y) >= 0);
+}
+
+long CGE2Engine::det(const V2D &a, const V2D &b, const V2D &c) {
+ return ((long)a.x * b.y + (long)b.x * c.y + (long)c.x * a.y) - ((long)c.x * b.y + (long)b.x * a.y + (long)a.x * c.y);
+}
+
+int CGE2Engine::sgn(long n) {
+ return (n == 0) ? 0 : ((n > 0) ? 1 : -1);
+}
+
+int Hero::mapCross(const V2D &a, const V2D &b) {
+ Hero *o = other();
+ int n = (o->_scene == _scene) ? o->cross(a, b) : 0;
+ if (!_ignoreMap)
+ n += _vm->mapCross(a, b);
+
+ return n;
+}
+
+int Hero::mapCross(const V3D &a, const V3D &b) {
+ return mapCross(V2D(_vm, a._x.round(), a._z.round()), V2D(_vm, b._x.round(), b._z.round()));
+}
+
+int CGE2Engine::mapCross(const V2D &a, const V2D &b) {
+ int cnt = 0;
+ V2D *n0 = nullptr;
+ V2D *p = nullptr;
+ for (int i = 0; i < _map->size(); i++) {
+ V2D *n = _map->getCoord(i);
+ if (p) {
+ if (cross(a, b, *n0, *n))
+ ++cnt;
+
+ if (*n == *p)
+ p = nullptr;
+ } else {
+ p = n;
+ }
+ n0 = n;
+ }
+ return cnt;
+}
+
+void Hero::setScene(int c) {
+ Sprite::setScene(c);
+ resetFun();
+}
+
+void Hero::operator++() {
+ if (_curDim > 0)
+ _ext->_shpList = _dim[--_curDim];
+}
+
+void Hero::operator--() {
+ if (_curDim < kDimMax - 1)
+ _ext->_shpList = _dim[++_curDim];
+}
+
+bool Sprite::works(Sprite *spr) {
+ if (!spr || !spr->_ext)
+ return false;
+
+ bool ok = false;
+
+ Action a = _vm->_heroTab[_vm->_sex]->_ptr->action();
+ CommandHandler::Command *ct = spr->_ext->_actions[a];
+ if (ct) {
+ int i = spr->_actionCtrl[a]._ptr;
+ int n = spr->_actionCtrl[a]._cnt;
+ while (i < n && !ok) {
+ CommandHandler::Command *c = &ct[i++];
+ if (c->_commandType != kCmdUse)
+ break;
+ ok = (c->_ref == _ref);
+ if (c->_val > 255) {
+ if (ok) {
+ int p = spr->labVal(a, c->_val >> 8);
+ if (p >= 0)
+ spr->_actionCtrl[a]._ptr = p;
+ else
+ ok = false;
+ }
+ } else {
+ if (c->_val && c->_val != _vm->_now)
+ ok = false;
+ break;
+ }
+ }
+ }
+
+ return ok;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/hero.h b/engines/cge2/hero.h
new file mode 100644
index 0000000000..3b5329e12c
--- /dev/null
+++ b/engines/cge2/hero.h
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_HERO_H
+#define CGE2_HERO_H
+
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/snail.h"
+
+namespace CGE2 {
+
+#define kMaxTry 400
+
+class Hero;
+
+struct HeroTab {
+ Hero *_ptr;
+ Sprite *_face;
+ Sprite *_pocket[kPocketMax + 1];
+ int _downPocketId[kPocketMax + 1];
+ int _pocPtr;
+ V2D *_posTab[kSceneMax];
+ HeroTab(CGE2Engine *vm) {
+ _ptr = nullptr;
+ _face = nullptr;
+ for (int i = 0; i < kPocketMax + 1; i++) {
+ _pocket[i] = nullptr;
+ _downPocketId[i] = -1;
+ }
+ _pocPtr = 0;
+ for (int i = 0; i < kSceneMax; i++)
+ _posTab[i] = nullptr;
+ }
+ ~HeroTab() {
+ for (int i = 0; i < kSceneMax; i++)
+ delete _posTab[i];
+ }
+};
+
+class Hero : public Sprite {
+ int _hig[kDimMax];
+ Sprite *_contact;
+public:
+ BitmapPtr _dim[kDimMax];
+ V3D _trace[kWayMax];
+ enum Dir { kNoDir = -1, kSS, kWW, kNN, kEE } _dir;
+ int _curDim;
+ int _tracePtr;
+ int _reachStart, _reachCycle, _sayStart, _funStart;
+ int _funDel0, _funDel;
+ int _maxDist;
+ bool _ignoreMap;
+ Hero(CGE2Engine *vm);
+ ~Hero();
+ void tick();
+ Sprite *expand();
+ Sprite *contract();
+ Sprite *setContact();
+ int stepSize() { return _ext->_seq[7]._dx; }
+ int distance(V3D pos);
+ int distance(Sprite * spr);
+ void turn(Dir d);
+ void park();
+ int len(V2D v);
+ bool findWay();
+ static int snap(int p, int q, int grid);
+ void walkTo(V3D pos);
+ void walkTo(V2D pos) { walkTo(screenToGround(pos)); }
+ V3D screenToGround(V2D pos);
+ void walkTo(Sprite *spr);
+ void say() { step(_sayStart); }
+ void fun();
+ void resetFun() { _funDel = _funDel0; }
+ void hStep();
+ bool lower(Sprite * spr);
+ int cross(const V2D &a, const V2D &b);
+ int mapCross(const V2D &a, const V2D &b);
+ int mapCross(const V3D &a, const V3D &b);
+ Hero *other() { return _vm->_heroTab[!(_ref & 1)]->_ptr;}
+ Action action() { return (Action)(_ref % 10); }
+ void reach(int mode);
+ void setCurrent();
+ void setScene(int c);
+ void operator++();
+ void operator--();
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_HERO_H
diff --git a/engines/cge2/inventory.cpp b/engines/cge2/inventory.cpp
new file mode 100644
index 0000000000..e62aa01e99
--- /dev/null
+++ b/engines/cge2/inventory.cpp
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/cge2.h"
+#include "cge2/hero.h"
+
+namespace CGE2 {
+
+int CGE2Engine::findActivePocket(int ref) {
+ for (int i = 0; i < kPocketMax; i++) {
+ Sprite *spr = _heroTab[_sex]->_pocket[i];
+ if (ref >= 0) {
+ if (spr && (spr->_ref == ref))
+ return i;
+ } else if (!spr)
+ return i;
+ }
+ return -1;
+}
+
+void CGE2Engine::selectPocket(int n) {
+ Sprite **p = _heroTab[_sex]->_pocket;
+ int &pp = _heroTab[_sex]->_pocPtr;
+ if ((n < 0) || (pp == n)) {
+ n = findActivePocket(-1);
+ if (n >= 0)
+ pp = n;
+ } else if (p[n])
+ pp = n;
+}
+
+void CGE2Engine::pocFul() {
+ Hero *h = _heroTab[_sex]->_ptr;
+ h->park();
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSound, -1, 2, h);
+ _commandHandler->addCommand(kCmdSay, -1, kPocketFull + _sex, h);
+}
+
+void CGE2Engine::releasePocket(Sprite *spr) {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ Sprite *&poc = _heroTab[i]->_pocket[j];
+ if (poc == spr) {
+ spr->_flags._kept = false;
+ poc = nullptr;
+ return;
+ }
+ }
+ }
+}
+
+int CGE2Engine::freePockets(int sx) {
+ int n = 0;
+ for (int i = 0; i < kPocketMax; i++){
+ if (_heroTab[sx]->_pocket[i] == nullptr)
+ ++n;
+ }
+ return n;
+}
+
+void CGE2Engine::openPocket() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax + 1; j++) {
+ int ref = (int)_heroTab[i]->_downPocketId[j];
+ _heroTab[i]->_pocket[j] = (ref == -1) ? nullptr : _vga->_showQ->locate(ref);
+ }
+ }
+}
+
+void CGE2Engine::closePocket() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax + 1; j++) {
+ Sprite *spr = _heroTab[i]->_pocket[j];
+ _heroTab[i]->_downPocketId[j] = (spr) ? spr->_ref : -1;
+ }
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/map.cpp b/engines/cge2/map.cpp
new file mode 100644
index 0000000000..1ed0ea7daf
--- /dev/null
+++ b/engines/cge2/map.cpp
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+Map::Map(CGE2Engine *vm) :_vm(vm) {}
+
+Map::~Map() {
+ _container.clear();
+}
+
+void Map::clear() {
+ _container.clear();
+}
+
+void Map::load(int scene) {
+ clear();
+
+ char fname[] = "%.2d.MAP\0";
+ Common::String fileName = Common::String::format(fname, scene);
+ if (!_vm->_resman->exist(fileName.c_str()))
+ return;
+
+ EncryptedStream file(_vm, fileName.c_str());
+
+ Common::String line;
+ for (line = file.readLine(); !file.eos(); line = file.readLine()) {
+ if (line.empty())
+ continue;
+
+ char tmpStr[kLineMax + 1];
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *currPos = tmpStr;
+ int x = nextNum(currPos);
+ while (true) {
+ int y = nextNum(nullptr);
+ _container.push_back(V2D(_vm, convertCoord(x), convertCoord(y)));
+ x = nextNum(nullptr);
+ if (x == -1) // We stop if there are no more data left to process in the current line.
+ break;
+ }
+ }
+}
+
+int Map::nextNum(char *currPos) {
+ currPos = strtok(currPos, " (),");
+ if (currPos == nullptr)
+ return -1;
+ int num = atoi(currPos);
+ return num;
+}
+
+int Map::convertCoord(int coord) {
+ return (coord + (kMapGrid >> 1)) & kMapMask;
+}
+
+int Map::size() {
+ return _container.size();
+}
+
+V2D *Map::getCoord(int idx) {
+ return &_container[idx];
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/map.h b/engines/cge2/map.h
new file mode 100644
index 0000000000..206479b929
--- /dev/null
+++ b/engines/cge2/map.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_MAP_H
+#define CGE2_MAP_H
+
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+#define kMapGrid 4
+#define kMapMask (~(kMapGrid - 1))
+
+class Map {
+ CGE2Engine *_vm;
+ Common::Array<V2D> _container;
+
+ int convertCoord(int coord);
+ int nextNum(char *currPos);
+public:
+ Map(CGE2Engine *vm);
+ ~Map();
+ void clear();
+ void load(int scene);
+ int size();
+ V2D *getCoord(int idx);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_MAP_H
diff --git a/engines/cge2/module.mk b/engines/cge2/module.mk
new file mode 100644
index 0000000000..4b321d88a8
--- /dev/null
+++ b/engines/cge2/module.mk
@@ -0,0 +1,30 @@
+MODULE := engines/cge2
+
+MODULE_OBJS = \
+ cge2.o \
+ detection.o \
+ fileio.o \
+ vga13h.o \
+ bitmap.o \
+ sound.o \
+ cge2_main.o \
+ text.o \
+ hero.o \
+ snail.o \
+ spare.o \
+ talk.o \
+ events.o \
+ map.o \
+ vmenu.o \
+ saveload.o \
+ toolbar.o \
+ inventory.o \
+ console.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_CGE2), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/cge2/saveload.cpp b/engines/cge2/saveload.cpp
new file mode 100644
index 0000000000..fd60422dff
--- /dev/null
+++ b/engines/cge2/saveload.cpp
@@ -0,0 +1,279 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/config-manager.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "graphics/thumbnail.h"
+#include "graphics/surface.h"
+#include "graphics/palette.h"
+#include "graphics/scaler.h"
+#include "cge2/events.h"
+#include "cge2/snail.h"
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/sound.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+#define kSavegameCheckSum (1997 + _now + _sex + kWorldHeight)
+#define kBadSVG 99
+
+bool CGE2Engine::canSaveGameStateCurrently() {
+ return (_gamePhase == kPhaseInGame) && _mouse->_active &&
+ _commandHandler->idle() && (_soundStat._wait == nullptr);
+}
+
+Common::Error CGE2Engine::saveGameState(int slot, const Common::String &desc) {
+ storeHeroPos();
+ saveGame(slot, desc);
+ sceneUp(_now);
+ return Common::kNoError;
+}
+
+void CGE2Engine::saveGame(int slotNumber, const Common::String &desc) {
+ // Set up the serializer
+ Common::String slotName = generateSaveName(slotNumber);
+ Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName);
+
+ // Write out the ScummVM savegame header
+ SavegameHeader header;
+ header.saveName = desc;
+ header.version = kSavegameVersion;
+ writeSavegameHeader(saveFile, header);
+
+ // Write out the data of the savegame
+ sceneDown();
+ syncGame(nullptr, saveFile);
+
+ // Finish writing out game data
+ saveFile->finalize();
+ delete saveFile;
+}
+
+bool CGE2Engine::canLoadGameStateCurrently() {
+ return (_gamePhase == kPhaseInGame) && _mouse->_active;
+}
+
+Common::Error CGE2Engine::loadGameState(int slot) {
+ _commandHandler->clear();
+ _commandHandlerTurbo->clear();
+ sceneDown();
+ if (!loadGame(slot))
+ return Common::kReadingFailed;
+ sceneUp(_now);
+ initToolbar();
+ return Common::kNoError;
+}
+
+bool CGE2Engine::loadGame(int slotNumber) {
+ Common::MemoryReadStream *readStream;
+
+ // Open up the savegame file
+ Common::String slotName = generateSaveName(slotNumber);
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
+
+ // Read the data into a data buffer
+ int size = saveFile->size();
+ byte *dataBuffer = (byte *)malloc(size);
+ saveFile->read(dataBuffer, size);
+ readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);
+ delete saveFile;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ readStream->read(buffer, kSavegameStrSize + 1);
+
+ if (strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) != 0) {
+ delete readStream;
+ return false;
+ } else {
+ SavegameHeader saveHeader;
+
+ if (!readSavegameHeader(readStream, saveHeader)) {
+ delete readStream;
+ return false;
+ }
+
+ // Delete the thumbnail
+ saveHeader.thumbnail->free();
+ delete saveHeader.thumbnail;
+ }
+
+ resetGame();
+
+ // Get in the savegame
+ syncGame(readStream, nullptr);
+ delete readStream;
+
+ loadHeroes();
+
+ return true;
+}
+
+void CGE2Engine::resetGame() {
+ _busyPtr = nullptr;
+ busy(false);
+ _spare->clear();
+ _vga->_showQ->clear();
+ loadScript("CGE.INI", true);
+ delete _infoLine;
+ _infoLine = new InfoLine(this, kInfoW);
+}
+
+void CGE2Engine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) {
+ // Write out a savegame header
+ out->write(kSavegameStr, kSavegameStrSize + 1);
+
+ out->writeByte(kSavegameVersion);
+
+ // Write savegame name
+ out->write(header.saveName.c_str(), header.saveName.size() + 1);
+
+ // Get the active palette
+ uint8 thumbPalette[256 * 3];
+ g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
+
+ // Stop the heroes from moving and redraw them before taking the picture.
+ for (int i = 0; i < 2; i++)
+ _heroTab[i]->_ptr->park();
+ _vga->show();
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ Graphics::Surface *s = _vga->_page[0];
+ ::createThumbnail(thumb, (const byte *)s->getPixels(), kScrWidth, kScrHeight, thumbPalette);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
+ header.thumbnail = nullptr;
+
+ // Get the savegame version
+ header.version = in->readByte();
+ if (header.version > kSavegameVersion)
+ 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)
+ return false;
+
+ // Read in save date/time
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
+ header.saveMinutes = in->readSint16LE();
+
+ return true;
+}
+
+void CGE2Engine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) {
+ Common::Serializer s(readStream, writeStream);
+
+ // Synchronise header data
+ syncHeader(s);
+
+ // Synchronise _spare
+ _spare->sync(s);
+
+ if (s.isSaving()) {
+ // Save the references of the items in the heroes pockets:
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ int ref = _heroTab[i]->_downPocketId[j];
+ s.syncAsSint16LE(ref);
+ }
+ }
+ } else {
+ // Load items to the pockets
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ int ref = 0;
+ s.syncAsSint16LE(ref);
+ _heroTab[i]->_downPocketId[j] = ref;
+ }
+ }
+ }
+
+ // Heroes' _posTabs
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kSceneMax; j++) {
+ s.syncAsSint16LE(_heroTab[i]->_posTab[j]->x);
+ s.syncAsSint16LE(_heroTab[i]->_posTab[j]->y);
+ }
+ }
+}
+
+void CGE2Engine::syncHeader(Common::Serializer &s) {
+ s.syncAsUint16LE(_now);
+ s.syncAsUint16LE(_sex);
+ s.syncAsUint16LE(_vga->_rot._len);
+ s.syncAsUint16LE(_waitSeq);
+ s.syncAsUint16LE(_waitRef);
+
+ if (s.isSaving()) {
+ // Write checksum
+ int checksum = kSavegameCheckSum;
+ s.syncAsUint16LE(checksum);
+ } else {
+ // Read checksum and validate it
+ uint16 checksum = 0;
+ s.syncAsUint16LE(checksum);
+ if (checksum != kSavegameCheckSum)
+ error("%s", _text->getText(kBadSVG));
+ }
+}
+
+/**
+* Support method that generates a savegame name
+* @param slot Slot number
+*/
+Common::String CGE2Engine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/snail.cpp b/engines/cge2/snail.cpp
new file mode 100644
index 0000000000..0bf63839e9
--- /dev/null
+++ b/engines/cge2/snail.cpp
@@ -0,0 +1,865 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/snail.h"
+#include "cge2/fileio.h"
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/sound.h"
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+const char *CommandHandler::_commandText[] = {
+ "NOP", "USE", "PAUSE", "INF", "CAVE", "SETX", "SETY", "SETZ", "ADD",
+ "FLASH", "CYCLE", "CLEAR", "MOUSE", "MAP", "MIDI", ".DUMMY.", "WAIT",
+ "HIDE", "ROOM", "SAY", "SOUND", "KILL", "RSEQ", "SEQ", "SEND", "SWAP",
+ "KEEP", "GIVE", "GETPOS", "GOTO", "PORT", "NEXT", "NNEXT", "MTNEXT",
+ "FTNEXT", "RNNEXT", "RMTNEXT", "RFTNEXT", "RMNEAR", "RMMTAKE", "RMFTAKE",
+ "SETREF", "WALKTO", "REACH", "COVER", "UNCOVER", "EXEC", "GHOST",
+ nullptr };
+
+CommandHandler::CommandHandler(CGE2Engine *vm, bool turbo)
+ : _turbo(turbo), _textDelay(false), _timerExpiry(0), _talkEnable(true),
+ _head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command)* 256)),
+ _vm(vm) {
+}
+
+CommandHandler::~CommandHandler() {
+ free(_commandList);
+}
+
+void CommandHandler::runCommand() {
+ if (!_turbo && _vm->_soundStat._wait) {
+ if (*(_vm->_soundStat._wait))
+ return;
+
+ ++_vm->_soundStat._ref[0];
+ if (_vm->_fx->exist(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0])) {
+ int16 oldRepeat = _vm->_sound->getRepeat();
+ _vm->_sound->setRepeat(1);
+ _vm->_sound->play(Audio::Mixer::kSFXSoundType, _vm->_fx->load(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0]), _vm->_sound->_smpinf._span);
+ _vm->_sound->setRepeat(oldRepeat);
+ return;
+ }
+ _vm->_soundStat._wait = nullptr;
+ }
+
+ uint8 tmpHead = _head;
+ while (_tail != tmpHead) {
+ Command tailCmd = _commandList[_tail];
+
+ if (!_turbo) { // only for the slower one
+ if (_vm->_waitRef)
+ break;
+
+ if (_timerExpiry) {
+ // Delay in progress
+ if (_timerExpiry > g_system->getMillis())
+ // Delay not yet ended
+ break;
+
+ // Delay is finished
+ _timerExpiry = 0;
+ } else if (_textDelay) {
+ if (_vm->_talk) {
+ _vm->snKill((Sprite *)_vm->_talk);
+ _vm->_talk = nullptr;
+ }
+ _textDelay = false;
+ }
+
+ if (_vm->_talk && tailCmd._commandType != kCmdPause)
+ break;
+ }
+ ++_tail;
+ _vm->_taken = false;
+ Sprite *spr = nullptr;
+ if (tailCmd._commandType > kCmdSpr)
+ spr = (tailCmd._ref < 0) ? ((Sprite *)tailCmd._spritePtr) : _vm->locate(tailCmd._ref);
+
+ Common::String sprStr;
+ if (spr && *spr->_file && (tailCmd._commandType != kCmdGhost))
+ // In case of kCmdGhost _spritePtr stores a pointer to a Bitmap, not to a Sprite...
+ sprStr = Common::String(spr->_file);
+ else
+ sprStr = "None";
+
+ if (sprStr.empty())
+ sprStr = "None";
+ debugC(1, kCGE2DebugOpcode, "Command: %s; Ref: %d; Val: %d; Sprite: %s;", getComStr(tailCmd._commandType), tailCmd._ref, tailCmd._val, sprStr.c_str());
+
+ switch (tailCmd._commandType) {
+ case kCmdUse:
+ break;
+ case kCmdPause:
+ _timerExpiry = g_system->getMillis() + tailCmd._val * kCommandFrameDelay;
+ if (_vm->_talk)
+ _textDelay = true;
+ break;
+ case kCmdWait:
+ if (spr && spr->active() && (spr->_scene == _vm->_now || spr->_scene == 0)) {
+ _vm->_waitSeq = tailCmd._val;
+ _vm->_waitRef = spr->_ref;
+ }
+ break;
+ case kCmdHide:
+ _vm->snHide(spr, tailCmd._val);
+ break;
+ case kCmdSay:
+ _vm->snSay(spr, tailCmd._val);
+ break;
+ case kCmdInf:
+ if (_talkEnable)
+ _vm->inf(((tailCmd._val) >= 0) ? _vm->_text->getText(tailCmd._val) : (const char *)tailCmd._spritePtr);
+ break;
+ case kCmdCave:
+ _vm->switchScene(tailCmd._val);
+ break;
+ case kCmdMidi:
+ _vm->snMidi(tailCmd._val);
+ break;
+ case kCmdKill:
+ _vm->snKill(spr);
+ break;
+ case kCmdSeq:
+ _vm->snSeq(spr, tailCmd._val);
+ break;
+ case kCmdRSeq:
+ _vm->snRSeq(spr, tailCmd._val);
+ break;
+ case kCmdSend:
+ _vm->snSend(spr, tailCmd._val);
+ break;
+ case kCmdSwap:
+ _vm->snSwap(spr, tailCmd._val);
+ break;
+ case kCmdCover:
+ _vm->snCover(spr, tailCmd._val);
+ break;
+ case kCmdUncover:
+ _vm->snUncover(spr, (tailCmd._val >= 0) ? _vm->locate(tailCmd._val) : ((Sprite *)tailCmd._spritePtr));
+ break;
+ case kCmdKeep:
+ _vm->snKeep(spr, tailCmd._val);
+ break;
+ case kCmdGive:
+ _vm->snGive(spr, tailCmd._val);
+ break;
+ case kCmdSetX:
+ _vm->_point[tailCmd._val]->_x = tailCmd._ref;
+ break;
+ case kCmdSetY:
+ _vm->_point[tailCmd._val]->_y = tailCmd._ref;
+ break;
+ case kCmdSetZ:
+ _vm->_point[tailCmd._val]->_z = tailCmd._ref;
+ break;
+ case kCmdAdd:
+ *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) + *(_vm->_point[tailCmd._val]);
+ break;
+ case kCmdGetPos:
+ if (spr)
+ *(_vm->_point[tailCmd._val]) = spr->_pos3D;
+ break;
+ case kCmdGoto:
+ _vm->snGoto(spr, tailCmd._val);
+ break;
+ case kCmdPort:
+ _vm->snPort(spr, tailCmd._val);
+ break;
+ case kCmdNext:
+ break;
+ case kCmdMouse:
+ _vm->snMouse(tailCmd._val != 0);
+ break;
+ case kCmdNNext:
+ _vm->snNNext(spr, kNear, tailCmd._val);
+ break;
+ case kCmdMTNext:
+ _vm->snNNext(spr, kMTake, tailCmd._val);
+ break;
+ case kCmdFTNext:
+ _vm->snNNext(spr, kFTake, tailCmd._val);
+ break;
+ case kCmdRNNext:
+ _vm->snRNNext(spr, tailCmd._val);
+ break;
+ case kCmdRMTNext:
+ _vm->snRMTNext(spr, tailCmd._val);
+ break;
+ case kCmdRFTNext:
+ _vm->snRFTNext(spr, tailCmd._val);
+ break;
+ case kCmdRMNear:
+ _vm->snRmNear(spr);
+ break;
+ case kCmdRMMTake:
+ _vm->snRmMTake(spr);
+ break;
+ case kCmdRMFTake:
+ _vm->snRmFTake(spr);
+ break;
+ case kCmdSetRef:
+ _vm->snSetRef(spr, tailCmd._val);
+ break;
+ case kCmdFlash:
+ _vm->snFlash(tailCmd._val != 0);
+ break;
+ case kCmdCycle:
+ _vm->snCycle(tailCmd._val);
+ break;
+ case kCmdWalk:
+ _vm->snWalk(spr, tailCmd._val);
+ break;
+ case kCmdReach:
+ _vm->snReach(spr, tailCmd._val);
+ break;
+ case kCmdSound:
+ _vm->snSound(spr, tailCmd._val);
+ _vm->_sound->setRepeat(1);
+ break;
+ case kCmdMap:
+ _vm->_heroTab[tailCmd._ref & 1]->_ptr->_ignoreMap = tailCmd._val == 0;
+ break;
+ case kCmdRoom:
+ _vm->snRoom(spr, tailCmd._val);
+ break;
+ case kCmdExec:
+ switch (tailCmd._cbType) {
+ case kQGame:
+ _vm->qGame();
+ break;
+ case kXScene:
+ _vm->xScene();
+ break;
+ default:
+ error("Unknown Callback Type in SNEXEC");
+ break;
+ }
+ break;
+ case kCmdGhost:
+ _vm->snGhost((Bitmap *)tailCmd._spritePtr);
+ break;
+ case kCmdNop: // Do nothing.
+ break;
+ default:
+ warning("Unhandled command");
+ break;
+ }
+
+ if (_vm->_taken && spr)
+ _vm->_spare->dispose(spr);
+
+ if (!_turbo)
+ break;
+ }
+}
+
+void CGE2Engine::snKill(Sprite *spr) {
+ if (spr) {
+ if (spr->_flags._kept)
+ releasePocket(spr);
+ Sprite *nx = spr->_next;
+ hide1(spr);
+ _vga->_showQ->remove(spr);
+ _eventManager->clearEvent(spr);
+ if (spr->_flags._kill) {
+ _spare->take(spr->_ref);
+ delete spr;
+ } else {
+ spr->setScene(-1);
+ _spare->dispose(spr);
+ }
+ if (nx && nx->_flags._slav)
+ snKill(nx);
+ }
+}
+
+void CGE2Engine::snHide(Sprite *spr, int val) {
+ if (spr) {
+ spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide);
+ if (spr->_flags._shad)
+ spr->_prev->_flags._hide = spr->_flags._hide;
+ }
+}
+
+void CGE2Engine::snMidi(int val) {
+ if (val < 0)
+ _midiPlayer->killMidi();
+ else if (_music)
+ _midiPlayer->loadMidi(val);
+}
+
+void CGE2Engine::snSeq(Sprite *spr, int val) {
+ if (spr) {
+ if (isHero(spr) && (val == 0))
+ ((Hero*)spr)->park();
+ else
+ spr->step(val);
+ }
+}
+
+void CGE2Engine::snRSeq(Sprite *spr, int val) {
+ if (spr)
+ snSeq(spr, spr->_seqPtr + val);
+}
+
+void CGE2Engine::snSend(Sprite *spr, int val) {
+ if (!spr)
+ return;
+
+ // Sending", spr->_file
+ // from scene", spr->_scene
+ // to scene", val
+ bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
+ bool val1 = (val == 0 || val == _now);
+ spr->_scene = val;
+ releasePocket(spr);
+ if (val1 != was1) {
+ if (was1) {
+ // deactivating
+ hide1(spr);
+ spr->_flags._slav = false;
+ if ((spr == _heroTab[_sex]->_ptr) && (_heroTab[!_sex]->_ptr->_scene == _now))
+ switchHero(!_sex);
+ _spare->dispose(spr);
+ } else {
+ // activating
+ if (byte(spr->_ref) == 0)
+ _bitmapPalette = _vga->_sysPal;
+ _vga->_showQ->insert(spr);
+ if (isHero(spr)) {
+ V2D p = *_heroTab[spr->_ref & 1]->_posTab[val];
+ spr->gotoxyz(V3D(p.x, 0, p.y));
+ ((Hero*)spr)->setCurrent();
+ }
+ _taken = false;
+ _bitmapPalette = nullptr;
+ }
+ }
+}
+
+void CGE2Engine::snSwap(Sprite *spr, int val) {
+ bool tak = _taken;
+ Sprite *xspr = locate(val);
+ if (spr && xspr) {
+ bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
+ bool xwas1 = (_vga->_showQ->locate(val) != nullptr);
+
+ int tmp = spr->_scene;
+ spr->setScene(xspr->_scene);
+ xspr->setScene(tmp);
+
+ SWAP(spr->_pos2D, xspr->_pos2D);
+ SWAP(spr->_pos3D, xspr->_pos3D);
+ if (spr->_flags._kept)
+ swapInPocket(spr, xspr);
+ if (xwas1 != was1) {
+ if (was1) {
+ hide1(spr);
+ _spare->dispose(spr);
+ } else
+ expandSprite(spr);
+ if (xwas1) {
+ hide1(xspr);
+ _spare->dispose(xspr);
+ } else {
+ expandSprite(xspr);
+ _taken = false;
+ }
+ }
+ }
+ if (_taken)
+ _spare->dispose(xspr);
+ _taken = tak;
+}
+
+void CGE2Engine::snCover(Sprite *spr, int val) {
+ bool tak = _taken;
+ Sprite *xspr = locate(val);
+ if (spr && xspr) {
+ spr->_flags._hide = true;
+ xspr->setScene(spr->_scene);
+ xspr->gotoxyz(spr->_pos3D);
+ expandSprite(xspr);
+ if ((xspr->_flags._shad = spr->_flags._shad) == true) {
+ _vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr);
+ spr->_flags._shad = false;
+ }
+ feedSnail(xspr, kNear, _heroTab[_sex]->_ptr);
+ _taken = false;
+ }
+ if (_taken)
+ _spare->dispose(xspr);
+ _taken = tak;
+}
+
+void CGE2Engine::snUncover(Sprite *spr, Sprite *spr2) {
+ if (spr && spr2) {
+ spr->_flags._hide = false;
+ spr->setScene(spr2->_scene);
+ if ((spr->_flags._shad = spr2->_flags._shad) == true) {
+ _vga->_showQ->insert(_vga->_showQ->remove(spr2->_prev), spr);
+ spr2->_flags._shad = false;
+ }
+ spr->gotoxyz(spr2->_pos3D);
+ snSend(spr2, -1);
+ if (spr->_time == 0)
+ ++spr->_time;
+ }
+}
+
+void CGE2Engine::snKeep(Sprite *spr, int stp) {
+ int sex = _sex;
+ if (stp > 127) {
+ _sex = stp & 1; // for another hero
+ stp = -1;
+ }
+ HeroTab *ht = _heroTab[_sex];
+ selectPocket(-1);
+ int pp = ht->_pocPtr;
+
+ if (spr && !spr->_flags._kept && ht->_pocket[pp] == nullptr) {
+ V3D pos(14, -10, -1);
+ int16 oldRepeat = _sound->getRepeat();
+ _sound->setRepeat(1);
+ snSound(ht->_ptr, 3);
+ _sound->setRepeat(oldRepeat);
+ if (_taken) {
+ _vga->_showQ->insert(spr);
+ _taken = false;
+ }
+ ht->_pocket[pp] = spr;
+ spr->setScene(0);
+ spr->_flags._kept = true;
+ if (!_sex)
+ pos._x += kScrWidth - 58;
+ if (pp & 1)
+ pos._x += 29;
+ if (pp >> 1)
+ pos._y -= 20;
+ pos._y -= (spr->_siz.y / 2);
+ spr->gotoxyz(pos);
+ if (stp >= 0)
+ spr->step(stp);
+ }
+ _sex = sex;
+ selectPocket(-1);
+}
+
+void CGE2Engine::snGive(Sprite *spr, int val) {
+ if (spr) {
+ int p = findActivePocket(spr->_ref);
+ if (p >= 0) {
+ releasePocket(spr);
+ spr->setScene(_now);
+ if (val >= 0)
+ spr->step(val);
+ }
+ }
+ selectPocket(-1);
+}
+
+void CGE2Engine::snGoto(Sprite *spr, int val) {
+ if (spr) {
+ V3D eye = *_eye;
+ if (spr->_scene > 0)
+ setEye(*_eyeTab[spr->_scene]);
+ spr->gotoxyz(*_point[val]);
+ setEye(eye);
+ }
+}
+
+void CGE2Engine::snPort(Sprite *spr, int port) {
+ if (spr)
+ spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
+}
+
+void CGE2Engine::snMouse(bool on) {
+ if (on)
+ _mouse->on();
+ else
+ _mouse->off();
+}
+
+void CGE2Engine::snNNext(Sprite *spr, Action act, int val) {
+ if (spr) {
+ if (val > 255)
+ val = spr->labVal(act, val >> 8);
+ spr->_actionCtrl[act]._ptr = val;
+ }
+}
+
+void CGE2Engine::snRNNext(Sprite *spr, int val) {
+ if (spr)
+ spr->_actionCtrl[kNear]._ptr += val;
+}
+
+void CGE2Engine::snRMTNext(Sprite *spr, int val) {
+ if (spr)
+ spr->_actionCtrl[kMTake]._ptr += val;
+}
+
+void CGE2Engine::snRFTNext(Sprite * spr, int val) {
+ if (spr)
+ spr->_actionCtrl[kFTake]._ptr += val;
+}
+
+void CGE2Engine::snRmNear(Sprite *spr) {
+ if (spr)
+ spr->_actionCtrl[kNear]._cnt = 0;
+}
+
+void CGE2Engine::snRmMTake(Sprite *spr) {
+ if (spr)
+ spr->_actionCtrl[kMTake]._cnt = 0;
+}
+
+void CGE2Engine::snRmFTake(Sprite *spr) {
+ if (spr)
+ spr->_actionCtrl[kFTake]._cnt = 0;
+}
+
+void CGE2Engine::snSetRef(Sprite *spr, int val) {
+ if (spr)
+ spr->_ref = val;
+}
+
+void CGE2Engine::snFlash(bool on) {
+ if (on) {
+ Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ if (pal) {
+ memcpy(pal, _vga->_sysPal, kPalSize);
+ for (int i = 0; i < kPalCount; i++) {
+ register int c;
+ c = pal[i]._r << 1;
+ pal[i]._r = (c < 64) ? c : 63;
+ c = pal[i]._g << 1;
+ pal[i]._g = (c < 64) ? c : 63;
+ c = pal[i]._b << 1;
+ pal[i]._b = (c < 64) ? c : 63;
+ }
+ _vga->setColors(pal, 64);
+ }
+
+ free(pal);
+ } else
+ _vga->setColors(_vga->_sysPal, 64);
+ _dark = false;
+}
+
+void CGE2Engine::snCycle(int cnt) {
+ _vga->_rot._len = cnt;
+}
+
+void CGE2Engine::snWalk(Sprite *spr, int val) {
+ if (isHero(spr)) {
+ if (val < kMaxPoint)
+ ((Hero *)spr)->walkTo(*_point[val]);
+ else {
+ Sprite *s = _vga->_showQ->locate(val);
+ if (s)
+ ((Hero *)spr)->walkTo(s);
+ }
+ ((Hero *)spr)->_time = 1;
+ }
+}
+
+void CGE2Engine::snReach(Sprite *spr, int val) {
+ if (isHero(spr))
+ ((Hero *)spr)->reach(val);
+}
+
+void CGE2Engine::snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType) {
+ if (wav == -1)
+ _sound->stop();
+ else {
+ if (_sound->_smpinf._counter && wav < 20)
+ return;
+ if (_soundStat._wait && ((wav & 255) > 80))
+ return;
+
+ _soundStat._ref[1] = wav;
+ _soundStat._ref[0] = !_fx->exist(_soundStat._ref[1]);
+ _sound->play(soundType, _fx->load(_soundStat._ref[1], _soundStat._ref[0]),
+ (spr) ? (spr->_pos2D.x / (kScrWidth / 16)) : 8);
+ }
+}
+
+void CGE2Engine::snRoom(Sprite *spr, bool on) {
+ if (!isHero(spr))
+ return;
+
+ int sex = spr->_ref & 1;
+ Sprite **p = _heroTab[sex]->_pocket;
+ if (on) {
+ if (freePockets(sex) == 0 && p[kPocketMax] == nullptr) {
+ SWAP(p[kPocketMax], p[kPocketMax - 1]);
+ snHide(p[kPocketMax], 1);
+ }
+ } else if (p[kPocketMax]) {
+ for (int i = 0; i < kPocketMax; i++) {
+ if (p[i] == nullptr) {
+ snHide(p[kPocketMax], 0);
+ SWAP(p[kPocketMax], p[i]);
+ break;
+ }
+ }
+ }
+}
+
+void CGE2Engine::snGhost(Bitmap *bmp) {
+ V2D p(this, bmp->_map & 0xFFFF, bmp->_map >> 16);
+ bmp->hide(p);
+ bmp->release();
+ delete[] bmp->_b;
+ bmp->_b = nullptr;
+ delete bmp;
+ bmp = nullptr;
+}
+
+void CGE2Engine::snSay(Sprite *spr, int val) {
+ if (spr && spr->active() && _commandHandler->_talkEnable) {
+ //-- mouth animation
+ if (isHero(spr) && spr->seqTest(-1))
+ ((Hero *)spr)->say();
+ if (_sayCap)
+ _text->say(_text->getText(val), spr);
+ if (_sayVox) {
+ int i = val;
+ if (i < 256)
+ i -= 100;
+ int16 oldRepeat = _sound->getRepeat();
+ _sound->setRepeat(1);
+ snSound(spr, i, Audio::Mixer::kSpeechSoundType);
+ _sound->setRepeat(oldRepeat);
+ _soundStat._wait = &_sound->_smpinf._counter;
+ }
+ }
+}
+
+void CGE2Engine::hide1(Sprite *spr) {
+ _commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
+}
+
+void CGE2Engine::swapInPocket(Sprite *spr, Sprite *xspr) {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ Sprite *&poc = _heroTab[i]->_pocket[j];
+ if (poc == spr) {
+ spr->_flags._kept = false;
+ poc = xspr;
+ xspr->_flags._kept = true;
+ xspr->_flags._port = false;
+ return;
+ }
+ }
+ }
+}
+
+Sprite *CGE2Engine::expandSprite(Sprite *spr) {
+ if (spr)
+ _vga->_showQ->insert(spr);
+ return spr;
+}
+
+void CGE2Engine::qGame() {
+ // Write out the user's progress
+ saveGame(0, Common::String("Automatic Savegame"));
+
+ busy(false);
+ _vga->sunset();
+ _endGame = true;
+}
+
+void CGE2Engine::xScene() {
+ sceneDown();
+ sceneUp(_req);
+}
+
+void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) {
+ if (ref == -2)
+ ref = 142 - _vm->_sex;
+ Command *headCmd = &_commandList[_head++];
+ headCmd->_commandType = com;
+ headCmd->_ref = ref;
+ headCmd->_val = val;
+ headCmd->_spritePtr = ptr;
+ headCmd->_cbType = kNullCB;
+ if (headCmd->_commandType == kCmdClear) {
+ clear();
+ }
+}
+
+void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) {
+ Command *headCmd = &_commandList[_head++];
+ headCmd->_commandType = com;
+ headCmd->_ref = ref;
+ headCmd->_val = val;
+ headCmd->_spritePtr = nullptr;
+ headCmd->_cbType = cbType;
+ if (headCmd->_commandType == kCmdClear) {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+ }
+}
+
+void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) {
+ if (ref == -2)
+ ref = 142 - _vm->_sex;
+ --_tail;
+ Command *tailCmd = &_commandList[_tail];
+ tailCmd->_commandType = com;
+ tailCmd->_ref = ref;
+ tailCmd->_val = val;
+ tailCmd->_spritePtr = ptr;
+ tailCmd->_cbType = kNullCB;
+ if (com == kCmdClear) {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+ }
+}
+
+bool CommandHandler::idle() {
+ return (!_vm->_waitRef && _head == _tail);
+}
+
+void CommandHandler::clear() {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+}
+
+int CommandHandler::getComId(const char *com) {
+ int i = _vm->takeEnum(_commandText, com);
+ return (i < 0) ? i : i + kCmdCom0 + 1;
+}
+
+const char *CommandHandler::getComStr(CommandType cmdType) {
+ return _commandText[cmdType - kCmdNop];
+}
+
+void CGE2Engine::feedSnail(Sprite *spr, Action snq, Hero *hero) {
+ if (!spr || !spr->active())
+ return;
+
+ int cnt = spr->_actionCtrl[snq]._cnt;
+ if (cnt) {
+ byte ptr = spr->_actionCtrl[snq]._ptr;
+ CommandHandler::Command *comtab = spr->snList(snq);
+ CommandHandler::Command *c = &comtab[ptr];
+ CommandHandler::Command *q = &comtab[cnt];
+
+ if (hero != nullptr) {
+ int pocFre = freePockets(hero->_ref & 1);
+ int pocReq = 0;
+ CommandHandler::Command *p = c;
+ for (; p < q && p->_commandType != kCmdNext; p++) { // scan commands
+ // drop from pocket?
+ if ((p->_commandType == kCmdSend && p->_val != _now)
+ || p->_commandType == kCmdGive) {
+ int ref = p->_ref;
+ if (ref < 0)
+ ref = spr->_ref;
+ if (findActivePocket(ref) >= 0)
+ --pocReq;
+ }
+ // make/dispose additional room?
+ if (p->_commandType == kCmdRoom) {
+ if (p->_val == 0)
+ ++pocReq;
+ else
+ --pocReq;
+ }
+ // put into pocket?
+ if (p->_commandType == kCmdKeep)
+ ++pocReq;
+ // overloaded?
+ if (pocReq > pocFre) {
+ pocFul();
+ return;
+ }
+ }
+ }
+
+ while (c < q) {
+ if ((c->_val == -1) && (c->_commandType == kCmdWalk || c->_commandType == kCmdReach))
+ c->_val = spr->_ref;
+
+ if (c->_commandType == kCmdNext) {
+ Sprite *s;
+
+ switch (c->_ref) {
+ case -2:
+ s = hero;
+ break;
+ case -1:
+ s = spr;
+ break;
+ default:
+ s = _vga->_showQ->locate(c->_ref);
+ break;
+ }
+
+ if (s && s->_actionCtrl[snq]._cnt) {
+ int v;
+ switch (c->_val) {
+ case -1:
+ v = int(c - comtab + 1);
+ break;
+ case -2:
+ v = int(c - comtab);
+ break;
+ case -3:
+ v = -1;
+ break;
+ default:
+ v = c->_val;
+ if ((v > 255) && s)
+ v = s->labVal(snq, v >> 8);
+ break;
+ }
+ if (v >= 0)
+ s->_actionCtrl[snq]._ptr = v;
+ }
+
+ if (s == spr)
+ break;
+ }
+
+ _commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
+
+ ++c;
+ }
+ }
+
+}
+
+} // End of namespace CGE2.
diff --git a/engines/cge2/snail.h b/engines/cge2/snail.h
new file mode 100644
index 0000000000..7e618daac8
--- /dev/null
+++ b/engines/cge2/snail.h
@@ -0,0 +1,129 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SNAIL_H
+#define CGE2_SNAIL_H
+
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kCommandFrameRate 80
+#define kCommandFrameDelay (1000 / kCommandFrameRate)
+#define kNoByte -1 // Recheck this! We have no proof for it's original value.
+
+
+enum CommandType {
+ kCmdCom0 = 128,
+ kCmdNop, // NOP :: do nothing
+ kCmdUse, // USE <spr> <cav>|<lab> :: hint for using
+ kCmdPause, // PAUSE -1 <dly> :: delay <dly>/72 seconds
+ kCmdInf, // INF -1 <ref> :: show text referrenced by <ref>
+ kCmdCave, // CAVE -1 <cav> :: go to board <cav>
+ kCmdSetX, // SETX <x> <idx> :: set sprite shift in x axis
+ kCmdSetY, // SETX <y> <idx> :: set sprite shift in y axis
+ kCmdSetZ, // SETX <z> <idx> :: set sprite shift in z axis
+ kCmdAdd, // ADD <idx1> <idx2> :: sum vectors
+ kCmdFlash, // FLASH -1 0|1 :: lighten whole image (on/off)
+ kCmdCycle, // CYCLE <cnt> :: rotate <cnt> colors from 1
+ kCmdClear, // CLEAR -1 0 :: clear kCmdAIL queue
+ kCmdMouse, // MOUSE -1 0|1 :: enable mouse (on/off)
+ kCmdMap, // MAP 0|1 0 :: temporarily turn off map for hero
+ kCmdMidi, // MIDI -1 <midi> :: play MIDI referenced by <midi> (-1 = off)
+
+ kCmdSpr,
+
+ kCmdWait, // WAIT <spr> <seq>|-1 :: wait for SEQ <seq> (-1 = freeze)
+ kCmdHide, // HIDE <spr> 0|1 :: visibility of sprite
+ kCmdRoom, // ROOM <hero> 0|1 :: additional room in pocket (no/yes)
+ kCmdSay, // SAY <spr> <ref> :: say text referenced by <ref>
+ kCmdSound, // SOUND <spr> <ref> :: play sound effect referenced by <ref>
+ kCmdKill, // KILL <spr> 0 :: remove sprite
+ kCmdRSeq, // RSEQ <spr> <nr> :: relative jump SEQ <nr> lines
+ kCmdSeq, // SEQ <spr> <seq> :: jump to certain SEQ
+ kCmdSend, // SEND <spr> <cav> :: move sprite to board <cav>
+ kCmdSwap, // SWAP <spr1> spr2> :: sprite exchange
+ kCmdKeep, // KEEP <spr> <seq> :: take sprite into pocket and jump to <seq>
+ kCmdGive, // GIVE <spr> <seq> :: remove sprite from pocket and jump to <seq>
+ kCmdGetPos, // GETPOS <spr> <idx> :: take sprite's position
+ kCmdGoto, // GOTO <spr> <idx> :: move sprite to position
+ kCmdPort, // PORT <spr> 0|1 :: clear/set "takeability" of sprite
+ kCmdNext, // NEXT <spr> <nr> :: jump to <nr> - NEAR or TAKE
+ kCmdNNext, // NNEXT <spr> <nr> :: jump to <nr> - NEAR
+ kCmdMTNext, // MTNEXT <spr> <nr> :: jump to <nr> - TAKE
+ kCmdFTNext, // FTNEXT <spr> <nr> :: jump to <nr> - TAKE
+ kCmdRNNext, // RNNEXT <spr> <nr> :: relative jump to <nr> - NEAR
+ kCmdRMTNext, // RMTNEXT <spr> <nr> :: relative jump to <nr> - TAKE
+ kCmdRFTNext, // RFTNEXT <spr> <nr> :: relative jump to <nr> - TAKE
+ kCmdRMNear, // RMNEAR <spr> 0 :: remove NEAR list
+ kCmdRMMTake, // RMMTAKE <spr> 0 :: remove TAKE list
+ kCmdRMFTake, // RMFTAKE <spr> 0 :: remove TAKE list
+ kCmdSetRef, // SETREF <spr> <ref> :: change reference of sprite <spr> to <ref>
+ kCmdWalk, // WALKTO <hero> <ref>|<point> :: go close to the sprite or point
+ kCmdReach, // REACH <hero> <ref>|<m> :: reach the sprite or point with <m> method
+ kCmdCover, // COVER <sp1> <sp2> :: cover sprite <sp1> with sprite <sp2>
+ kCmdUncover, // UNCOVER <sp1> <sp2> :: restore the state before COVER
+
+ kCmdExec,
+ kCmdGhost
+};
+
+class CommandHandler {
+public:
+ struct Command {
+ CommandType _commandType;
+ byte _lab;
+ int _ref;
+ int _val;
+ void *_spritePtr;
+ CallbackType _cbType;
+ } *_commandList;
+ static const char *_commandText[];
+ bool _talkEnable;
+
+ CommandHandler(CGE2Engine *vm, bool turbo);
+ ~CommandHandler();
+ void runCommand();
+ void addCommand(CommandType com, int ref, int val, void *ptr);
+ void addCallback(CommandType com, int ref, int val, CallbackType cbType);
+ void insertCommand(CommandType com, int ref, int val, void *ptr);
+ bool idle();
+ void clear();
+ int getComId(const char *com);
+ const char *getComStr(CommandType cmdType);
+private:
+ CGE2Engine *_vm;
+ bool _turbo;
+ uint8 _head;
+ uint8 _tail;
+ bool _textDelay;
+ uint32 _timerExpiry; // "pause" in the original.
+};
+
+} // End of namespace CGE2
+
+#endif
diff --git a/engines/cge2/sound.cpp b/engines/cge2/sound.cpp
new file mode 100644
index 0000000000..32f94b17b9
--- /dev/null
+++ b/engines/cge2/sound.cpp
@@ -0,0 +1,273 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/sound.h"
+#include "common/config-manager.h"
+#include "common/memstream.h"
+#include "audio/decoders/raw.h"
+#include "audio/audiostream.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+DataCk::DataCk(byte *buf, int bufSize) {
+ _buf = buf;
+ _ckSize = bufSize;
+}
+
+DataCk::~DataCk() {
+ free(_buf);
+}
+
+Sound::Sound(CGE2Engine *vm) : _vm(vm) {
+ _audioStream = nullptr;
+ _soundRepeatCount = 1;
+ open();
+}
+
+Sound::~Sound() {
+ close();
+}
+
+void Sound::close() {
+ _vm->_midiPlayer->killMidi();
+}
+
+void Sound::open() {
+ setRepeat(1);
+ if (_vm->_commandHandlerTurbo != nullptr)
+ _vm->switchSay();
+ play(Audio::Mixer::kSFXSoundType, _vm->_fx->load(99, 99));
+}
+
+void Sound::setRepeat(int16 count) {
+ _soundRepeatCount = count;
+}
+
+int16 Sound::getRepeat() {
+ return _soundRepeatCount;
+}
+
+void Sound::play(Audio::Mixer::SoundType soundType, DataCk *wav, int pan) {
+ if (wav) {
+ stop();
+ _smpinf._saddr = &*(wav->addr());
+ _smpinf._slen = (uint16)wav->size();
+ _smpinf._span = pan;
+ _smpinf._counter = getRepeat();
+ sndDigiStart(&_smpinf, soundType);
+ }
+}
+
+void Sound::sndDigiStart(SmpInfo *PSmpInfo, Audio::Mixer::SoundType soundType) {
+ // Create an audio stream wrapper for sound
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(PSmpInfo->_saddr,
+ PSmpInfo->_slen, DisposeAfterUse::NO);
+ _audioStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
+
+ // Decide which handle to use
+ Audio::SoundHandle *handle = nullptr;
+ switch (soundType) {
+ case Audio::Mixer::kSFXSoundType:
+ handle = &_sfxHandle;
+ break;
+ case Audio::Mixer::kSpeechSoundType:
+ handle = &_speechHandle;
+ break;
+ default:
+ error("Wrong sound type passed to sndDigiStart()");
+ }
+
+ // Start the new sound
+ _vm->_mixer->playStream(soundType, handle,
+ Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter));
+
+ // CGE pan:
+ // 8 = Center
+ // Less = Left
+ // More = Right
+ _vm->_mixer->setChannelBalance(*handle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127));
+}
+
+void Sound::stop() {
+ sndDigiStop(_sfxHandle);
+ sndDigiStop(_speechHandle);
+ _audioStream = nullptr;
+}
+
+void Sound::checkSoundHandles() {
+ if (!_vm->_mixer->isSoundHandleActive(_speechHandle) && !_vm->_mixer->isSoundHandleActive(_sfxHandle))
+ _smpinf._counter = 0;
+}
+
+void Sound::sndDigiStop(Audio::SoundHandle &handle) {
+ if (_vm->_mixer->isSoundHandleActive(handle))
+ _vm->_mixer->stopHandle(handle);
+}
+
+Fx::Fx(CGE2Engine *vm, int size) : _current(nullptr), _vm(vm) {
+}
+
+Fx::~Fx() {
+ clear();
+}
+
+void Fx::clear() {
+ if (_current)
+ delete _current;
+ _current = nullptr;
+}
+
+Common::String Fx::name(int ref, int sub) {
+ char fxname[] = "%.2dfx%.2d.WAV\0";
+ char subName[] = "%.2dfx%.2d?.WAV\0";
+ char *p = (sub) ? subName : fxname;
+ Common::String filename = Common::String::format(p, ref >> 8, ref & 0xFF);
+ if (sub)
+ filename.setChar('@' + sub, 6);
+ return filename;
+}
+
+bool Fx::exist(int ref, int sub) {
+ return _vm->_resman->exist(name(ref, sub).c_str());
+}
+
+DataCk *Fx::load(int ref, int sub) {
+ Common::String filename = name(ref, sub);
+ EncryptedStream file(_vm, filename.c_str());
+ clear();
+ return (_current = loadWave(&file));
+}
+
+DataCk *Fx::loadWave(EncryptedStream *file) {
+ byte *data = (byte *)malloc(file->size());
+
+ if (!data)
+ return 0;
+
+ file->read(data, file->size());
+
+ return new DataCk(data, file->size());
+}
+
+MusicPlayer::MusicPlayer(CGE2Engine *vm) : _vm(vm) {
+ _data = nullptr;
+ _isGM = false;
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ // TODO: Load cmf.ins with the instrument table. It seems that an
+ // interface for such an operation is supported for AdLib. Maybe for
+ // this card, setting instruments is necessary.
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+ _dataSize = -1;
+}
+
+MusicPlayer::~MusicPlayer() {
+ killMidi();
+}
+
+void MusicPlayer::killMidi() {
+ Audio::MidiPlayer::stop();
+
+ free(_data);
+ _data = nullptr;
+}
+
+void MusicPlayer::loadMidi(int ref) {
+ if (_vm->_midiNotify != nullptr)
+ (_vm->*_vm->_midiNotify)();
+
+ // Work out the filename and check the given MIDI file exists
+ Common::String filename = Common::String::format("%.2dSG%.2d.MID", ref >> 8, ref & 0xFF);
+ if (!_vm->_resman->exist(filename.c_str()))
+ return;
+
+ // Stop any currently playing MIDI file
+ killMidi();
+
+ // Read in the data for the file
+ EncryptedStream mid(_vm, filename.c_str());
+ _dataSize = mid.size();
+ _data = (byte *)malloc(_dataSize);
+ mid.read(_data, _dataSize);
+
+ // 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);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/sound.h b/engines/cge2/sound.h
new file mode 100644
index 0000000000..6673b67b7a
--- /dev/null
+++ b/engines/cge2/sound.h
@@ -0,0 +1,131 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SOUND_H
+#define CGE2_SOUND_H
+
+#include "cge2/fileio.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/fmopl.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "audio/midiplayer.h"
+#include "audio/mixer.h"
+#include "common/memstream.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+// sample info
+struct SmpInfo {
+ const uint8 *_saddr; // address
+ uint16 _slen; // length
+ uint16 _span; // left/right pan (0-15)
+ int _counter; // number of time the sample should be played
+};
+
+class DataCk {
+ byte *_buf;
+ int _ckSize;
+public:
+ DataCk(byte *buf, int bufSize);
+ ~DataCk();
+ inline const byte *addr() {
+ return _buf;
+ }
+ inline int size() {
+ return _ckSize;
+ }
+};
+
+class Sound {
+public:
+ SmpInfo _smpinf;
+
+ Sound(CGE2Engine *vm);
+ ~Sound();
+ void open();
+ void close();
+ void play(Audio::Mixer::SoundType soundType, DataCk *wav, int pan = 8);
+ int16 getRepeat();
+ void setRepeat(int16 count);
+ void stop();
+ void checkSoundHandles();
+private:
+ int _soundRepeatCount;
+ CGE2Engine *_vm;
+ Audio::SoundHandle _sfxHandle;
+ Audio::SoundHandle _speechHandle;
+ Audio::RewindableAudioStream *_audioStream;
+
+ void sndDigiStart(SmpInfo *PSmpInfo, Audio::Mixer::SoundType soundType);
+ void sndDigiStop(Audio::SoundHandle &handle);
+};
+
+class Fx {
+ CGE2Engine *_vm;
+
+ DataCk *loadWave(EncryptedStream *file);
+ Common::String name(int ref, int sub);
+public:
+ DataCk *_current;
+
+ Fx(CGE2Engine *vm, int size);
+ ~Fx();
+ void clear();
+ bool exist(int ref, int sub = 0);
+ DataCk *load(int ref, int sub = 0);
+};
+
+class MusicPlayer: public Audio::MidiPlayer {
+private:
+ CGE2Engine *_vm;
+ byte *_data;
+ int _dataSize;
+ bool _isGM;
+
+ // Start MIDI File
+ void sndMidiStart();
+
+ // Stop MIDI File
+ void sndMidiStop();
+public:
+ MusicPlayer(CGE2Engine *vm);
+ ~MusicPlayer();
+
+ void loadMidi(int ref);
+ void killMidi();
+
+ virtual void send(uint32 b);
+ virtual void sendToChannel(byte channel, uint32 b);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_SOUND_H
diff --git a/engines/cge2/spare.cpp b/engines/cge2/spare.cpp
new file mode 100644
index 0000000000..76bdbfa7ef
--- /dev/null
+++ b/engines/cge2/spare.cpp
@@ -0,0 +1,128 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/spare.h"
+
+namespace CGE2 {
+
+void Spare::sync(Common::Serializer &s) {
+ int size = 0;
+ if (s.isSaving()) {
+ for (uint i = 0; i < _container.size(); i++)
+ if (_container[i]->_ref >= 141)
+ size++;
+ s.syncAsSint16LE(size);
+
+ for (uint i = 0; i < _container.size(); i++) {
+ if (_container[i]->_ref >= 141)
+ _container[i]->sync(s);
+ }
+ } else {
+ s.syncAsSint16LE(size);
+
+ for (int i = 0; i < size; i++) {
+ Sprite *sprite = new Sprite(_vm);
+ sprite->sync(s);
+ update(sprite);
+ }
+ }
+}
+
+void Spare::clear() {
+ for (uint i = 0; i < _container.size(); i++)
+ delete _container[i];
+
+ _container.clear();
+}
+
+Sprite *Spare::locate(int ref) {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (_container[i]->_ref == ref)
+ return _container[i];
+ }
+ return nullptr;
+}
+
+Sprite *Spare::take(int ref) {
+ Sprite *spr = nullptr;
+ if ((spr = locate(ref)) != nullptr) {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (spr == _container[i]) {
+ _container.remove_at(i);
+ break;
+ }
+ }
+ }
+ return spr;
+}
+
+void Spare::takeScene(int cav) {
+ int bakRef = cav << 8;
+ Common::Array<Sprite*> tempCont = _container;
+ for (uint i = 0; i < tempCont.size(); ++i) {
+ Sprite *spr = tempCont[i];
+ int c = spr->_scene;
+ if ((c == _vm->_now || c == 0) && spr->_ref != bakRef) {
+ spr = locate(spr->_ref);
+ _vm->_vga->_showQ->insert(spr);
+ }
+ }
+}
+
+void Spare::store(Sprite *spr) {
+ _container.push_back(spr);
+}
+
+void Spare::update(Sprite *spr) {
+ Sprite *sp = locate(spr->_ref);
+ if (sp == nullptr)
+ store(spr);
+ else {
+ sp->contract();
+ *sp = *spr;
+ }
+}
+
+void Spare::dispose(Sprite *spr) {
+ if (spr) {
+ _vm->_vga->_showQ->remove(spr);
+ update(spr->contract());
+ }
+}
+
+void Spare::dispose(int ref) {
+ dispose(_vm->_vga->_showQ->locate(ref));
+}
+
+void Spare::dispose() {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (_container[i]->_ref > 255)
+ dispose(_container[i]);
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/spare.h b/engines/cge2/spare.h
new file mode 100644
index 0000000000..7dc6ce60f5
--- /dev/null
+++ b/engines/cge2/spare.h
@@ -0,0 +1,56 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SPARE_H
+#define CGE2_SPARE_H
+
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+class Spare {
+ CGE2Engine *_vm;
+ Common::Array<Sprite*> _container;
+public:
+ Spare(CGE2Engine *vm) : _vm(vm) {}
+ ~Spare() { clear(); }
+ void store(Sprite *spr);
+ Sprite *locate(int ref);
+ Sprite *take(int ref);
+ void takeScene(int cav);
+ void update(Sprite *spr);
+ void dispose(Sprite *spr);
+ void dispose(int ref);
+ void dispose();
+ void sync(Common::Serializer &s);
+ uint16 count() { return _container.size(); }
+ void clear();
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_SPARE_H
diff --git a/engines/cge2/talk.cpp b/engines/cge2/talk.cpp
new file mode 100644
index 0000000000..9109da90f1
--- /dev/null
+++ b/engines/cge2/talk.cpp
@@ -0,0 +1,312 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/general.h"
+#include "cge2/talk.h"
+
+namespace CGE2 {
+
+void CGE2Engine::setAutoColors() {
+ Dac def[4] = {
+ { 0, 0, 0 },
+ { 220 >> 2, 220 >> 2, 220 >> 2 },
+ { 190 >> 2, 190 >> 2, 190 >> 2 },
+ { 160 >> 2, 160 >> 2, 160 >> 2 },
+ };
+ Dac pal[kPalCount];
+ _vga->getColors(pal);
+ for (int i = 0; i < 4; i++)
+ _font->_colorSet[kCBRel][i] = _vga->closest(pal, def[i]);
+}
+
+Font::Font(CGE2Engine *vm) : _vm(vm) {
+ _map = new uint8[kMapSize];
+ _pos = new uint16[kPosSize];
+ _widthArr = new uint8[kWidSize];
+
+ load();
+}
+
+Font::~Font() {
+ delete[] _map;
+ delete[] _pos;
+ delete[] _widthArr;
+}
+
+void Font::load() {
+ char path[10];
+ strcpy(path, "CGE.CFT");
+ if (!_vm->_resman->exist(path))
+ error("Missing Font file! %s", path);
+
+ EncryptedStream fontFile(_vm, path);
+ assert(!fontFile.err());
+
+ fontFile.read(_widthArr, kWidSize);
+ assert(!fontFile.err());
+
+ uint16 p = 0;
+ for (uint16 i = 0; i < kPosSize; i++) {
+ _pos[i] = p;
+ p += _widthArr[i];
+ }
+ fontFile.read(_map, p);
+
+ strcpy(path, "CGE.TXC");
+ if (!_vm->_resman->exist(path))
+ error("Missing Color file! %s", path);
+
+ // Reading in _colorSet:
+ EncryptedStream colorFile(_vm, path);
+ assert(!colorFile.err());
+
+ char tmpStr[kLineMax + 1];
+ int n = 0;
+
+ for (Common::String line = colorFile.readLine(); !colorFile.eos(); line = colorFile.readLine()){
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ _colorSet[n][0] = _vm->number(tmpStr);
+
+ for (int i = 1; i < 4; i++)
+ _colorSet[n][i] = _vm->number(nullptr);
+
+ n++;
+ }
+}
+
+uint16 Font::width(const char *text) {
+ uint16 w = 0;
+ if (!text)
+ return 0;
+ while (*text)
+ w += _widthArr[(unsigned char)*(text++)];
+ return w;
+}
+
+Talk::Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode, ColorBank color, bool wideSpace)
+ : Sprite(vm), _mode(mode), _created(false), _wideSpace(wideSpace), _vm(vm) {
+ _color = _vm->_font->_colorSet[color];
+
+ if (color == kCBRel)
+ _vm->setAutoColors();
+ update(text);
+}
+
+Talk::Talk(CGE2Engine *vm, ColorBank color)
+ : Sprite(vm), _mode(kTBPure), _created(false), _wideSpace(false), _vm(vm) {
+ _color = _vm->_font->_colorSet[color];
+
+ if (color == kCBRel)
+ _vm->setAutoColors();
+}
+
+uint8 *Talk::box(V2D siz) {
+ uint16 n, r = (_mode == kTBRound) ? kTextRoundCorner : 0;
+ const byte lt = _color[1], bg = _color[2], dk = _color[3];
+
+ if (siz.x < 8)
+ siz.x = 8;
+ if (siz.y < 8)
+ siz.y = 8;
+ uint8 *b = new uint8[n = siz.area()];
+ memset(b, bg, n);
+
+ if (_mode) {
+ uint8 *p = b;
+ uint8 *q = b + n - siz.x;
+ memset(p, lt, siz.x);
+ memset(q, dk, siz.x);
+ while (p < q) {
+ p += siz.x;
+ *(p - 1) = dk;
+ *p = lt;
+ }
+ p = b;
+ for (int i = 0; i < r; i++) {
+ int j = 0;
+ for (; j < r - i; j++) {
+ p[j] = kPixelTransp;
+ p[siz.x - j - 1] = kPixelTransp;
+ q[j] = kPixelTransp;
+ q[siz.x - j - 1] = kPixelTransp;
+ }
+ p[j] = lt;
+ p[siz.x - j - 1] = dk;
+ q[j] = lt;
+ q[siz.x - j - 1] = dk;
+ p += siz.x;
+ q -= siz.x;
+ }
+ }
+ return b;
+}
+
+void Talk::update(const char *text) {
+ const uint16 vmarg = (_mode) ? kTextVMargin : 0;
+ const uint16 hmarg = (_mode) ? kTextHMargin : 0;
+ uint16 mw;
+ uint16 mh;
+ uint16 ln = vmarg;
+ uint8 *m;
+ uint8 *map;
+ uint8 fg = _color[0];
+
+ if (_created) {
+ mw = _ext->_shpList->_w;
+ mh = _ext->_shpList->_h;
+ delete _ext->_shpList;
+ } else {
+ uint16 k = 2 * hmarg;
+ mh = 2 * vmarg + kFontHigh;
+ mw = 0;
+ for (const char *p = text; *p; p++) {
+ if ((*p == '|') || (*p == '\n')) {
+ mh += kFontHigh + kTextLineSpace;
+ if (k > mw)
+ mw = k;
+ k = 2 * hmarg;
+ } else if ((*p == 0x20) && (_vm->_font->_widthArr[(unsigned char)*p] > 4) && (!_wideSpace))
+ k += _vm->_font->_widthArr[(unsigned char)*p] - 2;
+ else
+ k += _vm->_font->_widthArr[(unsigned char)*p];
+ }
+ if (k > mw)
+ mw = k;
+
+ _created = true;
+ }
+
+ V2D sz(_vm, mw, mh);
+ map = box(sz);
+
+ m = map + ln * mw + hmarg;
+
+ while (*text) {
+ if ((*text == '|') || (*text == '\n'))
+ m = map + (ln += kFontHigh + kTextLineSpace) * mw + hmarg;
+ else {
+ int cw = _vm->_font->_widthArr[(unsigned char)*text];
+ uint8 *f = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text];
+
+ // Handle properly space size, after it was enlarged to display properly
+ // 'F1' text.
+ int8 fontStart = 0;
+ if ((*text == 0x20) && (cw > 4) && (!_wideSpace))
+ fontStart = 2;
+
+ for (int i = fontStart; i < cw; i++) {
+ uint8 *pp = m;
+ uint16 n;
+ uint16 b = *(f++);
+ for (n = 0; n < kFontHigh; n++) {
+ if (b & 1)
+ *pp = fg;
+ b >>= 1;
+ pp += mw;
+ }
+ m++;
+ }
+ }
+ text++;
+ }
+ BitmapPtr b = new Bitmap[1];
+ b[0] = Bitmap(_vm, sz.x, sz.y, map);
+ delete[] map;
+ setShapeList(b, 1);
+}
+
+InfoLine::InfoLine(CGE2Engine *vm, uint16 w, ColorBank color)
+: Talk(vm), _oldText(nullptr), _newText(nullptr), _realTime(false), _vm(vm) {
+ _wideSpace = false;
+ BitmapPtr b = new Bitmap[1];
+ if (color == kCBRel)
+ _vm->setAutoColors();
+ _color = _vm->_font->_colorSet[color];
+ V2D siz = V2D(_vm, w, kFontHigh);
+ b[0] = Bitmap(_vm, siz.x, siz.y, _color[2]);
+ setShapeList(b, 1);
+}
+
+void InfoLine::update(const char *text) {
+ if (!_realTime && (text == _oldText))
+ return;
+
+ _oldText = text;
+
+ uint16 w = _ext->_shpList->_w;
+ uint16 h = _ext->_shpList->_h;
+ uint8 *v = _ext->_shpList->_v;
+ uint16 dsiz = w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = h * lsiz; // - last gape, but + plane trailer
+ uint16 size = 4 * psiz; // whole map size
+ uint8 fg = _color[0];
+ uint8 bg = _color[2];
+
+ // clear whole rectangle
+ memset(v + 2, bg, dsiz); // data bytes
+ for (byte *pDest = v + lsiz; pDest < (v + psiz); pDest += lsiz) {
+ Common::copy(v, v + lsiz, pDest);
+ }
+ *(uint16 *)(v + psiz - 2) = TO_LE_16(kBmpEOI); // plane trailer uint16
+ for (byte *pDest = v + psiz; pDest < (v + 4 * psiz); pDest += psiz) {
+ Common::copy(v, v + psiz, pDest);
+ }
+
+ // paint text line
+ if (_newText) {
+ uint8 *p = v + 2, *q = p + size;
+
+ while (*text) {
+ uint16 cw = _vm->_font->_widthArr[(unsigned char)*text];
+ uint8 *fp = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text];
+
+ // Handle properly space size, after it was enlarged to display properly
+ // 'F1' text.
+ int8 fontStart = 0;
+ if ((*text == 0x20) && (cw > 4) && (!_wideSpace))
+ fontStart = 2;
+
+ for (int i = fontStart; i < cw; i++) {
+ uint16 b = fp[i];
+ for (uint16 n = 0; n < kFontHigh; n++) {
+ if (b & 1)
+ *p = fg;
+ b >>= 1;
+ p += lsiz;
+ }
+ if (p >= q)
+ p = p - size + 1;
+ }
+ text++;
+ }
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/talk.h b/engines/cge2/talk.h
new file mode 100644
index 0000000000..d7484655cc
--- /dev/null
+++ b/engines/cge2/talk.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_TALK_H
+#define CGE2_TALK_H
+
+#include "cge2/general.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+#define kTextHMargin (6&~1) // EVEN horizontal margins!
+#define kTextVMargin 5 // vertical margins
+#define kTextLineSpace 2 // line spacing
+#define kTextRoundCorner 3 // rounded corners
+#define kWidSize 256
+#define kPosSize 256
+#define kMapSize (256*8)
+#define kFontHigh 8
+#define kCaptionSide 24
+#define kInfName 101
+#define kSayName 102
+
+class Font {
+ void load();
+ CGE2Engine *_vm;
+public:
+ uint8 *_widthArr;
+ uint16 *_pos;
+ uint8 *_map;
+ uint8 _colorSet[kColorNum][4];
+ Font(CGE2Engine *vm);
+ ~Font();
+ uint16 width(const char *text);
+};
+
+enum TextBoxStyle { kTBPure, kTBRect, kTBRound };
+
+class Talk : public Sprite {
+protected:
+ TextBoxStyle _mode;
+ bool _created;
+ uint8 *box(V2D siz);
+ bool _wideSpace;
+public:
+ uint8 *_color;
+
+ Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode = kTBPure, ColorBank color = kCBStd, bool wideSpace = false);
+ Talk(CGE2Engine *vm, ColorBank color = kCBStd);
+
+ void update(const char *text);
+private:
+ CGE2Engine *_vm;
+};
+
+class InfoLine : public Talk {
+ const char *_oldText, *_newText;
+public:
+ bool _realTime;
+ InfoLine(CGE2Engine *vm, uint16 wid, ColorBank color = kCBStd);
+ void update(const char *text);
+ void update() { update(_newText); }
+ void setText(const char *txt) { _newText = txt; }
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_TALK_H
diff --git a/engines/cge2/text.cpp b/engines/cge2/text.cpp
new file mode 100644
index 0000000000..d51c04843d
--- /dev/null
+++ b/engines/cge2/text.cpp
@@ -0,0 +1,197 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/text.h"
+#include "common/str.h"
+
+namespace CGE2 {
+
+Text::Text(CGE2Engine *vm, const char *fname) : _vm(vm) {
+ _vm->mergeExt(_fileName, fname, kSayExt);
+ if (!_vm->_resman->exist(_fileName))
+ error("No talk (%s)", _fileName);
+ _txtCount = count();
+ if (_txtCount == -1)
+ error("Unable to read dialog file %s", _fileName);
+
+ _txtCount += 2;
+ _cache = new Handler[_txtCount];
+ for (_size = 0; _size < _txtCount; _size++) {
+ _cache[_size]._ref = 0;
+ _cache[_size]._text = nullptr;
+ }
+ load();
+
+ _cache[_txtCount - 1]._ref = -1;
+ _cache[_txtCount - 1]._text = new char[3];
+ strcpy(_cache[_txtCount - 1]._text, "");
+}
+
+Text::~Text() {
+ clear();
+ delete[] _cache;
+}
+
+int16 Text::count() {
+ EncryptedStream tf(_vm, _fileName);
+ if (tf.err())
+ return -1;
+
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+
+ int counter = 0;
+
+ for (line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
+ char *s;
+ assert(line.size() <= 513);
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr)
+ continue;
+ if (!Common::isDigit(*s))
+ continue;
+
+ counter++;
+ }
+ return counter;
+}
+
+void Text::clear() {
+ for (int i = 0; i < _txtCount; i++) {
+ if (_cache[i]._ref) {
+ _cache[i]._ref = 0;
+ delete[] _cache[i]._text;
+ _cache[i]._text = nullptr;
+ }
+ }
+}
+
+void Text::load() {
+ EncryptedStream tf(_vm, _fileName);
+ assert(!tf.err());
+
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+ int idx;
+
+ for (idx = 0, line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
+ int n = line.size();
+ char *s;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr)
+ continue;
+ if (!Common::isDigit(*s))
+ continue;
+
+ int r = _vm->number(s);
+
+ s += strlen(s);
+ if (s < tmpStr + n)
+ ++s;
+
+ _cache[idx]._ref = r;
+ _cache[idx]._text = new char[strlen(s) + 1];
+ strcpy(_cache[idx]._text, s);
+ idx++;
+ }
+}
+
+char *Text::getText(int ref) {
+ int i;
+ for (i = 0; (i < _size) && (_cache[i]._ref != ref); i++)
+ ;
+
+ if (i < _size)
+ return _cache[i]._text;
+
+ warning("getText: Unable to find ref %d:%d", ref / 256, ref % 256);
+ return nullptr;
+}
+
+void Text::say(const char *text, Sprite *spr) {
+ _vm->killText();
+
+ _vm->_talk = new Talk(_vm, text, kTBRound, kCBSay);
+
+ Speaker *speaker = new Speaker(_vm);
+
+ bool east = spr->_flags._east;
+ V2D d(_vm, 20, spr->_siz.y - 2);
+ if (!east)
+ d.x = -d.x;
+ if (_vm->isHero(spr))
+ d = d.scale(spr->_pos3D._z.trunc());
+ V2D pos = spr->_pos2D + d;
+ uint16 sw = (speaker->_siz.x >> 1);
+ if (!east)
+ sw = -sw;
+
+ if (east) {
+ if (pos.x + sw + kTextRoundCorner + kCaptionSide >= kScrWidth)
+ east = false;
+ } else if (pos.x <= kCaptionSide + kTextRoundCorner - sw)
+ east = true;
+
+ if (east != (d.x > 0)) {
+ d.x = -d.x;
+ sw = -sw;
+ }
+ pos.x = spr->_pos2D.x + d.x + sw;
+
+ _vm->_talk->_flags._kill = true;
+ _vm->_talk->setName(getText(kSayName));
+ _vm->_talk->gotoxyz(pos.x, pos.y + speaker->_siz.y - 1, 0);
+
+ speaker->gotoxyz(pos.x, _vm->_talk->_pos3D._y.trunc() - speaker->_siz.y + 1, 0);
+ speaker->_flags._slav = true;
+ speaker->_flags._kill = true;
+ speaker->setName(getText(kSayName));
+ speaker->step(east);
+
+ _vm->_vga->_showQ->append(_vm->_talk);
+ _vm->_vga->_showQ->append(speaker);
+}
+
+void CGE2Engine::inf(const char *text, ColorBank col) {
+ killText();
+ _talk = new Talk(this, text, kTBRect, col, true);
+ _talk->_flags._kill = true;
+ _talk->setName(_text->getText(kInfName));
+ _talk->center();
+ _vga->_showQ->append(_talk);
+}
+
+void Text::sayTime(Sprite *spr) {
+ TimeDate curTime;
+ _vm->_system->getTimeAndDate(curTime);
+
+ char t[6];
+ snprintf(t, 6, "%d:%02d", curTime.tm_hour, curTime.tm_min);
+ say(t, spr);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/text.h b/engines/cge2/text.h
new file mode 100644
index 0000000000..88ed501158
--- /dev/null
+++ b/engines/cge2/text.h
@@ -0,0 +1,68 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_TEXT_H
+#define CGE2_TEXT_H
+
+#include "cge2/talk.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kSayExt ".SAY"
+#define kSysTextMax 1000
+#define kTextNoMouse 95
+#define kInfName 101
+#define kSayName 102
+#define kInfRef 301
+#define kSayRef 302
+
+
+class Text {
+ struct Handler {
+ int _ref;
+ char *_text;
+ } *_cache;
+ int _size;
+ int16 _txtCount;
+ char _fileName[kPathMax];
+ void load();
+ int16 count();
+public:
+ Text(CGE2Engine *vm, const char *fname);
+ ~Text();
+ void clear();
+ char *getText(int ref);
+ void say(const char *text, Sprite *spr);
+ void sayTime(Sprite *spr);
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_TEXT_H
diff --git a/engines/cge2/toolbar.cpp b/engines/cge2/toolbar.cpp
new file mode 100644
index 0000000000..6af64b1f5c
--- /dev/null
+++ b/engines/cge2/toolbar.cpp
@@ -0,0 +1,225 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "sound.h"
+#include "common/config-manager.h"
+#include "cge2/cge2.h"
+#include "cge2/events.h"
+#include "cge2/vmenu.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+#define kSoundNumtoStateRate 25.7
+// == 257 / 10; where 10 equals to the volume switches' number of states [0..9]
+// and ScummVM has a scale of 257 different values for setting sounds.
+
+#define kSoundStatetoNumRate 28.45
+// == 256 / 9 + 0.1; where 256 is the positive range of numbers we can set the volume to
+// and the 10 states of a switch cut this range up to 9 equally big parts.
+// We don't take into account 0 regarding the 256 different values (it would be the 257th),
+// since 0 * x == 0.
+// 0.1 is only for correct rounding at the 10th state.
+
+void CGE2Engine::optionTouch(int opt, uint16 mask) {
+ bool notMuted = !ConfMan.getBool("mute");
+ switch (opt) {
+ case 1:
+ if (mask & kMouseLeftUp)
+ switchColorMode();
+ break;
+ case 2:
+ if ((mask & kMouseLeftUp) && notMuted)
+ switchMusic();
+ break;
+ case 3:
+ if (mask & kMouseLeftUp)
+ quit();
+ break;
+ case 4:
+ if ((mask & (kMouseLeftUp | kMouseRightUp)) && notMuted)
+ setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1);
+ break;
+ case 5:
+ if ((mask & (kMouseLeftUp | kMouseRightUp)) && notMuted)
+ setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1);
+ break;
+ case 8:
+ if ((mask & kMouseLeftUp) && notMuted)
+ switchCap();
+ break;
+ case 9:
+ if ((mask & kMouseLeftUp) && notMuted)
+ switchVox();
+ break;
+ default:
+ break;
+ }
+}
+
+void CGE2Engine::switchColorMode() {
+ _commandHandlerTurbo->addCommand(kCmdSeq, 121, _vga->_mono = !_vga->_mono, nullptr);
+ ConfMan.setBool("enable_color_blind", _vga->_mono);
+ ConfMan.flushToDisk();
+ keyClick();
+ _vga->setColors(_vga->_sysPal, 64);
+}
+
+void CGE2Engine::switchMusic() {
+ _music = !_music;
+ _mixer->muteSoundType(Audio::Mixer::kMusicSoundType, !_music);
+ _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr);
+ keyClick();
+ _commandHandlerTurbo->addCommand(kCmdMidi, -1, _music ? (_now << 8) : -1, nullptr);
+}
+
+void CGE2Engine::quit() {
+ if (_commandHandler->idle()) {
+ if (VMenu::_addr) {
+ _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, VMenu::_addr);
+ ReturnToGameChoice rqsChoice(this);
+ rqsChoice.proc();
+ } else {
+ Common::Array<Choice *> quitMenu; // Deleted in VMenu's destructor.
+ quitMenu.push_back(new ExitGameChoice(this));
+ quitMenu.push_back(new ReturnToGameChoice(this));
+ (new VMenu(this, quitMenu, V2D(this, -1, -1), kCBMnu))->setName(_text->getText(kQuitTitle));
+ _commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 0, nullptr);
+ keyClick();
+ }
+ }
+}
+
+void CGE2Engine::setVolume(int idx, int cnt) {
+ if (cnt && _vol[idx]) {
+ int p = _vol[idx]->_seqPtr + cnt;
+ if ((p >= 0) && (p < _vol[idx]->_seqCnt)) {
+ _vol[idx]->step(p);
+ int newVolume = p * kSoundStatetoNumRate;
+ switch (idx) {
+ case 0:
+ _oldSfxVolume = ConfMan.getInt("sfx_volume");
+ ConfMan.setInt("sfx_volume", newVolume);
+ break;
+ case 1:
+ _oldMusicVolume = ConfMan.getInt("music_volume");
+ ConfMan.setInt("music_volume", newVolume);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void CGE2Engine::checkVolumeSwitches() {
+ int musicVolume = ConfMan.getInt("music_volume");
+ if (musicVolume != _oldMusicVolume)
+ _vol[1]->step(musicVolume / kSoundNumtoStateRate);
+
+ int sfxVolume = ConfMan.getInt("sfx_volume");
+ if (sfxVolume != _oldSfxVolume)
+ _vol[0]->step(sfxVolume / kSoundNumtoStateRate);
+}
+
+void CGE2Engine::switchCap() {
+ _sayCap = !_sayCap;
+ if (!_sayCap)
+ _sayVox = true;
+ keyClick();
+ switchSay();
+}
+
+void CGE2Engine::switchVox() {
+ _sayVox = !_sayVox;
+ _mixer->muteSoundType(Audio::Mixer::kSpeechSoundType, _sayVox);
+ if (!_sayVox)
+ _sayCap = true;
+ keyClick();
+ switchSay();
+}
+
+void CGE2Engine::switchSay() {
+ _commandHandlerTurbo->addCommand(kCmdSeq, 129, _sayVox, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdSeq, 128, _sayCap, nullptr);
+}
+
+void CGE2Engine::initToolbar() {
+ selectPocket(-1);
+
+ _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr);
+ if (!_music)
+ _midiPlayer->killMidi();
+
+ switchSay();
+
+ _infoLine->gotoxyz(V3D(kInfoX, kInfoY, 0));
+ _infoLine->setText(nullptr);
+ _vga->_showQ->insert(_infoLine);
+
+ _gamePhase = kPhaseInGame;
+ _mouse->center();
+ _mouse->off();
+ _mouse->on();
+
+ _keyboard->setClient(_sys);
+ _commandHandler->addCommand(kCmdSeq, kPowerRef, 1, nullptr);
+
+ _busyPtr = _vga->_showQ->locate(kBusyRef);
+
+ _vol[0] = _vga->_showQ->locate(kDvolRef);
+ _vol[1] = _vga->_showQ->locate(kMvolRef);
+
+ if (_vol[0]) {
+ int val = ConfMan.getInt("sfx_volume");
+ initVolumeSwitch(_vol[0], val);
+ }
+
+ if (_vol[1]) {
+ int val = ConfMan.getInt("music_volume");
+ initVolumeSwitch(_vol[1], val);
+ }
+}
+
+void CGE2Engine::initVolumeSwitch(Sprite *volSwitch, int val) {
+ int state = 0;
+ state = val / kSoundNumtoStateRate;
+ volSwitch->step(state);
+}
+
+void CGE2Engine::checkMute() {
+ bool mute = ConfMan.getBool("mute");
+ bool mutedChanged = mute != _muteAll;
+ if (mutedChanged) {
+ switchMusic();
+ switchVox();
+ _muteAll = mute;
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
new file mode 100644
index 0000000000..db96682237
--- /dev/null
+++ b/engines/cge2/vga13h.cpp
@@ -0,0 +1,1218 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/array.h"
+#include "common/config-manager.h"
+#include "common/rect.h"
+#include "graphics/palette.h"
+#include "cge2/general.h"
+#include "cge2/vga13h.h"
+#include "cge2/bitmap.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+void V3D::sync(Common::Serializer &s) {
+ _x.sync(s);
+ _y.sync(s);
+ _z.sync(s);
+}
+
+FXP FXP::operator*(const FXP& x) const {
+ FXP y;
+ int32 t1 = (v >> 8) * x.v;
+ int32 t2 = ((v & 0xFF) * x.v) >> 8;
+
+ y.v = t1 + t2;
+ return y;
+}
+
+FXP FXP::operator/(const FXP& x) const {
+ FXP y;
+ if (x.v != 0) {
+ int32 v1 = this->v;
+ int32 v2 = x.v;
+ bool negFlag = false;
+
+ if (v1 < 0) {
+ v1 = -v1;
+ negFlag = true;
+ }
+ if (v2 < 0) {
+ v2 = -v2;
+ negFlag ^= true;
+ }
+
+ int32 v3 = v1 / v2;
+ v1 -= v3 * v2;
+ v3 <<= 8;
+
+ if (v1 < 0xFFFFFF)
+ v1 <<= 8;
+ else
+ v2 >>= 8;
+
+ v3 += v1 / v2;
+
+ if (negFlag)
+ v3 = -v3;
+
+ y.v = v3;
+ }
+
+ return y;
+}
+
+void FXP::sync(Common::Serializer &s) {
+ s.syncAsSint32LE(v);
+}
+
+Seq *getConstantSeq(bool seqFlag) {
+ const Seq seq1[] = { { 0, 0, 0, 0, 0, 0 } };
+ const Seq seq2[] = { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0 } };
+
+ Seq *seq;
+ if (seqFlag) {
+ seq = (Seq *)malloc(1 * sizeof(Seq));
+ *seq = seq1[0];
+ } else {
+ seq = (Seq *)malloc(2 * sizeof(Seq));
+ seq[0] = seq2[0];
+ seq[1] = seq2[1];
+ }
+
+ return seq;
+}
+
+byte Sprite::_constY = 0;
+byte Sprite::_follow = 0;
+
+Seq Sprite::_stdSeq8[] =
+{ { 0, 0, 0, 0, 0, 0 },
+ { 1, 1, 0, 0, 0, 0 },
+ { 2, 2, 0, 0, 0, 0 },
+ { 3, 3, 0, 0, 0, 0 },
+ { 4, 4, 0, 0, 0, 0 },
+ { 5, 5, 0, 0, 0, 0 },
+ { 6, 6, 0, 0, 0, 0 },
+ { 7, 7, 0, 0, 0, 0 },
+};
+
+SprExt::SprExt(CGE2Engine *vm)
+ : _p0(vm, 0, 0), _p1(vm, 0, 0),
+ _b0(nullptr), _b1(nullptr), _shpList(nullptr),
+ _location(0), _seq(nullptr), _name(nullptr) {
+ for (int i = 0; i < kActions; i++)
+ _actions[i] = nullptr;
+}
+
+Sprite::Sprite(CGE2Engine *vm)
+ : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0),
+ _next(nullptr), _prev(nullptr), _time(0),
+ _ext(nullptr), _ref(-1), _scene(0), _vm(vm),
+ _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) {
+ memset(_actionCtrl, 0, sizeof(_actionCtrl));
+ memset(_file, 0, sizeof(_file));
+ memset(&_flags, 0, sizeof(_flags));
+ _flags._frnt = 1;
+}
+
+Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt)
+ : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0),
+ _next(nullptr), _prev(nullptr), _time(0),
+ _ext(nullptr), _ref(-1), _scene(0), _vm(vm),
+ _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) {
+ memset(_actionCtrl, 0, sizeof(_actionCtrl));
+ memset(_file, 0, sizeof(_file));
+ memset(&_flags, 0, sizeof(_flags));
+ _flags._frnt = 1;
+
+ setShapeList(shpP, cnt);
+}
+
+Sprite::~Sprite() {
+ contract();
+}
+
+BitmapPtr Sprite::getShp() {
+ SprExt *e = _ext;
+ if (!e || !e->_seq)
+ return nullptr;
+
+ int i = e->_seq[_seqPtr]._now;
+ if (i >= _shpCnt)
+ error("Invalid PHASE in SPRITE::Shp() %s - %d", _file, i);
+ return e->_shpList + i;
+}
+
+void Sprite::setShapeList(BitmapPtr shp, int cnt) {
+ _shpCnt = cnt;
+ _siz.x = 0;
+ _siz.y = 0;
+
+ if (shp) {
+ for (int i = 0; i < cnt; i++) {
+ BitmapPtr p = shp + i;
+ if (p->_w > _siz.x)
+ _siz.x = p->_w;
+ if (p->_h > _siz.y)
+ _siz.y = p->_h;
+ }
+ expand();
+ _ext->_shpList = shp;
+ if (!_ext->_seq) {
+ setSeq(_stdSeq8);
+ _seqCnt = (cnt < ARRAYSIZE(_stdSeq8)) ? cnt : ARRAYSIZE(_stdSeq8);
+ }
+ }
+}
+
+Seq *Sprite::setSeq(Seq *seq) {
+ expand();
+
+ Seq *s = _ext->_seq;
+ _ext->_seq = seq;
+ if (_seqPtr == kNoSeq)
+ step(0);
+ else if (_time == 0)
+ step(_seqPtr);
+ return s;
+}
+
+bool Sprite::seqTest(int n) {
+ if (n >= 0)
+ return (_seqPtr == n);
+ if (_ext)
+ return (_ext->_seq[_seqPtr]._next == _seqPtr);
+ return true;
+}
+
+void Sprite::setName(char *newName) {
+ if (!_ext)
+ return;
+
+ if (_ext->_name) {
+ delete[] _ext->_name;
+ _ext->_name = nullptr;
+ }
+ if (newName) {
+ _ext->_name = new char[strlen(newName) + 1];
+ strcpy(_ext->_name, newName);
+ }
+}
+
+int Sprite::labVal(Action snq, int lab) {
+ int lv = -1;
+ if (active()) {
+ int count = _actionCtrl[snq]._cnt;
+ CommandHandler::Command *com = snList(snq);
+
+ int i = 0;
+ for (; i < count; i++) {
+ if (com[i]._lab == lab)
+ break;
+ }
+
+ if (i < count)
+ return i;
+ } else {
+ char tmpStr[kLineMax + 1];
+ _vm->mergeExt(tmpStr, _file, kSprExt);
+
+ if (_vm->_resman->exist(tmpStr)) { // sprite description file exist
+ EncryptedStream sprf(_vm, tmpStr);
+ if (sprf.err())
+ error("Bad SPR [%s]", tmpStr);
+
+ int cnt = 0;
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+
+ while (lv == -1 && !sprf.eos()) {
+ line = sprf.readLine();
+ if (line.empty())
+ continue;
+
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p;
+ p = _vm->token(tmpStr);
+
+ if (*p == '@') {
+ if ((int)section == (int)snq && atoi(p + 1) == lab)
+ lv = cnt;
+ } else {
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdMTake:
+ case kIdFTake:
+ case kIdNear:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ default:
+ if (id < 0 && (int)section == (int)snq)
+ ++cnt;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return lv;
+}
+
+CommandHandler::Command *Sprite::snList(Action type) {
+ SprExt *e = _ext;
+ return (e) ? e->_actions[type] : nullptr;
+}
+
+Sprite *Sprite::expand() {
+ if (_ext)
+ return this;
+
+ if (_vm->_spriteNotify != nullptr)
+ (_vm->*_vm->_spriteNotify)();
+
+ char fname[kPathMax];
+ _vm->mergeExt(fname, _file, kSprExt);
+
+ if (_ext != nullptr)
+ delete _ext;
+ _ext = new SprExt(_vm);
+
+ if (!*_file)
+ return this;
+
+ BitmapPtr shplist = new Bitmap[_shpCnt];
+
+ int cnt[kActions],
+ shpcnt = 0,
+ seqcnt = 0,
+ maxnow = 0,
+ maxnxt = 0;
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ for (int i = 0; i < kActions; i++){
+ byte n = _actionCtrl[i]._cnt;
+ if (n)
+ _ext->_actions[i] = new CommandHandler::Command[n];
+ else
+ _ext->_actions[i] = nullptr;
+ }
+
+ Seq *curSeq = nullptr;
+ if (_seqCnt)
+ curSeq = new Seq[_seqCnt];
+
+ if (_vm->_resman->exist(fname)) { // sprite description file exist
+ EncryptedStream sprf(_vm, fname);
+ if (sprf.err())
+ error("Bad SPR [%s]", fname);
+
+ int label = kNoByte;
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) {
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = _vm->token(tmpStr);
+ if (*p == '@') {
+ label = atoi(p + 1);
+ continue;
+ }
+
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdType:
+ break;
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ case kIdName:
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ for (p = tmpStr; *p != '='; p++); // We search for the =
+ setName(_vm->tail(p));
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ Seq *s;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ id = (ID)_vm->_commandHandler->getComId(p);
+ if (_actionCtrl[section]._cnt) {
+ CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++];
+ c->_commandType = CommandType(id);
+ c->_lab = label;
+ c->_ref = _vm->number(nullptr);
+ c->_val = _vm->number(nullptr);
+ c->_spritePtr = nullptr;
+ }
+ break;
+ case kIdSeq:
+ s = &curSeq[seqcnt++];
+ s->_now = atoi(p);
+ if (s->_now > maxnow)
+ maxnow = s->_now;
+ s->_next = _vm->number(nullptr);
+ switch (s->_next) {
+ case 0xFF:
+ s->_next = seqcnt;
+ break;
+ case 0xFE:
+ s->_next = seqcnt - 1;
+ break;
+ }
+ if (s->_next > maxnxt)
+ maxnxt = s->_next;
+ s->_dx = _vm->number(nullptr);
+ s->_dy = _vm->number(nullptr);
+ s->_dz = _vm->number(nullptr);
+ s->_dly = _vm->number(nullptr);
+ break;
+ case kIdPhase:
+ shplist[shpcnt] = Bitmap(_vm, p);
+ shpcnt++;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ label = kNoByte;
+ }
+
+ if (!shpcnt)
+ error("No shapes - %s", fname);
+ } else // no sprite description: try to read immediately from .BMP
+ shplist[shpcnt++] = Bitmap(_vm, _file);
+
+ if (curSeq) {
+ if (maxnow >= shpcnt)
+ error("Bad PHASE in SEQ %s", fname);
+ if (maxnxt && (maxnxt >= seqcnt))
+ error("Bad JUMP in SEQ %s", fname);
+ setSeq(curSeq);
+ } else {
+ setSeq(_stdSeq8);
+ _seqCnt = (shpcnt < ARRAYSIZE(_stdSeq8)) ? shpcnt : ARRAYSIZE(_stdSeq8);
+ }
+
+ setShapeList(shplist, shpcnt);
+
+ if (_file[2] == '~') { // FLY-type sprite
+ Seq *nextSeq = _ext->_seq;
+ int x = (nextSeq + 1)->_dx, y = (nextSeq + 1)->_dy, z = (nextSeq + 1)->_dz;
+ // random position
+ nextSeq->_dx = _vm->newRandom(x + x) - x;
+ nextSeq->_dy = _vm->newRandom(y + y) - y;
+ nextSeq->_dz = _vm->newRandom(z + z) - z;
+ gotoxyz(_pos3D + V3D(nextSeq->_dx, nextSeq->_dy, nextSeq->_dz));
+ }
+
+ return this;
+}
+
+Sprite *Sprite::contract() {
+ SprExt *e = _ext;
+ if (!e)
+ return this;
+
+ if (_file[2] == '~') { // FLY-type sprite
+ Seq *curSeq = _ext->_seq;
+ // return to middle
+ gotoxyz(_pos3D - V3D(curSeq->_dx, curSeq->_dy, curSeq->_dz));
+ curSeq->_dx = curSeq->_dy = curSeq->_dz = 0;
+ }
+
+ if (_vm->_spriteNotify != nullptr)
+ (_vm->*_vm->_spriteNotify)();
+
+ if (e->_name) {
+ delete[] e->_name;
+ e->_name = nullptr;
+ }
+
+ if (e->_shpList) {
+ for (int i = 0; i < _shpCnt; i++)
+ e->_shpList[i].release();
+ delete[] e->_shpList;
+ e->_shpList = nullptr;
+ }
+
+ if (e->_seq) {
+ if (e->_seq == _stdSeq8)
+ _seqCnt = 0;
+ else {
+ delete[] e->_seq;
+ e->_seq = nullptr;
+ }
+ }
+
+ for (int i = 0; i < kActions; i++) {
+ if (e->_actions[i]) {
+ delete[] e->_actions[i];
+ e->_actions[i] = nullptr;
+ }
+ }
+
+ delete _ext;
+ _ext = nullptr;
+
+ return this;
+}
+
+void Sprite::backShow() {
+ expand();
+ show(2);
+ show(1);
+ _vm->_spare->dispose(this);
+}
+
+void Sprite::step(int nr) {
+ if (nr >= 0)
+ _seqPtr = nr;
+
+ if (_ext && _ext->_seq) {
+ V3D p = _pos3D;
+ Seq *seq = nullptr;
+
+ if (nr < 0)
+ _seqPtr = _ext->_seq[_seqPtr]._next;
+
+ if (_file[2] == '~') { // FLY-type sprite
+ seq = _ext->_seq;
+ // return to middle
+ p._x -= seq->_dx;
+ p._y -= seq->_dy;
+ p._z -= seq->_dz;
+ // generate motion
+ if (_vm->newRandom(10) < 5) {
+ if ((seq + 1)->_dx)
+ seq->_dx += _vm->newRandom(3) - 1;
+ if ((seq + 1)->_dy)
+ seq->_dy += _vm->newRandom(3) - 1;
+ if ((seq + 1)->_dz)
+ seq->_dz += _vm->newRandom(3) - 1;
+ }
+ if (seq->_dx < -(seq + 1)->_dx)
+ seq->_dx += 2;
+ if (seq->_dx >= (seq + 1)->_dx)
+ seq->_dx -= 2;
+ if (seq->_dy < -(seq + 1)->_dy)
+ seq->_dy += 2;
+ if (seq->_dy >= (seq + 1)->_dy)
+ seq->_dy -= 2;
+ if (seq->_dz < -(seq + 1)->_dz)
+ seq->_dz += 2;
+ if (seq->_dz >= (seq + 1)->_dz)
+ seq->_dz -= 2;
+ p._x += seq->_dx;
+ p._y += seq->_dy;
+ p._z += seq->_dz;
+ gotoxyz(p);
+ } else {
+ seq = _ext->_seq + _seqPtr;
+ if (seq) {
+ if (seq->_dz == 127 && seq->_dx != 0) {
+ _vm->_commandHandlerTurbo->addCommand(kCmdSound, -1, 256 * seq->_dy + seq->_dx, this);
+ } else {
+ p._x += seq->_dx;
+ p._y += seq->_dy;
+ p._z += seq->_dz;
+ gotoxyz(p);
+ }
+ }
+ }
+ if (seq && (seq->_dly >= 0))
+ _time = seq->_dly;
+ } else if (_vm->_waitRef && _vm->_waitRef == _ref)
+ _vm->_waitRef = 0;
+}
+
+void Sprite::tick() {
+ step();
+}
+
+void Sprite::setScene(int c) {
+ _scene = c;
+}
+
+void Sprite::gotoxyz(int x, int y, int z) {
+ gotoxyz(V3D(x, y, z));
+}
+
+void Sprite::gotoxyz() {
+ gotoxyz(_pos3D);
+}
+
+void Sprite::gotoxyz(V2D pos) {
+ V2D o = _pos2D;
+ int ctr = _siz.x >> 1;
+ int rem = _siz.x - ctr;
+ byte trim = 0;
+
+ if (_ref / 10 == 14) { // HERO
+ int z = _pos3D._z.trunc();
+ ctr = (ctr * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+ rem = (rem * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+ ctr = (ctr * 3) / 4;
+ rem = (rem * 3) / 4;
+ }
+
+ if (pos.x - ctr < 0) {
+ pos.x = ctr;
+ ++trim;
+ }
+ if (pos.x + rem > kScrWidth) {
+ pos.x = kScrWidth - rem;
+ ++trim;
+ }
+ _pos2D.x = pos.x;
+
+ if (pos.y < -kPanHeight) {
+ pos.y = -kPanHeight;
+ ++trim;
+ }
+ if (pos.y + _siz.y > kWorldHeight) {
+ pos.y = kWorldHeight - _siz.y;
+ ++trim;
+ }
+ _pos2D.y = pos.y;
+
+ _flags._trim = (trim != 0);
+
+ if (!_follow) {
+ FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z);
+ _pos3D._x = (_vm->_eye->_x + (_vm->_eye->_x - _pos2D.x) / m);
+ _pos3D._x.round();
+
+ if (!_constY) {
+ _pos3D._y = _vm->_eye->_y + (_vm->_eye->_y - _pos2D.y) / m;
+ _pos3D._y.round();
+ }
+ }
+
+ if (_next && _next->_flags._slav)
+ _next->gotoxyz(_next->_pos2D - o + _pos2D);
+
+ if (_flags._shad)
+ _prev->gotoxyz(_prev->_pos2D - o + _pos2D);
+}
+
+void Sprite::gotoxyz_(V2D pos) {
+ _constY++;
+ gotoxyz(pos);
+ --_constY;
+}
+
+void Sprite::gotoxyz(V3D pos) {
+ _follow++;
+ if (pos._z != _pos3D._z)
+ _flags._zmov = true;
+ gotoxyz(V2D(_vm, _pos3D = pos));
+ --_follow;
+}
+
+void Sprite::center() {
+ gotoxyz(kScrWidth >> 1, (kWorldHeight - _siz.y) >> 1, 0);
+}
+
+void Sprite::show() {
+ SprExt *e = _ext;
+ if (e) {
+ e->_p0 = e->_p1;
+ e->_b0 = e->_b1;
+ e->_p1 = _pos2D;
+ e->_b1 = getShp();
+
+ if (!_flags._hide)
+ e->_b1->show(e->_p1);
+ }
+}
+
+void Sprite::show(uint16 pg) {
+ assert(pg < 4);
+ Graphics::Surface *a = _vm->_vga->_page[1];
+ _vm->_vga->_page[1] = _vm->_vga->_page[pg];
+ getShp()->show(_pos2D);
+ _vm->_vga->_page[1] = a;
+}
+
+void Sprite::hide() {
+ SprExt *e = _ext;
+ if (e->_b0)
+ e->_b0->hide(e->_p0);
+}
+
+BitmapPtr Sprite::ghost() {
+ SprExt *e = _ext;
+ if (!e->_b1)
+ return nullptr;
+
+ BitmapPtr bmp = new Bitmap(_vm, 0, 0, (uint8 *)nullptr);
+ bmp->_w = e->_b1->_w;
+ bmp->_h = e->_b1->_h;
+ bmp->_b = new HideDesc[bmp->_h];
+ memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc)* bmp->_h);
+ uint8 *v = new uint8[1];
+ *v = (e->_p1.y << 16) + e->_p1.x;
+ bmp->_v = v;
+ bmp->_map = (e->_p1.y << 16) + e->_p1.x;
+
+ return bmp;
+}
+
+void Sprite::sync(Common::Serializer &s) {
+ s.syncAsUint16LE(_ref);
+ s.syncAsByte(_scene);
+
+ // bitfield in-memory storage is unpredictable, so to avoid
+ // any issues, pack/unpack everything manually
+ uint16 flags = 0;
+ if (s.isLoading()) {
+ s.syncAsUint16LE(flags);
+ _flags._hide = flags & 0x0001;
+ _flags._drag = flags & 0x0002;
+ _flags._hold = flags & 0x0004;
+ _flags._trim = flags & 0x0008;
+ _flags._slav = flags & 0x0010;
+ _flags._kill = flags & 0x0020;
+ _flags._xlat = flags & 0x0040;
+ _flags._port = flags & 0x0080;
+ _flags._kept = flags & 0x0100;
+ _flags._frnt = flags & 0x0200;
+ _flags._east = flags & 0x0400;
+ _flags._near = flags & 0x0800;
+ _flags._shad = flags & 0x1000;
+ _flags._back = flags & 0x2000;
+ _flags._zmov = flags & 0x4000;
+ _flags._tran = flags & 0x8000;
+ } else {
+ flags = (flags << 1) | (_flags._tran ? 1 : 0);
+ flags = (flags << 1) | (_flags._zmov ? 1 : 0);
+ flags = (flags << 1) | (_flags._back ? 1 : 0);
+ flags = (flags << 1) | (_flags._shad ? 1 : 0);
+ flags = (flags << 1) | (_flags._near ? 1 : 0);
+ flags = (flags << 1) | (_flags._east ? 1 : 0);
+ flags = (flags << 1) | (_flags._frnt ? 1 : 0);
+ flags = (flags << 1) | (_flags._kept ? 1 : 0);
+ flags = (flags << 1) | (_flags._port ? 1 : 0);
+ flags = (flags << 1) | (_flags._xlat ? 1 : 0);
+ flags = (flags << 1) | (_flags._kill ? 1 : 0);
+ flags = (flags << 1) | (_flags._slav ? 1 : 0);
+ flags = (flags << 1) | (_flags._trim ? 1 : 0);
+ flags = (flags << 1) | (_flags._hold ? 1 : 0);
+ flags = (flags << 1) | (_flags._drag ? 1 : 0);
+ flags = (flags << 1) | (_flags._hide ? 1 : 0);
+ s.syncAsUint16LE(flags);
+ }
+
+ s.syncAsSint16LE(_pos2D.x);
+ s.syncAsSint16LE(_pos2D.y);
+
+ _pos3D.sync(s);
+
+ s.syncAsSint16LE(_siz.x);
+ s.syncAsSint16LE(_siz.y);
+
+ s.syncAsUint16LE(_time);
+ for (int i = 0; i < kActions; i++){
+ s.syncAsByte(_actionCtrl[i]._ptr);
+ s.syncAsByte(_actionCtrl[i]._cnt);
+ }
+ s.syncAsSint16LE(_seqPtr);
+ s.syncAsSint16LE(_seqCnt);
+ s.syncAsUint16LE(_shpCnt);
+ s.syncBytes((byte *)&_file[0], 9);
+ _file[8] = '\0';
+}
+
+Queue::Queue(bool show) : _head(nullptr), _tail(nullptr) {
+}
+
+void Queue::append(Sprite *spr) {
+ if (spr->_flags._back)
+ spr->backShow();
+ else {
+ spr->expand();
+ if (_tail) {
+ spr->_prev = _tail;
+ _tail->_next = spr;
+ } else
+ _head = spr;
+
+ _tail = spr;
+ }
+}
+
+void Queue::insert(Sprite *spr, Sprite *nxt) {
+ if (spr->_flags._back)
+ spr->backShow();
+ else {
+ spr->expand();
+ if (nxt == _head) {
+ spr->_next = _head;
+ _head = spr;
+ if (!_tail)
+ _tail = spr;
+ } else {
+ spr->_next = nxt;
+ spr->_prev = nxt->_prev;
+ if (spr->_prev)
+ spr->_prev->_next = spr;
+ }
+ if (spr->_next)
+ spr->_next->_prev = spr;
+ }
+}
+
+void Queue::insert(Sprite *spr) {
+ if (locate(spr))
+ return; // We only queue it if it's not already queued.
+
+ Sprite *s;
+ for (s = _head; s; s = s->_next) {
+ if (s->_pos3D._z < spr->_pos3D._z)
+ break;
+ }
+
+ if (s)
+ insert(spr, s);
+ else
+ append(spr);
+}
+
+Sprite *Queue::remove(Sprite *spr) {
+ if (spr == _head)
+ _head = spr->_next;
+
+ if (spr == _tail)
+ _tail = spr->_prev;
+
+ if (spr->_next)
+ spr->_next->_prev = spr->_prev;
+
+ if (spr->_prev)
+ spr->_prev->_next = spr->_next;
+
+ spr->_prev = nullptr;
+ spr->_next = nullptr;
+ return spr;
+}
+
+Sprite *Queue::locate(int ref) {
+ for (Sprite *spr = _head; spr; spr = spr->_next) {
+ if (spr->_ref == ref)
+ return spr;
+ }
+ return nullptr;
+}
+
+bool Queue::locate(Sprite *spr) {
+ Sprite *s;
+ for (s = _head; s; s = s->_next) {
+ if (s == spr)
+ return true;
+ }
+
+ return false;
+}
+
+Vga::Vga(CGE2Engine *vm) : _frmCnt(0), _msg(nullptr), _name(nullptr), _setPal(false), _vm(vm) {
+ _rot._org = 1;
+ _rot._len = 0;
+ _rot._cnt = 0;
+ _rot._dly = 1;
+
+ _oldColors = nullptr;
+ _newColors = nullptr;
+ _showQ = new Queue(true);
+ _sysPal = new Dac[kPalCount];
+
+ for (int idx = 0; idx < 4; idx++) {
+ _page[idx] = new Graphics::Surface();
+ _page[idx]->create(kScrWidth, kScrHeight, Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ _mono = ConfMan.getBool("enable_color_blind");
+
+ _oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ _newColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ getColors(_oldColors);
+ sunset();
+ setColors();
+ clear(0);
+}
+
+Vga::~Vga() {
+ Common::String buffer = "";
+
+ free(_oldColors);
+ free(_newColors);
+ if (_msg)
+ buffer = Common::String(_msg);
+
+ if (_name)
+ buffer = buffer + " [" + _name + "]";
+
+ debugN("%s", buffer.c_str());
+
+ delete _showQ;
+ delete[] _sysPal;
+
+ for (int idx = 0; idx < 4; idx++) {
+ _page[idx]->free();
+ delete _page[idx];
+ }
+}
+
+void Vga::waitVR() {
+ // Since some of the game parts rely on using vertical sync as a delay mechanism,
+ // we're introducing a short delay to simulate it
+ g_system->delayMillis(5);
+}
+
+void Vga::getColors(Dac *tab) {
+ byte palData[kPalSize];
+ g_system->getPaletteManager()->grabPalette(palData, 0, kPalCount);
+ palToDac(palData, tab);
+}
+
+uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) {
+#define f(col, lum) ((((uint16)(col)) << 8) / lum)
+ uint16 i, dif = 0xFFFF, found = 0;
+ uint16 L = colR + colG + colB;
+ if (!L)
+ L++;
+ uint16 R = f(colR, L), G = f(colG, L), B = f(colB, L);
+ for (i = 0; i < 256; i++) {
+ uint16 l = pal[i]._r + pal[i]._g + pal[i]._b;
+ if (!l)
+ l++;
+ int r = f(pal[i]._r, l), g = f(pal[i]._g, l), b = f(pal[i]._b, l);
+ 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 ;
+
+ if (D < dif) {
+ found = i;
+ dif = D;
+ if (D == 0)
+ break; // exact!
+ }
+ }
+ return found;
+#undef f
+}
+
+uint8 Vga::closest(Dac *pal, Dac x) {
+ int exp = (sizeof(long) * 8 - 1);
+ long D = (1 << exp) - 1; // Maximum value of long.
+ long R = x._r;
+ long G = x._g;
+ long B = x._b;
+ int idx = 255;
+ for (int n = 0; n < 256; n++) {
+ long dR = R - pal[n]._r;
+ long dG = G - pal[n]._g;
+ long dB = B - pal[n]._b,
+ d = dR * dR + dG * dG + dB * dB;
+ if (d < D) {
+ idx = n;
+ D = d;
+ if (!d)
+ break;
+ }
+ }
+ return idx;
+}
+
+uint8 *Vga::glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) {
+ uint8 *x = (uint8 *)malloc(256);
+ if (x) {
+ for (uint16 i = 0; i < 256; i++) {
+ x[i] = closest(pal, ((uint16)(pal[i]._r) * colR) / 255,
+ ((uint16)(pal[i]._g) * colG) / 255,
+ ((uint16)(pal[i]._b) * colB) / 255);
+ }
+ }
+ return x;
+}
+
+void Vga::palToDac(const byte *palData, Dac *tab) {
+ const byte *colP = palData;
+ for (int idx = 0; idx < kPalCount; idx++, colP += 3) {
+ tab[idx]._r = *colP >> 2;
+ tab[idx]._g = *(colP + 1) >> 2;
+ tab[idx]._b = *(colP + 2) >> 2;
+ }
+}
+
+void Vga::dacToPal(const Dac *tab, byte *palData) {
+ for (int idx = 0; idx < kPalCount; idx++, palData += 3) {
+ *palData = tab[idx]._r << 2;
+ *(palData + 1) = tab[idx]._g << 2;
+ *(palData + 2) = tab[idx]._b << 2;
+ }
+}
+
+void Vga::setColors(Dac *tab, int lum) {
+ Dac *palP = tab, *destP = _newColors;
+ for (int idx = 0; idx < kPalCount; idx++, palP++, destP++) {
+ destP->_r = (palP->_r * lum) >> 6;
+ destP->_g = (palP->_g * lum) >> 6;
+ destP->_b = (palP->_b * lum) >> 6;
+ }
+
+ if (_mono) {
+ destP = _newColors;
+ for (int idx = 0; idx < kPalCount; idx++, destP++) {
+ // Form a grayscale color from 30% R, 59% G, 11% B
+ uint8 intensity = (((int)destP->_r * 77) + ((int)destP->_g * 151) + ((int)destP->_b * 28)) >> 8;
+ destP->_r = intensity;
+ destP->_g = intensity;
+ destP->_b = intensity;
+ }
+ }
+
+ _setPal = true;
+}
+
+void Vga::setColors() {
+ memset(_newColors, 0, kPalSize);
+ updateColors();
+}
+
+void Vga::sunrise(Dac *tab) {
+ for (int i = 0; i <= 64; i += kFadeStep) {
+ setColors(tab, i);
+ waitVR();
+ updateColors();
+ g_system->updateScreen();
+ }
+}
+
+void Vga::sunset() {
+ Dac tab[256];
+ getColors(tab);
+ for (int i = 64; i >= 0; i -= kFadeStep) {
+ setColors(tab, i);
+ waitVR();
+ updateColors();
+ g_system->updateScreen();
+ }
+}
+
+void Vga::show() {
+ _vm->_infoLine->update();
+
+ for (Sprite *spr = _showQ->first(); spr; spr = spr->_next) {
+ spr->show();
+ }
+
+ _vm->_mouse->show();
+ update();
+ rotate();
+
+ for (Sprite *spr = _showQ->first(); spr; spr = spr->_next) {
+ spr->hide();
+ if (spr->_flags._zmov) {
+ Sprite *s = nullptr;
+ Sprite *p = spr->_prev;
+ Sprite *n = spr->_next;
+
+ if (spr->_flags._shad) {
+ s = p;
+ p = s->_prev;
+ }
+
+ if ((p && spr->_pos3D._z > p->_pos3D._z) ||
+ (n && spr->_pos3D._z < n->_pos3D._z)) {
+ _showQ->insert(_showQ->remove(spr));
+ }
+ spr->_flags._zmov = false;
+ }
+ }
+ _vm->_mouse->hide();
+}
+
+void Vga::updateColors() {
+ byte palData[kPalSize];
+ dacToPal(_newColors, palData);
+ g_system->getPaletteManager()->setPalette(palData, 0, 256);
+}
+
+void Vga::update() {
+ SWAP(Vga::_page[0], Vga::_page[1]);
+
+ if (_setPal) {
+ updateColors();
+ _setPal = false;
+ }
+
+ g_system->copyRectToScreen(Vga::_page[0]->getPixels(), kScrWidth, 0, 0, kScrWidth, kScrHeight);
+ g_system->updateScreen();
+}
+
+void Vga::rotate() {
+ if (_rot._len) {
+ Dac c;
+ getColors(_newColors);
+ c = _newColors[_rot._org];
+ memmove(_newColors + _rot._org, _newColors + _rot._org + 1, (_rot._len - 1) * sizeof(Dac));
+ _newColors[_rot._org + _rot._len - 1] = c;
+ _setPal = true;
+ }
+}
+
+void Vga::clear(uint8 color) {
+ for (int paneNum = 0; paneNum < 4; paneNum++)
+ _page[paneNum]->fillRect(Common::Rect(0, 0, kScrWidth, kScrHeight), color);
+}
+
+void Vga::copyPage(uint16 d, uint16 s) {
+ _page[d]->copyFrom(*_page[s]);
+}
+
+void Bitmap::show(V2D pos) {
+ xLatPos(pos);
+
+ const byte *srcP = (const byte *)_v;
+ byte *screenStartP = (byte *)_vm->_vga->_page[1]->getPixels();
+ byte *screenEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight);
+
+ // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a
+ // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data
+ // must be decompressed and inserted into the surface
+ for (int planeCtr = 0; planeCtr < 4; planeCtr++) {
+ byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(pos.x + planeCtr, pos.y);
+
+ for (;;) {
+ uint16 v = READ_LE_UINT16(srcP);
+ srcP += 2;
+ int cmd = v >> 14;
+ int count = v & 0x3FFF;
+
+ if (cmd == 0) {
+ // End of image
+ break;
+ }
+
+ // Handle a set of pixels
+ while (count-- > 0) {
+ // Transfer operation
+ switch (cmd) {
+ case 1:
+ // SKIP
+ break;
+ case 2:
+ // REPEAT
+ if (destP >= screenStartP && destP < screenEndP)
+ *destP = *srcP;
+ break;
+ case 3:
+ // COPY
+ if (destP >= screenStartP && destP < screenEndP)
+ *destP = *srcP;
+ srcP++;
+ break;
+ }
+
+ // Move to next dest position
+ destP += 4;
+ }
+
+ if (cmd == 2)
+ srcP++;
+ }
+ }
+}
+
+void Bitmap::hide(V2D pos) {
+ xLatPos(pos);
+
+ // Perform clipping to screen
+ int w = MIN<int>(_w, kScrWidth - pos.x);
+ int h = MIN<int>(_h, kScrHeight - pos.y);
+ if (pos.x < 0) {
+ w -= -pos.x;
+ pos.x = 0;
+ if (w < 0)
+ return;
+ }
+ if (pos.y < 0) {
+ h -= -pos.y;
+ pos.y = 0;
+ if (h < 0)
+ return;
+ }
+
+ // Perform copying of screen section
+ for (int yp = pos.y; yp < pos.y + h; yp++) {
+ if (yp >= 0 && yp < kScrHeight) {
+ const byte *srcP = (const byte *)_vm->_vga->_page[2]->getBasePtr(pos.x, yp);
+ byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(pos.x, yp);
+
+ Common::copy(srcP, srcP + w, destP);
+ }
+ }
+}
+
+Speaker::Speaker(CGE2Engine *vm): Sprite(vm), _vm(vm) {
+ // Set the sprite list
+ BitmapPtr SP = new Bitmap[2];
+ uint8 *map = Bitmap::makeSpeechBubbleTail(0, _vm->_font->_colorSet);
+ SP[0] = Bitmap(_vm, 15, 16, map);
+ delete[] map;
+ map = Bitmap::makeSpeechBubbleTail(1, _vm->_font->_colorSet);
+ SP[1] = Bitmap(_vm, 15, 16, map);
+ delete[] map;
+ setShapeList(SP, 2);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vga13h.h b/engines/cge2/vga13h.h
new file mode 100644
index 0000000000..553f183de4
--- /dev/null
+++ b/engines/cge2/vga13h.h
@@ -0,0 +1,308 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_VGA13H_H
+#define CGE2_VGA13H_H
+
+#include "common/serializer.h"
+#include "common/events.h"
+#include "graphics/surface.h"
+#include "cge2/general.h"
+#include "cge2/bitmap.h"
+#include "cge2/snail.h"
+#include "cge2/spare.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kFadeStep 2
+#define kVgaColDark 207
+#define kVgaColDarkGray 225 /*219*/
+#define kVgaColGray 231
+#define kVgaColLightGray 237
+#define kPixelTransp 0xFE
+#define kNoSeq (-1)
+#define kNoPtr ((uint8)-1)
+#define kSprExt ".SPR"
+#define kPalCount 256
+#define kPalSize (kPalCount * 3)
+
+class FXP {
+ int32 v;
+public:
+ FXP(void) : v(0) {}
+ FXP (int i0, int f0 = 0) : v((i0 * 256) + ((i0 < 0) ? -f0 : f0)) {}
+ FXP &operator=(const int &x) { v = x << 8; return *this; }
+ FXP operator+(const FXP &x) const { FXP y; y.v = v + x.v; return y; }
+ FXP operator-(const FXP &x) const { FXP y; y.v = v - x.v; return y; }
+ FXP operator*(const FXP &x) const;
+ FXP operator/(const FXP &x) const;
+
+ friend int &operator+=(int &a, const FXP &b) { return a += b.trunc(); }
+ friend int &operator-=(int &a, const FXP &b) { return a -= b.trunc(); }
+ friend FXP &operator+=(FXP &a, const int &b) { a.v += b << 8; return a; }
+ friend FXP &operator-=(FXP &a, const int &b) { a.v -= b << 8; return a; }
+ friend bool operator==(const FXP &a, const FXP &b) { return a.v == b.v; }
+ friend bool operator!=(const FXP &a, const FXP &b) { return a.v != b.v; }
+ friend bool operator<(const FXP &a, const FXP &b) { return a.v < b.v; }
+ friend bool operator>(const FXP &a, const FXP &b) { return a.v > b.v; }
+ int trunc(void) const { return v >> 8; }
+ int round(void) const { return (v + 0x80) >> 8; }
+ bool empty() const { return v == 0; }
+ void sync(Common::Serializer &s);
+};
+
+class V3D {
+public:
+ FXP _x, _y, _z;
+ V3D() { }
+ V3D(FXP x, FXP y, FXP z = 0) : _x(x), _y(y), _z(z) { }
+ V3D(const V3D &p) : _x(p._x), _y(p._y), _z(p._z) { }
+ V3D operator+(const V3D &p) const { return V3D(_x + p._x, _y + p._y, _z + p._z); }
+ V3D operator-(const V3D &p) const { return V3D(_x - p._x, _y - p._y, _z - p._z); }
+ V3D operator*(long n) const { return V3D(_x * n, _y * n, _z * n); }
+ V3D operator/ (long n) const { return V3D(_x / n, _y / n, _z / n); }
+ bool operator==(const V3D &p) const { return _x == p._x && _y == p._y && _z == p._z; }
+ bool operator!=(const V3D &p) const { return _x != p._x || _y != p._y || _z != p._z; }
+ V3D& operator+=(const V3D &x) { return *this = *this + x; }
+ V3D& operator-=(const V3D &x) { return *this = *this - x; }
+ void sync(Common::Serializer &s);
+};
+
+class V2D : public Common::Point {
+ CGE2Engine *_vm;
+public:
+ V2D &operator=(const V3D &p3) {
+ FXP m = _vm->_eye->_z / (p3._z - _vm->_eye->_z);
+ FXP posx = _vm->_eye->_x + (_vm->_eye->_x - p3._x) * m;
+ x = posx.round();
+ FXP posy = _vm->_eye->_y + (_vm->_eye->_y - p3._y) * m;
+ y = posy.round();
+ return *this;
+ }
+ V2D(CGE2Engine *vm) : _vm(vm) { }
+ V2D(CGE2Engine *vm, const V3D &p3) : _vm(vm) { *this = p3; }
+ V2D(CGE2Engine *vm, int posx, int posy) : _vm(vm), Common::Point(posx, posy) { }
+ bool operator<(const V2D &p) const { return (x < p.x) && (y < p.y); }
+ bool operator<=(const V2D &p) const { return (x <= p.x) && (y <= p.y); }
+ bool operator>(const V2D &p) const { return (x > p.x) && (y > p.y); }
+ bool operator>=(const V2D &p) const { return (x >= p.x) && (y >= p.y); }
+ V2D operator+(const V2D &p) const { return V2D(_vm, x + p.x, y + p.y); }
+ V2D operator-(const V2D &p) const { return V2D(_vm, x - p.x, y - p.y); }
+ bool operator==(const V3D &p) const { V3D tmp(x, y); return tmp._x == p._x && tmp._y == p._y && tmp._z == p._z; }
+ bool operator!=(const V3D &p) const { V3D tmp(x, y); return tmp._x != p._x || tmp._y != p._y || tmp._z == p._z; }
+ bool operator==(const V2D &p) const { return x == p.x && y == p.y; }
+ uint16 area() { return x * y; }
+ bool limited(const V2D &p) {
+ return ((x < p.x) && (y < p.y));
+ }
+ V2D scale (int z) {
+ FXP m = _vm->_eye->_z / (_vm->_eye->_z - z);
+ FXP posx = m * x;
+ FXP posy = m * y;
+ return V2D(_vm, posx.trunc(), posy.trunc());
+ }
+};
+
+struct Seq {
+ uint8 _now;
+ uint8 _next;
+ int8 _dx;
+ int8 _dy;
+ int8 _dz;
+ int _dly;
+};
+
+class SprExt {
+public:
+ V2D _p0;
+ V2D _p1;
+ BitmapPtr _b0;
+ BitmapPtr _b1;
+ BitmapPtr _shpList;
+ int _location;
+ Seq *_seq;
+ char *_name;
+ CommandHandler::Command *_actions[kActions];
+ SprExt(CGE2Engine *vm);
+};
+
+class Sprite {
+protected:
+ SprExt *_ext;
+ CGE2Engine *_vm;
+public:
+ int _ref;
+ signed char _scene;
+ struct Flags {
+ bool _hide; // general visibility switch
+ bool _drag; // sprite is moveable
+ bool _hold; // sprite is held with mouse
+ bool _trim; // Trim flag
+ bool _slav; // slave object
+ bool _kill; // dispose memory after remove
+ bool _xlat; // 2nd way display: xlat table
+ bool _port; // portable
+ bool _kept; // kept in pocket
+ bool _frnt; // stay in front of sprite
+ bool _east; // talk to east (in opposite to west)
+ bool _near; // Near action lock
+ bool _shad; // shadow
+ bool _back; // 'send to background' request
+ bool _zmov; // sprite needs Z-update in queue
+ bool _tran; // transparent (untouchable)
+ } _flags;
+ V2D _pos2D;
+ V3D _pos3D;
+ V2D _siz;
+ uint16 _time;
+ struct { byte _ptr, _cnt; } _actionCtrl[kActions];
+ int _seqPtr;
+ int _seqCnt;
+ int _shpCnt;
+ char _file[kMaxFile];
+ // Following trailer is not saved with the game:
+ Sprite *_prev;
+ Sprite *_next;
+ static byte _constY;
+ static byte _follow;
+ static Seq _stdSeq8[];
+
+ bool works(Sprite *spr);
+ bool seqTest(int n);
+ inline bool active() {
+ return _ext != nullptr;
+ }
+ Sprite(CGE2Engine *vm);
+ Sprite(CGE2Engine *vm, BitmapPtr shp, int cnt);
+ virtual ~Sprite();
+ BitmapPtr getShp();
+ void setShapeList(BitmapPtr shp, int cnt);
+ void moveShapesHi();
+ void moveShapesLo();
+ int labVal(Action snq, int lab);
+ virtual Sprite *expand();
+ virtual Sprite *contract();
+ void backShow();
+ void setName(char *newName);
+ inline char *name() {
+ return (_ext) ? _ext->_name : nullptr;
+ }
+ void gotoxyz(int x, int y, int z = 0);
+ void gotoxyz();
+ void gotoxyz(V2D pos);
+ void gotoxyz_(V2D pos);
+ void gotoxyz(V3D pos);
+ void center();
+ void show(uint16 pg);
+ void hide(uint16 pg);
+ void show();
+ void hide();
+ BitmapPtr ghost();
+ void step(int nr = -1);
+ Seq *setSeq(Seq *seq);
+ CommandHandler::Command *snList(Action type);
+ virtual void touch(uint16 mask, V2D pos, Common::KeyCode keyCode);
+ virtual void tick();
+ virtual void setScene(int c);
+ void clrHide() { if (_ext) _ext->_b0 = nullptr; }
+
+ void sync(Common::Serializer &s);
+
+ static void (*notify) ();
+};
+
+class Queue {
+ Sprite *_head;
+ Sprite *_tail;
+public:
+ Queue(bool show);
+
+ void append(Sprite *spr);
+ void insert(Sprite *spr, Sprite *nxt);
+ void insert(Sprite *spr);
+ Sprite *remove(Sprite *spr);
+ Sprite *first() {
+ return _head;
+ }
+ Sprite *last() {
+ return _tail;
+ }
+ Sprite *locate(int ref);
+ bool locate(Sprite *spr);
+ void clear() { _head = _tail = nullptr; }
+};
+
+class Vga {
+ CGE2Engine *_vm;
+ bool _setPal;
+ Dac *_oldColors;
+ Dac *_newColors;
+ const char *_msg;
+ const char *_name;
+
+ void updateColors();
+ void setColors();
+ void waitVR();
+ uint8 closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
+
+public:
+ uint32 _frmCnt;
+ Queue *_showQ;
+ bool _mono;
+ Graphics::Surface *_page[4];
+ Dac *_sysPal;
+ struct { uint8 _org, _len, _cnt, _dly; } _rot;
+
+ Vga(CGE2Engine *vm);
+ ~Vga();
+
+ uint8 *glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
+ void getColors(Dac *tab);
+ void setColors(Dac *tab, int lum);
+ void clear(uint8 color);
+ void copyPage(uint16 d, uint16 s);
+ void sunrise(Dac *tab);
+ void sunset();
+ void show();
+ void update();
+ void rotate();
+ uint8 closest(Dac *pal, Dac x);
+
+ void palToDac(const byte *palData, Dac *tab);
+ void dacToPal(const Dac *tab, byte *palData);
+};
+
+class Speaker: public Sprite {
+ CGE2Engine *_vm;
+public:
+ Speaker(CGE2Engine *vm);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_VGA13H_H
diff --git a/engines/cge2/vmenu.cpp b/engines/cge2/vmenu.cpp
new file mode 100644
index 0000000000..6afe5e9a61
--- /dev/null
+++ b/engines/cge2/vmenu.cpp
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/text.h"
+#include "cge2/vmenu.h"
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+Choice::Choice(CGE2Engine *vm) : _vm(vm), _text(nullptr) {}
+
+ExitGameChoice::ExitGameChoice(CGE2Engine *vm) : Choice(vm) {
+ _text = _vm->_text->getText(kQuitText);
+}
+
+void ExitGameChoice::proc() {
+ _vm->switchScene(-1);
+}
+
+ReturnToGameChoice::ReturnToGameChoice(CGE2Engine *vm) : Choice(vm) {
+ _text = _vm->_text->getText(kNoQuitText);
+}
+
+void ReturnToGameChoice::proc() {
+ _vm->_commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 1, nullptr);
+ _vm->keyClick();
+}
+
+MenuBar::MenuBar(CGE2Engine *vm, uint16 w, byte *c) : Talk(vm) {
+ _color = c;
+ int h = kFontHigh + 2 * kMenuBarVerticalMargin, i = (w += 2 * kMenuBarHorizontalMargin) * h;
+ uint8 *p = new uint8[i];
+ uint8 *p1;
+ uint8 *p2;
+ uint8 lt = _color[kLt];
+ uint8 rb = _color[kRb];
+ BitmapPtr b;
+
+ memset(p + w, kPixelTransp, i - 2 * w);
+ memset(p, lt, w);
+ memset(p + i - w, rb, w);
+ p1 = p;
+ p2 = p + i - 1;
+ for (i = 0; i < h; i++) {
+ *p1 = lt;
+ *p2 = rb;
+ p1 += w;
+ p2 -= w;
+ }
+ b = new Bitmap[1];
+ b[0] = Bitmap(vm, w, h, p);
+ delete[] p;
+ setShapeList(b, 1);
+ _flags._slav = true;
+ _flags._tran = true;
+ _flags._kill = true;
+}
+
+VMenu *VMenu::_addr = nullptr;
+
+VMenu::VMenu(CGE2Engine *vm, Common::Array<Choice *> list, V2D pos, ColorBank col)
+ : Talk(vm, vmGather(list), kTBRect, col), _menu(list), _bar(nullptr), _items(list.size()), _vm(vm) {
+ delete[] _vmgt; // Lefotver of vmGather.
+
+ _addr = this;
+ _recent = -1;
+ _flags._kill = true;
+
+ if (pos.x < 0 || pos.y < 0)
+ center();
+ else
+ gotoxyz(V2D(_vm, pos.x - _siz.x / 2, pos.y - (kTextVMargin + kFontHigh / 2)));
+
+ _vm->_vga->_showQ->append(this);
+ _bar = new MenuBar(_vm, _siz.x - 2 * kTextHMargin, _color);
+ _bar->gotoxyz(V2D(_vm, _pos2D.x, _pos2D.y + kTextVMargin - kMenuBarVerticalMargin));
+ _vm->_vga->_showQ->append(_bar);
+}
+
+char *VMenu::vmGather(Common::Array<Choice *> list) {
+ int len = 0;
+ int h = 0;
+
+ for (uint i = 0; i < list.size(); i++) {
+ len += strlen(list[i]->_text);
+ ++h;
+ }
+ _vmgt = new char[len + h];
+ *_vmgt = '\0';
+ for (uint i = 0; i < list.size(); i++) {
+ if (*_vmgt)
+ strcat(_vmgt, "|");
+ strcat(_vmgt, list[i]->_text);
+ ++h;
+ }
+
+ return _vmgt;
+}
+
+
+VMenu::~VMenu() {
+ _addr = nullptr;
+
+ for (uint i = 0; i < _menu.size(); i++) {
+ delete _menu[i];
+ }
+}
+
+void VMenu::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
+ if (_items) {
+ Sprite::touch(mask, pos, keyCode);
+
+ int n = 0;
+ bool ok = false;
+ int h = kFontHigh + kTextLineSpace;
+ pos.y -= kTextVMargin - 1;
+ if (pos.y >= 0) {
+ if (pos.x < 0)
+ pos.x = -pos.x;
+ n = pos.y / h;
+ if (n < _items)
+ ok = (pos.x <= (_siz.x >> 1) - kTextHMargin);
+ else
+ n = _items - 1;
+ }
+
+ _bar->gotoxyz(V2D(_vm, _pos2D.x, _pos2D.y + kTextVMargin + n * h - kMenuBarVerticalMargin));
+ n = _items - 1 - n;
+
+ if (ok && (mask & kMouseLeftUp)) {
+ _items = 0;
+ _vm->_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, this);
+ _menu[_recent = n]->proc();
+ }
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vmenu.h b/engines/cge2/vmenu.h
new file mode 100644
index 0000000000..f34812dcf4
--- /dev/null
+++ b/engines/cge2/vmenu.h
@@ -0,0 +1,89 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_VMENU_H
+#define CGE2_VMENU_H
+
+#define kMenuBarVerticalMargin 1
+#define kMenuBarHorizontalMargin 3
+#define kLt 3
+#define kRb 1
+
+#include "cge2/cge2.h"
+#include "cge2/talk.h"
+
+namespace CGE2 {
+
+class Choice {
+protected:
+ CGE2Engine *_vm;
+public:
+ char *_text;
+
+ virtual void proc() = 0;
+
+ Choice(CGE2Engine *vm);
+ virtual ~Choice() {};
+};
+
+class ExitGameChoice : public Choice {
+public:
+ ExitGameChoice(CGE2Engine *vm);
+ void proc();
+};
+
+class ReturnToGameChoice : public Choice {
+public:
+ ReturnToGameChoice(CGE2Engine *vm);
+ void proc();
+};
+
+class MenuBar : public Talk {
+public:
+ MenuBar(CGE2Engine *vm, uint16 w, byte *c);
+};
+
+class VMenu : public Talk {
+ CGE2Engine *_vm;
+
+ uint16 _items;
+ Common::Array<Choice *> _menu;
+public:
+ char *_vmgt;
+ static VMenu *_addr;
+ int _recent;
+ MenuBar *_bar;
+
+ VMenu(CGE2Engine *vm, Common::Array<Choice *> list, V2D pos, ColorBank col);
+ ~VMenu();
+ void touch(uint16 mask, V2D pos, Common::KeyCode keyCode);
+ char *vmGather(Common::Array<Choice *> list);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_VMENU_H
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index 471a29030b..f070338978 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -135,7 +135,7 @@ Common::Error ComposerEngine::run() {
else
loadLibrary(_pendingPageChanges[i]._pageId);
- lastDrawTime = _system->getMillis();
+ lastDrawTime = 0;
}
_pendingPageChanges.clear();
@@ -168,9 +168,10 @@ Common::Error ComposerEngine::run() {
else
lastDrawTime += frameTime;
+ tickOldScripts();
+
redraw();
- tickOldScripts();
processAnimFrame();
} else if (_needsUpdate) {
redraw();
diff --git a/engines/composer/scripting.cpp b/engines/composer/scripting.cpp
index 94ca2c1bc8..cd78202ecd 100644
--- a/engines/composer/scripting.cpp
+++ b/engines/composer/scripting.cpp
@@ -746,6 +746,7 @@ void ComposerEngine::stopOldScript(uint16 id) {
for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++) {
if ((*i)->_id == id) {
+ removeSprite(0, id);
delete *i;
i = _oldScripts.reverse_erase(i);
}
diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp
index 5c1a37a8eb..eebd8fdc15 100644
--- a/engines/cruise/cruise.cpp
+++ b/engines/cruise/cruise.cpp
@@ -53,8 +53,7 @@ CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc
PCFadeFlag = false;
_preLoad = false;
_savedCursor = CURSOR_NOMOUSE;
- lastTick = 0;
- lastTickDebug = 0;
+ _lastTick = 0;
_gameSpeed = GAME_FRAME_DELAY_1;
_speedFlag = false;
_polyStructs = nullptr;
diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h
index c81e5dd5ec..8624ba693e 100644
--- a/engines/cruise/cruise.h
+++ b/engines/cruise/cruise.h
@@ -60,7 +60,7 @@ private:
PCSound *_sound;
Common::StringArray _langStrings;
CursorType _savedCursor;
- uint32 lastTick, lastTickDebug;
+ uint32 _lastTick;
int _gameSpeed;
bool _speedFlag;
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index f2f7e0c2b0..0ad1416df2 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -934,8 +934,11 @@ bool createDialog(int objOvl, int objIdx, int x, int y) {
else
color = -1;
- ptr = getObjectName(ptrHead->obj1Number, ovl3->arrayNameObj);
- addSelectableMenuEntry(j, i, menuTable[0], 1, color, ptr);
+ if (ovl3) {
+ ptr = getObjectName(ptrHead->obj1Number, ovl3->arrayNameObj);
+ addSelectableMenuEntry(j, i, menuTable[0], 1, color, ptr);
+ } else
+ error("Unexpected null pointer in createDialog()");
}
}
}
@@ -1157,7 +1160,7 @@ void callSubRelation(menuElementSubStruct *pMenuElement, int nOvl, int nObj) {
createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, 0, 0);
}
- userWait = 1;
+ userWait = true;
autoOvl = ovlIdx;
autoMsg = pHeader->id;
@@ -1186,7 +1189,7 @@ void callSubRelation(menuElementSubStruct *pMenuElement, int nOvl, int nObj) {
pTrack->flag = 1;
autoTrack = true;
- userWait = 0;
+ userWait = false;
userEnabled = 0;
freezeCell(&cellHead, ovlIdx, pHeader->id, 5, -1, 0, 9998);
}
@@ -1303,7 +1306,7 @@ void callRelation(menuElementSubStruct *pMenuElement, int nObj2) {
createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, 0, 0);
}
- userWait = 1;
+ userWait = true;
autoOvl = ovlIdx;
autoMsg = pHeader->id;
@@ -1334,7 +1337,7 @@ void callRelation(menuElementSubStruct *pMenuElement, int nObj2) {
pTrack->flag = 1;
autoTrack = true;
- userWait = 0;
+ userWait = false;
userEnabled = 0;
freezeCell(&cellHead, ovlIdx, pHeader->id, 5, -1, 0, 9998);
}
@@ -1455,7 +1458,7 @@ int CruiseEngine::processInput() {
if (userWait) {
// Check for left mouse button click or Space to end user waiting
if ((keyboardCode == Common::KEYCODE_SPACE) || (button == CRS_MB_LEFT))
- userWait = 0;
+ userWait = false;
keyboardCode = Common::KEYCODE_INVALID;
return 0;
@@ -1772,9 +1775,7 @@ void CruiseEngine::mainLoop() {
currentActiveMenu = -1;
autoMsg = -1;
linkedRelation = 0;
- main21 = 0;
- main22 = 0;
- userWait = 0;
+ userWait = false;
autoTrack = false;
initAllData();
@@ -1829,10 +1830,7 @@ void CruiseEngine::mainLoop() {
if (!skipEvents || bFastMode)
skipEvents = manageEvents();
- if (bFastMode) {
- if (currentTick >= (lastTickDebug + 10))
- lastTickDebug = currentTick;
- } else {
+ if (!bFastMode) {
g_system->delayMillis(10);
currentTick = g_system->getMillis();
}
@@ -1841,11 +1839,11 @@ void CruiseEngine::mainLoop() {
break;
_vm->getDebugger()->onFrame();
- } while (currentTick < lastTick + _gameSpeed && !bFastMode);
+ } while (currentTick < _lastTick + _gameSpeed && !bFastMode);
if (_playerDontAskQuit)
break;
- lastTick = g_system->getMillis();
+ _lastTick = g_system->getMillis();
// Handle switchover in game speed after intro
if (!_speedFlag && canLoadGameStateCurrently()) {
@@ -1860,7 +1858,7 @@ void CruiseEngine::mainLoop() {
// readKeyboard();
- bool isUserWait = userWait != 0;
+ bool isUserWait = userWait;
// WORKAROUND: This prevents hotspots responding during
// delays i.e. Menu opening if you click fast on another
// hotspot after trying to open a locked door, which
@@ -1941,7 +1939,7 @@ void CruiseEngine::mainLoop() {
mainDraw(userWait);
flipScreen();
- if (userWait == 1) {
+ if (userWait) {
// Waiting for press - original wait loop has been integrated into the
// main event loop
continue;
@@ -1956,7 +1954,7 @@ void CruiseEngine::mainLoop() {
char* pText = getText(autoMsg, autoOvl);
if (strlen(pText))
- userWait = 1;
+ userWait = true;
}
changeScriptParamInList(-1, -1, &relHead, 9998, 0);
diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp
index 33f3bbaf4a..3f794c4e70 100644
--- a/engines/cruise/function.cpp
+++ b/engines/cruise/function.cpp
@@ -1512,6 +1512,9 @@ int16 Op_Itoa() {
int param[160];
char txt[40];
+ for (int i = 0; i < 160; ++i)
+ param[i] = 0;
+
for (int i = nbp - 1; i >= 0; i--)
param[i] = popVar();
@@ -1829,7 +1832,7 @@ int16 Op_ThemeReset() {
}
int16 Op_UserWait() {
- userWait = 1;
+ userWait = true;
if (currentScriptPtr->type == scriptType_PROC) {
changeScriptParamInList(currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, &procHead, -1, 9999);
} else if (currentScriptPtr->type == scriptType_REL) {
diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp
index 98e7e66aa6..5777b846b4 100644
--- a/engines/cruise/mainDraw.cpp
+++ b/engines/cruise/mainDraw.cpp
@@ -1377,7 +1377,7 @@ int getValueFromObjectQuerry(objectParamsQuery *params, int idx) {
return 0;
}
-void mainDraw(int16 param) {
+void mainDraw(bool waitFl) {
uint8 *bgPtr;
cellStruct *currentObjPtr;
int16 currentObjIdx;
@@ -1461,7 +1461,7 @@ void mainDraw(int16 param) {
}
// automatic animation process
- if (currentObjPtr->animStep && !param) {
+ if (currentObjPtr->animStep && !waitFl) {
if (currentObjPtr->animCounter <= 0) {
bool change = true;
diff --git a/engines/cruise/mainDraw.h b/engines/cruise/mainDraw.h
index bb71b9759b..1af403fca5 100644
--- a/engines/cruise/mainDraw.h
+++ b/engines/cruise/mainDraw.h
@@ -33,7 +33,7 @@ extern int m_color;
int upscaleValue(int value, int scale);
void pixel(int x, int y, char color);
-void mainDraw(int16 param);
+void mainDraw(bool waitFl);
void flipScreen();
void buildPolyModel(int X, int Y, int scale, char *ptr2, char *destBuffer, char *dataPtr);
void drawSprite(int width, int height, cellStruct *currentObjPtr, const uint8 *dataIn, int ys, int xs, uint8 *output, const uint8 *dataBuf);
diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp
index c72192fc1b..cf0b872646 100644
--- a/engines/cruise/menu.cpp
+++ b/engines/cruise/menu.cpp
@@ -160,7 +160,7 @@ int processMenu(menuStruct *pMenu) {
int si;
currentActiveMenu = 0;
- mainDraw(1);
+ mainDraw(true);
flipScreen();
di = 0;
@@ -179,7 +179,7 @@ int processMenu(menuStruct *pMenu) {
di = 1;
}
- mainDraw(1);
+ mainDraw(true);
flipScreen();
manageEvents();
@@ -190,7 +190,7 @@ int processMenu(menuStruct *pMenu) {
currentActiveMenu = -1;
- mainDraw(1);
+ mainDraw(true);
flipScreen();
if (mouseButton & 1) {
diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp
index 8e64faa14c..a62648df08 100644
--- a/engines/cruise/saveload.cpp
+++ b/engines/cruise/saveload.cpp
@@ -947,7 +947,7 @@ Common::Error loadSavegameData(int saveGameIdx) {
// to finish
changeCursor(CURSOR_NORMAL);
- mainDraw(1);
+ mainDraw(true);
flipScreen();
return Common::kNoError;
diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp
index cc9a17eb9a..0b0fab8c4a 100644
--- a/engines/cruise/sound.cpp
+++ b/engines/cruise/sound.cpp
@@ -607,6 +607,13 @@ PCSoundFxPlayer::PCSoundFxPlayer(PCSoundDriver *driver)
_sfxData = NULL;
_fadeOutCounter = 0;
_driver->setUpdateCallback(updateCallback, this);
+
+ _currentPos = 0;
+ _currentOrder = 0;
+ _numOrders = 0;
+ _eventsDelay = 0;
+ _looping = false;
+ _updateTicksCounter = 0;
}
PCSoundFxPlayer::~PCSoundFxPlayer() {
@@ -792,6 +799,7 @@ PCSound::PCSound(Audio::Mixer *mixer, CruiseEngine *vm) {
_mixer = mixer;
_soundDriver = new AdLibSoundDriverADL(_mixer);
_player = new PCSoundFxPlayer(_soundDriver);
+ _genVolume = 0;
}
PCSound::~PCSound() {
diff --git a/engines/cruise/vars.cpp b/engines/cruise/vars.cpp
index 9a59c8a714..e9b68968ef 100644
--- a/engines/cruise/vars.cpp
+++ b/engines/cruise/vars.cpp
@@ -53,9 +53,7 @@ char nextOverlay[38];
int16 currentActiveMenu;
int16 autoMsg;
menuElementSubStruct* linkedRelation;
-int16 main21;
-int16 main22;
-int16 userWait;
+bool userWait;
int16 autoTrack;
int16 currentDiskNumber = 1;
diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h
index fe3f7d6303..e7c687d5fb 100644
--- a/engines/cruise/vars.h
+++ b/engines/cruise/vars.h
@@ -156,9 +156,7 @@ extern char nextOverlay[38];
extern int16 currentActiveMenu;
extern int16 autoMsg;
extern menuElementSubStruct* linkedRelation;
-extern int16 main21;
-extern int16 main22;
-extern int16 userWait;
+extern bool userWait;
extern int16 autoTrack;
extern int16 currentDiskNumber;
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index b158969f46..5009a62e84 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -45,9 +45,6 @@ void DrasculaEngine::updateAnim(int y, int destX, int destY, int width, int heig
void DrasculaEngine::animation_1_1() {
debug(4, "animation_1_1()");
- int l, l2, p;
- //int pixelPos[6];
-
while (term_int == 0 && !shouldQuit()) {
playMusic(29);
playFLI("logoddm.bin", 9);
@@ -119,8 +116,8 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit())
break;
- for (l2 = 0; l2 < 3; l2++)
- for (l = 0; l < 7; l++) {
+ for (int l2 = 0; l2 < 3; l2++)
+ for (int l = 0; l < 7; l++) {
copyBackground();
copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface);
updateScreen();
@@ -133,9 +130,7 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit())
break;
- l2 = 0; p = 0;
-
- for (l = 0; l < 180; l++) {
+ for (int l = 0, l2 = 0, p = 0; l < 180; l++) {
copyBackground(0, 0, 320 - l, 0, l, 200, drawSurface3, screenSurface);
copyBackground(l, 0, 0, 0, 320 - l, 200, bgSurface, screenSurface);
@@ -703,17 +698,15 @@ void DrasculaEngine::animation_4_2() {
void DrasculaEngine::animation_14_2() {
debug(4, "animation_14_2()");
- int cY = -160;
- int l = 0;
-
loadPic("an14_2.alg", backSurface);
+ int l = 0;
for (int n = -160; n <= 0; n = n + 5 + l) {
copyBackground();
updateRefresh_pre();
moveCharacters();
moveVonBraun();
- cY = n;
+ int cY = n;
copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface);
updateRefresh();
updateScreen();
@@ -959,8 +952,6 @@ void DrasculaEngine::animation_23_2() {
void DrasculaEngine::animation_25_2() {
debug(4, "animation_25_2()");
- int cY = 0;
-
loadPic("an14_2.alg", backSurface);
loadPic(18, bgSurface);
@@ -975,8 +966,7 @@ void DrasculaEngine::animation_25_2() {
moveCharacters();
moveVonBraun();
- cY = n;
-
+ int cY = n;
copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface);
updateRefresh();
@@ -1594,20 +1584,18 @@ void DrasculaEngine::animation_1_6() {
void DrasculaEngine::animation_5_6() {
debug(4, "animation_5_6()");
- int pY = -125;
-
animate("man.bin", 14);
for (int n = -125; n <= 0; n = n + 2) {
copyBackground();
updateRefresh_pre();
- pY = n;
+ int pY = n;
copyRect(1, 29, 204, pY, 18, 125, drawSurface3, screenSurface);
updateRefresh();
-
updateScreen();
updateEvents();
+
pause(2);
}
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 35461f1d71..797b6d94b0 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -194,6 +194,9 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
_console = 0;
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "audio");
+
int cd_num = ConfMan.getInt("cdrom");
if (cd_num >= 0)
_system->getAudioCDManager()->openCD(cd_num);
diff --git a/engines/fullpipe/configure.engine b/engines/fullpipe/configure.engine
index fce5951e26..a9042449db 100644
--- a/engines/fullpipe/configure.engine
+++ b/engines/fullpipe/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 fullpipe "Full Pipe" no
+add_engine fullpipe "Full Pipe" no "" "" "16bit"
diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp
index f4444ef707..bb0838395d 100644
--- a/engines/fullpipe/fullpipe.cpp
+++ b/engines/fullpipe/fullpipe.cpp
@@ -34,6 +34,7 @@
#include "fullpipe/modal.h"
#include "fullpipe/input.h"
#include "fullpipe/motion.h"
+#include "fullpipe/statics.h"
#include "fullpipe/scenes.h"
#include "fullpipe/floaters.h"
#include "fullpipe/console.h"
@@ -83,6 +84,7 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc)
_currentCheatPos = 0;
_modalObject = 0;
+ _origFormat = 0;
_liftEnterMQ = 0;
_liftExitMQ = 0;
@@ -242,12 +244,14 @@ void FullpipeEngine::restartGame() {
}
Common::Error FullpipeEngine::run() {
- const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0);
+ const Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
// Initialize backend
initGraphics(800, 600, true, &format);
_backgroundSurface.create(800, 600, format);
+ _origFormat = new Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
+
_console = new Console(this);
initialize();
@@ -413,21 +417,34 @@ void FullpipeEngine::updateEvents() {
}
}
-
-#if 0
- warning("STUB: FullpipeEngine::updateEvents() <mainWindowProc>");
- if (Msg == MSG_SC11_SHOWSWING && _modalObject) {
- _modalObject->method14();
- }
-#endif
+ // pollEvent() is implemented only for video player. So skip it.
+ //if (event.kbd.keycode == MSG_SC11_SHOWSWING && _modalObject) {
+ // _modalObject->pollEvent();
+ //}
}
void FullpipeEngine::freeGameLoader() {
- warning("STUB: FullpipeEngine::freeGameLoader()");
+ setCursor(0);
+ delete _movTable;
+ _floaters->stopAll();
+ delete _gameLoader;
+ _currentScene = 0;
+ _scene2 = 0;
+ _loaderScene = 0;
}
void FullpipeEngine::cleanup() {
- warning("STUB: FullpipeEngine::cleanup()");
+ //cleanRecorder();
+ clearMessageHandlers();
+ clearMessages();
+ _globalMessageQueueList->compact();
+
+ for (uint i = 0; i < _globalMessageQueueList->size(); i++)
+ delete (*_globalMessageQueueList)[i];
+
+ stopAllSoundStreams();
+
+ delete _origFormat;
}
void FullpipeEngine::updateScreen() {
diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h
index afdc493258..7f20a6d6af 100644
--- a/engines/fullpipe/fullpipe.h
+++ b/engines/fullpipe/fullpipe.h
@@ -32,7 +32,7 @@
#include "audio/mixer.h"
-#include "graphics/surface.h"
+#include "graphics/transparent_surface.h"
#include "engines/engine.h"
@@ -108,6 +108,7 @@ public:
void updateEvents();
Graphics::Surface _backgroundSurface;
+ Graphics::PixelFormat *_origFormat;
GameLoader *_gameLoader;
GameProject *_gameProject;
@@ -242,6 +243,7 @@ public:
int (*_updateCursorCallback)();
void drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha);
+ void sceneFade(Scene *sc, bool direction);
int _cursorId;
int _minCursorId;
diff --git a/engines/fullpipe/gameloader.cpp b/engines/fullpipe/gameloader.cpp
index c8b01939dd..fbf96b3060 100644
--- a/engines/fullpipe/gameloader.cpp
+++ b/engines/fullpipe/gameloader.cpp
@@ -84,7 +84,29 @@ GameLoader::~GameLoader() {
delete _interactionController;
delete _inputController;
- warning("STUB: GameLoader::~GameLoader()");
+ g_fp->_gameLoader = 0;
+
+ for (uint i = 0; i < _sc2array.size(); i++) {
+ if (_sc2array[i]._defPicAniInfos)
+ delete _sc2array[i]._defPicAniInfos;
+
+ if (_sc2array[i]._picAniInfos)
+ delete _sc2array[i]._picAniInfos;
+
+ if (_sc2array[i]._motionController)
+ delete _sc2array[i]._motionController;
+
+ if (_sc2array[i]._data1)
+ free(_sc2array[i]._data1);
+
+ if (_sc2array[i]._entranceData)
+ free(_sc2array[i]._entranceData);
+ }
+
+ delete _gameVar;
+ _gameVar = 0;
+
+ _sc2array.clear();
}
bool GameLoader::load(MfcArchive &file) {
@@ -635,7 +657,16 @@ bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header)
}
void GameLoader::restoreDefPicAniInfos() {
- warning("STUB: restoreDefPicAniInfos()");
+ for (uint i = 0; i < _sc2array.size(); i++) {
+ if (_sc2array[i]._picAniInfos) {
+ free(_sc2array[i]._picAniInfos);
+ _sc2array[i]._picAniInfos = 0;
+ _sc2array[i]._picAniInfosCount = 0;
+ }
+
+ if (_sc2array[i]._scene)
+ applyPicAniInfos(_sc2array[i]._scene, _sc2array[i]._defPicAniInfos, _sc2array[i]._defPicAniInfosCount);
+ }
}
GameVar *FullpipeEngine::getGameLoaderGameVar() {
diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp
index 520e81835b..61fbf7192f 100644
--- a/engines/fullpipe/gfx.cpp
+++ b/engines/fullpipe/gfx.cpp
@@ -33,51 +33,6 @@
namespace Fullpipe {
-Bitmap::Bitmap() {
- _x = 0;
- _y = 0;
- _width = 0;
- _height = 0;
- _pixels = 0;
- _type = 0;
- _dataSize = 0;
- _flags = 0;
-}
-
-Bitmap::Bitmap(Bitmap *src) {
- _x = src->_x;
- _y = src->_y;
- _flags = src->_flags;
- _dataSize = src->_dataSize;
- _type = src->_type;
- _width = src->_width;
- _height = src->_height;
- _pixels = src->_pixels;
-}
-
-Bitmap::~Bitmap() {
- if (_pixels)
- free(_pixels);
-
- _pixels = 0;
-}
-
-void Bitmap::load(Common::ReadStream *s) {
- debug(5, "Bitmap::load()");
-
- _x = s->readUint32LE();
- _y = s->readUint32LE();
- _width = s->readUint32LE();
- _height = s->readUint32LE();
- s->readUint32LE(); // pixels
- _type = s->readUint32LE();
- _dataSize = s->readUint32LE();
- _flags = s->readUint32LE();
-
- debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize);
- debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags);
-}
-
Background::Background() {
_x = 0;
_y = 0;
@@ -514,7 +469,7 @@ void Picture::freePicture() {
if (_bitmap) {
if (testFlags() && !_field_54) {
freeData();
- free(_bitmap);
+ //free(_bitmap);
_bitmap = 0;
}
}
@@ -633,6 +588,10 @@ void Picture::getDibInfo() {
_bitmap->load(s);
_bitmap->_pixels = _data;
+
+ _bitmap->decode((int32 *)(_paletteData ? _paletteData : g_fp->_globalPalette));
+
+ _bitmap->_pixels = 0;
}
Bitmap *Picture::getPixelData() {
@@ -677,12 +636,12 @@ void Picture::draw(int x, int y, int style, int angle) {
case 1:
//flip
getDimensions(&point);
- _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal);
+ _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal, _alpha);
break;
case 2:
//vrtSetFadeRatio(g_vrtDrawHandle, 0.34999999);
//vrtSetFadeTable(g_vrtDrawHandle, &unk_477F88, 1.0, 1000.0, 0, 0);
- _bitmap->drawShaded(2, x1, y1, pal);
+ _bitmap->drawShaded(2, x1, y1, pal, _alpha);
//vrtSetFadeRatio(g_vrtDrawHandle, 0.0);
//vrtSetFadeTable(g_vrtDrawHandle, &unk_477F90, 1.0, 1000.0, 0, 0);
break;
@@ -690,7 +649,7 @@ void Picture::draw(int x, int y, int style, int angle) {
if (angle)
drawRotated(x1, y1, angle);
else {
- _bitmap->putDib(x1, y1, (int32 *)pal);
+ _bitmap->putDib(x1, y1, (int32 *)pal, _alpha);
}
}
}
@@ -789,54 +748,71 @@ int Picture::getPixelAtPosEx(int x, int y) {
return 0;
}
-bool Bitmap::isPixelHitAtPos(int x, int y) {
- if (x < _x || x >= _width + _x || y < _y || y >= _y + _height)
- return false;
+Bitmap::Bitmap() {
+ _x = 0;
+ _y = 0;
+ _width = 0;
+ _height = 0;
+ _pixels = 0;
+ _type = 0;
+ _dataSize = 0;
+ _flags = 0;
+ _surface = 0;
+ _flipping = Graphics::FLIP_NONE;
+}
- int off;
+Bitmap::Bitmap(Bitmap *src) {
+ _x = src->_x;
+ _y = src->_y;
+ _flags = src->_flags;
+ _dataSize = src->_dataSize;
+ _type = src->_type;
+ _width = src->_width;
+ _height = src->_height;
+ _pixels = src->_pixels;
+ _surface = new Graphics::TransparentSurface(*src->_surface);
+ _flipping = src->_flipping;
+}
- if (_type == 'CB\x05e')
- off = 2 * ((_width + 1) / 2);
- else
- off = 4 * ((_width + 3) / 4);
+Bitmap::~Bitmap() {
+ if (_pixels)
+ free(_pixels);
- off = x + off * (_y + _height - y - 1) - _x;
+ delete _surface;
- if (_flags & 0x1000000) {
- switch (_type) {
- case 'CB\0\0':
- if (_pixels[off] == (_flags & 0xff))
- return false;
- break;
- case 'CB\x05e':
- if (!*(int16 *)&_pixels[2 * off])
- return false;
- break;
- case 'RB\0\0':
- return isPixelAtHitPosRB(x, y);
- }
- }
- return true;
+ _pixels = 0;
}
-bool Bitmap::isPixelAtHitPosRB(int x, int y) {
- int ox = _x;
- int oy = _y;
+void Bitmap::load(Common::ReadStream *s) {
+ debug(5, "Bitmap::load()");
+
+ _x = s->readUint32LE();
+ _y = s->readUint32LE();
+ _width = s->readUint32LE();
+ _height = s->readUint32LE();
+ s->readUint32LE(); // pixels
+ _type = s->readUint32LE();
+ _dataSize = s->readUint32LE();
+ _flags = s->readUint32LE();
+
+ debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize);
+ debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags);
+}
- _x = _y = 0;
+bool Bitmap::isPixelHitAtPos(int x, int y) {
+ if (x < _x || x >= _width + _x || y < _y || y >= _y + _height)
+ return false;
- bool res = putDibRB(0, x, y);
- _x = ox;
- _y = oy;
+ if (!_surface)
+ return false;
- return res;
+ return ((*((int32 *)_surface->getBasePtr(x, y)) & 0xff000000) != 0);
}
-void Bitmap::putDib(int x, int y, int32 *palette) {
- debug(7, "Bitmap::putDib(%d, %d)", x, y);
+void Bitmap::decode(int32 *palette) {
+ _surface = new Graphics::TransparentSurface;
- _x = x - g_fp->_sceneRect.left;
- _y = y - g_fp->_sceneRect.top;
+ _surface->create(_width, _height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
if (_type == MKTAG('R', 'B', '\0', '\0'))
putDibRB(palette);
@@ -844,46 +820,64 @@ void Bitmap::putDib(int x, int y, int32 *palette) {
putDibCB(palette);
}
-bool Bitmap::putDibRB(int32 *palette, int pX, int pY) {
- uint16 *curDestPtr;
+void Bitmap::putDib(int x, int y, int32 *palette, int alpha) {
+ debug(7, "Bitmap::putDib(%d, %d)", x, y);
+
+ int x1 = x - g_fp->_sceneRect.left;
+ int y1 = y - g_fp->_sceneRect.top;
+
+ if (!_width || !_height || !_surface)
+ return;
+
+ Common::Rect sub(0, 0, _width, _height);
+
+ if (x1 < 0) {
+ sub.left = -x1;
+ x1 = 0;
+ }
+
+ if (y1 < 0) {
+ sub.top = -y1;
+ y1 = 0;
+ }
+
+ if (x1 + sub.width() > 799)
+ sub.right -= x1 + sub.width() - 799;
+
+ if (y1 + sub.height() > 599)
+ sub.bottom -= y1 + sub.height() - 599;
+
+ if (sub.width() <= 0 || sub.height() <= 0)
+ return;
+
+ int alphac = TS_ARGB(0xff, alpha, 0xff, 0xff);
+
+ _surface->blit(g_fp->_backgroundSurface, x1, y1, _flipping, &sub, alphac);
+ g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(x1, y1), g_fp->_backgroundSurface.pitch, x1, y1, sub.width(), sub.height());
+}
+
+bool Bitmap::putDibRB(int32 *palette) {
+ uint32 *curDestPtr;
int endy;
int x;
int start1;
int fillLen;
uint16 pixel;
- int endx;
int y;
uint16 *srcPtr2;
uint16 *srcPtr;
- if (!palette && pX == -1) {
+ if (!palette) {
debug(2, "Bitmap::putDibRB(): Both global and local palettes are empty");
return false;
}
debug(8, "Bitmap::putDibRB()");
- endx = _width + _x - 1;
- endy = _height + _y - 1;
-
- if (_x > 799 || endx < 0 || _y > 599 || endy < 0)
- return false;
-
- if (pX == -1) {
- if (endy > 599)
- endy = 599;
-
- if (endx > 799)
- endx = 799;
- }
-
- int startx = _x;
- if (startx < 0)
- startx = 0;
+ endy = _height - 1;
- int starty = _y;
- if (starty < 0)
- starty = 0;
+ int startx = 0;
+ int starty = 0;
y = endy;
@@ -927,14 +921,9 @@ bool Bitmap::putDibRB(int32 *palette, int pX, int pY) {
if (fillLen > 0 || start1 >= 0) {
if (x <= 799 + 1 || (fillLen += 799 - x + 1, fillLen > 0)) {
if (y <= endy) {
- if (pX == -1) {
- int bgcolor = palette[(pixel >> 8) & 0xff];
- curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(start1, y);
- colorFill(curDestPtr, fillLen, bgcolor);
- } else {
- if (y == pY && pX >= start1 && pX < start1 + fillLen)
- return true;
- }
+ int bgcolor = palette[(pixel >> 8) & 0xff];
+ curDestPtr = (uint32 *)_surface->getBasePtr(start1, y);
+ colorFill(curDestPtr, fillLen, bgcolor);
}
}
}
@@ -959,45 +948,26 @@ bool Bitmap::putDibRB(int32 *palette, int pX, int pY) {
}
if (y <= endy) {
- if (pX == -1) {
- curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(start1, y);
- paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette);
- } else {
- if (y == pY && pX >= start1 && pX < start1 + fillLen)
- return true;
- }
+ curDestPtr = (uint32 *)_surface->getBasePtr(start1, y);
+ paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette);
}
}
}
}
- if (pX == -1)
- g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(startx, starty), g_fp->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty);
-
return false;
}
void Bitmap::putDibCB(int32 *palette) {
- uint16 *curDestPtr;
+ uint32 *curDestPtr;
int endx;
int endy;
int bpp;
uint pitch;
bool cb05_format;
- endx = _width + _x - 1;
- endy = _height + _y - 1;
-
- debug(8, "Bitmap::putDibCB(): %d, %d, %d, %d [%d, %d]", _x, _y, endx, endy, _width, _height);
-
- if (_x > 799 || endx < 0 || _y > 599 || endy < 0)
- return;
-
- if (endy > 599)
- endy = 599;
-
- if (endx > 799)
- endx = 799;
+ endx = _width - 1;
+ endy = _height - 1;
cb05_format = (_type == MKTAG('C', 'B', '\05', 'e'));
@@ -1007,39 +977,28 @@ void Bitmap::putDibCB(int32 *palette) {
bpp = cb05_format ? 2 : 1;
pitch = (bpp * _width + 3) & 0xFFFFFFFC;
- byte *srcPtr = &_pixels[pitch * (endy - _y)];
+ byte *srcPtr = &_pixels[pitch * endy];
- if (endy - _y < _height)
+ if (endy < _height)
srcPtr = &_pixels[pitch * (_height - 1)];
- int starty = _y;
- if (starty < 0) {
- starty = 0;
- srcPtr = &_pixels[pitch * (_height + _y)];
- }
-
- int startx = _x;
- if (startx < 0) {
- srcPtr += bpp * -_x;
- startx = 0;
- }
+ int starty = 0;
+ int startx = 0;
if (_flags & 0x1000000) {
for (int y = starty; y <= endy; srcPtr -= pitch, y++) {
- curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(startx, y);
+ curDestPtr = (uint32 *)_surface->getBasePtr(startx, y);
copierKeyColor(curDestPtr, srcPtr, endx - startx + 1, _flags & 0xff, (int32 *)palette, cb05_format);
}
} else {
for (int y = starty; y <= endy; srcPtr -= pitch, y++) {
- curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(startx, y);
+ curDestPtr = (uint32 *)_surface->getBasePtr(startx, y);
copier(curDestPtr, srcPtr, endx - startx + 1, (int32 *)palette, cb05_format);
}
}
-
- g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(startx, starty), g_fp->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty);
}
-void Bitmap::colorFill(uint16 *dest, int len, int32 color) {
+void Bitmap::colorFill(uint32 *dest, int len, int32 color) {
#if 0
if (blendMode) {
if (blendMode != 1)
@@ -1050,12 +1009,17 @@ void Bitmap::colorFill(uint16 *dest, int len, int32 color) {
colorFill = ptrfillColor16bit;
}
#endif
+ byte r, g, b;
+
+ g_fp->_origFormat->colorToRGB(color, r, g, b);
+
+ uint32 c = TS_ARGB(0xff, r, g, b);
for (int i = 0; i < len; i++)
- *dest++ = (int16)(color & 0xffff);
+ *dest++ = c;
}
-void Bitmap::paletteFill(uint16 *dest, byte *src, int len, int32 *palette) {
+void Bitmap::paletteFill(uint32 *dest, byte *src, int len, int32 *palette) {
#if 0
if (blendMode) {
if (blendMode != 1)
@@ -1067,11 +1031,16 @@ void Bitmap::paletteFill(uint16 *dest, byte *src, int len, int32 *palette) {
}
#endif
- for (int i = 0; i < len; i++)
- *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff;
+ byte r, g, b;
+
+ for (int i = 0; i < len; i++) {
+ g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src++]) & 0xffff, r, g, b);
+
+ *dest++ = TS_ARGB(0xff, r, g, b);
+ }
}
-void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) {
+void Bitmap::copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) {
#if 0
if (blendMode) {
if (blendMode == 1) {
@@ -1089,10 +1058,14 @@ void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int3
}
#endif
+ byte r, g, b;
+
if (!cb05_format) {
for (int i = 0; i < len; i++) {
- if (*src != keyColor)
- *dest = READ_LE_UINT32(&palette[*src]) & 0xffff;
+ if (*src != keyColor) {
+ g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src]) & 0xffff, r, g, b);
+ *dest = TS_ARGB(0xff, r, g, b);
+ }
dest++;
src++;
@@ -1101,8 +1074,10 @@ void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int3
int16 *src16 = (int16 *)src;
for (int i = 0; i < len; i++) {
- if (*src16 != 0)
- *dest = *src16;
+ if (*src16 != 0) {
+ g_fp->_origFormat->colorToRGB(READ_LE_UINT16(src16) & 0xffff, r, g, b);
+ *dest = TS_ARGB(0xff, r, g, b);
+ }
dest++;
src16++;
@@ -1110,7 +1085,7 @@ void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int3
}
}
-void Bitmap::copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format) {
+void Bitmap::copier(uint32 *dest, byte *src, int len, int32 *palette, bool cb05_format) {
#if 0
if (blendMode) {
if (blendMode == 1) {
@@ -1128,100 +1103,49 @@ void Bitmap::copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_
}
#endif
- if (!cb05_format) {
- for (int i = 0; i < len; i++)
- *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff;
- } else {
- int16 *src16 = (int16 *)src;
-
- for (int i = 0; i < len; i++)
- *dest++ = *src16++;
- }
-}
-
-Bitmap *Bitmap::reverseImage() {
- switch (_type) {
- case MKTAG('R', 'B', '\0', '\0'):
- return reverseImageRB();
- case MKTAG('C', 'B', '\0', '\0'):
- return reverseImageCB();
- case MKTAG('C', 'B', '\05', 'e'):
- return reverseImageCB05();
- default:
- error("Bitmap::reverseImage: Unknown image type: %x", _type);
- }
-
- return 0;
-}
-
-Bitmap *Bitmap::reverseImageRB() {
- uint16 *newpixels = (uint16 *)calloc(((_dataSize + 15) & 0xfffffff0) + sizeof(Bitmap), 1);
- uint16 *srcPtr = (uint16 *)_pixels;
-
- int idx = 0;
- while (srcPtr[idx] != 0x100) {
- uint16 *srcPtr2 = &srcPtr[idx];
+ byte r, g, b;
- int prevIdx = idx;
- int i = idx;
+ if (!cb05_format) {
+ for (int i = 0; i < len; i++) {
+ g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src++]) & 0xffff, r, g, b);
- while (*srcPtr2) {
- ++srcPtr2;
- ++idx;
+ *dest++ = TS_ARGB(0xff, r, g, b);
}
+ } else {
+ int16 *src16 = (int16 *)src;
- int idx2 = idx;
-
- newpixels[idx] = srcPtr[idx];
-
- while (i != idx) {
- int fillLen = 2 - ((srcPtr[prevIdx] & 0xff) != 0 ? 1 : 0);
- idx2 -= fillLen;
- memcpy(&newpixels[idx2], &srcPtr[prevIdx], 2 * fillLen);
- prevIdx = fillLen + i;
- i += fillLen;
+ for (int i = 0; i < len; i++) {
+ g_fp->_origFormat->colorToRGB(READ_LE_UINT32(src16++) & 0xffff, r, g, b);
+ *dest++ = TS_ARGB(0xff, r, g, b);
}
- ++idx;
}
- newpixels[idx] = 256;
-
- int oldBmp = ((_dataSize + 15) >> 1) & 0x7FFFFFF8;
- memcpy(&newpixels[oldBmp], &srcPtr[oldBmp], sizeof(Bitmap));
-
- Bitmap *res = new Bitmap(this);
- res->_pixels = (byte *)newpixels;
-
- return res;
}
-Bitmap *Bitmap::reverseImageCB() {
- warning("STUB: Bitmap::reverseImageCB()");
-
- return this;
-}
-
-Bitmap *Bitmap::reverseImageCB05() {
- warning("STUB: Bitmap::reverseImageCB05()");
+Bitmap *Bitmap::reverseImage(bool flip) {
+ if (flip)
+ _flipping = Graphics::FLIP_H;
+ else
+ _flipping = Graphics::FLIP_NONE;
return this;
}
Bitmap *Bitmap::flipVertical() {
- warning("STUB: Bitmap::flipVertical()");
+ _flipping = Graphics::FLIP_V;
return this;
}
-void Bitmap::drawShaded(int type, int x, int y, byte *palette) {
+void Bitmap::drawShaded(int type, int x, int y, byte *palette, int alpha) {
warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y);
- putDib(x, y, (int32 *)palette);
+ putDib(x, y, (int32 *)palette, alpha);
}
- void Bitmap::drawRotated(int x, int y, int angle, byte *palette) {
+void Bitmap::drawRotated(int x, int y, int angle, byte *palette, int alpha) {
warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle);
- putDib(x, y, (int32 *)palette);
+ putDib(x, y, (int32 *)palette, alpha);
}
bool BigPicture::load(MfcArchive &file) {
@@ -1251,7 +1175,7 @@ void BigPicture::draw(int x, int y, int style, int angle) {
//vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, v9);
}
- _bitmap->putDib(nx, ny, 0);
+ _bitmap->putDib(nx, ny, 0, 0xff);
if (_alpha < 0xFF) {
//vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255);
@@ -1332,4 +1256,23 @@ void FullpipeEngine::drawAlphaRectangle(int x1, int y1, int x2, int y2, int alph
warning("STUB: FullpipeEngine::drawAlphaRectangle()");
}
+void FullpipeEngine::sceneFade(Scene *sc, bool direction) {
+ warning("STUB: FullpipeEngine::sceneFade()");
+
+#if 0
+ for (int dim = 0; dim < 255; dim += 20) {
+ v5 = GetTickCount();
+ vrtSetAlphaBlendMode(*(_DWORD *)virt, 0, 255);
+ sc->draw();
+ drawAlphaRectangle(0, 0, 800, 600, direction ? 255 - dim : dim);
+ vrtFlush(*(_DWORD *)virt);
+ v7 = GetTickCount();
+ if ( v7 - v5 < 42 )
+ Sleep(v5 - v7 + 42);
+ }
+ vrtSetAlphaBlendMode(*(_DWORD *)virt, 0, 255);
+#endif
+
+}
+
} // End of namespace Fullpipe
diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h
index 191df7709a..d94dd40452 100644
--- a/engines/fullpipe/gfx.h
+++ b/engines/fullpipe/gfx.h
@@ -38,32 +38,31 @@ struct Bitmap {
int _type;
int _dataSize;
int _flags;
+ Graphics::TransparentSurface *_surface;
+ int _flipping;
Bitmap();
Bitmap(Bitmap *src);
~Bitmap();
void load(Common::ReadStream *s);
- void putDib(int x, int y, int32 *palette);
- bool putDibRB(int32 *palette, int x = -1, int y = -1);
+ void decode(int32 *palette);
+ void putDib(int x, int y, int32 *palette, int alpha);
+ bool putDibRB(int32 *palette);
void putDibCB(int32 *palette);
- void colorFill(uint16 *dest, int len, int32 color);
- void paletteFill(uint16 *dest, byte *src, int len, int32 *palette);
- void copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format);
- void copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format);
+ void colorFill(uint32 *dest, int len, int32 color);
+ void paletteFill(uint32 *dest, byte *src, int len, int32 *palette);
+ void copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format);
+ void copier(uint32 *dest, byte *src, int len, int32 *palette, bool cb05_format);
- Bitmap *reverseImage();
- Bitmap *reverseImageRB();
- Bitmap *reverseImageCB();
- Bitmap *reverseImageCB05();
+ Bitmap *reverseImage(bool flip = true);
Bitmap *flipVertical();
- void drawShaded(int type, int x, int y, byte *palette);
- void drawRotated(int x, int y, int angle, byte *palette);
+ void drawShaded(int type, int x, int y, byte *palette, int alpha);
+ void drawRotated(int x, int y, int angle, byte *palette, int alpha);
bool isPixelHitAtPos(int x, int y);
- bool isPixelAtHitPosRB(int x, int y);
};
class Picture : public MemoryObject {
diff --git a/engines/fullpipe/mgm.cpp b/engines/fullpipe/mgm.cpp
new file mode 100644
index 0000000000..aacfd5452a
--- /dev/null
+++ b/engines/fullpipe/mgm.cpp
@@ -0,0 +1,719 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "fullpipe/fullpipe.h"
+
+#include "fullpipe/utils.h"
+#include "fullpipe/statics.h"
+#include "fullpipe/motion.h"
+#include "fullpipe/messages.h"
+
+namespace Fullpipe {
+
+void MGM::clear() {
+ _items.clear();
+}
+
+MessageQueue *MGM::genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr) {
+ int idx = getItemIndexById(ani->_id);
+
+ if (idx == -1)
+ return 0;
+
+ int stid = staticsId;
+
+ if (!staticsId) {
+ if (ani->_movement) {
+ stid = ani->_movement->_staticsObj2->_staticsId;
+ } else {
+ if (!ani->_statics)
+ return 0;
+
+ stid = ani->_statics->_staticsId;
+ }
+ }
+
+ if (stid == staticsIndex)
+ return new MessageQueue(g_fp->_globalMessageQueueList->compact());
+
+ int startidx = getStaticsIndexById(idx, stid);
+ int endidx = getStaticsIndexById(idx, staticsIndex);
+ int subidx = startidx + endidx * _items[idx]->statics.size();
+
+ if (!_items[idx]->subItems[subidx]->movement) {
+ clearMovements2(idx);
+ recalcOffsets(idx, startidx, endidx, 0, 1);
+ }
+
+ if (!_items[idx]->subItems[subidx]->movement)
+ return 0;
+
+ MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact());
+ Common::Point point;
+ ExCommand *ex;
+
+ int i = 0;
+ do {
+ subidx = startidx + endidx * _items[idx]->statics.size();
+
+ _items[idx]->subItems[subidx]->movement->calcSomeXY(point, 0, -1);
+
+ if (pointArr) {
+ int sz;
+
+ if (_items[idx]->subItems[subidx]->movement->_currMovement)
+ sz = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size();
+ else
+ sz = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size();
+
+ ex = new ExCommand2(20, ani->_id, &pointArr[i], sz);
+
+ ex->_messageNum = _items[idx]->subItems[subidx]->movement->_id;
+ } else {
+ ex = new ExCommand(ani->_id, 1, _items[idx]->subItems[subidx]->movement->_id, 0, 0, 0, 1, 0, 0, 0);
+ }
+
+ ex->_keyCode = ani->_okeyCode;
+ ex->_field_3C = 1;
+ ex->_field_24 = 1;
+
+ mq->addExCommandToEnd(ex);
+
+ if (resStatId)
+ *resStatId = _items[idx]->subItems[subidx]->movement->_id;
+
+ startidx = _items[idx]->subItems[subidx]->staticsIndex;
+
+ uint step;
+
+ if (_items[idx]->subItems[subidx]->movement->_currMovement)
+ step = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size();
+ else
+ step = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size();
+
+ i += step;
+ } while (startidx != endidx);
+
+ return mq;
+}
+
+MGMItem::MGMItem() {
+ objId = 0;
+}
+
+MGMSubItem::MGMSubItem() {
+ movement = 0;
+ staticsIndex = 0;
+ field_8 = 0;
+ field_C = 0;
+ x = 0;
+ y = 0;
+}
+
+void MGM::addItem(int objId) {
+ if (getItemIndexById(objId) == -1) {
+ MGMItem *item = new MGMItem();
+
+ item->objId = objId;
+ _items.push_back(item);
+ }
+ rebuildTables(objId);
+}
+
+void MGM::rebuildTables(int objId) {
+ int idx = getItemIndexById(objId);
+
+ if (idx == -1)
+ return;
+
+ _items[idx]->subItems.clear();
+ _items[idx]->statics.clear();
+ _items[idx]->movements1.clear();
+ _items[idx]->movements2.clear();
+
+ StaticANIObject *obj = g_fp->_currentScene->getStaticANIObject1ById(objId, -1);
+
+ if (!obj)
+ return;
+
+ for (uint i = 0; i < obj->_staticsList.size(); i++)
+ _items[idx]->statics.push_back((Statics *)obj->_staticsList[i]);
+
+ for (uint i = 0; i < obj->_movements.size(); i++)
+ _items[idx]->movements1.push_back((Movement *)obj->_movements[i]);
+
+ _items[idx]->subItems.clear();
+}
+
+int MGM::getItemIndexById(int objId) {
+ for (uint i = 0; i < _items.size(); i++)
+ if (_items[i]->objId == objId)
+ return i;
+
+ return -1;
+}
+
+MessageQueue *MGM::genMovement(MGMInfo *mgminfo) {
+ if (!mgminfo->ani)
+ return 0;
+
+ Movement *mov = mgminfo->ani->_movement;
+
+ if (!mov && !mgminfo->ani->_statics)
+ return 0;
+
+ if (!(mgminfo->flags & 1)) {
+ if (mov)
+ mgminfo->staticsId1 = mov->_staticsObj2->_staticsId;
+ else
+ mgminfo->staticsId1 = mgminfo->ani->_statics->_staticsId;
+ }
+
+ Common::Point point;
+
+ if (!(mgminfo->flags & 0x10) || !(mgminfo->flags & 0x20)) {
+ int nx = mgminfo->ani->_ox;
+ int ny = mgminfo->ani->_oy;
+
+ if (mgminfo->ani->_movement) {
+ mgminfo->ani->calcNextStep(&point);
+
+ nx += point.x;
+ ny += point.y;
+ }
+
+ if (!(mgminfo->flags & 0x10))
+ mgminfo->x2 = nx;
+
+ if (!(mgminfo->flags & 0x20))
+ mgminfo->y2 = ny;
+ }
+
+ mov = mgminfo->ani->getMovementById(mgminfo->movementId);
+
+ if (!mov)
+ return 0;
+
+ int itemIdx = getItemIndexById(mgminfo->ani->_id);
+ int subIdx = getStaticsIndexById(itemIdx, mgminfo->staticsId1);
+ int st2idx = getStaticsIndexById(itemIdx, mov->_staticsObj1->_staticsId);
+ int st1idx = getStaticsIndexById(itemIdx, mov->_staticsObj2->_staticsId);
+ int subOffset = getStaticsIndexById(itemIdx, mgminfo->staticsId2);
+
+ clearMovements2(itemIdx);
+ recalcOffsets(itemIdx, subIdx, st2idx, 0, 1);
+ clearMovements2(itemIdx);
+ recalcOffsets(itemIdx, st1idx, subOffset, 0, 1);
+
+ MGMSubItem *sub1 = _items[itemIdx]->subItems[subIdx + st2idx * _items[itemIdx]->statics.size()];
+ MGMSubItem *sub2 = _items[itemIdx]->subItems[st1idx + subOffset * _items[itemIdx]->statics.size()];
+
+ if (subIdx != st2idx && !sub1->movement)
+ return 0;
+
+ if (st1idx != subOffset && !sub2->movement)
+ return 0;
+
+ int n1x = mgminfo->x1 - mgminfo->x2 - sub1->x - sub2->x;
+ int n1y = mgminfo->y1 - mgminfo->y2 - sub1->y - sub2->y;
+
+ Common::Point point1;
+
+ mov->calcSomeXY(point1, 0, -1);
+
+ int n2x = point1.x;
+ int n2y = point1.y;
+ int mult;
+ int len = -1;
+
+ if (mgminfo->flags & 0x40) {
+ mult = mgminfo->field_10;
+ len = -1;
+ n2x *= mult;
+ n2y *= mult;
+ } else {
+ calcLength(&point, mov, n1x, n1y, &mult, &len, 1);
+ n2x = point.x;
+ n2y = point.y;
+ }
+
+ if (!(mgminfo->flags & 2)) {
+ len = -1;
+ n2x = mult * point1.x;
+ n1x = mult * point1.x;
+ mgminfo->x1 = mgminfo->x2 + mult * point1.x + sub1->x + sub2->x;
+ }
+
+ if (!(mgminfo->flags & 4)) {
+ n2y = mult * point1.y;
+ n1y = mult * point1.y;
+ len = -1;
+ mgminfo->y1 = mgminfo->y2 + mult * point1.y + sub1->y + sub2->y;
+ }
+
+ int px = 0;
+ int py = 0;
+
+ if (sub1->movement) {
+ px = countPhases(itemIdx, subIdx, st2idx, 1);
+ py = countPhases(itemIdx, subIdx, st2idx, 2);
+ }
+
+ if (mult > 1) {
+ px += (mult - 1) * mov->countPhasesWithFlag(-1, 1);
+ py += (mult - 1) * mov->countPhasesWithFlag(-1, 2);
+ }
+
+ if (mult > 0) {
+ px += mov->countPhasesWithFlag(len, 1);
+ py += mov->countPhasesWithFlag(len, 2);
+ }
+
+ if (sub2->movement) {
+ px += countPhases(itemIdx, st1idx, subOffset, 1);
+ py += countPhases(itemIdx, st1idx, subOffset, 2);
+ }
+
+ int dx1 = n1x - n2x;
+ int dy1 = n1y - n2y;
+ int x1, y1;
+
+ if (px) {
+ x1 = (int)((double)dx1 / (double)px);
+ } else {
+ x1 = 0;
+ }
+
+ if (py) {
+ y1 = (int)((double)dy1 / (double)py);
+ } else {
+ y1 = 0;
+ }
+
+ Common::Point x2, y2;
+
+ y2.x = dx1 - px * x1;
+ y2.y = dy1 - py * y1;
+
+ if (n1x - n2x == px * x1)
+ x2.x = 0;
+ else
+ x2.x = (dx1 - px * x1) / abs(dx1 - px * x1);
+
+ if (dy1 == py * y1)
+ x2.y = 0;
+ else
+ x2.y = (dy1 - py * y1) / abs(dy1 - py * y1);
+
+ MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact());
+ ExCommand2 *ex2;
+
+ for (int i = subIdx; i != st2idx;) {
+ MGMSubItem *s = _items[itemIdx]->subItems[i + subOffset * _items[itemIdx]->statics.size()];
+
+ ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1);
+ ex2->_parId = mq->_id;
+ ex2->_keyCode = mgminfo->ani->_okeyCode;
+
+ mq->addExCommandToEnd(ex2);
+
+ i = s->staticsIndex;
+ }
+
+ for (int i = 0; i < mult; ++i) {
+ int plen;
+
+ if (i == mult - 1)
+ plen = len;
+ else
+ plen = -1;
+
+ ex2 = buildExCommand2(mov, mgminfo->ani->_id, x1, y1, &x2, &y2, plen);
+ ex2->_parId = mq->_id;
+ ex2->_keyCode = mgminfo->ani->_okeyCode;
+
+ mq->addExCommandToEnd(ex2);
+ }
+
+ for (int j = st1idx; j != subOffset;) {
+ MGMSubItem *s = _items[itemIdx]->subItems[j + subOffset * _items[itemIdx]->statics.size()];
+
+ ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1);
+ ex2->_parId = mq->_id;
+ ex2->_keyCode = mgminfo->ani->_okeyCode;
+
+ mq->addExCommandToEnd(ex2);
+
+ j = s->staticsIndex;
+ }
+
+ ExCommand *ex = new ExCommand(mgminfo->ani->_id, 5, -1, mgminfo->x1, mgminfo->y1, 0, 1, 0, 0, 0);
+
+ ex->_field_14 = mgminfo->field_1C;
+ ex->_keyCode = mgminfo->ani->_okeyCode;
+ ex->_field_24 = 0;
+ ex->_excFlags |= 3;
+
+ mq->addExCommandToEnd(ex);
+
+ return mq;
+}
+
+int MGM::countPhases(int idx, int subIdx, int endIdx, int flag) {
+ int res = 0;
+
+ if (endIdx < 0)
+ return 0;
+
+ while (subIdx != endIdx) {
+ if (subIdx < 0)
+ break;
+
+ res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(-1, flag);
+
+ subIdx = _items[idx]->subItems[subIdx + 6 * endIdx * _items[idx]->statics.size()]->staticsIndex;
+ }
+
+ return res;
+}
+void MGM::updateAnimStatics(StaticANIObject *ani, int staticsId) {
+ if (getItemIndexById(ani->_id) == -1)
+ return;
+
+ if (ani->_movement) {
+ ani->queueMessageQueue(0);
+ ani->_movement->gotoLastFrame();
+ ani->_statics = ani->_movement->_staticsObj2;
+
+ int x = ani->_movement->_ox;
+ int y = ani->_movement->_oy;
+
+ ani->_movement = 0;
+
+ ani->setOXY(x, y);
+ }
+
+ if (ani->_statics) {
+ Common::Point point;
+
+ getPoint(&point, ani->_id, ani->_statics->_staticsId, staticsId);
+
+ ani->setOXY(ani->_ox + point.x, ani->_oy + point.y);
+
+ ani->_statics = ani->getStaticsById(staticsId);
+ }
+}
+
+Common::Point *MGM::getPoint(Common::Point *point, int objectId, int staticsId1, int staticsId2) {
+ int idx = getItemIndexById(objectId);
+
+ if (idx == -1) {
+ point->x = -1;
+ point->y = -1;
+ } else {
+ int st1idx = getStaticsIndexById(idx, staticsId1);
+ int st2idx = getStaticsIndexById(idx, staticsId2);
+
+ if (st1idx == st2idx) {
+ point->x = 0;
+ point->y = 0;
+ } else {
+ int subidx = st1idx + st2idx * _items[idx]->statics.size();
+
+ if (!_items[idx]->subItems[subidx]->movement) {
+ clearMovements2(idx);
+ recalcOffsets(idx, st1idx, st2idx, false, true);
+
+ if (!_items[idx]->subItems[subidx]->movement) {
+ clearMovements2(idx);
+ recalcOffsets(idx, st1idx, st2idx, true, false);
+ }
+ }
+
+ MGMSubItem *sub = _items[idx]->subItems[subidx];
+
+ if (sub->movement) {
+ point->x = sub->x;
+ point->y = sub->y;
+ } else {
+ point->x = 0;
+ point->y = 0;
+ }
+ }
+ }
+
+ return point;
+}
+
+int MGM::getStaticsIndexById(int idx, int16 id) {
+ if (!_items[idx]->statics.size())
+ return -1;
+
+ for (uint i = 0; i < _items[idx]->statics.size(); i++) {
+ if (_items[idx]->statics[i]->_staticsId == id)
+ return i;
+ }
+
+ return 0;
+}
+
+int MGM::getStaticsIndex(int idx, Statics *st) {
+ if (!_items[idx]->statics.size())
+ return -1;
+
+ for (uint i = 0; i < _items[idx]->statics.size(); i++) {
+ if (_items[idx]->statics[i] == st)
+ return i;
+ }
+
+ return 0;
+}
+
+void MGM::clearMovements2(int idx) {
+ _items[idx]->movements2.clear();
+}
+
+int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) {
+ MGMItem *item = _items[idx];
+ int subIdx = st1idx + st2idx * item->statics.size();
+
+ if (st1idx == st2idx) {
+ memset(&item->subItems[subIdx], 0, sizeof(item->subItems[subIdx]));
+ return 0;
+ }
+
+ if (item->subItems[subIdx])
+ return item->subItems[subIdx]->field_8;
+
+ Common::Point point;
+
+ for (uint i = 0; i < item->movements1.size(); i++) {
+ Movement *mov = item->movements1[i];
+
+ if (mov->_staticsObj1 == item->statics[st1idx]) {
+ if (!item->movements2[i] && (!flop || mov->_field_50)) {
+ item->movements2[i] = 1;
+
+ int stidx = getStaticsIndex(idx, item->movements1[i]->_staticsObj2);
+ int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
+ int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+ int newsz = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C;
+
+ if (recalc >= 0) {
+ if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 ||
+ (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) {
+ item->subItems[subIdx]->movement = mov;
+ item->subItems[subIdx]->staticsIndex = stidx;
+ item->subItems[subIdx]->field_8 = recalc + 1;
+ item->subItems[subIdx]->field_C = newsz;
+
+ mov->calcSomeXY(point, 0, -1);
+
+ item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x + point.x;
+ item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y + point.y;
+ }
+ }
+ }
+ } else if (flip) {
+ if (mov->_staticsObj2 == item->statics[st1idx]) {
+ if (!item->movements2[i] && (!flop || mov->_field_50)) {
+ item->movements2[i] = 1;
+
+ int stidx = getStaticsIndex(idx, mov->_staticsObj1);
+ int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
+
+ if (recalc >= 0) {
+ if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) {
+ item->subItems[subIdx]->movement = mov;
+ item->subItems[subIdx]->staticsIndex = stidx;
+ item->subItems[subIdx]->field_8 = recalc + 1;
+
+ int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+
+ item->subItems[subIdx]->field_C = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C;
+
+ mov->calcSomeXY(point, 0, -1);
+
+ item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x - point.x;
+ item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y - point.y;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (item->subItems[subIdx]->movement)
+ return item->subItems[subIdx]->field_8;
+
+ return -1;
+}
+
+int MGM::refreshOffsets(int objectId, int idx1, int idx2) {
+ int idx = getItemIndexById(objectId);
+
+ if (idx != -1) {
+ int from = getStaticsIndexById(idx, idx1);
+ int to = getStaticsIndexById(idx, idx2);
+
+ MGMSubItem *sub = _items[idx]->subItems[from + to * _items[idx]->statics.size()];
+
+ if (sub->movement) {
+ idx = sub->field_8;
+ } else {
+ clearMovements2(idx);
+ idx = recalcOffsets(idx, from, to, 0, 1);
+ }
+ }
+
+ return idx;
+}
+
+Common::Point *MGM::calcLength(Common::Point *pRes, Movement *mov, int x, int y, int *mult, int *len, int flag) {
+ Common::Point point;
+
+ mov->calcSomeXY(point, 0, -1);
+ int p1x = point.x;
+ int p1y = point.y;
+
+ int newmult = 0;
+ int oldlen = *len;
+
+ if (abs(p1y) > abs(p1x)) {
+ if (mov->calcSomeXY(point, 0, -1)->y)
+ newmult = (int)((double)y / mov->calcSomeXY(point, 0, -1)->y);
+ } else if (mov->calcSomeXY(point, 0, -1)->x) {
+ newmult = (int)((double)x / mov->calcSomeXY(point, 0, -1)->x);
+ }
+
+ if (newmult < 0)
+ newmult = 0;
+
+ *mult = newmult;
+
+ int phase = 1;
+ int sz;
+
+ if (flag) {
+ if (abs(p1y) > abs(p1x)) {
+ while (abs(p1y * newmult + mov->calcSomeXY(point, 0, phase)->y) < abs(y)) {
+ sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+
+ if (phase > sz)
+ break;
+
+ phase++;
+ }
+ } else {
+ while (abs(p1x * newmult + mov->calcSomeXY(point, 0, phase)->x) < abs(x)) {
+ sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
+
+ if (phase >= sz)
+ break;
+
+ phase++;
+ }
+ }
+
+ *len = phase - 1;
+ } else {
+ *len = -1;
+ }
+
+ int p2x = 0;
+ int p2y = 0;
+
+ if (!oldlen)
+ oldlen = -1;
+
+ if (oldlen > 0) {
+ ++*mult;
+
+ mov->calcSomeXY(point, 0, oldlen);
+ p2x = point.x;
+ p2y = point.y;
+
+ if (abs(p1y) > abs(p1x))
+ p2x = p1x;
+ else
+ p2y = p1y;
+ }
+
+ pRes->x = p2x + p1x * newmult;
+ pRes->y = p2y + p1y * newmult;
+
+ return pRes;
+}
+
+ExCommand2 *MGM::buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len) {
+ uint cnt;
+
+ if (mov->_currMovement)
+ cnt = mov->_currMovement->_dynamicPhases.size();
+ else
+ cnt = mov->_dynamicPhases.size();
+
+ if (len > 0 && cnt > (uint)len)
+ cnt = len;
+
+ Common::Point **points = (Common::Point **)malloc(sizeof(Common::Point *) * cnt);
+
+ for (uint i = 0; i < cnt; i++) {
+ int flags = mov->getDynamicPhaseByIndex(i)->getDynFlags();
+
+ points[i] = new Common::Point;
+
+ if (flags & 1) {
+ points[i]->x = x1 + x2->x;
+
+ y2->x -= x2->x;
+
+ if (!y2->x)
+ x2->x = 0;
+ }
+
+ if (flags & 2) {
+ points[i]->y = y1 + x2->y;
+
+ y2->y -= x2->y;
+
+ if (!y2->y)
+ x2->y = 0;
+ }
+ }
+
+ ExCommand2 *ex = new ExCommand2(20, objId, points, cnt);
+ ex->_excFlags = 2;
+ ex->_messageNum = mov->_id;
+ ex->_field_14 = len;
+ ex->_field_24 = 1;
+ ex->_keyCode = -1;
+
+ for (uint i = 0; i < cnt; i++)
+ delete points[i];
+
+ free(points);
+
+ return ex;
+}
+
+} // End of namespace Fullpipe
diff --git a/engines/fullpipe/mgm.h b/engines/fullpipe/mgm.h
new file mode 100644
index 0000000000..13195891da
--- /dev/null
+++ b/engines/fullpipe/mgm.h
@@ -0,0 +1,95 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FULLPIPE_MGM_H
+#define FULLPIPE_MGM_H
+
+namespace Fullpipe {
+
+class ExCommand2;
+class Movement;
+class Statics;
+
+struct MGMSubItem {
+ Movement *movement;
+ int staticsIndex;
+ int field_8;
+ int field_C;
+ int x;
+ int y;
+
+ MGMSubItem();
+};
+
+struct MGMItem {
+ int16 objId;
+ Common::Array<MGMSubItem *> subItems;
+ Common::Array<Statics *> statics;
+ Common::Array<Movement *> movements1;
+ Common::Array<int> movements2;
+
+ MGMItem();
+};
+
+struct MGMInfo {
+ StaticANIObject *ani;
+ int staticsId1;
+ int staticsId2;
+ int movementId;
+ int field_10;
+ int x1;
+ int y1;
+ int field_1C;
+ int x2;
+ int y2;
+ int flags;
+
+ MGMInfo() { memset(this, 0, sizeof(MGMInfo)); }
+};
+
+class MGM : public CObject {
+public:
+ Common::Array<MGMItem *> _items;
+
+public:
+ void clear();
+ void addItem(int objId);
+ void rebuildTables(int objId);
+ int getItemIndexById(int objId);
+
+ MessageQueue *genMovement(MGMInfo *mgminfo);
+ void updateAnimStatics(StaticANIObject *ani, int staticsId);
+ Common::Point *getPoint(Common::Point *point, int aniId, int staticsId1, int staticsId2);
+ int getStaticsIndexById(int idx, int16 id);
+ int getStaticsIndex(int idx, Statics *st);
+ void clearMovements2(int idx);
+ int recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop);
+ Common::Point *calcLength(Common::Point *point, Movement *mov, int x, int y, int *mult, int *len, int flag);
+ ExCommand2 *buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len);
+ MessageQueue *genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr);
+ int countPhases(int idx, int subIdx, int subOffset, int flag);
+ int refreshOffsets(int objectId, int idx1, int idx2);
+};
+
+} // End of namespace Fullpipe
+
+#endif /* FULLPIPE_MGM_H */
diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp
index 3dbbeb78c4..2fd7ef0c21 100644
--- a/engines/fullpipe/modal.cpp
+++ b/engines/fullpipe/modal.cpp
@@ -198,11 +198,9 @@ bool ModalIntro::init(int counterdiff) {
}
void ModalIntro::update() {
- warning("STUB: ModalIntro::update()");
-
if (g_fp->_currentScene) {
if (_introFlags & 1) {
- //sceneFade(virt, g_currentScene, 1);
+ g_fp->sceneFade(g_fp->_currentScene, true);
_stillRunning = 255;
_introFlags &= 0xfe;
@@ -210,12 +208,12 @@ void ModalIntro::update() {
g_fp->playSound(SND_INTR_019, 0);
} else if (_introFlags & 2) {
if (g_vars->sceneIntro_needBlackout) {
- //vrtRectangle(*(_DWORD *)virt, 0, 0, 0, 800, 600);
+ g_fp->drawAlphaRectangle(0, 0, 800, 600, 0);
g_vars->sceneIntro_needBlackout = 0;
_stillRunning = 0;
_introFlags &= 0xfd;
} else {
- //sceneFade(virt, g_currentScene, 0);
+ g_fp->sceneFade(g_fp->_currentScene, false);
_stillRunning = 0;
_introFlags &= 0xfd;
}
@@ -728,8 +726,6 @@ bool ModalCredits::init(int counterdiff) {
}
void ModalCredits::update() {
- warning("STUB: ModalCredits::update()");
-
if (_fadeOut) {
if (_fadeIn) {
_sceneTitles->draw();
@@ -737,14 +733,14 @@ void ModalCredits::update() {
return;
}
} else if (_fadeIn) {
- //sceneFade(virt, this->_sceneTitles, 1); // TODO
+ g_fp->sceneFade(_sceneTitles, true);
_fadeOut = 1;
return;
}
if (_fadeOut) {
- //sceneFade(virt, this->_sceneTitles, 0); // TODO
+ g_fp->sceneFade(_sceneTitles, false);
_fadeOut = 0;
return;
}
@@ -922,7 +918,7 @@ bool ModalMainMenu::init(int counterdiff) {
g_fp->_modalObject = mq;
mq->_parentObj = this;
- mq->create(_scene, (PictureObject *)_scene->_picObjList[0], PIC_MEX_BGR);
+ mq->create(_scene, _scene, PIC_MEX_BGR);
_hoverAreaId = 0;
@@ -1322,7 +1318,7 @@ void ModalHelp::launch() {
}
ModalQuery::ModalQuery() {
- _picObjList = 0;
+ _bgScene = 0;
_bg = 0;
_okBtn = 0;
_cancelBtn = 0;
@@ -1335,7 +1331,7 @@ ModalQuery::~ModalQuery() {
_okBtn->_flags &= 0xFFFB;
}
-bool ModalQuery::create(Scene *sc, PictureObject *picObjList, int id) {
+bool ModalQuery::create(Scene *sc, Scene *bgScene, int id) {
if (id == PIC_MEX_BGR) {
_bg = sc->getPictureObjectById(PIC_MEX_BGR, 0);
@@ -1372,14 +1368,14 @@ bool ModalQuery::create(Scene *sc, PictureObject *picObjList, int id) {
}
_queryResult = -1;
- _picObjList = picObjList;
+ _bgScene = bgScene;
return true;
}
void ModalQuery::update() {
- if (_picObjList)
- _picObjList->draw();
+ if (_bgScene)
+ _bgScene->draw();
_bg->draw();
@@ -1430,9 +1426,12 @@ bool ModalQuery::init(int counterdiff) {
_okBtn->_flags &= 0xFFFB;
if (_queryResult == 1) {
+ if (_bgScene)
+ g_fp->sceneFade(_bgScene, false);
+
warning("STUB: ModalQuery::init()");
- //sceneFade(g_vrtDrawHandle, (Scene *)this->_picObjList, 0);
+ // Quit game
//if (inputArFlag) {
// g_needRestart = 1;
// return 0;
@@ -1596,7 +1595,7 @@ void ModalSaveGame::setup(Scene *sc, int mode) {
fileinfo = new FileInfo;
memset(fileinfo, 0, sizeof(FileInfo));
- strncpy(fileinfo->filename, getSavegameFile(i), 160);
+ Common::strlcpy(fileinfo->filename, getSavegameFile(i), 160);
if (!getFileInfo(i, fileinfo)) {
fileinfo->empty = true;
diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h
index 01d8e6b0ee..a08cb3bce2 100644
--- a/engines/fullpipe/modal.h
+++ b/engines/fullpipe/modal.h
@@ -235,12 +235,12 @@ public:
virtual void update();
virtual void saveload() {}
- bool create(Scene *sc, PictureObject *picObjList, int picId);
+ bool create(Scene *sc, Scene *bgScene, int picId);
int getQueryResult() { return _queryResult; }
private:
- PictureObject *_picObjList;
+ Scene *_bgScene;
PictureObject *_bg;
PictureObject *_okBtn;
PictureObject *_cancelBtn;
diff --git a/engines/fullpipe/module.mk b/engines/fullpipe/module.mk
index 3962fe64ba..96bd91fd39 100644
--- a/engines/fullpipe/module.mk
+++ b/engines/fullpipe/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS = \
lift.o \
messagehandlers.o \
messages.o \
+ mgm.o \
modal.o \
motion.o \
ngiarchive.o \
diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp
index 321df7fd22..49cf88434e 100644
--- a/engines/fullpipe/motion.cpp
+++ b/engines/fullpipe/motion.cpp
@@ -22,15 +22,10 @@
#include "fullpipe/fullpipe.h"
-#include "common/file.h"
-#include "common/array.h"
-#include "common/list.h"
-
-#include "fullpipe/objects.h"
+#include "fullpipe/utils.h"
#include "fullpipe/statics.h"
#include "fullpipe/gameloader.h"
#include "fullpipe/motion.h"
-#include "fullpipe/messages.h"
namespace Fullpipe {
@@ -1470,12 +1465,12 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla
return arr;
}
-void MovGraph::shuffleTree(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2) {
+void MovGraph::findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &allPaths) {
if (lnk == lnk2) {
for (uint i = 0; i < tempObList1.size(); i++)
- tempObList2.push_back(tempObList1[i]);
+ allPaths.push_back(tempObList1[i]);
- tempObList2.push_back(lnk);
+ allPaths.push_back(lnk);
} else {
lnk->_flags |= 0x80000000;
@@ -1492,39 +1487,42 @@ void MovGraph::shuffleTree(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<
}
if (!(l->_flags & 0xA0000000))
- shuffleTree(l, lnk2, tempObList1, tempObList2);
+ findAllPaths(l, lnk2, tempObList1, allPaths);
}
lnk->_flags &= 0x7FFFFFFF;
}
}
-Common::Array<MovItem *> *MovGraph::calcMovItems(MovArr *movarr1, MovArr *movarr2, int *listCount) {
+// Returns a list of possible paths two points in graph space
+Common::Array<MovItem *> *MovGraph::calcMovItems(MovArr *currPos, MovArr *destPos, int *pathCount) {
Common::Array<MovGraphLink *> tempObList1;
- Common::Array<MovGraphLink *> tempObList2;
+ Common::Array<MovGraphLink *> allPaths;
- shuffleTree(movarr1->_link, movarr2->_link, tempObList1, tempObList2);
+ // Get all paths between two edges of the graph
+ findAllPaths(currPos->_link, destPos->_link, tempObList1, allPaths);
- *listCount = 0;
+ *pathCount = 0;
- if (!tempObList2.size())
+ if (!allPaths.size())
return 0;
- *listCount = tempObList2.size();
+ *pathCount = allPaths.size();
Common::Array<MovItem *> *res = new Common::Array<MovItem *>;
- for (int i = 0; i < *listCount; i++) {
+ for (int i = 0; i < *pathCount; i++) {
MovItem *r = new MovItem;
- genMovItem(r, tempObList2[i], movarr1, movarr2);
+ genMovItem(r, allPaths[i], currPos, destPos);
res->push_back(r);
- delete tempObList2[i];
+ delete allPaths[i];
}
- movarr2->_link = movarr1->_link;
+ // Start the resulting path from current position
+ destPos->_link = currPos->_link;
return res;
}
@@ -2430,7 +2428,7 @@ MessageQueue *MovGraph2::genMovement(MovInfo1 *info) {
int y = info->pt2.y - info->pt1.y - my2 - my1;
int x = info->pt2.x - info->pt1.x - mx2 - mx1;
- int a2;
+ int a2 = 0;
int mgmLen;
_mgm.calcLength(&point, _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov, x, y, &mgmLen, &a2, info->flags & 1);
@@ -2776,693 +2774,6 @@ MovGraphNode *MovGraph::calcOffset(int ox, int oy) {
return res;
}
-void MGM::clear() {
- _items.clear();
-}
-
-MessageQueue *MGM::genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr) {
- int idx = getItemIndexById(ani->_id);
-
- if (idx == -1)
- return 0;
-
- int stid = staticsId;
-
- if (!staticsId) {
- if (ani->_movement) {
- stid = ani->_movement->_staticsObj2->_staticsId;
- } else {
- if (!ani->_statics)
- return 0;
-
- stid = ani->_statics->_staticsId;
- }
- }
-
- if (stid == staticsIndex)
- return new MessageQueue(g_fp->_globalMessageQueueList->compact());
-
- int startidx = getStaticsIndexById(idx, stid);
- int endidx = getStaticsIndexById(idx, staticsIndex);
- int subidx = startidx + endidx * _items[idx]->statics.size();
-
- if (!_items[idx]->subItems[subidx]->movement) {
- clearMovements2(idx);
- recalcOffsets(idx, startidx, endidx, 0, 1);
- }
-
- if (!_items[idx]->subItems[subidx]->movement)
- return 0;
-
- MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact());
- Common::Point point;
- ExCommand *ex;
-
- int i = 0;
- do {
- subidx = startidx + endidx * _items[idx]->statics.size();
-
- _items[idx]->subItems[subidx]->movement->calcSomeXY(point, 0, -1);
-
- if (pointArr) {
- int sz;
-
- if (_items[idx]->subItems[subidx]->movement->_currMovement)
- sz = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size();
- else
- sz = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size();
-
- ex = new ExCommand2(20, ani->_id, &pointArr[i], sz);
-
- ex->_messageNum = _items[idx]->subItems[subidx]->movement->_id;
- } else {
- ex = new ExCommand(ani->_id, 1, _items[idx]->subItems[subidx]->movement->_id, 0, 0, 0, 1, 0, 0, 0);
- }
-
- ex->_keyCode = ani->_okeyCode;
- ex->_field_3C = 1;
- ex->_field_24 = 1;
-
- mq->addExCommandToEnd(ex);
-
- if (resStatId)
- *resStatId = _items[idx]->subItems[subidx]->movement->_id;
-
- startidx = _items[idx]->subItems[subidx]->staticsIndex;
-
- uint step;
-
- if (_items[idx]->subItems[subidx]->movement->_currMovement)
- step = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size();
- else
- step = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size();
-
- i += step;
- } while (startidx != endidx);
-
- return mq;
-}
-
-MGMItem::MGMItem() {
- objId = 0;
-}
-
-MGMSubItem::MGMSubItem() {
- movement = 0;
- staticsIndex = 0;
- field_8 = 0;
- field_C = 0;
- x = 0;
- y = 0;
-}
-
-void MGM::addItem(int objId) {
- if (getItemIndexById(objId) == -1) {
- MGMItem *item = new MGMItem();
-
- item->objId = objId;
- _items.push_back(item);
- }
- rebuildTables(objId);
-}
-
-void MGM::rebuildTables(int objId) {
- int idx = getItemIndexById(objId);
-
- if (idx == -1)
- return;
-
- _items[idx]->subItems.clear();
- _items[idx]->statics.clear();
- _items[idx]->movements1.clear();
- _items[idx]->movements2.clear();
-
- StaticANIObject *obj = g_fp->_currentScene->getStaticANIObject1ById(objId, -1);
-
- if (!obj)
- return;
-
- for (uint i = 0; i < obj->_staticsList.size(); i++)
- _items[idx]->statics.push_back((Statics *)obj->_staticsList[i]);
-
- for (uint i = 0; i < obj->_movements.size(); i++)
- _items[idx]->movements1.push_back((Movement *)obj->_movements[i]);
-
- _items[idx]->subItems.clear();
-}
-
-int MGM::getItemIndexById(int objId) {
- for (uint i = 0; i < _items.size(); i++)
- if (_items[i]->objId == objId)
- return i;
-
- return -1;
-}
-
-MessageQueue *MGM::genMovement(MGMInfo *mgminfo) {
- if (!mgminfo->ani)
- return 0;
-
- Movement *mov = mgminfo->ani->_movement;
-
- if (!mov && !mgminfo->ani->_statics)
- return 0;
-
- if (!(mgminfo->flags & 1)) {
- if (mov)
- mgminfo->staticsId1 = mov->_staticsObj2->_staticsId;
- else
- mgminfo->staticsId1 = mgminfo->ani->_statics->_staticsId;
- }
-
- Common::Point point;
-
- if (!(mgminfo->flags & 0x10) || !(mgminfo->flags & 0x20)) {
- int nx = mgminfo->ani->_ox;
- int ny = mgminfo->ani->_oy;
-
- if (mgminfo->ani->_movement) {
- mgminfo->ani->calcNextStep(&point);
-
- nx += point.x;
- ny += point.y;
- }
-
- if (!(mgminfo->flags & 0x10))
- mgminfo->x2 = nx;
-
- if (!(mgminfo->flags & 0x20))
- mgminfo->y2 = ny;
- }
-
- mov = mgminfo->ani->getMovementById(mgminfo->movementId);
-
- if (!mov)
- return 0;
-
- int itemIdx = getItemIndexById(mgminfo->ani->_id);
- int subIdx = getStaticsIndexById(itemIdx, mgminfo->staticsId1);
- int st2idx = getStaticsIndexById(itemIdx, mov->_staticsObj1->_staticsId);
- int st1idx = getStaticsIndexById(itemIdx, mov->_staticsObj2->_staticsId);
- int subOffset = getStaticsIndexById(itemIdx, mgminfo->staticsId2);
-
- clearMovements2(itemIdx);
- recalcOffsets(itemIdx, subIdx, st2idx, 0, 1);
- clearMovements2(itemIdx);
- recalcOffsets(itemIdx, st1idx, subOffset, 0, 1);
-
- MGMSubItem *sub1 = _items[itemIdx]->subItems[subIdx + st2idx * _items[itemIdx]->statics.size()];
- MGMSubItem *sub2 = _items[itemIdx]->subItems[st1idx + subOffset * _items[itemIdx]->statics.size()];
-
- if (subIdx != st2idx && !sub1->movement)
- return 0;
-
- if (st1idx != subOffset && !sub2->movement)
- return 0;
-
- int n1x = mgminfo->x1 - mgminfo->x2 - sub1->x - sub2->x;
- int n1y = mgminfo->y1 - mgminfo->y2 - sub1->y - sub2->y;
-
- Common::Point point1;
-
- mov->calcSomeXY(point1, 0, -1);
-
- int n2x = point1.x;
- int n2y = point1.y;
- int mult;
- int len = -1;
-
- if (mgminfo->flags & 0x40) {
- mult = mgminfo->field_10;
- len = -1;
- n2x *= mult;
- n2y *= mult;
- } else {
- calcLength(&point, mov, n1x, n1y, &mult, &len, 1);
- n2x = point.x;
- n2y = point.y;
- }
-
- if (!(mgminfo->flags & 2)) {
- len = -1;
- n2x = mult * point1.x;
- n1x = mult * point1.x;
- mgminfo->x1 = mgminfo->x2 + mult * point1.x + sub1->x + sub2->x;
- }
-
- if (!(mgminfo->flags & 4)) {
- n2y = mult * point1.y;
- n1y = mult * point1.y;
- len = -1;
- mgminfo->y1 = mgminfo->y2 + mult * point1.y + sub1->y + sub2->y;
- }
-
- int px = 0;
- int py = 0;
-
- if (sub1->movement) {
- px = countPhases(itemIdx, subIdx, st2idx, 1);
- py = countPhases(itemIdx, subIdx, st2idx, 2);
- }
-
- if (mult > 1) {
- px += (mult - 1) * mov->countPhasesWithFlag(-1, 1);
- py += (mult - 1) * mov->countPhasesWithFlag(-1, 2);
- }
-
- if (mult > 0) {
- px += mov->countPhasesWithFlag(len, 1);
- py += mov->countPhasesWithFlag(len, 2);
- }
-
- if (sub2->movement) {
- px += countPhases(itemIdx, st1idx, subOffset, 1);
- py += countPhases(itemIdx, st1idx, subOffset, 2);
- }
-
- int dx1 = n1x - n2x;
- int dy1 = n1y - n2y;
- int x1, y1;
-
- if (px) {
- x1 = (int)((double)dx1 / (double)px);
- } else {
- x1 = 0;
- }
-
- if (py) {
- y1 = (int)((double)dy1 / (double)py);
- } else {
- y1 = 0;
- }
-
- Common::Point x2, y2;
-
- y2.x = dx1 - px * x1;
- y2.y = dy1 - py * y1;
-
- if (n1x - n2x == px * x1)
- x2.x = 0;
- else
- x2.x = (dx1 - px * x1) / abs(dx1 - px * x1);
-
- if (dy1 == py * y1)
- x2.y = 0;
- else
- x2.y = (dy1 - py * y1) / abs(dy1 - py * y1);
-
- MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact());
- ExCommand2 *ex2;
-
- for (int i = subIdx; i != st2idx;) {
- MGMSubItem *s = _items[itemIdx]->subItems[i + subOffset * _items[itemIdx]->statics.size()];
-
- ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1);
- ex2->_parId = mq->_id;
- ex2->_keyCode = mgminfo->ani->_okeyCode;
-
- mq->addExCommandToEnd(ex2);
-
- i = s->staticsIndex;
- }
-
- for (int i = 0; i < mult; ++i) {
- int plen;
-
- if (i == mult - 1)
- plen = len;
- else
- plen = -1;
-
- ex2 = buildExCommand2(mov, mgminfo->ani->_id, x1, y1, &x2, &y2, plen);
- ex2->_parId = mq->_id;
- ex2->_keyCode = mgminfo->ani->_okeyCode;
-
- mq->addExCommandToEnd(ex2);
- }
-
- for (int j = st1idx; j != subOffset;) {
- MGMSubItem *s = _items[itemIdx]->subItems[j + subOffset * _items[itemIdx]->statics.size()];
-
- ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1);
- ex2->_parId = mq->_id;
- ex2->_keyCode = mgminfo->ani->_okeyCode;
-
- mq->addExCommandToEnd(ex2);
-
- j = s->staticsIndex;
- }
-
- ExCommand *ex = new ExCommand(mgminfo->ani->_id, 5, -1, mgminfo->x1, mgminfo->y1, 0, 1, 0, 0, 0);
-
- ex->_field_14 = mgminfo->field_1C;
- ex->_keyCode = mgminfo->ani->_okeyCode;
- ex->_field_24 = 0;
- ex->_excFlags |= 3;
-
- mq->addExCommandToEnd(ex);
-
- return mq;
-}
-
-int MGM::countPhases(int idx, int subIdx, int endIdx, int flag) {
- int res = 0;
-
- if (endIdx < 0)
- return 0;
-
- while (subIdx != endIdx) {
- if (subIdx < 0)
- break;
-
- res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(-1, flag);
-
- subIdx = _items[idx]->subItems[subIdx + 6 * endIdx * _items[idx]->statics.size()]->staticsIndex;
- }
-
- return res;
-}
-void MGM::updateAnimStatics(StaticANIObject *ani, int staticsId) {
- if (getItemIndexById(ani->_id) == -1)
- return;
-
- if (ani->_movement) {
- ani->queueMessageQueue(0);
- ani->_movement->gotoLastFrame();
- ani->_statics = ani->_movement->_staticsObj2;
-
- int x = ani->_movement->_ox;
- int y = ani->_movement->_oy;
-
- ani->_movement = 0;
-
- ani->setOXY(x, y);
- }
-
- if (ani->_statics) {
- Common::Point point;
-
- getPoint(&point, ani->_id, ani->_statics->_staticsId, staticsId);
-
- ani->setOXY(ani->_ox + point.x, ani->_oy + point.y);
-
- ani->_statics = ani->getStaticsById(staticsId);
- }
-}
-
-Common::Point *MGM::getPoint(Common::Point *point, int objectId, int staticsId1, int staticsId2) {
- int idx = getItemIndexById(objectId);
-
- if (idx == -1) {
- point->x = -1;
- point->y = -1;
- } else {
- int st1idx = getStaticsIndexById(idx, staticsId1);
- int st2idx = getStaticsIndexById(idx, staticsId2);
-
- if (st1idx == st2idx) {
- point->x = 0;
- point->y = 0;
- } else {
- int subidx = st1idx + st2idx * _items[idx]->statics.size();
-
- if (!_items[idx]->subItems[subidx]->movement) {
- clearMovements2(idx);
- recalcOffsets(idx, st1idx, st2idx, false, true);
-
- if (!_items[idx]->subItems[subidx]->movement) {
- clearMovements2(idx);
- recalcOffsets(idx, st1idx, st2idx, true, false);
- }
- }
-
- MGMSubItem *sub = _items[idx]->subItems[subidx];
-
- if (sub->movement) {
- point->x = sub->x;
- point->y = sub->y;
- } else {
- point->x = 0;
- point->y = 0;
- }
- }
- }
-
- return point;
-}
-
-int MGM::getStaticsIndexById(int idx, int16 id) {
- if (!_items[idx]->statics.size())
- return -1;
-
- for (uint i = 0; i < _items[idx]->statics.size(); i++) {
- if (_items[idx]->statics[i]->_staticsId == id)
- return i;
- }
-
- return 0;
-}
-
-int MGM::getStaticsIndex(int idx, Statics *st) {
- if (!_items[idx]->statics.size())
- return -1;
-
- for (uint i = 0; i < _items[idx]->statics.size(); i++) {
- if (_items[idx]->statics[i] == st)
- return i;
- }
-
- return 0;
-}
-
-void MGM::clearMovements2(int idx) {
- _items[idx]->movements2.clear();
-}
-
-int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) {
- MGMItem *item = _items[idx];
- int subIdx = st1idx + st2idx * item->statics.size();
-
- if (st1idx == st2idx) {
- memset(&item->subItems[subIdx], 0, sizeof(item->subItems[subIdx]));
- return 0;
- }
-
- if (item->subItems[subIdx])
- return item->subItems[subIdx]->field_8;
-
- Common::Point point;
-
- for (uint i = 0; i < item->movements1.size(); i++) {
- Movement *mov = item->movements1[i];
-
- if (mov->_staticsObj1 == item->statics[st1idx]) {
- if (!item->movements2[i] && (!flop || mov->_field_50)) {
- item->movements2[i] = 1;
-
- int stidx = getStaticsIndex(idx, item->movements1[i]->_staticsObj2);
- int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
- int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
- int newsz = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C;
-
- if (recalc >= 0) {
- if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 ||
- (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) {
- item->subItems[subIdx]->movement = mov;
- item->subItems[subIdx]->staticsIndex = stidx;
- item->subItems[subIdx]->field_8 = recalc + 1;
- item->subItems[subIdx]->field_C = newsz;
-
- mov->calcSomeXY(point, 0, -1);
-
- item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x + point.x;
- item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y + point.y;
- }
- }
- }
- } else if (flip) {
- if (mov->_staticsObj2 == item->statics[st1idx]) {
- if (!item->movements2[i] && (!flop || mov->_field_50)) {
- item->movements2[i] = 1;
-
- int stidx = getStaticsIndex(idx, mov->_staticsObj1);
- int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop);
-
- if (recalc >= 0) {
- if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) {
- item->subItems[subIdx]->movement = mov;
- item->subItems[subIdx]->staticsIndex = stidx;
- item->subItems[subIdx]->field_8 = recalc + 1;
-
- int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
-
- item->subItems[subIdx]->field_C = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C;
-
- mov->calcSomeXY(point, 0, -1);
-
- item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x - point.x;
- item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y - point.y;
- }
- }
- }
- }
- }
- }
-
- if (item->subItems[subIdx]->movement)
- return item->subItems[subIdx]->field_8;
-
- return -1;
-}
-
-int MGM::refreshOffsets(int objectId, int idx1, int idx2) {
- int idx = getItemIndexById(objectId);
-
- if (idx != -1) {
- int from = getStaticsIndexById(idx, idx1);
- int to = getStaticsIndexById(idx, idx2);
-
- MGMSubItem *sub = _items[idx]->subItems[from + to * _items[idx]->statics.size()];
-
- if (sub->movement) {
- idx = sub->field_8;
- } else {
- clearMovements2(idx);
- idx = recalcOffsets(idx, from, to, 0, 1);
- }
- }
-
- return idx;
-}
-
-Common::Point *MGM::calcLength(Common::Point *pRes, Movement *mov, int x, int y, int *mult, int *len, int flag) {
- Common::Point point;
-
- mov->calcSomeXY(point, 0, -1);
- int p1x = point.x;
- int p1y = point.y;
-
- int newmult = 0;
- int oldlen = *len;
-
- if (abs(p1y) > abs(p1x)) {
- if (mov->calcSomeXY(point, 0, -1)->y)
- newmult = (int)((double)y / mov->calcSomeXY(point, 0, -1)->y);
- } else if (mov->calcSomeXY(point, 0, -1)->x) {
- newmult = (int)((double)x / mov->calcSomeXY(point, 0, -1)->x);
- }
-
- if (newmult < 0)
- newmult = 0;
-
- *mult = newmult;
-
- int phase = 1;
- int sz;
-
- if (flag) {
- if (abs(p1y) > abs(p1x)) {
- while (abs(p1y * newmult + mov->calcSomeXY(point, 0, phase)->y) < abs(y)) {
- sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
-
- if (phase > sz)
- break;
-
- phase++;
- }
- } else {
- while (abs(p1x * newmult + mov->calcSomeXY(point, 0, phase)->x) < abs(x)) {
- sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size();
-
- if (phase >= sz)
- break;
-
- phase++;
- }
- }
-
- *len = phase - 1;
- } else {
- *len = -1;
- }
-
- int p2x = 0;
- int p2y = 0;
-
- if (!oldlen)
- oldlen = -1;
-
- if (oldlen > 0) {
- ++*mult;
-
- mov->calcSomeXY(point, 0, oldlen);
- p2x = point.x;
- p2y = point.y;
-
- if (abs(p1y) > abs(p1x))
- p2x = p1x;
- else
- p2y = p1y;
- }
-
- pRes->x = p2x + p1x * newmult;
- pRes->y = p2y + p1y * newmult;
-
- return pRes;
-}
-
-ExCommand2 *MGM::buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len) {
- uint cnt;
-
- if (mov->_currMovement)
- cnt = mov->_currMovement->_dynamicPhases.size();
- else
- cnt = mov->_dynamicPhases.size();
-
- if (len > 0 && cnt > (uint)len)
- cnt = len;
-
- Common::Point **points = (Common::Point **)malloc(sizeof(Common::Point *) * cnt);
-
- for (uint i = 0; i < cnt; i++) {
- int flags = mov->getDynamicPhaseByIndex(i)->getDynFlags();
-
- points[i] = new Common::Point;
-
- if (flags & 1) {
- points[i]->x = x1 + x2->x;
-
- y2->x -= x2->x;
-
- if (!y2->x)
- x2->x = 0;
- }
-
- if (flags & 2) {
- points[i]->y = y1 + x2->y;
-
- y2->y -= x2->y;
-
- if (!y2->y)
- x2->y = 0;
- }
- }
-
- ExCommand2 *ex = new ExCommand2(20, objId, points, cnt);
- ex->_excFlags = 2;
- ex->_messageNum = mov->_id;
- ex->_field_14 = len;
- ex->_field_24 = 1;
- ex->_keyCode = -1;
-
- for (uint i = 0; i < cnt; i++)
- delete points[i];
-
- free(points);
-
- return ex;
-}
-
MovGraphLink::MovGraphLink() {
_distance = 0;
_angle = 0;
diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h
index 2cbf999f86..c488039e22 100644
--- a/engines/fullpipe/motion.h
+++ b/engines/fullpipe/motion.h
@@ -23,14 +23,13 @@
#ifndef FULLPIPE_MOTION_H
#define FULLPIPE_MOTION_H
+#include "fullpipe/mgm.h"
+
namespace Fullpipe {
-class Statics;
-class Movement;
class MctlConnectionPoint;
class MovGraphLink;
class MessageQueue;
-class ExCommand2;
struct MovArr;
struct MovItem;
@@ -124,67 +123,6 @@ public:
MotionController *getMotionController(int num) { return _motionControllers[num]->_motionControllerObj; }
};
-struct MGMSubItem {
- Movement *movement;
- int staticsIndex;
- int field_8;
- int field_C;
- int x;
- int y;
-
- MGMSubItem();
-};
-
-struct MGMItem {
- int16 objId;
- Common::Array<MGMSubItem *> subItems;
- Common::Array<Statics *> statics;
- Common::Array<Movement *> movements1;
- Common::Array<int> movements2;
-
- MGMItem();
-};
-
-struct MGMInfo {
- StaticANIObject *ani;
- int staticsId1;
- int staticsId2;
- int movementId;
- int field_10;
- int x1;
- int y1;
- int field_1C;
- int x2;
- int y2;
- int flags;
-
- MGMInfo() { memset(this, 0, sizeof(MGMInfo)); }
-};
-
-class MGM : public CObject {
-public:
- Common::Array<MGMItem *> _items;
-
-public:
- void clear();
- void addItem(int objId);
- void rebuildTables(int objId);
- int getItemIndexById(int objId);
-
- MessageQueue *genMovement(MGMInfo *mgminfo);
- void updateAnimStatics(StaticANIObject *ani, int staticsId);
- Common::Point *getPoint(Common::Point *point, int aniId, int staticsId1, int staticsId2);
- int getStaticsIndexById(int idx, int16 id);
- int getStaticsIndex(int idx, Statics *st);
- void clearMovements2(int idx);
- int recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop);
- Common::Point *calcLength(Common::Point *point, Movement *mov, int x, int y, int *mult, int *len, int flag);
- ExCommand2 *buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len);
- MessageQueue *genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr);
- int countPhases(int idx, int subIdx, int subOffset, int flag);
- int refreshOffsets(int objectId, int idx1, int idx2);
-};
-
struct MctlLadderMovementVars {
int varUpGo;
int varDownGo;
@@ -370,7 +308,7 @@ public:
MovGraphNode *calcOffset(int ox, int oy);
int getItemIndexByStaticAni(StaticANIObject *ani);
Common::Array<MovArr *> *genMovArr(int x, int y, int *arrSize, int flag1, int flag2);
- void shuffleTree(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2);
+ void findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2);
Common::Array<MovItem *> *calcMovItems(MovArr *movarr1, MovArr *movarr2, int *listCount);
void genMovItem(MovItem *movitem, MovGraphLink *grlink, MovArr *movarr1, MovArr *movarr2);
bool calcChunk(int idx, int x, int y, MovArr *arr, int a6);
diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp
index 1247d9380e..8463b3ab40 100644
--- a/engines/fullpipe/scene.cpp
+++ b/engines/fullpipe/scene.cpp
@@ -654,7 +654,7 @@ void Scene::drawContent(int minPri, int maxPri, bool drawBg) {
g_fp->_globalPalette = _palette->_data;
}
- debug(8, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg);
+ debug(1, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg);
if (_picObjList.size() > 2) { // We need to z-sort them
objectList_sortByPriority(_picObjList, true);
@@ -666,11 +666,17 @@ void Scene::drawContent(int minPri, int maxPri, bool drawBg) {
if (maxPri == -1)
maxPri = 60000;
- debug(8, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg);
+ debug(1, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg);
Common::Point point;
- debug(8, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size());
+ debug(1, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size());
+
+ for (uint i = 0; i < _picObjList.size(); i++) {
+ debug(1, "%d: %d", i, ((PictureObject *)_picObjList[i])->_priority);
+ }
+
+
if (drawBg && _bigPictureArray1Count && _picObjList.size()) {
_bigPictureArray[0][0]->getDimensions(&point);
diff --git a/engines/fullpipe/scenes/scene04.cpp b/engines/fullpipe/scenes/scene04.cpp
index 0a69335bea..fd1ececdf2 100644
--- a/engines/fullpipe/scenes/scene04.cpp
+++ b/engines/fullpipe/scenes/scene04.cpp
@@ -633,6 +633,7 @@ MessageQueue *sceneHandler04_kozFly5(StaticANIObject *ani, double phase) {
mq1->addExCommandToEnd(mq2->getExCommandByIndex(0)->createClone());
delete mq2;
+ mq2 = 0;
ExCommand *ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_STANDUP, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 2;
@@ -662,6 +663,9 @@ MessageQueue *sceneHandler04_kozFly5(StaticANIObject *ani, double phase) {
mq1->addExCommandToEnd(ex);
}
+ if (mq2)
+ delete mq2;
+
return mq1;
}
diff --git a/engines/fullpipe/scenes/scene29.cpp b/engines/fullpipe/scenes/scene29.cpp
index 2d5127137d..8f82e99ad1 100644
--- a/engines/fullpipe/scenes/scene29.cpp
+++ b/engines/fullpipe/scenes/scene29.cpp
@@ -972,7 +972,7 @@ int sceneHandler29(ExCommand *cmd) {
break;
case MSG_SC29_SHOWLASTRED:
- if (g_vars->scene29_balls.numBalls) {
+ if (g_vars->scene29_redBalls.numBalls) { // original uses scene29_balls which looks like a copy/paste error
g_vars->scene29_redBalls.field_8->ani->show1(-1, -1, -1, 0);
g_vars->scene29_redBalls.field_8->ani->startAnim(MV_SHR_HITASS, 0, -1);
}
diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp
index 65c9bf84ca..a4ca06f489 100644
--- a/engines/fullpipe/sound.cpp
+++ b/engines/fullpipe/sound.cpp
@@ -268,7 +268,7 @@ void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) {
while (sub) {
if (_musicAllowed & sub->_value.intValue) {
- strcpy(_sceneTracks[_numSceneTracks], sub->_varName);
+ Common::strlcpy(_sceneTracks[_numSceneTracks], sub->_varName, 260);
_numSceneTracks++;
}
@@ -286,7 +286,7 @@ void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) {
if (seq) {
_sceneTrackHasSequence = true;
- strcpy(_trackName, seq->_value.stringValue);
+ Common::strlcpy(_trackName, seq->_value.stringValue, 2600);
}
if (_musicLocal)
@@ -432,7 +432,7 @@ void FullpipeEngine::playTrack(GameVar *sceneVar, const char *name, bool delayed
while (sub) {
if (_musicAllowed & sub->_value.intValue) {
- strcpy(_sceneTracks[_numSceneTracks], sub->_varName);
+ Common::strlcpy(_sceneTracks[_numSceneTracks], sub->_varName, 260);
_numSceneTracks++;
}
@@ -450,7 +450,7 @@ void FullpipeEngine::playTrack(GameVar *sceneVar, const char *name, bool delayed
if (seq) {
_sceneTrackHasSequence = true;
- strcpy(_trackName, seq->_value.stringValue);
+ Common::strlcpy(_trackName, seq->_value.stringValue, 2600);
}
if (delayed) {
diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp
index 41641457d3..141196c7d7 100644
--- a/engines/fullpipe/stateloader.cpp
+++ b/engines/fullpipe/stateloader.cpp
@@ -162,7 +162,43 @@ GameVar::GameVar() {
}
GameVar::~GameVar() {
- warning("STUB: GameVar::~GameVar()");
+ if (_varType == 2)
+ free(_value.stringValue);
+
+ if (_parentVarObj && !_prevVarObj ) {
+ if (_parentVarObj->_subVars == this) {
+ _parentVarObj->_subVars = _nextVarObj;
+ } else if (_parentVarObj->_field_14 == this) {
+ _parentVarObj->_field_14 = _nextVarObj;
+ } else {
+ _parentVarObj = 0;
+ }
+ }
+
+ if (_prevVarObj)
+ _prevVarObj->_nextVarObj = _nextVarObj;
+
+ if (_nextVarObj)
+ _nextVarObj->_prevVarObj = _prevVarObj;
+
+ _prevVarObj = 0;
+ _nextVarObj = 0;
+
+ GameVar *s = _subVars;
+
+ while (s) {
+ delete s;
+ s = _subVars;
+ }
+
+ s = _field_14;
+
+ while (s) {
+ delete s;
+ s = _field_14;
+ }
+
+ free(_varName);
}
bool GameVar::load(MfcArchive &file) {
diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp
index 292ef08914..717de84925 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -528,15 +528,15 @@ void Movement::draw(bool flipFlag, int angle) {
if (_currMovement) {
bmp = _currDynamicPhase->getPixelData()->reverseImage();
} else {
- bmp = _currDynamicPhase->getPixelData();
+ bmp = _currDynamicPhase->getPixelData()->reverseImage(false);
}
if (flipFlag) {
- bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData);
+ bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
} if (angle) {
- bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData);
+ bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
} else {
- bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData);
+ bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
}
if (_currDynamicPhase->_rect->top) {
@@ -549,11 +549,11 @@ void Movement::draw(bool flipFlag, int angle) {
if (_currDynamicPhase->_convertedBitmap) {
if (_currMovement) {
//vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top));
- _currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData);
+ _currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
//vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255);
} else {
//vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top));
- _currDynamicPhase->_convertedBitmap->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData);
+ _currDynamicPhase->_convertedBitmap->reverseImage(false)->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
//vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255);
}
}
@@ -1454,14 +1454,8 @@ bool Statics::load(MfcArchive &file) {
void Statics::init() {
Picture::init();
- if (_staticsId & 0x4000) {
- Bitmap *bmp = _bitmap->reverseImage();
-
- freePixelData();
-
- _bitmap = bmp;
- _data = bmp->_pixels;
- }
+ if (_staticsId & 0x4000)
+ _bitmap->reverseImage();
}
Common::Point *Statics::getSomeXY(Common::Point &p) {
@@ -2212,9 +2206,12 @@ DynamicPhase::DynamicPhase(DynamicPhase *src, bool reverse) {
_libHandle = src->_libHandle;
_bitmap = src->_bitmap;
- if (_bitmap)
+ if (_bitmap) {
_field_54 = 1;
+ _bitmap = src->_bitmap->reverseImage(false);
+ }
+
_someX = src->_someX;
_someY = src->_someY;
}
diff --git a/engines/gob/detection/tables_ween.h b/engines/gob/detection/tables_ween.h
index 66a83aff0f..bf65685d46 100644
--- a/engines/gob/detection/tables_ween.h
+++ b/engines/gob/detection/tables_ween.h
@@ -228,93 +228,6 @@
0, 0, 0
},
-// -- DOS VGA Floppy --
-
-{
- {
- "ween",
- "",
- AD_ENTRY1("intro.stk", "2bb8878a8042244dd2b96ff682381baa"),
- EN_GRB,
- kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
- },
- kGameTypeWeen,
- kFeaturesAdLib,
- 0, 0, 0
-},
-{
- {
- "ween",
- "",
- AD_ENTRY1s("intro.stk", "de92e5c6a8c163007ffceebef6e67f7d", 7117568),
- EN_USA,
- kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
- },
- kGameTypeWeen,
- kFeaturesAdLib,
- 0, 0, 0
-},
-{ // Supplied by cybot_tmin in bug report #1667743
- {
- "ween",
- "",
- AD_ENTRY1s("intro.stk", "6d60f9205ecfbd8735da2ee7823a70dc", 7014426),
- ES_ESP,
- kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
- },
- kGameTypeWeen,
- kFeaturesAdLib,
- 0, 0, 0
-},
-{
- {
- "ween",
- "",
- AD_ENTRY1("intro.stk", "4b10525a3782aa7ecd9d833b5c1d308b"),
- FR_FRA,
- kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
- },
- kGameTypeWeen,
- kFeaturesAdLib,
- 0, 0, 0
-},
-{ // Supplied by cartman_ on #scummvm
- {
- "ween",
- "",
- AD_ENTRY1("intro.stk", "63170e71f04faba88673b3f510f9c4c8"),
- DE_DEU,
- kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
- },
- kGameTypeWeen,
- kFeaturesAdLib,
- 0, 0, 0
-},
-{ // Supplied by glorfindel in bugreport #1722142
- {
- "ween",
- "",
- AD_ENTRY1s("intro.stk", "8b57cd510da8a3bbd99e3a0297a8ebd1", 7018771),
- IT_ITA,
- kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
- },
- kGameTypeWeen,
- kFeaturesAdLib,
- 0, 0, 0
-},
-
// -- Demos --
{
diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp
index f2a9637dfe..e1f864ddd2 100644
--- a/engines/kyra/items_lol.cpp
+++ b/engines/kyra/items_lol.cpp
@@ -265,7 +265,7 @@ bool LoLEngine::addItemToInventory(Item itemIndex) {
gui_drawInventory();
}
- assert(pos > 0 && pos < 48);
+ assert(pos >= 0 && pos < 48);
_inventory[pos] = itemIndex;
gui_drawInventory();
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index f950f9d5aa..89ee41e859 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -61,7 +61,7 @@ public:
~AdLibDriver();
void initDriver();
- void setSoundData(uint8 *data);
+ void setSoundData(uint8 *data, uint32 size);
void queueTrack(int track, int volume);
bool isChannelPlaying(int channel) const;
void stopAllChannels();
@@ -130,13 +130,13 @@ private:
struct Channel {
bool lock; // New to ScummVM
uint8 opExtraLevel2;
- uint8 *dataptr;
+ const uint8 *dataptr;
uint8 duration;
uint8 repeatCounter;
int8 baseOctave;
uint8 priority;
uint8 dataptrStackPos;
- uint8 *dataptrStack[4];
+ const uint8 *dataptrStack[4];
int8 baseNote;
uint8 unk29;
uint8 unk31;
@@ -194,7 +194,7 @@ private:
void setupDuration(uint8 duration, Channel &channel);
void setupNote(uint8 rawNote, Channel &channel, bool flag = false);
- void setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel);
+ void setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel);
void noteOn(Channel &channel);
void adjustVolume(Channel &channel);
@@ -216,14 +216,24 @@ private:
// * One for instruments, starting at offset 500.
uint8 *getProgram(int progId) {
- uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
- //TODO: Check in LoL CD AdLib driver
- if (offset == 0xFFFF)
- return 0;
- return _soundData + READ_LE_UINT16(_soundData + 2 * progId);
+ const uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
+
+ // In case an invalid offset is specified we return nullptr to
+ // indicate an error. 0xFFFF seems to indicate "this is not a valid
+ // program/instrument". However, 0 is also invalid because it points
+ // inside the offset table itself. We also ignore any offsets outside
+ // of the actual data size.
+ // The original does not contain any safety checks and will simply
+ // read outside of the valid sound data in case an invalid offset is
+ // encountered.
+ if (offset == 0 || offset >= _soundDataSize) {
+ return nullptr;
+ } else {
+ return _soundData + offset;
+ }
}
- uint8 *getInstrument(int instrumentId) {
+ const uint8 *getInstrument(int instrumentId) {
return getProgram(_numPrograms + instrumentId);
}
@@ -231,7 +241,7 @@ private:
void executePrograms();
struct ParserOpcode {
- typedef int (AdLibDriver::*POpcode)(uint8 *&dataptr, Channel &channel, uint8 value);
+ typedef int (AdLibDriver::*POpcode)(const uint8 *&dataptr, Channel &channel, uint8 value);
POpcode function;
const char *name;
};
@@ -240,61 +250,61 @@ private:
const ParserOpcode *_parserOpcodeTable;
int _parserOpcodeTableSize;
- int update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_jump(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_playRest(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_writeAdLib(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_playNote(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_nop(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_jump(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_nop(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value);
private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
@@ -358,6 +368,7 @@ private:
FM_OPL *_adlib;
uint8 *_soundData;
+ uint32 _soundDataSize;
struct QueueEntry {
QueueEntry() : data(0), id(0), volume(0) {}
@@ -421,6 +432,7 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
memset(_channels, 0, sizeof(_channels));
_soundData = 0;
+ _soundDataSize = 0;
_vibratoAndAMDepthBits = _curRegOffset = 0;
@@ -522,7 +534,7 @@ void AdLibDriver::initDriver() {
resetAdLibState();
}
-void AdLibDriver::setSoundData(uint8 *data) {
+void AdLibDriver::setSoundData(uint8 *data, uint32 size) {
Common::StackLock lock(_mutex);
// Drop all tracks that are still queued. These would point to the old
@@ -536,6 +548,7 @@ void AdLibDriver::setSoundData(uint8 *data) {
}
_soundData = data;
+ _soundDataSize = size;
}
void AdLibDriver::queueTrack(int track, int volume) {
@@ -791,7 +804,7 @@ void AdLibDriver::executePrograms() {
// This fixes a subtle music bug where the
// wrong music would play when getting the
// quill in Kyra 1.
- uint8 *dataptr = channel.dataptr;
+ const uint8 *dataptr = channel.dataptr;
while (dataptr) {
uint8 opcode = *dataptr++;
uint8 param = *dataptr++;
@@ -1030,7 +1043,7 @@ void AdLibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) {
writeOPL(0xB0 + _curChannel, channel.regBx);
}
-void AdLibDriver::setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel) {
+void AdLibDriver::setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel) {
debugC(9, kDebugLevelSound, "setupInstrument(%d, %p, %lu)", regOffset, (const void *)dataptr, (long)(&channel - _channels));
if (_curChannel >= 9)
@@ -1340,12 +1353,12 @@ uint8 AdLibDriver::calculateOpLevel2(Channel &channel) {
// parser opcodes
-int AdLibDriver::update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.repeatCounter = value;
return 0;
}
-int AdLibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value) {
++dataptr;
if (--channel.repeatCounter) {
int16 add = READ_LE_UINT16(dataptr - 2);
@@ -1354,14 +1367,23 @@ int AdLibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 val
return 0;
}
-int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (value == 0xFF)
return 0;
- uint8 *ptr = getProgram(value);
- //TODO: Check in LoL CD AdLib driver
- if (!ptr)
+ const uint8 *ptr = getProgram(value);
+
+ // In case we encounter an invalid program we simply ignore it and do
+ // nothing instead. The original did not care about invalid programs and
+ // simply tried to play them anyway... But to avoid crashes due we ingore
+ // them.
+ // This, for example, happens in the Lands of Lore intro when Scotia gets
+ // the ring in the intro.
+ if (!ptr) {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupProgram: Invalid program %d specified", value);
return 0;
+ }
+
uint8 chan = *ptr++;
uint8 priority = *ptr++;
@@ -1390,12 +1412,12 @@ int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va
return 0;
}
-int AdLibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.spacing1 = value;
return 0;
}
-int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_jump(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
if (_version == 1)
@@ -1407,7 +1429,7 @@ int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) {
return 0;
}
-int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
channel.dataptrStack[channel.dataptrStackPos++] = dataptr;
@@ -1418,17 +1440,17 @@ int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint
return 0;
}
-int AdLibDriver::update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value) {
dataptr = channel.dataptrStack[--channel.dataptrStackPos];
return 0;
}
-int AdLibDriver::update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.baseOctave = value;
return 0;
}
-int AdLibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.priority = 0;
if (_curChannel != 9)
noteOff(channel);
@@ -1436,30 +1458,30 @@ int AdLibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 val
return 2;
}
-int AdLibDriver::update_playRest(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupDuration(value, channel);
noteOff(channel);
return (value != 0);
}
-int AdLibDriver::update_writeAdLib(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value) {
writeOPL(value, *dataptr++);
return 0;
}
-int AdLibDriver::update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupNote(value, channel);
value = *dataptr++;
setupDuration(value, channel);
return (value != 0);
}
-int AdLibDriver::update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.baseNote = value;
return 0;
}
-int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk18 = value;
channel.unk19 = value;
channel.unk20 = channel.unk21 = *dataptr++;
@@ -1483,7 +1505,7 @@ int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel,
return 0;
}
-int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value) {
Channel &channel2 = _channels[value];
channel2.duration = 0;
channel2.priority = 0;
@@ -1491,8 +1513,16 @@ int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint
return 0;
}
-int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) {
- uint8 *ptr = getProgram(value);
+int AdLibDriver::update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value) {
+ const uint8 *ptr = getProgram(value);
+
+ // Safety check in case an invalid program is specified. This would make
+ // getProgram return a nullptr and thus cause invalid memory reads.
+ if (!ptr) {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_waitForEndOfProgram: Invalid program %d specified", value);
+ return 0;
+ }
+
uint8 chan = *ptr;
if (!_channels[chan].dataptr)
@@ -1502,12 +1532,25 @@ int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, u
return 2;
}
-int AdLibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) {
- setupInstrument(_curRegOffset, getInstrument(value), channel);
+int AdLibDriver::update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value) {
+ const uint8 *instrument = getInstrument(value);
+
+ // We add a safety check to avoid setting up invalid instruments. This is
+ // not done in the original. However, to avoid crashes due to invalid
+ // memory reads we simply ignore the request.
+ // This happens, for example, in Hand of Fate when using the swampsnake
+ // potion on Zanthia to scare off the rat in the cave in the first chapter
+ // of the game.
+ if (!instrument) {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupInstrument: Invalid instrument %d specified", value);
+ return 0;
+ }
+
+ setupInstrument(_curRegOffset, instrument, channel);
return 0;
}
-int AdLibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk29 = value;
channel.unk30 = READ_BE_UINT16(dataptr);
dataptr += 2;
@@ -1516,19 +1559,19 @@ int AdLibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, u
return 0;
}
-int AdLibDriver::update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.primaryEffect = 0;
channel.unk30 = 0;
return 0;
}
-int AdLibDriver::update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.baseFreq = value;
return 0;
}
-int AdLibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk32 = value;
channel.unk33 = *dataptr++;
uint8 temp = *dataptr++;
@@ -1539,12 +1582,12 @@ int AdLibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, u
return 0;
}
-int AdLibDriver::update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.priority = value;
return 0;
}
-int AdLibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value) {
value >>= 1;
_unkValue1 = _unkValue2 = value;
_callbackTimer = 0xFF;
@@ -1552,7 +1595,7 @@ int AdLibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (_unkValue5) {
if (_unkValue4 & value) {
_unkValue5 = 0;
@@ -1568,50 +1611,50 @@ int AdLibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value
return 2;
}
-int AdLibDriver::update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.opExtraLevel1 = value;
adjustVolume(channel);
return 0;
}
-int AdLibDriver::update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupDuration(value, channel);
return (value != 0);
}
-int AdLibDriver::update_playNote(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupDuration(value, channel);
noteOn(channel);
return (value != 0);
}
-int AdLibDriver::update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.fractionalSpacing = value & 7;
return 0;
}
-int AdLibDriver::update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
_tempo = value;
return 0;
}
-int AdLibDriver::update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.secondaryEffect = 0;
return 0;
}
-int AdLibDriver::update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.tempo = value;
return 0;
}
-int AdLibDriver::update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.opExtraLevel3 = value;
return 0;
}
-int AdLibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
_curChannel = value;
@@ -1623,7 +1666,7 @@ int AdLibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8
return 0;
}
-int AdLibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
_curChannel = value;
@@ -1638,7 +1681,7 @@ int AdLibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uin
// Apart from initializing to zero, these two functions are the only ones that
// modify _vibratoAndAMDepthBits.
-int AdLibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (value & 1)
_vibratoAndAMDepthBits |= 0x80;
else
@@ -1648,7 +1691,7 @@ int AdLibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 valu
return 0;
}
-int AdLibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (value & 1)
_vibratoAndAMDepthBits |= 0x40;
else
@@ -1658,13 +1701,13 @@ int AdLibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8
return 0;
}
-int AdLibDriver::update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.opExtraLevel1 += value;
adjustVolume(channel);
return 0;
}
-int AdLibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
_curChannel = value;
@@ -1693,7 +1736,7 @@ int AdLibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (_curChannel >= 9)
return 0;
@@ -1714,35 +1757,35 @@ int AdLibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.primaryEffect = 0;
return 0;
}
-int AdLibDriver::update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.pitchBend = value;
setupNote(channel.rawNote, channel, true);
return 0;
}
-int AdLibDriver::update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.tempo = _tempo;
return 0;
}
-int AdLibDriver::update_nop(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_nop(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
return 0;
}
-int AdLibDriver::update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.durationRandomness = value;
return 0;
}
-int AdLibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
int tempo = channel.tempo + (int8)value;
if (tempo <= 0)
@@ -1754,7 +1797,7 @@ int AdLibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, ui
return 0;
}
-int AdLibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 entry = *dataptr++;
_tablePtr1 = _unkTable2[entry++];
_tablePtr2 = _unkTable2[entry];
@@ -1765,27 +1808,43 @@ int AdLibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
int regOffsetBackUp = _curRegOffset;
_curChannel = 6;
_curRegOffset = _regOffset[6];
- setupInstrument(_curRegOffset, getInstrument(value), channel);
+ const uint8 *instrument;
+ instrument = getInstrument(value);
+ if (instrument) {
+ setupInstrument(_curRegOffset, instrument, channel);
+ } else {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 6 specified", value);
+ }
_unkValue6 = channel.opLevel2;
_curChannel = 7;
_curRegOffset = _regOffset[7];
- setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel);
+ instrument = getInstrument(*dataptr++);
+ if (instrument) {
+ setupInstrument(_curRegOffset, instrument, channel);
+ } else {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 7 specified", value);
+ }
_unkValue7 = channel.opLevel1;
_unkValue8 = channel.opLevel2;
_curChannel = 8;
_curRegOffset = _regOffset[8];
- setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel);
+ instrument = getInstrument(*dataptr++);
+ if (instrument) {
+ setupInstrument(_curRegOffset, instrument, channel);
+ } else {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 8 specified", value);
+ }
_unkValue9 = channel.opLevel1;
_unkValue10 = channel.opLevel2;
@@ -1810,7 +1869,7 @@ int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, ui
return 0;
}
-int AdLibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) {
// Any instrument that we want to play, and which was already playing,
// is temporarily keyed off. Instruments that were off already, or
// which we don't want to play, retain their old on/off status. This is
@@ -1830,7 +1889,7 @@ int AdLibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uin
return 0;
}
-int AdLibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
_rhythmSectionBits = 0;
@@ -1841,7 +1900,7 @@ int AdLibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, u
return 0;
}
-int AdLibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 value2 = *dataptr++;
if (value & 1) {
@@ -1882,7 +1941,7 @@ int AdLibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 value2 = *dataptr++;
if (value & 1) {
@@ -1923,7 +1982,7 @@ int AdLibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 value2 = *dataptr++;
if (value & 1) {
@@ -1964,17 +2023,17 @@ int AdLibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value) {
_soundTrigger = value;
return 0;
}
-int AdLibDriver::update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.tempoReset = value;
return 0;
}
-int AdLibDriver::updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk39 = value;
channel.unk40 = *dataptr++;
return 0;
@@ -2487,13 +2546,13 @@ void SoundAdLibPC::internalLoadFile(Common::String file) {
_soundDataPtr = new uint8[soundDataSize];
assert(_soundDataPtr);
- memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8));
+ memcpy(_soundDataPtr, p, soundDataSize);
delete[] fileData;
fileData = p = 0;
fileSize = 0;
- _driver->setSoundData(_soundDataPtr);
+ _driver->setSoundData(_soundDataPtr, soundDataSize);
_soundFileLoaded = file;
}
diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp
index 57943f9a8d..a6cecc7408 100644
--- a/engines/lastexpress/debug.cpp
+++ b/engines/lastexpress/debug.cpp
@@ -653,7 +653,6 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) {
// Make sure we are not called in a loop
_numParams = 0;
-
// Check if we got a nis filename or an animation index
if (name.contains('.')) {
Animation animation;
@@ -796,7 +795,10 @@ bool Debugger::cmdFight(int argc, const char **argv) {
break;
}
- loadArchive(index);
+ if (!loadArchive(index)) {
+ debugPrintf("Error: failed to load archive %d\n", index);
+ return true;
+ }
// Store command
if (!hasCommand()) {
@@ -854,7 +856,10 @@ error:
bool Debugger::cmdBeetle(int argc, const char **argv) {
if (argc == 1) {
// Load proper data file (beetle game in in Cd2)
- loadArchive(kArchiveCd2);
+ if (!loadArchive(kArchiveCd2)) {
+ debugPrintf("Error: failed to load archive 2");
+ return true;
+ }
// Store command
if (!hasCommand()) {
@@ -924,7 +929,6 @@ bool Debugger::cmdBeetle(int argc, const char **argv) {
break;
}
-
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
// Update coordinates
diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp
index 5393410add..1581916e07 100644
--- a/engines/lastexpress/entities/abbot.cpp
+++ b/engines/lastexpress/entities/abbot.cpp
@@ -415,7 +415,7 @@ IMPLEMENT_FUNCTION(22, Abbot, haveLunch)
break;
case kActionNone:
- Entity::timeCheckSavepoint(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752);
+ Entity::timeCheckSavepoint(kTime1971000, params->param1, kEntityAbbot, kEntityWaiter1, kAction218586752);
if (getState()->time > kTime1989000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->inventoryItem = kItemNone;
@@ -476,7 +476,7 @@ IMPLEMENT_FUNCTION(23, Abbot, leaveLunch)
case 1:
getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67);
- getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760);
+ getSavePoints()->push(kEntityAbbot, kEntityWaiter1, kAction270068760);
getSavePoints()->push(kEntityAbbot, kEntityAnna, kAction238936000);
getEntities()->drawSequenceRight(kEntityAbbot, "804DS");
@@ -1324,7 +1324,7 @@ IMPLEMENT_FUNCTION(41, Abbot, chapter4Handler)
break;
case kActionNone:
- Entity::timeCheckSavepoint(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129);
+ Entity::timeCheckSavepoint(kTime2358000, params->param1, kEntityAbbot, kEntityWaiter1, kAction218128129);
if (getState()->time > kTime2389500 && getEntities()->isSomebodyInsideRestaurantOrSalon())
setup_leaveDinner();
@@ -1368,7 +1368,7 @@ IMPLEMENT_FUNCTION(42, Abbot, leaveDinner)
case 1:
getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67);
- getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760);
+ getSavePoints()->push(kEntityAbbot, kEntityWaiter1, kAction270068760);
getEntities()->drawSequenceRight(kEntityAbbot, "804DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
@@ -1779,7 +1779,7 @@ IMPLEMENT_FUNCTION(49, Abbot, catchCath)
getData()->location = kLocationInsideCompartment;
getSavePoints()->call(kEntityAbbot, kEntityTables4, kActionDrawTablesWithChairs, "029G");
- getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760);
+ getSavePoints()->push(kEntityAbbot, kEntityWaiter1, kAction270068760);
getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction125039808);
getObjects()->update(kObjectCompartment2, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectHandleInsideBathroom, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand);
diff --git a/engines/lastexpress/entities/alexei.cpp b/engines/lastexpress/entities/alexei.cpp
index 9b56fca39f..5ea3ff4898 100644
--- a/engines/lastexpress/entities/alexei.cpp
+++ b/engines/lastexpress/entities/alexei.cpp
@@ -607,7 +607,7 @@ IMPLEMENT_FUNCTION(19, Alexei, returnCompartment)
case 7:
getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63);
- getSavePoints()->push(kEntityAlexei, kEntityServers1, kAction302996448);
+ getSavePoints()->push(kEntityAlexei, kEntityWaiter2, kAction302996448);
setCallback(8);
setup_draw("934");
diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp
index ff65be9772..3354964af2 100644
--- a/engines/lastexpress/entities/anna.cpp
+++ b/engines/lastexpress/entities/anna.cpp
@@ -907,7 +907,7 @@ IMPLEMENT_FUNCTION(23, Anna, waitingDinner)
case kActionDefault:
getEntities()->drawSequenceLeft(kEntityAnna, "001D");
- getSavePoints()->push(kEntityAnna, kEntityServers0, kAction270410280);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction270410280);
getSavePoints()->push(kEntityAnna, kEntityTables0, kAction136455232);
setCallback(1);
@@ -931,7 +931,7 @@ IMPLEMENT_FUNCTION(23, Anna, waitingDinner)
break;
case 3:
- getSavePoints()->push(kEntityAnna, kEntityServers0, kAction203859488);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction203859488);
setup_waitingDinner2();
break;
}
@@ -964,7 +964,7 @@ IMPLEMENT_FUNCTION(24, Anna, waitingDinner2)
break;
case 2:
- getSavePoints()->push(kEntityAnna, kEntityServers0, kAction136702400);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction136702400);
setup_eatingDinner();
break;
}
@@ -1034,7 +1034,7 @@ IMPLEMENT_FUNCTION(26, Anna, leaveDinner)
case 1:
getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 62);
- getSavePoints()->push(kEntityAnna, kEntityServers0, kAction237485916);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction237485916);
getEntities()->drawSequenceRight(kEntityAnna, "801DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
@@ -2145,7 +2145,7 @@ label_callback_4:
break;
case 2:
- getSavePoints()->push(kEntityAnna, kEntityServers0, kAction218983616);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction218983616);
break;
case 3:
@@ -2285,7 +2285,7 @@ IMPLEMENT_FUNCTION(51, Anna, afterLunch)
getData()->location = kLocationInsideCompartment;
getEntities()->drawSequenceLeft(kEntityAnna, "112B");
getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 57);
- getSavePoints()->push(kEntityAnna, kEntityServers1, kAction219377792);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter2, kAction219377792);
break;
case 2:
@@ -3473,7 +3473,7 @@ IMPLEMENT_FUNCTION(69, Anna, goSalon4)
case 3:
getData()->location = kLocationInsideCompartment;
getEntities()->drawSequenceLeft(kEntityAnna, "127B");
- getSavePoints()->push(kEntityAnna, kEntityServers1, kAction258136010);
+ getSavePoints()->push(kEntityAnna, kEntityWaiter2, kAction258136010);
break;
case 4:
diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp
index c5029537ad..14dcf200f0 100644
--- a/engines/lastexpress/entities/august.cpp
+++ b/engines/lastexpress/entities/august.cpp
@@ -452,11 +452,17 @@ IMPLEMENT_FUNCTION_I(20, August, function20, bool)
}
if (params->param1) {
- strcpy((char *)&parameters->seq2, Common::String::format("%s%s", (char *)&parameters->seq1, "Gc").c_str());
+ Common::String sequence = Common::String::format("%s%s", (char *)&parameters->seq1, "Gc");
+ assert(sequence.size() <= 13);
+
+ strcpy((char *)&parameters->seq2, sequence.c_str());
getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue);
} else {
- strcpy((char *)&parameters->seq2, Common::String::format("%s%s", (char *)&parameters->seq1, "Ec").c_str());
+ Common::String sequence = Common::String::format("%s%s", (char *)&parameters->seq1, "Ec");
+ assert(sequence.size() <= 13);
+
+ strcpy((char *)&parameters->seq2, sequence.c_str());
}
setCallback(1);
@@ -484,15 +490,22 @@ IMPLEMENT_FUNCTION_I(20, August, function20, bool)
setCallback(2);
setup_playSound("AUG2094");
}
+
}
break;
case 2:
- case 3:
+ case 3: {
getSavePoints()->push(kEntityAugust, kEntityMertens, kAction269436673);
- strcpy((char *)&parameters->seq2, Common::String::format("%s%s", (char *)&parameters->seq1, "Qc").c_str());
+
+ Common::String sequence = Common::String::format("%s%s", (char *)&parameters->seq1, "Qc");
+ assert(sequence.size() <= 13);
+
+ strcpy((char *)&parameters->seq2, sequence.c_str());
getEntities()->drawSequenceLeft(kEntityAugust, (char *)&parameters->seq2);
+
+ }
break;
}
break;
@@ -1162,7 +1175,7 @@ IMPLEMENT_FUNCTION(25, August, chapter1Handler)
break;
case 1:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction204704037);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction204704037);
getEntities()->drawSequenceRight(kEntityAugust, "803DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
getEntities()->updateFrame(kEntityAugust);
@@ -1195,7 +1208,7 @@ IMPLEMENT_FUNCTION(25, August, chapter1Handler)
break;
case 5:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction204704037);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction204704037);
getEntities()->drawSequenceRight(kEntityAugust, "803DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
getEntities()->updateFrame(kEntityAugust);
@@ -1366,7 +1379,7 @@ IMPLEMENT_FUNCTION(28, August, function28)
params->param1 = kItemInvalid;
getEntities()->drawSequenceLeft(kEntityAugust, "010B");
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction304061224);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction304061224);
getData()->inventoryItem = (InventoryItem)params->param1;
break;
@@ -1376,13 +1389,13 @@ IMPLEMENT_FUNCTION(28, August, function28)
break;
case 1:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction203859488);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction203859488);
getData()->inventoryItem = (InventoryItem)params->param1;
getEntities()->drawSequenceLeft(kEntityAugust, "010B");
break;
case 2:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction136702400);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction136702400);
getEntities()->drawSequenceLeft(kEntityAugust, "010B");
setup_function29();
break;
@@ -1399,7 +1412,7 @@ IMPLEMENT_FUNCTION(28, August, function28)
case kAction170016384:
getData()->inventoryItem = kItemNone;
- getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK");
getEntities()->drawSequenceLeft(kEntityAugust, "010G");
setCallback(2);
@@ -1551,7 +1564,7 @@ IMPLEMENT_FUNCTION(30, August, restaurant)
break;
case 3:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction292758554);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction292758554);
getSavePoints()->push(kEntityAugust, kEntityAnna, kAction122358304);
getEntities()->drawSequenceLeft(kEntityAugust, "001K");
getSound()->playSound(kEntityAugust, "AUG1003");
@@ -1815,7 +1828,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler)
break;
case kActionNone:
- Entity::timeCheckSavepoint(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704);
+ Entity::timeCheckSavepoint(kTime1755000, params->param2, kEntityAugust, kEntityWaiter1, kAction252568704);
if (getState()->time > kTime1773000 && params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->inventoryItem = kItemNone;
@@ -1863,7 +1876,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler)
break;
case 3:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction286534136);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction286534136);
setCallback(4);
setup_updateEntity(kCarGreenSleeping, kPosition_6470);
@@ -1882,7 +1895,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler)
if (!getEvent(kEventAugustGoodMorning))
getData()->inventoryItem = kItemInvalid;
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction219522616);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction219522616);
getEntities()->drawSequenceLeft(kEntityAugust, "016B");
params->param1 = 1;
break;
@@ -3044,7 +3057,7 @@ IMPLEMENT_FUNCTION(60, August, function60)
}
if (pushSavepoint)
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction207330561);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction207330561);
if (!params->param1)
break;
@@ -3074,7 +3087,7 @@ IMPLEMENT_FUNCTION(60, August, function60)
break;
case 2:
- getSavePoints()->push(kEntityAugust, kEntityServers0, kAction286403504);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction286403504);
setup_function61();
break;
}
@@ -3199,7 +3212,7 @@ IMPLEMENT_FUNCTION(62, August, function62)
case 5:
getEntities()->drawSequenceLeft(kEntityAugust, "122B");
- getSavePoints()->push(kEntityAugust, kEntityServers1, kAction291721418);
+ getSavePoints()->push(kEntityAugust, kEntityWaiter2, kAction291721418);
break;
}
break;
diff --git a/engines/lastexpress/entities/boutarel.cpp b/engines/lastexpress/entities/boutarel.cpp
index 979381afb0..32507b0d63 100644
--- a/engines/lastexpress/entities/boutarel.cpp
+++ b/engines/lastexpress/entities/boutarel.cpp
@@ -310,7 +310,7 @@ IMPLEMENT_FUNCTION_I(14, Boutarel, function14, bool)
break;
case 2:
- getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction326144276);
+ getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction326144276);
getEntities()->drawSequenceRight(kEntityBoutarel, "812DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
getEntities()->updateFrame(kEntityBoutarel);
@@ -674,7 +674,7 @@ IMPLEMENT_FUNCTION(20, Boutarel, function20)
break;
case 2:
- getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
+ getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction256200848);
break;
case 3:
@@ -937,7 +937,7 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29)
case kActionNone:
if (Entity::updateParameter(params->param2, getState()->time, 450)) {
- getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
+ getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction256200848);
}
if (!params->param1)
@@ -1086,7 +1086,7 @@ IMPLEMENT_FUNCTION(33, Boutarel, function33)
break;
case 2:
- getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848);
+ getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction256200848);
break;
case 3:
diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp
index fe977a577f..f1a7d02384 100644
--- a/engines/lastexpress/entities/chapters.cpp
+++ b/engines/lastexpress/entities/chapters.cpp
@@ -44,13 +44,13 @@
#include "lastexpress/entities/pascale.h"
#include "lastexpress/entities/rebecca.h"
#include "lastexpress/entities/salko.h"
-#include "lastexpress/entities/servers0.h"
-#include "lastexpress/entities/servers1.h"
#include "lastexpress/entities/sophie.h"
#include "lastexpress/entities/tatiana.h"
#include "lastexpress/entities/vassili.h"
#include "lastexpress/entities/verges.h"
#include "lastexpress/entities/vesna.h"
+#include "lastexpress/entities/waiter1.h"
+#include "lastexpress/entities/waiter2.h"
#include "lastexpress/entities/yasmin.h"
#include "lastexpress/game/action.h"
@@ -77,7 +77,7 @@ Chapters::Chapters(LastExpressEngine *engine) : Entity(engine, kEntityChapters)
ADD_CALLBACK_FUNCTION(Chapters, exitStation);
ADD_CALLBACK_FUNCTION(Chapters, chapter1);
ADD_CALLBACK_FUNCTION(Chapters, resetMainEntities);
- ADD_CALLBACK_FUNCTION(Chapters, chapter1End);
+ ADD_CALLBACK_FUNCTION(Chapters, firstDream);
ADD_CALLBACK_FUNCTION(Chapters, chapter1Init);
ADD_CALLBACK_FUNCTION(Chapters, chapter1Handler);
ADD_CALLBACK_FUNCTION(Chapters, chapter1Next);
@@ -154,7 +154,8 @@ IMPLEMENT_FUNCTION(5, Chapters, resetMainEntities)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(6, Chapters, chapter1End)
+IMPLEMENT_FUNCTION(6, Chapters, firstDream)
+ // Chapter 1 end
switch (savepoint.action) {
default:
break;
@@ -207,9 +208,9 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End)
case kActionDefault:
RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_function19);
- RESET_ENTITY_STATE(kEntityServers0, Servers0, setup_function22);
- RESET_ENTITY_STATE(kEntityServers1, Servers1, setup_function16);
- RESET_ENTITY_STATE(kEntityCooks, Cooks, setup_function7);
+ RESET_ENTITY_STATE(kEntityWaiter1, Waiter1, setup_function22);
+ RESET_ENTITY_STATE(kEntityWaiter2, Waiter2, setup_function16);
+ RESET_ENTITY_STATE(kEntityCooks, Cooks, setup_lockUp);
RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function42);
RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_chapter1Handler);
@@ -220,7 +221,7 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End)
getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
RESET_ENTITY_STATE(kEntityKronos, Kronos, setup_function10);
- RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function13);
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_cathDone);
RESET_ENTITY_STATE(kEntityAnna, Anna, setup_asleep);
RESET_ENTITY_STATE(kEntityAugust, August, setup_function34);
RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function24);
@@ -270,7 +271,6 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End)
if (getSoundQueue()->isBuffered("ZFX1007B"))
getSoundQueue()->processEntry("ZFX1007B");
-
getSound()->playSound(kEntityPlayer, "MUS008", kFlagDefault);
getInventory()->unselectItem();
@@ -385,6 +385,7 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler)
+ // Moving at night
switch (savepoint.action) {
default:
break;
@@ -705,7 +706,7 @@ label_chapter1_next:
setup_chapter1Next();
} else {
setCallback(23);
- setup_chapter1End();
+ setup_firstDream();
}
break;
}
@@ -918,6 +919,7 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler)
+ // Moving during the afternoon
switch (savepoint.action) {
default:
break;
@@ -1078,6 +1080,7 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(16, Chapters, viennaEvents)
+ // End in Vienna
switch (savepoint.action) {
default:
break;
@@ -1225,6 +1228,7 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler)
+ // Moving during the second night
switch (savepoint.action) {
default:
break;
@@ -1518,8 +1522,8 @@ label_callback_4:
RESET_ENTITY_STATE(kEntityAugust, August, setup_function65);
RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function48);
RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_function53);
- RESET_ENTITY_STATE(kEntityServers0, Servers0, setup_chapter4Handler);
- RESET_ENTITY_STATE(kEntityServers1, Servers1, setup_chapter4Handler);
+ RESET_ENTITY_STATE(kEntityWaiter1, Waiter1, setup_serving4);
+ RESET_ENTITY_STATE(kEntityWaiter2, Waiter2, setup_serving4);
RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_chapter4Handler);
RESET_ENTITY_STATE(kEntityVerges, Verges, setup_chapter4Handler);
RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function49);
@@ -1535,12 +1539,12 @@ label_callback_4:
RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_function17);
RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_function19);
RESET_ENTITY_STATE(kEntityAlouan, Alouan, setup_function19);
- RESET_ENTITY_STATE(kEntityMax, Max, setup_chapter4Handler);
+ RESET_ENTITY_STATE(kEntityMax, Max, setup_inCageFriendly);
getSavePoints()->push(kEntityChapters, kEntityAnna, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityMertens, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
- getSavePoints()->push(kEntityChapters, kEntityServers0, kAction201431954);
- getSavePoints()->push(kEntityChapters, kEntityServers1, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityWaiter1, kAction201431954);
+ getSavePoints()->push(kEntityChapters, kEntityWaiter2, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityPascale, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
@@ -1754,7 +1758,6 @@ IMPLEMENT_FUNCTION(22, Chapters, chapter5Handler)
}
IMPLEMENT_FUNCTION_END
-
//////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h
index 39739aa92e..abc464845f 100644
--- a/engines/lastexpress/entities/chapters.h
+++ b/engines/lastexpress/entities/chapters.h
@@ -70,7 +70,7 @@ public:
/**
* Handle end of Chapter 1 events
*/
- DECLARE_FUNCTION(chapter1End)
+ DECLARE_FUNCTION(firstDream)
/**
* Init Chapter 1 data
diff --git a/engines/lastexpress/entities/cooks.cpp b/engines/lastexpress/entities/cooks.cpp
index e24180e58d..749e93999b 100644
--- a/engines/lastexpress/entities/cooks.cpp
+++ b/engines/lastexpress/entities/cooks.cpp
@@ -37,17 +37,17 @@ namespace LastExpress {
Cooks::Cooks(LastExpressEngine *engine) : Entity(engine, kEntityCooks) {
ADD_CALLBACK_FUNCTION(Cooks, draw);
ADD_CALLBACK_FUNCTION(Cooks, playSound);
- ADD_CALLBACK_FUNCTION(Cooks, function3);
- ADD_CALLBACK_FUNCTION(Cooks, function4);
+ ADD_CALLBACK_FUNCTION(Cooks, uptrainVersion);
+ ADD_CALLBACK_FUNCTION(Cooks, downtrainVersion);
ADD_CALLBACK_FUNCTION(Cooks, chapter1);
- ADD_CALLBACK_FUNCTION(Cooks, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Cooks, function7);
+ ADD_CALLBACK_FUNCTION(Cooks, inKitchenDinner);
+ ADD_CALLBACK_FUNCTION(Cooks, lockUp);
ADD_CALLBACK_FUNCTION(Cooks, chapter2);
- ADD_CALLBACK_FUNCTION(Cooks, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, inKitchenBreakfast);
ADD_CALLBACK_FUNCTION(Cooks, chapter3);
- ADD_CALLBACK_FUNCTION(Cooks, chapter3Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, inKitchenLunch);
ADD_CALLBACK_FUNCTION(Cooks, chapter4);
- ADD_CALLBACK_FUNCTION(Cooks, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Cooks, inKitchenDinner2);
ADD_CALLBACK_FUNCTION(Cooks, chapter5);
}
@@ -62,7 +62,7 @@ IMPLEMENT_FUNCTION_S(2, Cooks, playSound)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(3, Cooks, function3)
+IMPLEMENT_FUNCTION(3, Cooks, uptrainVersion)
switch (savepoint.action) {
default:
break;
@@ -147,7 +147,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(4, Cooks, function4)
+IMPLEMENT_FUNCTION(4, Cooks, downtrainVersion)
switch (savepoint.action) {
default:
break;
@@ -239,7 +239,7 @@ IMPLEMENT_FUNCTION(5, Cooks, chapter1)
break;
case kActionNone:
- Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Cooks, setup_chapter1Handler));
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Cooks, setup_inKitchenDinner));
break;
case kActionDefault:
@@ -254,7 +254,7 @@ IMPLEMENT_FUNCTION(5, Cooks, chapter1)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler)
+IMPLEMENT_FUNCTION(6, Cooks, inKitchenDinner)
switch (savepoint.action) {
default:
break;
@@ -281,7 +281,7 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler)
if (params->param1) {
if (getEntities()->isPlayerPosition(kCarRestaurant, 73)) {
setCallback(1);
- setup_function3();
+ setup_uptrainVersion();
}
} else {
if (params->param3) {
@@ -311,7 +311,7 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler)
break;
case kAction101632192:
- setup_function7();
+ setup_lockUp();
break;
case kAction224849280:
@@ -322,7 +322,7 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(7, Cooks, function7)
+IMPLEMENT_FUNCTION(7, Cooks, lockUp)
switch (savepoint.action) {
default:
break;
@@ -350,7 +350,7 @@ IMPLEMENT_FUNCTION(8, Cooks, chapter2)
break;
case kActionNone:
- setup_chapter2Handler();
+ setup_inKitchenBreakfast();
break;
case kActionDefault:
@@ -368,7 +368,7 @@ IMPLEMENT_FUNCTION(8, Cooks, chapter2)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(9, Cooks, chapter2Handler)
+IMPLEMENT_FUNCTION(9, Cooks, inKitchenBreakfast)
switch (savepoint.action) {
default:
break;
@@ -411,7 +411,7 @@ IMPLEMENT_FUNCTION(10, Cooks, chapter3)
break;
case kActionNone:
- setup_chapter3Handler();
+ setup_inKitchenLunch();
break;
case kActionDefault:
@@ -428,7 +428,7 @@ IMPLEMENT_FUNCTION(10, Cooks, chapter3)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler)
+IMPLEMENT_FUNCTION(11, Cooks, inKitchenLunch)
switch (savepoint.action) {
default:
break;
@@ -459,7 +459,7 @@ IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler)
if (params->param1) {
if (getEntities()->isPlayerPosition(kCarRestaurant, 80)) {
setCallback(1);
- setup_function4();
+ setup_downtrainVersion();
}
} else {
if (params->param3) {
@@ -502,7 +502,7 @@ IMPLEMENT_FUNCTION(12, Cooks, chapter4)
break;
case kActionNone:
- setup_chapter4Handler();
+ setup_inKitchenDinner2();
break;
case kActionDefault:
@@ -520,7 +520,7 @@ IMPLEMENT_FUNCTION(12, Cooks, chapter4)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler)
+IMPLEMENT_FUNCTION(13, Cooks, inKitchenDinner2)
switch (savepoint.action) {
default:
break;
@@ -553,7 +553,6 @@ IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler)
}
break;
-
case kActionCallback:
// Play the next part of background sound
if (getCallback() == 1 || getCallback() == 2) {
diff --git a/engines/lastexpress/entities/cooks.h b/engines/lastexpress/entities/cooks.h
index 79addb0a02..6a65a25801 100644
--- a/engines/lastexpress/entities/cooks.h
+++ b/engines/lastexpress/entities/cooks.h
@@ -48,9 +48,9 @@ public:
*/
DECLARE_FUNCTION_1(playSound, const char *filename)
- DECLARE_FUNCTION(function3)
+ DECLARE_FUNCTION(uptrainVersion)
- DECLARE_FUNCTION(function4)
+ DECLARE_FUNCTION(downtrainVersion)
/**
* Setup Chapter 1
@@ -58,21 +58,21 @@ public:
DECLARE_FUNCTION(chapter1)
/**
- * Handle Chapter 1 events
+ * Chapter 1: Prepare dinner in kitchen
*/
- DECLARE_FUNCTION(chapter1Handler)
+ DECLARE_FUNCTION(inKitchenDinner)
- DECLARE_FUNCTION(function7)
+ DECLARE_FUNCTION(lockUp)
/**
* Setup Chapter 2
*/
DECLARE_FUNCTION(chapter2)
- /**
- * Handle Chapter 2 events
+ /*
+ * Chapter 2: Prepare breakfast in kitchen
*/
- DECLARE_FUNCTION(chapter2Handler)
+ DECLARE_FUNCTION(inKitchenBreakfast)
/**
* Setup Chapter 3
@@ -80,9 +80,9 @@ public:
DECLARE_FUNCTION(chapter3)
/**
- * Handle Chapter 3 events
+ * Chapter 3: Prepare lunch in kitchen
*/
- DECLARE_FUNCTION(chapter3Handler)
+ DECLARE_FUNCTION(inKitchenLunch)
/**
* Setup Chapter 4
@@ -90,9 +90,9 @@ public:
DECLARE_FUNCTION(chapter4)
/**
- * Handle Chapter 4 events
+ * Chapter 4: Prepare second dinner in kitchen
*/
- DECLARE_FUNCTION(chapter4Handler)
+ DECLARE_FUNCTION(inKitchenDinner2)
/**
* Setup Chapter 5
diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp
index 07e82d296e..170248de52 100644
--- a/engines/lastexpress/entities/entity.cpp
+++ b/engines/lastexpress/entities/entity.cpp
@@ -51,6 +51,9 @@ EntityData::EntityCallData::~EntityCallData() {
}
void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, uint length) const {
+ assert(length <= 13);
+ assert(string.size() <= 13);
+
char seqName[13];
memset(&seqName, 0, length);
@@ -972,5 +975,4 @@ bool Entity::timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint &paramet
return false;
}
-
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp
index 7b31c592cd..b628b8dfe7 100644
--- a/engines/lastexpress/entities/gendarmes.cpp
+++ b/engines/lastexpress/entities/gendarmes.cpp
@@ -37,16 +37,16 @@ namespace LastExpress {
Gendarmes::Gendarmes(LastExpressEngine *engine) : Entity(engine, kEntityGendarmes) {
ADD_CALLBACK_FUNCTION(Gendarmes, reset);
ADD_CALLBACK_FUNCTION(Gendarmes, chapter1);
- ADD_CALLBACK_FUNCTION(Gendarmes, arrestDraw);
- ADD_CALLBACK_FUNCTION(Gendarmes, arrestPlaysound);
- ADD_CALLBACK_FUNCTION(Gendarmes, arrestPlaysound16);
- ADD_CALLBACK_FUNCTION(Gendarmes, arrestCallback);
+ ADD_CALLBACK_FUNCTION(Gendarmes, doDraw);
+ ADD_CALLBACK_FUNCTION(Gendarmes, doDialog);
+ ADD_CALLBACK_FUNCTION(Gendarmes, doDialogFullVolume);
+ ADD_CALLBACK_FUNCTION(Gendarmes, doWait);
ADD_CALLBACK_FUNCTION(Gendarmes, savegame);
- ADD_CALLBACK_FUNCTION(Gendarmes, arrestUpdateEntity);
- ADD_CALLBACK_FUNCTION(Gendarmes, function9);
- ADD_CALLBACK_FUNCTION(Gendarmes, function10);
+ ADD_CALLBACK_FUNCTION(Gendarmes, doWalk);
+ ADD_CALLBACK_FUNCTION(Gendarmes, doCompartment);
+ ADD_CALLBACK_FUNCTION(Gendarmes, trappedCath);
ADD_CALLBACK_FUNCTION(Gendarmes, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Gendarmes, function12);
+ ADD_CALLBACK_FUNCTION(Gendarmes, searchTrain);
ADD_CALLBACK_FUNCTION(Gendarmes, function13);
ADD_CALLBACK_FUNCTION(Gendarmes, chapter2);
ADD_CALLBACK_FUNCTION(Gendarmes, chapter3);
@@ -76,23 +76,23 @@ IMPLEMENT_FUNCTION(2, Gendarmes, chapter1)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(3, Gendarmes, arrestDraw)
- arrest(savepoint);
+IMPLEMENT_FUNCTION_S(3, Gendarmes, doDraw)
+ handleAction(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(4, Gendarmes, arrestPlaysound)
- arrest(savepoint, true);
+IMPLEMENT_FUNCTION_S(4, Gendarmes, doDialog)
+ handleAction(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(5, Gendarmes, arrestPlaysound16)
- arrest(savepoint, true, kFlagDefault);
+IMPLEMENT_FUNCTION_S(5, Gendarmes, doDialogFullVolume)
+ handleAction(savepoint, true, kFlagDefault);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_I(6, Gendarmes, arrestCallback, uint32)
- arrest(savepoint, true, kFlagInvalid, true);
+IMPLEMENT_FUNCTION_I(6, Gendarmes, doWait, uint32)
+ handleAction(savepoint, true, kFlagInvalid, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
@@ -101,12 +101,12 @@ IMPLEMENT_FUNCTION_II(7, Gendarmes, savegame, SavegameType, uint32)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_II(8, Gendarmes, arrestUpdateEntity, CarIndex, EntityPosition)
- arrest(savepoint, true, kFlagInvalid, false, true);
+IMPLEMENT_FUNCTION_II(8, Gendarmes, doWalk, CarIndex, EntityPosition)
+ handleAction(savepoint, true, kFlagInvalid, false, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
+IMPLEMENT_FUNCTION_IISS(9, Gendarmes, doCompartment, CarIndex, EntityPosition)
EntityData::EntityParametersSSS *parameters1 = (EntityData::EntityParametersSSS*)_data->getCurrentParameters(1);
EntityData::EntityParametersISII *parameters2 = (EntityData::EntityParametersISII*)_data->getCurrentParameters(2);
@@ -169,6 +169,9 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
strcpy((char *)&parameters1->seq3, "632F");
}
+ // The sequence 3 string needs to be a maximum of 9 characters, leaving 5 characters after the initial setup
+ assert(Common::String(params->seq1).size() <= 5);
+
strcat((char *)&parameters1->seq1, (char *)&params->seq1);
strcat((char *)&parameters1->seq2, (char *)&params->seq1);
strcat((char *)&parameters1->seq3, (char *)&params->seq1);
@@ -178,13 +181,13 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
|| (params->param1 == kCarGreenSleeping && params->param2 == kPosition_8200 && getEntities()->isOutsideAlexeiWindow()))
&& !getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_7850)) {
setCallback(1);
- setup_function10((CarIndex)params->param1, (EntityPosition)params->param2, (ObjectIndex)parameters2->param5);
+ setup_trappedCath((CarIndex)params->param1, (EntityPosition)params->param2, (ObjectIndex)parameters2->param5);
} else {
getEntities()->drawSequenceLeft(kEntityGendarmes, (char *)&parameters1->seq1);
getEntities()->enterCompartment(kEntityGendarmes, (ObjectIndex)CURRENT_PARAM(2, 5));
setCallback(parameters2->param6 ? 2 : 3);
- setup_arrestPlaysound(parameters2->param6 ? "POL1044A" : "POL1044B");
+ setup_doDialog(parameters2->param6 ? "POL1044A" : "POL1044B");
}
break;
@@ -202,14 +205,14 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
getEntities()->drawSequenceLeft(kEntityGendarmes, (char *)&parameters1->seq2);
if (getEntities()->isNobodyInCompartment((CarIndex)params->param1, (EntityPosition)params->param2) || !strcmp(params->seq2, "NODIALOG")) {
setCallback(4);
- setup_arrestCallback(150);
+ setup_doWait(150);
} else {
char *arrestSound = (char *)&parameters2->seq;
strcpy(arrestSound, "POL1045");
strcat(arrestSound, (char *)&params->seq2);
setCallback(5);
- setup_arrestPlaysound(arrestSound);
+ setup_doDialog(arrestSound);
}
break;
@@ -226,7 +229,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
getData()->location = kLocationInsideCompartment;
setCallback(6);
- setup_arrestDraw((char *)&parameters1->seq3);
+ setup_doDraw((char *)&parameters1->seq3);
break;
case 6:
@@ -240,7 +243,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, ObjectIndex)
+IMPLEMENT_FUNCTION_III(10, Gendarmes, trappedCath, CarIndex, EntityPosition, ObjectIndex)
switch (savepoint.action) {
default:
break;
@@ -287,7 +290,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje
getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).status, kCursorNormal, kCursorNormal);
setCallback(5);
- setup_arrestPlaysound16("POL1046B");
+ setup_doDialogFullVolume("POL1046B");
break;
case kActionOpenDoor:
@@ -299,7 +302,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje
getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).status, kCursorNormal, kCursorNormal);
setCallback(1);
- setup_arrestPlaysound16("POL1046");
+ setup_doDialogFullVolume("POL1046");
break;
case kActionCallback:
@@ -351,12 +354,12 @@ IMPLEMENT_FUNCTION_END
IMPLEMENT_FUNCTION(11, Gendarmes, chapter1Handler)
if (savepoint.action == kAction169499649) {
getSavePoints()->push(kEntityGendarmes, kEntityMertens, kAction190082817);
- setup_function12();
+ setup_searchTrain();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(12, Gendarmes, function12)
+IMPLEMENT_FUNCTION(12, Gendarmes, searchTrain)
switch (savepoint.action) {
default:
break;
@@ -369,7 +372,7 @@ IMPLEMENT_FUNCTION(12, Gendarmes, function12)
getProgress().field_14 = 29;
setCallback(1);
- setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_5540);
+ setup_doWalk(kCarGreenSleeping, kPosition_5540);
break;
case kActionCallback:
@@ -379,42 +382,42 @@ IMPLEMENT_FUNCTION(12, Gendarmes, function12)
case 1:
setCallback(2);
- setup_function9(kCarGreenSleeping, kPosition_5790, "d", "A");
+ setup_doCompartment(kCarGreenSleeping, kPosition_5790, "d", "A");
break;
case 2:
setCallback(3);
- setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_6220);
+ setup_doWalk(kCarGreenSleeping, kPosition_6220);
break;
case 3:
setCallback(4);
- setup_function9(kCarGreenSleeping, kPosition_6470, "c", "B");
+ setup_doCompartment(kCarGreenSleeping, kPosition_6470, "c", "B");
break;
case 4:
setCallback(5);
- setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_7250);
+ setup_doWalk(kCarGreenSleeping, kPosition_7250);
break;
case 5:
setCallback(6);
- setup_function9(kCarGreenSleeping, kPosition_7500, "b", "C");
+ setup_doCompartment(kCarGreenSleeping, kPosition_7500, "b", "C");
break;
case 6:
setCallback(7);
- setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_7950);
+ setup_doWalk(kCarGreenSleeping, kPosition_7950);
break;
case 7:
setCallback(8);
- setup_function9(kCarGreenSleeping, kPosition_8200, "a", "NODIALOG");
+ setup_doCompartment(kCarGreenSleeping, kPosition_8200, "a", "NODIALOG");
break;
case 8:
setCallback(9);
- setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_9460);
+ setup_doWalk(kCarGreenSleeping, kPosition_9460);
break;
case 9:
@@ -427,77 +430,77 @@ IMPLEMENT_FUNCTION(12, Gendarmes, function12)
}
setCallback(10);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_2490);
+ setup_doWalk(kCarRedSleeping, kPosition_2490);
break;
case 10:
setCallback(11);
- setup_function9(kCarRedSleeping, kPosition_2740, "h", "NODIALOG");
+ setup_doCompartment(kCarRedSleeping, kPosition_2740, "h", "NODIALOG");
break;
case 11:
setCallback(12);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_3820);
+ setup_doWalk(kCarRedSleeping, kPosition_3820);
break;
case 12:
setCallback(13);
- setup_function9(kCarRedSleeping, kPosition_4070, "f", "E");
+ setup_doCompartment(kCarRedSleeping, kPosition_4070, "f", "E");
break;
case 13:
setCallback(14);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_4590);
+ setup_doWalk(kCarRedSleeping, kPosition_4590);
break;
case 14:
setCallback(15);
- setup_function9(kCarRedSleeping, kPosition_4840, "e", "F");
+ setup_doCompartment(kCarRedSleeping, kPosition_4840, "e", "F");
break;
case 15:
setCallback(16);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_5540);
+ setup_doWalk(kCarRedSleeping, kPosition_5540);
break;
case 16:
setCallback(17);
- setup_function9(kCarRedSleeping, kPosition_5790, "d", "G");
+ setup_doCompartment(kCarRedSleeping, kPosition_5790, "d", "G");
break;
case 17:
setCallback(18);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_6220);
+ setup_doWalk(kCarRedSleeping, kPosition_6220);
break;
case 18:
setCallback(19);
- setup_function9(kCarRedSleeping, kPosition_6470, "c", "H");
+ setup_doCompartment(kCarRedSleeping, kPosition_6470, "c", "H");
break;
case 19:
setCallback(20);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_7250);
+ setup_doWalk(kCarRedSleeping, kPosition_7250);
break;
case 20:
setCallback(21);
- setup_function9(kCarRedSleeping, kPosition_7500, "b", "J");
+ setup_doCompartment(kCarRedSleeping, kPosition_7500, "b", "J");
break;
case 21:
setCallback(22);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_7950);
+ setup_doWalk(kCarRedSleeping, kPosition_7950);
break;
case 22:
setCallback(23);
- setup_function9(kCarRedSleeping, kPosition_8200, "a", "NODIALOG");
+ setup_doCompartment(kCarRedSleeping, kPosition_8200, "a", "NODIALOG");
break;
case 23:
setCallback(24);
- setup_arrestUpdateEntity(kCarRedSleeping, kPosition_9460);
+ setup_doWalk(kCarRedSleeping, kPosition_9460);
break;
case 24:
@@ -544,7 +547,7 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////
-void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFlag flag, bool checkCallback, bool shouldUpdateEntity) {
+void Gendarmes::handleAction(const SavePoint &savepoint, bool shouldPlaySound, SoundFlag flag, bool checkCallback, bool shouldUpdateEntity) {
switch (savepoint.action) {
default:
break;
diff --git a/engines/lastexpress/entities/gendarmes.h b/engines/lastexpress/entities/gendarmes.h
index 8475c50799..1cde626a22 100644
--- a/engines/lastexpress/entities/gendarmes.h
+++ b/engines/lastexpress/entities/gendarmes.h
@@ -46,10 +46,10 @@ public:
*/
DECLARE_FUNCTION(chapter1)
- DECLARE_FUNCTION_1(arrestDraw, const char *sequence)
- DECLARE_FUNCTION_1(arrestPlaysound, const char *soundName)
- DECLARE_FUNCTION_1(arrestPlaysound16, const char *soundName)
- DECLARE_FUNCTION_1(arrestCallback, uint32 timeValue)
+ DECLARE_FUNCTION_1(doDraw, const char *sequence)
+ DECLARE_FUNCTION_1(doDialog, const char *soundName)
+ DECLARE_FUNCTION_1(doDialogFullVolume, const char *soundName)
+ DECLARE_FUNCTION_1(doWait, uint32 timeValue)
/**
* Saves the game
@@ -59,11 +59,11 @@ public:
*/
DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
- DECLARE_FUNCTION_2(arrestUpdateEntity, CarIndex car, EntityPosition entityPosition)
- DECLARE_FUNCTION_4(function9, CarIndex car, EntityPosition entityPosition, const char *sequence1, const char *sequence2)
- DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, ObjectIndex object)
+ DECLARE_FUNCTION_2(doWalk, CarIndex car, EntityPosition entityPosition)
+ DECLARE_FUNCTION_4(doCompartment, CarIndex car, EntityPosition entityPosition, const char *sequence1, const char *sequence2)
+ DECLARE_FUNCTION_3(trappedCath, CarIndex car, EntityPosition entityPosition, ObjectIndex object)
DECLARE_FUNCTION(chapter1Handler)
- DECLARE_FUNCTION(function12)
+ DECLARE_FUNCTION(searchTrain)
DECLARE_FUNCTION(function13)
/**
@@ -87,7 +87,7 @@ public:
DECLARE_FUNCTION(chapter5)
private:
- void arrest(const SavePoint &savepoint, bool playSound = false, SoundFlag flag = kFlagInvalid, bool checkCallback = false, bool shouldUpdateEntity = false);
+ void handleAction(const SavePoint &savepoint, bool playSound = false, SoundFlag flag = kFlagInvalid, bool checkCallback = false, bool shouldUpdateEntity = false);
};
} // End of namespace LastExpress
diff --git a/engines/lastexpress/entities/hadija.cpp b/engines/lastexpress/entities/hadija.cpp
index 14d5b714ca..eb255d77f8 100644
--- a/engines/lastexpress/entities/hadija.cpp
+++ b/engines/lastexpress/entities/hadija.cpp
@@ -38,10 +38,10 @@ Hadija::Hadija(LastExpressEngine *engine) : Entity(engine, kEntityHadija) {
ADD_CALLBACK_FUNCTION(Hadija, playSound);
ADD_CALLBACK_FUNCTION(Hadija, updateFromTime);
ADD_CALLBACK_FUNCTION(Hadija, updateEntity);
- ADD_CALLBACK_FUNCTION(Hadija, compartment6);
- ADD_CALLBACK_FUNCTION(Hadija, compartment8);
- ADD_CALLBACK_FUNCTION(Hadija, compartment6to8);
- ADD_CALLBACK_FUNCTION(Hadija, compartment8to6);
+ ADD_CALLBACK_FUNCTION(Hadija, peekF);
+ ADD_CALLBACK_FUNCTION(Hadija, peekH);
+ ADD_CALLBACK_FUNCTION(Hadija, goFtoH);
+ ADD_CALLBACK_FUNCTION(Hadija, goHtoF);
ADD_CALLBACK_FUNCTION(Hadija, chapter1);
ADD_CALLBACK_FUNCTION(Hadija, chapter1Handler);
ADD_CALLBACK_FUNCTION(Hadija, function12);
@@ -55,7 +55,7 @@ Hadija::Hadija(LastExpressEngine *engine) : Entity(engine, kEntityHadija) {
ADD_CALLBACK_FUNCTION(Hadija, chapter5);
ADD_CALLBACK_FUNCTION(Hadija, chapter5Handler);
ADD_CALLBACK_FUNCTION(Hadija, function22);
- ADD_CALLBACK_FUNCTION(Hadija, function23);
+ ADD_CALLBACK_FUNCTION(Hadija, hiding);
ADD_NULL_FUNCTION();
}
@@ -85,22 +85,22 @@ IMPLEMENT_FUNCTION_II(5, Hadija, updateEntity, CarIndex, EntityPosition)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(6, Hadija, compartment6)
+IMPLEMENT_FUNCTION(6, Hadija, peekF)
Entity::goToCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Cf", "619Df");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(7, Hadija, compartment8)
+IMPLEMENT_FUNCTION(7, Hadija, peekH)
Entity::goToCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(8, Hadija, compartment6to8)
+IMPLEMENT_FUNCTION(8, Hadija, goFtoH)
Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(9, Hadija, compartment8to6)
+IMPLEMENT_FUNCTION(9, Hadija, goHtoF)
Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af");
IMPLEMENT_FUNCTION_END
@@ -134,7 +134,7 @@ IMPLEMENT_FUNCTION(11, Hadija, chapter1Handler)
break;
label_callback1:
- if (Entity::timeCheckCallback(kTime1084500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ if (Entity::timeCheckCallback(kTime1084500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH)))
break;
label_callback2:
@@ -147,7 +147,7 @@ label_callback2:
if (!params->param3) {
setCallback(3);
- setup_compartment8();
+ setup_peekH();
return;
}
}
@@ -159,11 +159,11 @@ label_callback2:
params->param3 = kTimeInvalid;
setCallback(3);
- setup_compartment8();
+ setup_peekH();
}
label_callback3:
- if (Entity::timeCheckCallback(kTime1156500, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ if (Entity::timeCheckCallback(kTime1156500, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)))
break;
label_callback4:
@@ -175,7 +175,7 @@ label_callback4:
if (!params->param5) {
setCallback(5);
- setup_compartment6();
+ setup_peekF();
return;
}
}
@@ -187,7 +187,7 @@ label_callback4:
params->param5 = kTimeInvalid;
setCallback(5);
- setup_compartment6();
+ setup_peekF();
}
break;
@@ -254,7 +254,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
}
if (params->param2 == kTimeInvalid || getState()->time <= kTime1786500) {
- Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6));
+ Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF));
break;
}
@@ -264,7 +264,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
params->param2 = (uint)getState()->time + 75;
if (params->param2 >= getState()->time) {
- Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6));
+ Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF));
break;
}
}
@@ -272,7 +272,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
params->param2 = kTimeInvalid;
setCallback(1);
- setup_compartment8();
+ setup_peekH();
break;
case kActionCallback:
@@ -281,7 +281,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler)
break;
case 1:
- Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6));
+ Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF));
break;
case 2:
@@ -321,24 +321,24 @@ IMPLEMENT_FUNCTION(16, Hadija, chapter3Handler)
break;
case kActionNone:
- if (Entity::timeCheckCallback(kTime1998000, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ if (Entity::timeCheckCallback(kTime1998000, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH)))
break;
label_callback1:
- if (Entity::timeCheckCallback(kTime2020500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ if (Entity::timeCheckCallback(kTime2020500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)))
break;
label_callback2:
- if (Entity::timeCheckCallback(kTime2079000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ if (Entity::timeCheckCallback(kTime2079000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH)))
break;
label_callback3:
- if (Entity::timeCheckCallback(kTime2187000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ if (Entity::timeCheckCallback(kTime2187000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)))
break;
label_callback4:
if (params->param5 != kTimeInvalid && getState()->time > kTime2196000) {
- if (Entity::timeCheckCar(kTime2254500, params->param5, 5, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6)))
+ if (Entity::timeCheckCar(kTime2254500, params->param5, 5, WRAP_SETUP_FUNCTION(Hadija, setup_peekF)))
break;
}
break;
@@ -394,21 +394,21 @@ IMPLEMENT_FUNCTION(18, Hadija, chapter4Handler)
case kActionNone:
if (params->param1 != kTimeInvalid) {
- if (Entity::timeCheckCar(kTime1714500, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6)))
+ if (Entity::timeCheckCar(kTime1714500, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_peekF)))
break;
}
label_callback1:
- if (Entity::timeCheckCallback(kTime2367000, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8)))
+ if (Entity::timeCheckCallback(kTime2367000, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH)))
break;
label_callback2:
- if (Entity::timeCheckCallback(kTime2421000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)))
+ if (Entity::timeCheckCallback(kTime2421000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)))
break;
label_callback3:
if (params->param4 != kTimeInvalid && getState()->time > kTime2425500) {
- if (Entity::timeCheckCar(kTime2484000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6)))
+ if (Entity::timeCheckCar(kTime2484000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_peekF)))
break;
}
break;
@@ -483,7 +483,7 @@ IMPLEMENT_FUNCTION(22, Hadija, function22)
if (!Entity::updateParameter(params->param1, getState()->time, 2700))
break;
- setup_function23();
+ setup_hiding();
break;
case kActionDefault:
@@ -494,14 +494,14 @@ IMPLEMENT_FUNCTION(22, Hadija, function22)
case kActionDrawScene:
if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) {
- setup_function23();
+ setup_hiding();
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(23, Hadija, function23)
+IMPLEMENT_FUNCTION(23, Hadija, hiding)
switch (savepoint.action) {
default:
break;
diff --git a/engines/lastexpress/entities/hadija.h b/engines/lastexpress/entities/hadija.h
index 8e92dc6891..a66aa33628 100644
--- a/engines/lastexpress/entities/hadija.h
+++ b/engines/lastexpress/entities/hadija.h
@@ -70,10 +70,10 @@ public:
*/
DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition)
- DECLARE_FUNCTION(compartment6)
- DECLARE_FUNCTION(compartment8)
- DECLARE_FUNCTION(compartment6to8)
- DECLARE_FUNCTION(compartment8to6)
+ DECLARE_FUNCTION(peekF)
+ DECLARE_FUNCTION(peekH)
+ DECLARE_FUNCTION(goFtoH)
+ DECLARE_FUNCTION(goHtoF)
/**
* Setup Chapter 1
@@ -130,7 +130,7 @@ public:
DECLARE_FUNCTION(chapter5Handler)
DECLARE_FUNCTION(function22)
- DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(hiding)
DECLARE_NULL_FUNCTION()
};
diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp
index b7697d0c52..12a23e7d37 100644
--- a/engines/lastexpress/entities/ivo.cpp
+++ b/engines/lastexpress/entities/ivo.cpp
@@ -47,29 +47,29 @@ Ivo::Ivo(LastExpressEngine *engine) : Entity(engine, kEntityIvo) {
ADD_CALLBACK_FUNCTION(Ivo, playSound);
ADD_CALLBACK_FUNCTION(Ivo, callbackActionRestaurantOrSalon);
ADD_CALLBACK_FUNCTION(Ivo, savegame);
- ADD_CALLBACK_FUNCTION(Ivo, function11);
+ ADD_CALLBACK_FUNCTION(Ivo, goCompartment);
ADD_CALLBACK_FUNCTION(Ivo, sitAtTableWithSalko);
ADD_CALLBACK_FUNCTION(Ivo, leaveTableWithSalko);
ADD_CALLBACK_FUNCTION(Ivo, chapter1);
ADD_CALLBACK_FUNCTION(Ivo, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Ivo, function16);
+ ADD_CALLBACK_FUNCTION(Ivo, inCompartment);
ADD_CALLBACK_FUNCTION(Ivo, function17);
ADD_CALLBACK_FUNCTION(Ivo, chapter2);
- ADD_CALLBACK_FUNCTION(Ivo, function19);
- ADD_CALLBACK_FUNCTION(Ivo, function20);
+ ADD_CALLBACK_FUNCTION(Ivo, goBreakfast);
+ ADD_CALLBACK_FUNCTION(Ivo, atBreakfast);
ADD_CALLBACK_FUNCTION(Ivo, function21);
ADD_CALLBACK_FUNCTION(Ivo, chapter3);
ADD_CALLBACK_FUNCTION(Ivo, chapter3Handler);
ADD_CALLBACK_FUNCTION(Ivo, chapter4);
ADD_CALLBACK_FUNCTION(Ivo, chapter4Handler);
- ADD_CALLBACK_FUNCTION(Ivo, function26);
- ADD_CALLBACK_FUNCTION(Ivo, function27);
- ADD_CALLBACK_FUNCTION(Ivo, function28);
+ ADD_CALLBACK_FUNCTION(Ivo, returnCompartment4);
+ ADD_CALLBACK_FUNCTION(Ivo, inCompartment4);
+ ADD_CALLBACK_FUNCTION(Ivo, hiding);
ADD_CALLBACK_FUNCTION(Ivo, function29);
ADD_CALLBACK_FUNCTION(Ivo, chapter5);
ADD_CALLBACK_FUNCTION(Ivo, chapter5Handler);
- ADD_CALLBACK_FUNCTION(Ivo, fight);
- ADD_CALLBACK_FUNCTION(Ivo, function33);
+ ADD_CALLBACK_FUNCTION(Ivo, fightCath);
+ ADD_CALLBACK_FUNCTION(Ivo, knockedOut);
ADD_CALLBACK_FUNCTION(Ivo, function34);
}
@@ -129,7 +129,7 @@ IMPLEMENT_FUNCTION_II(10, Ivo, savegame, SavegameType, uint32)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(11, Ivo, function11)
+IMPLEMENT_FUNCTION(11, Ivo, goCompartment)
switch (savepoint.action) {
default:
break;
@@ -279,12 +279,12 @@ IMPLEMENT_FUNCTION(15, Ivo, chapter1Handler)
case 1:
setCallback(2);
- setup_function11();
+ setup_goCompartment();
break;
case 2:
getSavePoints()->push(kEntityIvo, kEntityMilos, kAction135024800);
- setup_function16();
+ setup_inCompartment();
break;
}
break;
@@ -297,7 +297,7 @@ IMPLEMENT_FUNCTION(15, Ivo, chapter1Handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(16, Ivo, function16)
+IMPLEMENT_FUNCTION(16, Ivo, inCompartment)
switch (savepoint.action) {
default:
break;
@@ -371,7 +371,7 @@ IMPLEMENT_FUNCTION(18, Ivo, chapter2)
break;
case kActionNone:
- Entity::timeCheck(kTime1777500, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_function19));
+ Entity::timeCheck(kTime1777500, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_goBreakfast));
break;
case kActionDefault:
@@ -391,7 +391,7 @@ IMPLEMENT_FUNCTION(18, Ivo, chapter2)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(19, Ivo, function19)
+IMPLEMENT_FUNCTION(19, Ivo, goBreakfast)
switch (savepoint.action) {
default:
break;
@@ -434,7 +434,7 @@ IMPLEMENT_FUNCTION(19, Ivo, function19)
case 5:
getData()->location = kLocationInsideCompartment;
- setup_function20();
+ setup_atBreakfast();
break;
}
break;
@@ -447,7 +447,7 @@ IMPLEMENT_FUNCTION(19, Ivo, function19)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(20, Ivo, function20)
+IMPLEMENT_FUNCTION(20, Ivo, atBreakfast)
switch (savepoint.action) {
default:
break;
@@ -464,7 +464,7 @@ IMPLEMENT_FUNCTION(20, Ivo, function20)
break;
case kActionDefault:
- getSavePoints()->push(kEntityIvo, kEntityServers1, kAction189688608);
+ getSavePoints()->push(kEntityIvo, kEntityWaiter2, kAction189688608);
getEntities()->drawSequenceLeft(kEntityIvo, "023B");
break;
@@ -474,18 +474,18 @@ IMPLEMENT_FUNCTION(20, Ivo, function20)
break;
case 1:
- getSavePoints()->push(kEntityIvo, kEntityServers1, kAction101106391);
+ getSavePoints()->push(kEntityIvo, kEntityWaiter2, kAction101106391);
getEntities()->drawSequenceLeft(kEntityIvo, "023B");
params->param1 = 1;
break;
case 2:
setCallback(3);
- setup_function11();
+ setup_goCompartment();
break;
case 3:
- getSavePoints()->push(kEntityIvo, kEntityServers1, kAction236237423);
+ getSavePoints()->push(kEntityIvo, kEntityWaiter2, kAction236237423);
setup_function21();
break;
}
@@ -567,7 +567,7 @@ IMPLEMENT_FUNCTION(25, Ivo, chapter4Handler)
case kActionNone:
if (getState()->time > kTime2361600 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
getData()->location = kLocationOutsideCompartment;
- setup_function26();
+ setup_returnCompartment4();
}
break;
@@ -579,7 +579,7 @@ IMPLEMENT_FUNCTION(25, Ivo, chapter4Handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(26, Ivo, function26)
+IMPLEMENT_FUNCTION(26, Ivo, returnCompartment4)
switch (savepoint.action) {
default:
break;
@@ -596,11 +596,11 @@ IMPLEMENT_FUNCTION(26, Ivo, function26)
case 1:
setCallback(2);
- setup_function11();
+ setup_goCompartment();
break;
case 2:
- setup_function27();
+ setup_inCompartment4();
break;
}
break;
@@ -608,7 +608,7 @@ IMPLEMENT_FUNCTION(26, Ivo, function26)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(27, Ivo, function27)
+IMPLEMENT_FUNCTION(27, Ivo, inCompartment4)
switch (savepoint.action) {
default:
break;
@@ -634,7 +634,7 @@ IMPLEMENT_FUNCTION(27, Ivo, function27)
case 2:
getEntities()->clearSequences(kEntityIvo);
- setup_function28();
+ setup_hiding();
break;
case 3:
@@ -676,7 +676,7 @@ IMPLEMENT_FUNCTION(27, Ivo, function27)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(28, Ivo, function28)
+IMPLEMENT_FUNCTION(28, Ivo, hiding)
switch (savepoint.action) {
default:
break;
@@ -745,11 +745,11 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(31, Ivo, chapter5Handler)
if (savepoint.action == kActionProceedChapter5)
- setup_fight();
+ setup_fightCath();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(32, Ivo, fight)
+IMPLEMENT_FUNCTION(32, Ivo, fightCath)
switch (savepoint.action) {
default:
break;
@@ -783,7 +783,7 @@ IMPLEMENT_FUNCTION(32, Ivo, fight)
getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, true);
} else {
getScenes()->loadSceneFromPosition(kCarBaggageRear, 96);
- setup_function33();
+ setup_knockedOut();
}
break;
}
@@ -792,7 +792,7 @@ IMPLEMENT_FUNCTION(32, Ivo, fight)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(33, Ivo, function33)
+IMPLEMENT_FUNCTION(33, Ivo, knockedOut)
switch (savepoint.action) {
default:
break;
diff --git a/engines/lastexpress/entities/ivo.h b/engines/lastexpress/entities/ivo.h
index a23d06cd3f..3646bc19f2 100644
--- a/engines/lastexpress/entities/ivo.h
+++ b/engines/lastexpress/entities/ivo.h
@@ -102,7 +102,7 @@ public:
*/
DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
- DECLARE_FUNCTION(function11)
+ DECLARE_FUNCTION(goCompartment)
DECLARE_FUNCTION(sitAtTableWithSalko)
DECLARE_FUNCTION(leaveTableWithSalko)
@@ -116,7 +116,7 @@ public:
*/
DECLARE_FUNCTION(chapter1Handler)
- DECLARE_FUNCTION(function16)
+ DECLARE_FUNCTION(inCompartment)
DECLARE_FUNCTION(function17)
/**
@@ -124,8 +124,8 @@ public:
*/
DECLARE_FUNCTION(chapter2)
- DECLARE_FUNCTION(function19)
- DECLARE_FUNCTION(function20)
+ DECLARE_FUNCTION(goBreakfast)
+ DECLARE_FUNCTION(atBreakfast)
DECLARE_FUNCTION(function21)
/**
@@ -148,9 +148,9 @@ public:
*/
DECLARE_FUNCTION(chapter4Handler)
- DECLARE_FUNCTION(function26)
- DECLARE_FUNCTION(function27)
- DECLARE_FUNCTION(function28)
+ DECLARE_FUNCTION(returnCompartment4)
+ DECLARE_FUNCTION(inCompartment4)
+ DECLARE_FUNCTION(hiding)
DECLARE_FUNCTION(function29)
/**
@@ -163,8 +163,8 @@ public:
*/
DECLARE_FUNCTION(chapter5Handler)
- DECLARE_FUNCTION(fight)
- DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(fightCath)
+ DECLARE_FUNCTION(knockedOut)
DECLARE_FUNCTION(function34)
};
diff --git a/engines/lastexpress/entities/kahina.cpp b/engines/lastexpress/entities/kahina.cpp
index b7af87751f..bbb2853721 100644
--- a/engines/lastexpress/entities/kahina.cpp
+++ b/engines/lastexpress/entities/kahina.cpp
@@ -43,28 +43,28 @@ Kahina::Kahina(LastExpressEngine *engine) : Entity(engine, kEntityKahina) {
ADD_CALLBACK_FUNCTION(Kahina, savegame);
ADD_CALLBACK_FUNCTION(Kahina, updateFromTime);
ADD_CALLBACK_FUNCTION(Kahina, updateFromTicks);
- ADD_CALLBACK_FUNCTION(Kahina, function6);
+ ADD_CALLBACK_FUNCTION(Kahina, lookingForCath);
ADD_CALLBACK_FUNCTION(Kahina, updateEntity2);
ADD_CALLBACK_FUNCTION(Kahina, updateEntity);
ADD_CALLBACK_FUNCTION(Kahina, enterExitCompartment);
ADD_CALLBACK_FUNCTION(Kahina, chapter1);
ADD_CALLBACK_FUNCTION(Kahina, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Kahina, function12);
- ADD_CALLBACK_FUNCTION(Kahina, function13);
+ ADD_CALLBACK_FUNCTION(Kahina, awaitingCath);
+ ADD_CALLBACK_FUNCTION(Kahina, cathDone);
ADD_CALLBACK_FUNCTION(Kahina, function14);
- ADD_CALLBACK_FUNCTION(Kahina, function15);
+ ADD_CALLBACK_FUNCTION(Kahina, searchTrain);
ADD_CALLBACK_FUNCTION(Kahina, chapter2);
- ADD_CALLBACK_FUNCTION(Kahina, chapter2Handler);
+ ADD_CALLBACK_FUNCTION(Kahina, inSeclusionPart2);
ADD_CALLBACK_FUNCTION(Kahina, chapter3);
ADD_CALLBACK_FUNCTION(Kahina, function19);
- ADD_CALLBACK_FUNCTION(Kahina, chapter3Handler);
- ADD_CALLBACK_FUNCTION(Kahina, function21);
- ADD_CALLBACK_FUNCTION(Kahina, function22);
- ADD_CALLBACK_FUNCTION(Kahina, function23);
- ADD_CALLBACK_FUNCTION(Kahina, function24);
- ADD_CALLBACK_FUNCTION(Kahina, function25);
- ADD_CALLBACK_FUNCTION(Kahina, function26);
- ADD_CALLBACK_FUNCTION(Kahina, function27);
+ ADD_CALLBACK_FUNCTION(Kahina, beforeConcert);
+ ADD_CALLBACK_FUNCTION(Kahina, concert);
+ ADD_CALLBACK_FUNCTION(Kahina, finished);
+ ADD_CALLBACK_FUNCTION(Kahina, findFirebird);
+ ADD_CALLBACK_FUNCTION(Kahina, seekCath);
+ ADD_CALLBACK_FUNCTION(Kahina, searchCath);
+ ADD_CALLBACK_FUNCTION(Kahina, searchTatiana);
+ ADD_CALLBACK_FUNCTION(Kahina, killCathAnywhere);
ADD_CALLBACK_FUNCTION(Kahina, chapter4);
ADD_CALLBACK_FUNCTION(Kahina, chapter5);
}
@@ -100,7 +100,7 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Kahina, updateFromTicks)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue)
+IMPLEMENT_FUNCTION_I(6, Kahina, lookingForCath, TimeValue)
switch (savepoint.action) {
default:
break;
@@ -270,17 +270,17 @@ IMPLEMENT_FUNCTION(11, Kahina, chapter1Handler)
Entity::timeCheckSavepoint(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837);
if (getProgress().eventMertensKronosInvitation)
- setup_function12();
+ setup_awaitingCath();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(12, Kahina, function12)
+IMPLEMENT_FUNCTION(12, Kahina, awaitingCath)
switch (savepoint.action) {
default:
break;
case kActionNone:
- Entity::timeCheck(kTime1485000, params->param2, WRAP_SETUP_FUNCTION(Kahina, setup_function13));
+ Entity::timeCheck(kTime1485000, params->param2, WRAP_SETUP_FUNCTION(Kahina, setup_cathDone));
break;
case kActionKnock:
@@ -316,13 +316,13 @@ IMPLEMENT_FUNCTION(12, Kahina, function12)
break;
case kAction137685712:
- setup_function13();
+ setup_cathDone();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(13, Kahina, function13)
+IMPLEMENT_FUNCTION(13, Kahina, cathDone)
switch (savepoint.action) {
default:
break;
@@ -347,7 +347,7 @@ IMPLEMENT_FUNCTION(13, Kahina, function13)
label_callback:
setCallback(1);
- setup_function15();
+ setup_searchTrain();
break;
case kActionDefault:
@@ -387,7 +387,7 @@ IMPLEMENT_FUNCTION(14, Kahina, function14)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(15, Kahina, function15)
+IMPLEMENT_FUNCTION(15, Kahina, searchTrain)
switch (savepoint.action) {
default:
break;
@@ -554,7 +554,7 @@ IMPLEMENT_FUNCTION(16, Kahina, chapter2)
break;
case kActionNone:
- setup_chapter2Handler();
+ setup_inSeclusionPart2();
break;
case kActionDefault:
@@ -573,7 +573,7 @@ IMPLEMENT_FUNCTION(16, Kahina, chapter2)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(17, Kahina, chapter2Handler)
+IMPLEMENT_FUNCTION(17, Kahina, inSeclusionPart2)
switch (savepoint.action) {
default:
break;
@@ -700,7 +700,7 @@ IMPLEMENT_FUNCTION(18, Kahina, chapter3)
break;
case kActionNone:
- setup_chapter3Handler();
+ setup_beforeConcert();
break;
case kActionDefault:
@@ -724,7 +724,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition)
case kActionNone:
if (getEvent(kEventAnnaBaggageArgument)) {
- RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function22);
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_finished);
}
if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2))
@@ -750,7 +750,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(20, Kahina, chapter3Handler)
+IMPLEMENT_FUNCTION(20, Kahina, beforeConcert)
switch (savepoint.action) {
default:
break;
@@ -781,7 +781,7 @@ label_callback_2:
if (getEntities()->isInKronosSalon(kEntityPlayer))
getScenes()->loadSceneFromPosition(kCarKronos, 87);
- setup_function21();
+ setup_concert();
break;
}
@@ -917,7 +917,7 @@ label_callback_2:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(21, Kahina, function21)
+IMPLEMENT_FUNCTION(21, Kahina, concert)
switch (savepoint.action) {
default:
break;
@@ -930,7 +930,7 @@ IMPLEMENT_FUNCTION(21, Kahina, function21)
if (params->param6 != kTimeInvalid) {
if (Entity::updateParameterTime((TimeValue)params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param5, 0)) {
setCallback(2);
- setup_function23();
+ setup_findFirebird();
break;
}
}
@@ -961,10 +961,10 @@ label_callback_2:
if (location == kObjectLocation3 || location == kObjectLocation7) {
setCallback(3);
- setup_function25();
+ setup_searchCath();
} else if (location == kObjectLocation1 || location == kObjectLocation2) {
setCallback(4);
- setup_function26();
+ setup_searchTatiana();
}
}
break;
@@ -997,17 +997,17 @@ label_callback_2:
case kAction92186062:
if (params->param1) {
setCallback(1);
- setup_function23();
+ setup_findFirebird();
}
break;
case kAction134611040:
if (getEvent(kEventConcertLeaveWithBriefcase))
- setup_function24();
+ setup_seekCath();
break;
case kAction137503360:
- setup_function22();
+ setup_finished();
break;
case kAction237555748:
@@ -1017,7 +1017,7 @@ label_callback_2:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(22, Kahina, function22)
+IMPLEMENT_FUNCTION(22, Kahina, finished)
switch (savepoint.action) {
default:
break;
@@ -1028,10 +1028,10 @@ IMPLEMENT_FUNCTION(22, Kahina, function22)
if (ENTITY_PARAM(0, 3) || location == kObjectLocation3 || location == kObjectLocation7) {
setCallback(1);
- setup_function25();
+ setup_searchCath();
} else if (location == kObjectLocation2 || location == kObjectLocation1) {
setCallback(2);
- setup_function26();
+ setup_searchTatiana();
}
}
break;
@@ -1050,7 +1050,7 @@ IMPLEMENT_FUNCTION(22, Kahina, function22)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(23, Kahina, function23)
+IMPLEMENT_FUNCTION(23, Kahina, findFirebird)
switch (savepoint.action) {
default:
break;
@@ -1133,7 +1133,7 @@ IMPLEMENT_FUNCTION(23, Kahina, function23)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(24, Kahina, function24)
+IMPLEMENT_FUNCTION(24, Kahina, seekCath)
switch (savepoint.action) {
default:
break;
@@ -1149,12 +1149,12 @@ IMPLEMENT_FUNCTION(24, Kahina, function24)
if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos))
getSavePoints()->push(kEntityKahina, kEntityKronos, kActionOpenDoor);
else
- setup_function27();
+ setup_killCathAnywhere();
break;
case kActionDefault:
setCallback(1);
- setup_function6(kTime2241000);
+ setup_lookingForCath(kTime2241000);
break;
case kActionCallback:
@@ -1170,12 +1170,12 @@ IMPLEMENT_FUNCTION(24, Kahina, function24)
getProgress().field_44 = 0;
- setup_function22();
+ setup_finished();
} else if (ENTITY_PARAM(0, 1)) {
setCallback(2);
setup_savegame(kSavegameTypeEvent, kEventKahinaGunYellow);
} else {
- setup_function27();
+ setup_killCathAnywhere();
}
break;
@@ -1205,13 +1205,13 @@ IMPLEMENT_FUNCTION(24, Kahina, function24)
getProgress().field_44 = 0;
- setup_function22();
+ setup_finished();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(25, Kahina, function25)
+IMPLEMENT_FUNCTION(25, Kahina, searchCath)
switch (savepoint.action) {
default:
break;
@@ -1369,7 +1369,7 @@ IMPLEMENT_FUNCTION(25, Kahina, function25)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(26, Kahina, function26)
+IMPLEMENT_FUNCTION(26, Kahina, searchTatiana)
switch (savepoint.action) {
default:
break;
@@ -1470,7 +1470,7 @@ IMPLEMENT_FUNCTION(26, Kahina, function26)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(27, Kahina, function27)
+IMPLEMENT_FUNCTION(27, Kahina, killCathAnywhere)
switch (savepoint.action) {
default:
break;
diff --git a/engines/lastexpress/entities/kahina.h b/engines/lastexpress/entities/kahina.h
index ee9ccf5c81..15c446c53d 100644
--- a/engines/lastexpress/entities/kahina.h
+++ b/engines/lastexpress/entities/kahina.h
@@ -69,7 +69,7 @@ public:
*/
DECLARE_FUNCTION_NOSETUP(updateFromTicks)
- DECLARE_FUNCTION_1(function6, TimeValue timeValue)
+ DECLARE_FUNCTION_1(lookingForCath, TimeValue timeValue)
/**
* Updates the entity
@@ -105,20 +105,16 @@ public:
*/
DECLARE_FUNCTION(chapter1Handler)
- DECLARE_FUNCTION(function12)
- DECLARE_FUNCTION(function13)
+ DECLARE_FUNCTION(awaitingCath)
+ DECLARE_FUNCTION(cathDone)
DECLARE_FUNCTION(function14)
- DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(searchTrain)
/**
* Setup Chapter 2
*/
DECLARE_FUNCTION(chapter2)
-
- /**
- * Handle Chapter 2 events
- */
- DECLARE_FUNCTION(chapter2Handler)
+ DECLARE_FUNCTION(inSeclusionPart2)
/**
* Setup Chapter 3
@@ -133,18 +129,14 @@ public:
*/
DECLARE_FUNCTION_2(function19, CarIndex car, EntityPosition entityPosition)
- /**
- * Handle Chapter 3 events
- */
- DECLARE_FUNCTION(chapter3Handler)
-
- DECLARE_FUNCTION(function21)
- DECLARE_FUNCTION(function22)
- DECLARE_FUNCTION(function23)
- DECLARE_FUNCTION(function24)
- DECLARE_FUNCTION(function25)
- DECLARE_FUNCTION(function26)
- DECLARE_FUNCTION(function27)
+ DECLARE_FUNCTION(beforeConcert)
+ DECLARE_FUNCTION(concert)
+ DECLARE_FUNCTION(finished)
+ DECLARE_FUNCTION(findFirebird)
+ DECLARE_FUNCTION(seekCath)
+ DECLARE_FUNCTION(searchCath)
+ DECLARE_FUNCTION(searchTatiana)
+ DECLARE_FUNCTION(killCathAnywhere)
/**
* Setup Chapter 4
diff --git a/engines/lastexpress/entities/kronos.cpp b/engines/lastexpress/entities/kronos.cpp
index 8bf158943b..1fe478fea9 100644
--- a/engines/lastexpress/entities/kronos.cpp
+++ b/engines/lastexpress/entities/kronos.cpp
@@ -70,21 +70,21 @@ Kronos::Kronos(LastExpressEngine *engine) : Entity(engine, kEntityKronos) {
ADD_CALLBACK_FUNCTION(Kronos, updateFromTicks);
ADD_CALLBACK_FUNCTION(Kronos, chapter1);
ADD_CALLBACK_FUNCTION(Kronos, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Kronos, function9);
+ ADD_CALLBACK_FUNCTION(Kronos, greetCath);
ADD_CALLBACK_FUNCTION(Kronos, function10);
ADD_CALLBACK_FUNCTION(Kronos, function11);
ADD_CALLBACK_FUNCTION(Kronos, chapter2);
ADD_CALLBACK_FUNCTION(Kronos, chapter3);
ADD_CALLBACK_FUNCTION(Kronos, chapter3Handler);
ADD_CALLBACK_FUNCTION(Kronos, function15);
- ADD_CALLBACK_FUNCTION(Kronos, function16);
- ADD_CALLBACK_FUNCTION(Kronos, function17);
- ADD_CALLBACK_FUNCTION(Kronos, function18);
- ADD_CALLBACK_FUNCTION(Kronos, function19);
- ADD_CALLBACK_FUNCTION(Kronos, function20);
- ADD_CALLBACK_FUNCTION(Kronos, function21);
- ADD_CALLBACK_FUNCTION(Kronos, function22);
- ADD_CALLBACK_FUNCTION(Kronos, function23);
+ ADD_CALLBACK_FUNCTION(Kronos, visitSalon);
+ ADD_CALLBACK_FUNCTION(Kronos, returnCompartment);
+ ADD_CALLBACK_FUNCTION(Kronos, preConcert);
+ ADD_CALLBACK_FUNCTION(Kronos, startConcert);
+ ADD_CALLBACK_FUNCTION(Kronos, duringConcert);
+ ADD_CALLBACK_FUNCTION(Kronos, afterConcert);
+ ADD_CALLBACK_FUNCTION(Kronos, awaitingCath);
+ ADD_CALLBACK_FUNCTION(Kronos, finished);
ADD_CALLBACK_FUNCTION(Kronos, chapter4);
ADD_CALLBACK_FUNCTION(Kronos, chapter5);
}
@@ -155,13 +155,13 @@ IMPLEMENT_FUNCTION(8, Kronos, chapter1Handler)
break;
case kAction202621266:
- setup_function9();
+ setup_greetCath();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(9, Kronos, function9)
+IMPLEMENT_FUNCTION(9, Kronos, greetCath)
switch (savepoint.action) {
default:
break;
@@ -294,7 +294,7 @@ IMPLEMENT_FUNCTION(15, Kronos, function15)
case kActionNone:
if (params->param1 && !getEntities()->isInSalon(kEntityBoutarel)) {
if (Entity::updateParameter(params->param2, getState()->timeTicks, 75)) {
- setup_function16();
+ setup_visitSalon();
break;
}
}
@@ -311,13 +311,13 @@ IMPLEMENT_FUNCTION(15, Kronos, function15)
params->param3 = kTimeInvalid;
if (getEntities()->isInSalon(kEntityPlayer)) {
- setup_function16();
+ setup_visitSalon();
} else {
getSavePoints()->push(kEntityKronos, kEntityAnna, kAction101169422);
getSavePoints()->push(kEntityKronos, kEntityTatiana, kAction101169422);
getSavePoints()->push(kEntityKronos, kEntityAbbot, kAction101169422);
- setup_function18();
+ setup_preConcert();
}
}
break;
@@ -333,7 +333,7 @@ IMPLEMENT_FUNCTION(15, Kronos, function15)
case kActionDrawScene:
if (params->param1 && getEntities()->isPlayerPosition(kCarRestaurant, 51) && !getEntities()->isInSalon(kEntityBoutarel))
- setup_function16();
+ setup_visitSalon();
else
params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 60)
|| getEntities()->isPlayerPosition(kCarRestaurant, 59)
@@ -345,7 +345,7 @@ IMPLEMENT_FUNCTION(15, Kronos, function15)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(16, Kronos, function16)
+IMPLEMENT_FUNCTION(16, Kronos, visitSalon)
switch (savepoint.action) {
default:
break;
@@ -363,14 +363,14 @@ IMPLEMENT_FUNCTION(16, Kronos, function16)
getSavePoints()->push(kEntityKronos, kEntityAbbot, kAction101169422);
getScenes()->loadSceneFromPosition(kCarRestaurant, 60);
- setup_function17();
+ setup_returnCompartment();
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(17, Kronos, function17)
+IMPLEMENT_FUNCTION(17, Kronos, returnCompartment)
switch (savepoint.action) {
default:
break;
@@ -386,13 +386,13 @@ IMPLEMENT_FUNCTION(17, Kronos, function17)
case kActionCallback:
if (getCallback() == 1)
- setup_function18();
+ setup_preConcert();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(18, Kronos, function18)
+IMPLEMENT_FUNCTION(18, Kronos, preConcert)
switch (savepoint.action) {
default:
break;
@@ -405,7 +405,7 @@ IMPLEMENT_FUNCTION(18, Kronos, function18)
params->param2 = 1;
}
- if (!Entity::timeCheck(kTime2106000, params->param3, WRAP_SETUP_FUNCTION(Kronos, setup_function19))) {
+ if (!Entity::timeCheck(kTime2106000, params->param3, WRAP_SETUP_FUNCTION(Kronos, setup_startConcert))) {
if (params->param1 && getEntities()->isInKronosSanctum(kEntityPlayer)) {
setCallback(1);
setup_savegame(kSavegameTypeEvent, kEventKahinaPunchSuite4);
@@ -429,7 +429,7 @@ IMPLEMENT_FUNCTION(18, Kronos, function18)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(19, Kronos, function19)
+IMPLEMENT_FUNCTION(19, Kronos, startConcert)
switch (savepoint.action) {
default:
break;
@@ -465,7 +465,7 @@ IMPLEMENT_FUNCTION(19, Kronos, function19)
RESET_ENTITY_STATE(kEntityAnna, Anna, setup_concert);
RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function35);
- setup_function20();
+ setup_duringConcert();
break;
}
break;
@@ -473,7 +473,7 @@ IMPLEMENT_FUNCTION(19, Kronos, function19)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(20, Kronos, function20)
+IMPLEMENT_FUNCTION(20, Kronos, duringConcert)
switch (savepoint.action) {
default:
break;
@@ -585,7 +585,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20)
getSound()->playSound(kEntityPlayer, "BUMP");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 26);
- setup_function21();
+ setup_afterConcert();
break;
}
@@ -602,7 +602,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20)
break;
}
- setup_function21();
+ setup_afterConcert();
break;
case kActionOpenDoor:
@@ -668,7 +668,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20)
getData()->entityPosition = kPosition_6000;
getAction()->playAnimation(kEventConcertLeaveWithBriefcase);
- RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function21);
+ RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_concert);
getScenes()->loadSceneFromPosition(kCarKronos, 87);
break;
@@ -678,7 +678,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20)
getSound()->playSound(kEntityPlayer, "BUMP");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 26);
- setup_function21();
+ setup_afterConcert();
break;
}
break;
@@ -686,7 +686,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(21, Kronos, function21)
+IMPLEMENT_FUNCTION(21, Kronos, afterConcert)
switch (savepoint.action) {
default:
break;
@@ -703,7 +703,7 @@ IMPLEMENT_FUNCTION(21, Kronos, function21)
getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal);
getSavePoints()->push(kEntityKronos, kEntityRebecca, kAction191668032);
if (!getEvent(kEventConcertLeaveWithBriefcase))
- setup_function22();
+ setup_awaitingCath();
break;
case kActionCallback:
@@ -722,13 +722,13 @@ IMPLEMENT_FUNCTION(21, Kronos, function21)
break;
case kAction235599361:
- setup_function22();
+ setup_awaitingCath();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(22, Kronos, function22)
+IMPLEMENT_FUNCTION(22, Kronos, awaitingCath)
switch (savepoint.action) {
default:
break;
@@ -791,7 +791,7 @@ IMPLEMENT_FUNCTION(22, Kronos, function22)
getInventory()->removeItem(kItemFirebird);
getInventory()->removeItem(kItemScarf);
- setup_function23();
+ setup_finished();
break;
case 2:
@@ -800,7 +800,7 @@ IMPLEMENT_FUNCTION(22, Kronos, function22)
getInventory()->removeItem(kItemFirebird);
getInventory()->get(kItemFirebird)->location = kObjectLocation5;
- setup_function23();
+ setup_finished();
break;
case 3:
@@ -809,7 +809,7 @@ IMPLEMENT_FUNCTION(22, Kronos, function22)
getAction()->playAnimation(kEventKronosBringEgg);
getScenes()->loadSceneFromPosition(kCarKronos, 87);
getInventory()->addItem(kItemBriefcase);
- setup_function23();
+ setup_finished();
break;
case 4:
@@ -835,12 +835,12 @@ IMPLEMENT_FUNCTION(22, Kronos, function22)
break;
case kAction138085344:
- setup_function23();
+ setup_finished();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(23, Kronos, function23)
+IMPLEMENT_FUNCTION(23, Kronos, finished)
switch (savepoint.action) {
default:
break;
diff --git a/engines/lastexpress/entities/kronos.h b/engines/lastexpress/entities/kronos.h
index 48da419a6e..00564b8ce5 100644
--- a/engines/lastexpress/entities/kronos.h
+++ b/engines/lastexpress/entities/kronos.h
@@ -89,7 +89,7 @@ public:
*/
DECLARE_FUNCTION(chapter1Handler)
- DECLARE_FUNCTION(function9)
+ DECLARE_FUNCTION(greetCath)
DECLARE_FUNCTION(function10)
DECLARE_FUNCTION(function11)
@@ -109,14 +109,14 @@ public:
DECLARE_FUNCTION(chapter3Handler)
DECLARE_FUNCTION(function15)
- DECLARE_FUNCTION(function16)
- DECLARE_FUNCTION(function17)
- DECLARE_FUNCTION(function18)
- DECLARE_FUNCTION(function19)
- DECLARE_FUNCTION(function20)
- DECLARE_FUNCTION(function21)
- DECLARE_FUNCTION(function22)
- DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(visitSalon)
+ DECLARE_FUNCTION(returnCompartment)
+ DECLARE_FUNCTION(preConcert)
+ DECLARE_FUNCTION(startConcert)
+ DECLARE_FUNCTION(duringConcert)
+ DECLARE_FUNCTION(afterConcert)
+ DECLARE_FUNCTION(awaitingCath)
+ DECLARE_FUNCTION(finished)
/**
* Setup Chapter 4
diff --git a/engines/lastexpress/entities/max.cpp b/engines/lastexpress/entities/max.cpp
index 1056e7fd7a..d75b6af7f5 100644
--- a/engines/lastexpress/entities/max.cpp
+++ b/engines/lastexpress/entities/max.cpp
@@ -42,16 +42,16 @@ Max::Max(LastExpressEngine *engine) : Entity(engine, kEntityMax) {
ADD_CALLBACK_FUNCTION(Max, draw);
ADD_CALLBACK_FUNCTION(Max, enterExitCompartment);
ADD_CALLBACK_FUNCTION(Max, savegame);
- ADD_CALLBACK_FUNCTION(Max, chapter12_handler);
- ADD_CALLBACK_FUNCTION(Max, function7);
- ADD_CALLBACK_FUNCTION(Max, chapter4Handler);
+ ADD_CALLBACK_FUNCTION(Max, withAnna);
+ ADD_CALLBACK_FUNCTION(Max, guardingCompartment);
+ ADD_CALLBACK_FUNCTION(Max, inCageFriendly);
ADD_CALLBACK_FUNCTION(Max, function9);
ADD_CALLBACK_FUNCTION(Max, chapter1);
ADD_CALLBACK_FUNCTION(Max, chapter2);
ADD_CALLBACK_FUNCTION(Max, chapter3);
ADD_CALLBACK_FUNCTION(Max, chapter3Handler);
- ADD_CALLBACK_FUNCTION(Max, freeFromCage);
- ADD_CALLBACK_FUNCTION(Max, function15);
+ ADD_CALLBACK_FUNCTION(Max, inCageMad);
+ ADD_CALLBACK_FUNCTION(Max, letMeIn);
ADD_CALLBACK_FUNCTION(Max, chapter4);
ADD_CALLBACK_FUNCTION(Max, function17);
ADD_CALLBACK_FUNCTION(Max, chapter5);
@@ -83,7 +83,7 @@ IMPLEMENT_FUNCTION_II(5, Max, savegame, SavegameType, uint32)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(6, Max, chapter12_handler)
+IMPLEMENT_FUNCTION(6, Max, withAnna)
switch (savepoint.action) {
default:
break;
@@ -105,7 +105,7 @@ IMPLEMENT_FUNCTION(6, Max, chapter12_handler)
case kAction71277948:
setCallback(1);
- setup_function7();
+ setup_guardingCompartment();
break;
case kAction158007856:
@@ -118,7 +118,7 @@ IMPLEMENT_FUNCTION(6, Max, chapter12_handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(7, Max, function7)
+IMPLEMENT_FUNCTION(7, Max, guardingCompartment)
switch (savepoint.action) {
default:
break;
@@ -208,7 +208,7 @@ IMPLEMENT_FUNCTION(7, Max, function7)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(8, Max, chapter4Handler)
+IMPLEMENT_FUNCTION(8, Max, inCageFriendly)
switch (savepoint.action) {
default:
break;
@@ -296,7 +296,7 @@ IMPLEMENT_FUNCTION(9, Max, function9)
setup_functions:
if (getProgress().chapter == kChapter3)
- setup_function15();
+ setup_letMeIn();
if (getProgress().chapter == kChapter4)
setup_function17();
@@ -324,7 +324,7 @@ IMPLEMENT_FUNCTION(10, Max, chapter1)
break;
case kActionNone:
- Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Max, setup_chapter12_handler));
+ Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Max, setup_withAnna));
break;
case kActionDefault:
@@ -343,7 +343,7 @@ IMPLEMENT_FUNCTION(11, Max, chapter2)
break;
case kActionNone:
- setup_chapter12_handler();
+ setup_withAnna();
break;
case kActionDefault:
@@ -413,7 +413,7 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler)
case kAction71277948:
setCallback(1);
- setup_function7();
+ setup_guardingCompartment();
break;
case kAction122358304:
@@ -421,7 +421,7 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler)
break;
case kActionMaxFreeFromCage:
- setup_freeFromCage();
+ setup_inCageMad();
break;
case kAction158007856:
@@ -437,7 +437,7 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(14, Max, freeFromCage)
+IMPLEMENT_FUNCTION(14, Max, inCageMad)
switch (savepoint.action) {
default:
break;
@@ -504,7 +504,7 @@ IMPLEMENT_FUNCTION(14, Max, freeFromCage)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(15, Max, function15)
+IMPLEMENT_FUNCTION(15, Max, letMeIn)
switch (savepoint.action) {
default:
break;
@@ -551,7 +551,7 @@ IMPLEMENT_FUNCTION(15, Max, function15)
case kActionMaxFreeFromCage:
getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true);
- setup_chapter4Handler();
+ setup_inCageFriendly();
break;
}
IMPLEMENT_FUNCTION_END
@@ -563,7 +563,7 @@ IMPLEMENT_FUNCTION(16, Max, chapter4)
break;
case kActionNone:
- setup_chapter4Handler();
+ setup_inCageFriendly();
break;
case kActionDefault:
@@ -606,7 +606,7 @@ IMPLEMENT_FUNCTION(17, Max, function17)
case kActionMaxFreeFromCage:
getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true);
- setup_chapter4Handler();
+ setup_inCageFriendly();
break;
}
IMPLEMENT_FUNCTION_END
diff --git a/engines/lastexpress/entities/max.h b/engines/lastexpress/entities/max.h
index 7b7780742b..e12b4b6dad 100644
--- a/engines/lastexpress/entities/max.h
+++ b/engines/lastexpress/entities/max.h
@@ -70,18 +70,9 @@ public:
*/
DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param)
- /**
- * Handle Chapter 1 & 2 events
- */
- DECLARE_FUNCTION(chapter12_handler)
-
- DECLARE_FUNCTION(function7)
-
- /**
- * Handle Chapter 4 events
- */
- DECLARE_FUNCTION(chapter4Handler)
-
+ DECLARE_FUNCTION(withAnna)
+ DECLARE_FUNCTION(guardingCompartment)
+ DECLARE_FUNCTION(inCageFriendly)
DECLARE_FUNCTION(function9)
/**
@@ -104,8 +95,8 @@ public:
*/
DECLARE_FUNCTION(chapter3Handler)
- DECLARE_FUNCTION(freeFromCage)
- DECLARE_FUNCTION(function15)
+ DECLARE_FUNCTION(inCageMad)
+ DECLARE_FUNCTION(letMeIn)
/**
* Setup Chapter 4
diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp
index 601187b672..90a397c7cb 100644
--- a/engines/lastexpress/entities/milos.cpp
+++ b/engines/lastexpress/entities/milos.cpp
@@ -722,7 +722,7 @@ IMPLEMENT_FUNCTION(15, Milos, chapter1Handler)
break;
case kActionNone:
- Entity::timeCheckSavepoint(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560);
+ Entity::timeCheckSavepoint(kTime1071000, params->param3, kEntityMilos, kEntityWaiter2, kAction223002560);
if (getState()->time > kTime1089000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) {
setup_function16();
@@ -801,7 +801,7 @@ IMPLEMENT_FUNCTION(16, Milos, function16)
break;
case 1:
- getSavePoints()->push(kEntityMilos, kEntityServers1, kAction269485588);
+ getSavePoints()->push(kEntityMilos, kEntityWaiter2, kAction269485588);
getSavePoints()->push(kEntityMilos, kEntityIvo, kAction125242096);
getEntities()->drawSequenceRight(kEntityMilos, "807DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
diff --git a/engines/lastexpress/entities/pascale.cpp b/engines/lastexpress/entities/pascale.cpp
index b6356a0acb..24b7f0409b 100644
--- a/engines/lastexpress/entities/pascale.cpp
+++ b/engines/lastexpress/entities/pascale.cpp
@@ -46,29 +46,29 @@ Pascale::Pascale(LastExpressEngine *engine) : Entity(engine, kEntityPascale) {
ADD_CALLBACK_FUNCTION(Pascale, welcomeSophieAndRebecca);
ADD_CALLBACK_FUNCTION(Pascale, sitSophieAndRebecca);
ADD_CALLBACK_FUNCTION(Pascale, welcomeCath);
- ADD_CALLBACK_FUNCTION(Pascale, function11);
+ ADD_CALLBACK_FUNCTION(Pascale, seatCath);
ADD_CALLBACK_FUNCTION(Pascale, chapter1);
- ADD_CALLBACK_FUNCTION(Pascale, getMessageFromAugustToTyler);
- ADD_CALLBACK_FUNCTION(Pascale, sitAnna);
- ADD_CALLBACK_FUNCTION(Pascale, welcomeAnna);
- ADD_CALLBACK_FUNCTION(Pascale, serveTatianaVassili);
- ADD_CALLBACK_FUNCTION(Pascale, chapter1Handler);
+ ADD_CALLBACK_FUNCTION(Pascale, greetAugust);
+ ADD_CALLBACK_FUNCTION(Pascale, seatAnna);
+ ADD_CALLBACK_FUNCTION(Pascale, greetAnna);
+ ADD_CALLBACK_FUNCTION(Pascale, greetTatiana);
+ ADD_CALLBACK_FUNCTION(Pascale, servingDinner);
ADD_CALLBACK_FUNCTION(Pascale, function18);
ADD_CALLBACK_FUNCTION(Pascale, function19);
ADD_CALLBACK_FUNCTION(Pascale, chapter2);
ADD_CALLBACK_FUNCTION(Pascale, chapter3);
ADD_CALLBACK_FUNCTION(Pascale, chapter3Handler);
- ADD_CALLBACK_FUNCTION(Pascale, function23);
+ ADD_CALLBACK_FUNCTION(Pascale, abbotSeatMe3);
ADD_CALLBACK_FUNCTION(Pascale, welcomeAbbot);
ADD_CALLBACK_FUNCTION(Pascale, chapter4);
ADD_CALLBACK_FUNCTION(Pascale, chapter4Handler);
- ADD_CALLBACK_FUNCTION(Pascale, function27);
- ADD_CALLBACK_FUNCTION(Pascale, messageFromAnna);
- ADD_CALLBACK_FUNCTION(Pascale, function29);
- ADD_CALLBACK_FUNCTION(Pascale, function30);
+ ADD_CALLBACK_FUNCTION(Pascale, meetCoudert);
+ ADD_CALLBACK_FUNCTION(Pascale, tellAugust);
+ ADD_CALLBACK_FUNCTION(Pascale, walkDownTrain);
+ ADD_CALLBACK_FUNCTION(Pascale, walkUpTrain);
ADD_CALLBACK_FUNCTION(Pascale, chapter5);
ADD_CALLBACK_FUNCTION(Pascale, chapter5Handler);
- ADD_CALLBACK_FUNCTION(Pascale, function33);
+ ADD_CALLBACK_FUNCTION(Pascale, hiding);
ADD_NULL_FUNCTION();
}
@@ -118,6 +118,7 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(8, Pascale, welcomeSophieAndRebecca)
+ // Welcomes Sophie And Rebecca
switch (savepoint.action) {
default:
break;
@@ -244,7 +245,7 @@ IMPLEMENT_FUNCTION(10, Pascale, welcomeCath)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(11, Pascale, function11)
+IMPLEMENT_FUNCTION(11, Pascale, seatCath)
switch (savepoint.action) {
default:
break;
@@ -295,7 +296,7 @@ IMPLEMENT_FUNCTION(12, Pascale, chapter1)
break;
case kActionNone:
- setup_chapter1Handler();
+ setup_servingDinner();
break;
case kActionDefault:
@@ -319,7 +320,7 @@ IMPLEMENT_FUNCTION(12, Pascale, chapter1)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler)
+IMPLEMENT_FUNCTION(13, Pascale, greetAugust)
switch (savepoint.action) {
default:
break;
@@ -372,7 +373,7 @@ IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(14, Pascale, sitAnna)
+IMPLEMENT_FUNCTION(14, Pascale, seatAnna)
switch (savepoint.action) {
default:
break;
@@ -394,7 +395,7 @@ IMPLEMENT_FUNCTION(14, Pascale, sitAnna)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna)
+IMPLEMENT_FUNCTION(15, Pascale, greetAnna)
switch (savepoint.action) {
default:
break;
@@ -416,7 +417,7 @@ IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna)
getSound()->playSound(kEntityPascale, "ANN1047");
setCallback(2);
- setup_sitAnna();
+ setup_seatAnna();
break;
case 2:
@@ -439,7 +440,7 @@ IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili)
+IMPLEMENT_FUNCTION(16, Pascale, greetTatiana)
switch (savepoint.action) {
default:
break;
@@ -492,7 +493,7 @@ IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(17, Pascale, chapter1Handler)
+IMPLEMENT_FUNCTION(17, Pascale, servingDinner)
switch (savepoint.action) {
default:
break;
@@ -521,28 +522,28 @@ switch (savepoint.action) {
if (params->param1 && !params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61)) {
setCallback(1);
- setup_function11();
+ setup_seatCath();
break;
}
label_callback1:
if (ENTITY_PARAM(0, 1) && !ENTITY_PARAM(1, 3)) {
setCallback(2);
- setup_getMessageFromAugustToTyler();
+ setup_greetAugust();
break;
}
label_callback2:
if (ENTITY_PARAM(0, 3)) {
setCallback(3);
- setup_serveTatianaVassili();
+ setup_greetTatiana();
break;
}
label_callback3:
if (ENTITY_PARAM(0, 2)) {
setCallback(4);
- setup_welcomeAnna();
+ setup_greetAnna();
break;
}
@@ -584,8 +585,8 @@ IMPLEMENT_FUNCTION(18, Pascale, function18)
if (getState()->time > kTime1242000 && !params->param1) {
params->param1 = 1;
- getSavePoints()->push(kEntityPascale, kEntityServers0, kAction101632192);
- getSavePoints()->push(kEntityPascale, kEntityServers1, kAction101632192);
+ getSavePoints()->push(kEntityPascale, kEntityWaiter1, kAction101632192);
+ getSavePoints()->push(kEntityPascale, kEntityWaiter2, kAction101632192);
getSavePoints()->push(kEntityPascale, kEntityCooks, kAction101632192);
getSavePoints()->push(kEntityPascale, kEntityVerges, kAction101632192);
@@ -674,7 +675,7 @@ IMPLEMENT_FUNCTION(22, Pascale, chapter3Handler)
if (ENTITY_PARAM(0, 7)) {
setCallback(1);
- setup_function23();
+ setup_abbotSeatMe3();
break;
}
@@ -693,7 +694,7 @@ label_callback:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(23, Pascale, function23)
+IMPLEMENT_FUNCTION(23, Pascale, abbotSeatMe3)
switch (savepoint.action) {
default:
break;
@@ -806,7 +807,7 @@ IMPLEMENT_FUNCTION(26, Pascale, chapter4Handler)
if (getEntities()->isSomebodyInsideRestaurantOrSalon()) {
if (ENTITY_PARAM(0, 8)) {
setCallback(1);
- setup_function27();
+ setup_meetCoudert();
break;
}
@@ -820,7 +821,7 @@ label_callback1:
if (params->param3 < getState()->time) {
params->param5 = kTimeInvalid;
setCallback(2);
- setup_messageFromAnna();
+ setup_tellAugust();
break;
}
@@ -830,7 +831,7 @@ label_callback1:
if (params->param5 < getState()->time) {
params->param5 = kTimeInvalid;
setCallback(2);
- setup_messageFromAnna();
+ setup_tellAugust();
break;
}
}
@@ -839,7 +840,7 @@ label_callback1:
label_callback2:
if (params->param1 && !params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61)) {
setCallback(3);
- setup_function11();
+ setup_seatCath();
break;
}
}
@@ -906,7 +907,7 @@ label_callback3:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(27, Pascale, function27)
+IMPLEMENT_FUNCTION(27, Pascale, meetCoudert)
switch (savepoint.action) {
default:
break;
@@ -920,7 +921,7 @@ IMPLEMENT_FUNCTION(27, Pascale, function27)
case kActionDefault:
setCallback(1);
- setup_function29();
+ setup_walkDownTrain();
break;
case kActionCallback:
@@ -941,7 +942,7 @@ IMPLEMENT_FUNCTION(27, Pascale, function27)
case 3:
setCallback(4);
- setup_function30();
+ setup_walkUpTrain();
break;
case 4:
@@ -959,7 +960,8 @@ IMPLEMENT_FUNCTION(27, Pascale, function27)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna)
+IMPLEMENT_FUNCTION(28, Pascale, tellAugust)
+ // Tell August the message from Anna
switch (savepoint.action) {
default:
break;
@@ -1005,7 +1007,7 @@ IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(29, Pascale, function29)
+IMPLEMENT_FUNCTION(29, Pascale, walkDownTrain)
switch (savepoint.action) {
default:
break;
@@ -1043,7 +1045,7 @@ IMPLEMENT_FUNCTION(29, Pascale, function29)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(30, Pascale, function30)
+IMPLEMENT_FUNCTION(30, Pascale, walkUpTrain)
switch (savepoint.action) {
default:
break;
@@ -1104,11 +1106,11 @@ IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(32, Pascale, chapter5Handler)
if (savepoint.action == kActionProceedChapter5)
- setup_function33();
+ setup_hiding();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(33, Pascale, function33)
+IMPLEMENT_FUNCTION(33, Pascale, hiding)
switch (savepoint.action) {
default:
break;
diff --git a/engines/lastexpress/entities/pascale.h b/engines/lastexpress/entities/pascale.h
index 1b7777dec9..c8df7587ae 100644
--- a/engines/lastexpress/entities/pascale.h
+++ b/engines/lastexpress/entities/pascale.h
@@ -88,22 +88,22 @@ public:
DECLARE_FUNCTION(welcomeSophieAndRebecca)
DECLARE_FUNCTION(sitSophieAndRebecca)
DECLARE_FUNCTION(welcomeCath)
- DECLARE_FUNCTION(function11)
+ DECLARE_FUNCTION(seatCath)
/**
* Setup Chapter 1
*/
DECLARE_FUNCTION(chapter1)
- DECLARE_FUNCTION(getMessageFromAugustToTyler)
- DECLARE_FUNCTION(sitAnna)
- DECLARE_FUNCTION(welcomeAnna)
- DECLARE_FUNCTION(serveTatianaVassili)
+ DECLARE_FUNCTION(greetAugust)
+ DECLARE_FUNCTION(seatAnna)
+ DECLARE_FUNCTION(greetAnna)
+ DECLARE_FUNCTION(greetTatiana)
/**
* Handle Chapter 1 events
*/
- DECLARE_FUNCTION(chapter1Handler)
+ DECLARE_FUNCTION(servingDinner)
DECLARE_FUNCTION(function18)
DECLARE_FUNCTION(function19)
@@ -123,7 +123,7 @@ public:
*/
DECLARE_FUNCTION(chapter3Handler)
- DECLARE_FUNCTION(function23)
+ DECLARE_FUNCTION(abbotSeatMe3)
DECLARE_FUNCTION(welcomeAbbot)
/**
@@ -136,10 +136,10 @@ public:
*/
DECLARE_FUNCTION(chapter4Handler)
- DECLARE_FUNCTION(function27)
- DECLARE_FUNCTION(messageFromAnna)
- DECLARE_FUNCTION(function29)
- DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(meetCoudert)
+ DECLARE_FUNCTION(tellAugust)
+ DECLARE_FUNCTION(walkDownTrain)
+ DECLARE_FUNCTION(walkUpTrain)
/**
* Setup Chapter 5
@@ -151,7 +151,7 @@ public:
*/
DECLARE_FUNCTION(chapter5Handler)
- DECLARE_FUNCTION(function33)
+ DECLARE_FUNCTION(hiding)
DECLARE_NULL_FUNCTION()
};
diff --git a/engines/lastexpress/entities/rebecca.cpp b/engines/lastexpress/entities/rebecca.cpp
index 05211663bd..40175ad8c4 100644
--- a/engines/lastexpress/entities/rebecca.cpp
+++ b/engines/lastexpress/entities/rebecca.cpp
@@ -437,7 +437,7 @@ IMPLEMENT_FUNCTION(19, Rebecca, function19)
break;
case 2:
- getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction337548856);
+ getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction337548856);
getEntities()->drawSequenceRight(kEntityRebecca, "810DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
getEntities()->updateFrame(kEntityRebecca);
@@ -850,7 +850,7 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24)
break;
case kActionNone:
- Entity::timeCheckSavepoint(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416);
+ Entity::timeCheckSavepoint(kTime1134000, params->param2, kEntityRebecca, kEntityWaiter1, kAction223712416);
if (!params->param1)
break;
@@ -920,7 +920,7 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24)
break;
case 8:
- getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400);
+ getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction136702400);
getEntities()->drawSequenceLeft(kEntityRebecca, "012G");
params->param1 = 1;
break;
@@ -928,7 +928,7 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24)
break;
case kAction123712592:
- getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK");
getEntities()->drawSequenceLeft(kEntityRebecca, "012E");
setCallback(8);
@@ -1244,7 +1244,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34)
params->param2 = kTimeInvalid;
- getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416);
+ getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction223712416);
}
Entity::timeCheckCallback(kTime2052000, params->param3, 1, WRAP_SETUP_FUNCTION(Rebecca, setup_function19));
@@ -1280,7 +1280,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34)
break;
case 4:
- getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400);
+ getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction136702400);
getEntities()->drawSequenceLeft(kEntityRebecca, "012G");
params->param1 = 1;
break;
@@ -1288,7 +1288,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34)
break;
case kAction123712592:
- getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK");
getSound()->playSound(kEntityRebecca, "Reb3003");
setCallback(4);
@@ -1624,7 +1624,7 @@ IMPLEMENT_FUNCTION(44, Rebecca, function44)
params->param3 = kTimeInvalid;
- getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416);
+ getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction223712416);
}
label_next:
@@ -1684,7 +1684,7 @@ label_callback_2:
break;
case 4:
- getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400);
+ getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction136702400);
getEntities()->drawSequenceLeft(kEntityRebecca, "012G");
params->param2 = 1;
break;
diff --git a/engines/lastexpress/entities/tatiana.cpp b/engines/lastexpress/entities/tatiana.cpp
index c6788fd4b2..951e89d595 100644
--- a/engines/lastexpress/entities/tatiana.cpp
+++ b/engines/lastexpress/entities/tatiana.cpp
@@ -507,7 +507,7 @@ IMPLEMENT_FUNCTION(20, Tatiana, function20)
case 2:
getEntities()->updatePositionExit(kEntityTatiana, kCarRestaurant, 67);
- getSavePoints()->push(kEntityTatiana, kEntityServers0, kAction188893625);
+ getSavePoints()->push(kEntityTatiana, kEntityWaiter1, kAction188893625);
setCallback(3);
setup_function18();
@@ -917,7 +917,7 @@ IMPLEMENT_FUNCTION(29, Tatiana, function29)
case 2:
getEntities()->updatePositionExit(kEntityTatiana, kCarRestaurant, 63);
- getSavePoints()->push(kEntityTatiana, kEntityServers1, kAction302203328);
+ getSavePoints()->push(kEntityTatiana, kEntityWaiter2, kAction302203328);
getEntities()->drawSequenceRight(kEntityTatiana, "805DS");
if (getEntities()->isInRestaurant(kEntityPlayer))
diff --git a/engines/lastexpress/entities/servers0.cpp b/engines/lastexpress/entities/waiter1.cpp
index 590efa7157..80ec471f1b 100644
--- a/engines/lastexpress/entities/servers0.cpp
+++ b/engines/lastexpress/entities/waiter1.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "lastexpress/entities/servers0.h"
+#include "lastexpress/entities/waiter1.h"
#include "lastexpress/game/entities.h"
#include "lastexpress/game/logic.h"
@@ -39,69 +39,69 @@ namespace LastExpress {
break; \
}
-Servers0::Servers0(LastExpressEngine *engine) : Entity(engine, kEntityServers0) {
- ADD_CALLBACK_FUNCTION(Servers0, callSavepoint);
- ADD_CALLBACK_FUNCTION(Servers0, updateFromTime);
- ADD_CALLBACK_FUNCTION(Servers0, draw);
- ADD_CALLBACK_FUNCTION(Servers0, updatePosition);
- ADD_CALLBACK_FUNCTION(Servers0, callbackActionOnDirection);
- ADD_CALLBACK_FUNCTION(Servers0, playSound);
- ADD_CALLBACK_FUNCTION(Servers0, function7);
- ADD_CALLBACK_FUNCTION(Servers0, function8);
- ADD_CALLBACK_FUNCTION(Servers0, function9);
- ADD_CALLBACK_FUNCTION(Servers0, function10);
- ADD_CALLBACK_FUNCTION(Servers0, chapter1);
- ADD_CALLBACK_FUNCTION(Servers0, function12);
- ADD_CALLBACK_FUNCTION(Servers0, function13);
- ADD_CALLBACK_FUNCTION(Servers0, function14);
- ADD_CALLBACK_FUNCTION(Servers0, function15);
- ADD_CALLBACK_FUNCTION(Servers0, function16);
- ADD_CALLBACK_FUNCTION(Servers0, function17);
- ADD_CALLBACK_FUNCTION(Servers0, function18);
- ADD_CALLBACK_FUNCTION(Servers0, function19);
- ADD_CALLBACK_FUNCTION(Servers0, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Servers0, function21);
- ADD_CALLBACK_FUNCTION(Servers0, function22);
- ADD_CALLBACK_FUNCTION(Servers0, chapter2);
- ADD_CALLBACK_FUNCTION(Servers0, chapter2Handler);
- ADD_CALLBACK_FUNCTION(Servers0, function25);
- ADD_CALLBACK_FUNCTION(Servers0, function26);
- ADD_CALLBACK_FUNCTION(Servers0, chapter3);
- ADD_CALLBACK_FUNCTION(Servers0, chapter3Handler);
- ADD_CALLBACK_FUNCTION(Servers0, augustAnnaDateOrder);
- ADD_CALLBACK_FUNCTION(Servers0, function30);
- ADD_CALLBACK_FUNCTION(Servers0, chapter4);
- ADD_CALLBACK_FUNCTION(Servers0, chapter4Handler);
- ADD_CALLBACK_FUNCTION(Servers0, augustOrderSteak);
- ADD_CALLBACK_FUNCTION(Servers0, augustServeDuck);
- ADD_CALLBACK_FUNCTION(Servers0, function35);
- ADD_CALLBACK_FUNCTION(Servers0, chapter5);
- ADD_CALLBACK_FUNCTION(Servers0, chapter5Handler);
+Waiter1::Waiter1(LastExpressEngine *engine) : Entity(engine, kEntityWaiter1) {
+ ADD_CALLBACK_FUNCTION(Waiter1, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Waiter1, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Waiter1, draw);
+ ADD_CALLBACK_FUNCTION(Waiter1, updatePosition);
+ ADD_CALLBACK_FUNCTION(Waiter1, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Waiter1, playSound);
+ ADD_CALLBACK_FUNCTION(Waiter1, rebeccaFeedUs);
+ ADD_CALLBACK_FUNCTION(Waiter1, rebeccaClearOurTable);
+ ADD_CALLBACK_FUNCTION(Waiter1, abbotCheckMe);
+ ADD_CALLBACK_FUNCTION(Waiter1, abbotClearTable);
+ ADD_CALLBACK_FUNCTION(Waiter1, chapter1);
+ ADD_CALLBACK_FUNCTION(Waiter1, annaOrder);
+ ADD_CALLBACK_FUNCTION(Waiter1, augustOrder);
+ ADD_CALLBACK_FUNCTION(Waiter1, serveAnna);
+ ADD_CALLBACK_FUNCTION(Waiter1, serveAugust);
+ ADD_CALLBACK_FUNCTION(Waiter1, clearAnna);
+ ADD_CALLBACK_FUNCTION(Waiter1, clearTatiana);
+ ADD_CALLBACK_FUNCTION(Waiter1, clearAugust1);
+ ADD_CALLBACK_FUNCTION(Waiter1, clearAugust2);
+ ADD_CALLBACK_FUNCTION(Waiter1, servingDinner);
+ ADD_CALLBACK_FUNCTION(Waiter1, function21);
+ ADD_CALLBACK_FUNCTION(Waiter1, function22);
+ ADD_CALLBACK_FUNCTION(Waiter1, chapter2);
+ ADD_CALLBACK_FUNCTION(Waiter1, inKitchen);
+ ADD_CALLBACK_FUNCTION(Waiter1, augustComeHere2);
+ ADD_CALLBACK_FUNCTION(Waiter1, augustClearTable2);
+ ADD_CALLBACK_FUNCTION(Waiter1, chapter3);
+ ADD_CALLBACK_FUNCTION(Waiter1, serving3);
+ ADD_CALLBACK_FUNCTION(Waiter1, annaComeHere3);
+ ADD_CALLBACK_FUNCTION(Waiter1, abbotServeLunch3);
+ ADD_CALLBACK_FUNCTION(Waiter1, chapter4);
+ ADD_CALLBACK_FUNCTION(Waiter1, serving4);
+ ADD_CALLBACK_FUNCTION(Waiter1, augustOrder4);
+ ADD_CALLBACK_FUNCTION(Waiter1, serveAugust4);
+ ADD_CALLBACK_FUNCTION(Waiter1, augustClearTable);
+ ADD_CALLBACK_FUNCTION(Waiter1, chapter5);
+ ADD_CALLBACK_FUNCTION(Waiter1, chapter5Handler);
ADD_NULL_FUNCTION();
}
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_SIIS(1, Servers0, callSavepoint, EntityIndex, ActionIndex)
+IMPLEMENT_FUNCTION_SIIS(1, Waiter1, callSavepoint, EntityIndex, ActionIndex)
Entity::callSavepoint(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_NOSETUP(2, Servers0, updateFromTime)
+IMPLEMENT_FUNCTION_NOSETUP(2, Waiter1, updateFromTime)
Entity::updateFromTime(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(3, Servers0, draw)
+IMPLEMENT_FUNCTION_S(3, Waiter1, draw)
Entity::draw(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_NOSETUP(4, Servers0, updatePosition)
+IMPLEMENT_FUNCTION_NOSETUP(4, Waiter1, updatePosition)
Entity::updatePosition(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection)
+IMPLEMENT_FUNCTION_NOSETUP(5, Waiter1, callbackActionOnDirection)
EXPOSE_PARAMS(EntityData::EntityParametersIIII);
switch (savepoint.action) {
@@ -119,7 +119,7 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection)
case kActionExcuseMeCath:
if (!params->param1) {
- getSound()->excuseMe(kEntityServers0);
+ getSound()->excuseMe(kEntityWaiter1);
params->param1 = 1;
}
break;
@@ -127,12 +127,12 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(6, Servers0, playSound)
+IMPLEMENT_FUNCTION_S(6, Waiter1, playSound)
Entity::playSound(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(7, Servers0, function7)
+IMPLEMENT_FUNCTION(7, Waiter1, rebeccaFeedUs)
switch (savepoint.action) {
default:
break;
@@ -153,12 +153,12 @@ IMPLEMENT_FUNCTION(7, Servers0, function7)
break;
case 1:
- getEntities()->clearSequences(kEntityServers0);
- getSavePoints()->push(kEntityServers0, kEntityRebecca, kAction123712592);
+ getEntities()->clearSequences(kEntityWaiter1);
+ getSavePoints()->push(kEntityWaiter1, kEntityRebecca, kAction123712592);
break;
case 2:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_5900;
callbackAction();
break;
@@ -173,12 +173,12 @@ IMPLEMENT_FUNCTION(7, Servers0, function7)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(8, Servers0, function8)
+IMPLEMENT_FUNCTION(8, Waiter1, rebeccaClearOurTable)
serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "913", &ENTITY_PARAM(1, 2));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(9, Servers0, function9)
+IMPLEMENT_FUNCTION(9, Waiter1, abbotCheckMe)
switch (savepoint.action) {
default:
break;
@@ -197,15 +197,15 @@ IMPLEMENT_FUNCTION(9, Servers0, function9)
break;
case 1:
- getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122358304);
- getEntities()->drawSequenceLeft(kEntityServers0, "029D");
+ getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "029D");
setCallback(2);
setup_playSound(getProgress().chapter == kChapter3 ? "Abb3016" : "Abb4001");
break;
case 2:
- getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122288808);
+ getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122288808);
setCallback(3);
setup_draw("917");
@@ -213,7 +213,7 @@ IMPLEMENT_FUNCTION(9, Servers0, function9)
case 3:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
ENTITY_PARAM(2, 2) = 0;
ENTITY_PARAM(1, 6) = 0;
@@ -225,37 +225,37 @@ IMPLEMENT_FUNCTION(9, Servers0, function9)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(10, Servers0, function10)
+IMPLEMENT_FUNCTION(10, Waiter1, abbotClearTable)
serveTable(savepoint, "916", kEntityTables4, "014E", "014F", "918", &ENTITY_PARAM(2, 3), false);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(11, Servers0, chapter1)
+IMPLEMENT_FUNCTION(11, Waiter1, chapter1)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter1Handler();
+ setup_servingDinner();
break;
case kActionDefault:
- getSavePoints()->addData(kEntityServers0, kAction270410280, 0);
- getSavePoints()->addData(kEntityServers0, kAction304061224, 1);
- getSavePoints()->addData(kEntityServers0, kAction252568704, 10);
- getSavePoints()->addData(kEntityServers0, kAction286534136, 11);
- getSavePoints()->addData(kEntityServers0, kAction218983616, 12);
- getSavePoints()->addData(kEntityServers0, kAction218586752, 13);
- getSavePoints()->addData(kEntityServers0, kAction207330561, 14);
- getSavePoints()->addData(kEntityServers0, kAction286403504, 16);
- getSavePoints()->addData(kEntityServers0, kAction218128129, 17);
- getSavePoints()->addData(kEntityServers0, kAction270068760, 18);
- getSavePoints()->addData(kEntityServers0, kAction223712416, 2);
- getSavePoints()->addData(kEntityServers0, kAction237485916, 5);
- getSavePoints()->addData(kEntityServers0, kAction188893625, 8);
- getSavePoints()->addData(kEntityServers0, kAction204704037, 6);
- getSavePoints()->addData(kEntityServers0, kAction292758554, 7);
- getSavePoints()->addData(kEntityServers0, kAction337548856, 9);
+ getSavePoints()->addData(kEntityWaiter1, kAction270410280, 0);
+ getSavePoints()->addData(kEntityWaiter1, kAction304061224, 1);
+ getSavePoints()->addData(kEntityWaiter1, kAction252568704, 10);
+ getSavePoints()->addData(kEntityWaiter1, kAction286534136, 11);
+ getSavePoints()->addData(kEntityWaiter1, kAction218983616, 12);
+ getSavePoints()->addData(kEntityWaiter1, kAction218586752, 13);
+ getSavePoints()->addData(kEntityWaiter1, kAction207330561, 14);
+ getSavePoints()->addData(kEntityWaiter1, kAction286403504, 16);
+ getSavePoints()->addData(kEntityWaiter1, kAction218128129, 17);
+ getSavePoints()->addData(kEntityWaiter1, kAction270068760, 18);
+ getSavePoints()->addData(kEntityWaiter1, kAction223712416, 2);
+ getSavePoints()->addData(kEntityWaiter1, kAction237485916, 5);
+ getSavePoints()->addData(kEntityWaiter1, kAction188893625, 8);
+ getSavePoints()->addData(kEntityWaiter1, kAction204704037, 6);
+ getSavePoints()->addData(kEntityWaiter1, kAction292758554, 7);
+ getSavePoints()->addData(kEntityWaiter1, kAction337548856, 9);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -265,47 +265,47 @@ IMPLEMENT_FUNCTION(11, Servers0, chapter1)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(12, Servers0, function12)
+IMPLEMENT_FUNCTION(12, Waiter1, annaOrder)
handleServer(savepoint, "907", kEntityAnna, kAction268773672, &ENTITY_PARAM(0, 1));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(13, Servers0, function13)
+IMPLEMENT_FUNCTION(13, Waiter1, augustOrder)
handleServer(savepoint, "911", kEntityAugust, kAction268773672, &ENTITY_PARAM(0, 2), "010F");
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(14, Servers0, function14)
+IMPLEMENT_FUNCTION(14, Waiter1, serveAnna)
handleServer(savepoint, "908", kEntityAnna, kAction170016384, &ENTITY_PARAM(0, 4));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(15, Servers0, function15)
+IMPLEMENT_FUNCTION(15, Waiter1, serveAugust)
handleServer(savepoint, "912", kEntityAugust, kAction170016384, &ENTITY_PARAM(0, 5));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(16, Servers0, function16)
+IMPLEMENT_FUNCTION(16, Waiter1, clearAnna)
serveTable(savepoint, "907", kEntityTables0, "001N", "001P", "909", &ENTITY_PARAM(0, 6));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(17, Servers0, function17)
+IMPLEMENT_FUNCTION(17, Waiter1, clearTatiana)
serveTable(savepoint, "915", kEntityTables4, "014E", "014F", "917", &ENTITY_PARAM(1, 1), true, false, 67);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(18, Servers0, function18)
+IMPLEMENT_FUNCTION(18, Waiter1, clearAugust1)
serveTable(savepoint, "911", kEntityTables3, "010L", "010H", "913", &ENTITY_PARAM(0, 7));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(19, Servers0, function19)
+IMPLEMENT_FUNCTION(19, Waiter1, clearAugust2)
serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "913", &ENTITY_PARAM(0, 8), true, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
+IMPLEMENT_FUNCTION(20, Waiter1, servingDinner)
switch (savepoint.action) {
default:
break;
@@ -325,19 +325,19 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
}
}
- if (!getEntities()->isInKitchen(kEntityServers0) && !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter1) && !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
- HANDLE_TABLE(0, 1, 1, setup_function12);
- HANDLE_TABLE(0, 2, 2, setup_function13);
- HANDLE_TABLE(0, 3, 3, setup_function7);
- HANDLE_TABLE(0, 4, 4, setup_function14);
- HANDLE_TABLE(0, 5, 5, setup_function15);
- HANDLE_TABLE(0, 6, 6, setup_function16);
- HANDLE_TABLE(1, 1, 7, setup_function17);
- HANDLE_TABLE(0, 7, 8, setup_function18);
- HANDLE_TABLE(0, 8, 9, setup_function19);
- HANDLE_TABLE(1, 2, 10, setup_function8);
+ HANDLE_TABLE(0, 1, 1, setup_annaOrder);
+ HANDLE_TABLE(0, 2, 2, setup_augustOrder);
+ HANDLE_TABLE(0, 3, 3, setup_rebeccaFeedUs);
+ HANDLE_TABLE(0, 4, 4, setup_serveAnna);
+ HANDLE_TABLE(0, 5, 5, setup_serveAugust);
+ HANDLE_TABLE(0, 6, 6, setup_clearAnna);
+ HANDLE_TABLE(1, 1, 7, setup_clearTatiana);
+ HANDLE_TABLE(0, 7, 8, setup_clearAugust1);
+ HANDLE_TABLE(0, 8, 9, setup_clearAugust2);
+ HANDLE_TABLE(1, 2, 10, setup_rebeccaClearOurTable);
break;
case kActionCallback:
@@ -346,13 +346,13 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
break;
case 10:
- getSavePoints()->push(kEntityServers0, kEntityPascale, kAction352703104);
+ getSavePoints()->push(kEntityWaiter1, kEntityPascale, kAction352703104);
setup_function21();
break;
case 11:
case 12:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_5900;
if (getCallback() == 11)
@@ -363,7 +363,7 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
case 13:
case 14:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_5900;
break;
}
@@ -382,7 +382,7 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(21, Servers0, function21)
+IMPLEMENT_FUNCTION(21, Waiter1, function21)
switch (savepoint.action) {
default:
break;
@@ -398,28 +398,28 @@ IMPLEMENT_FUNCTION(21, Servers0, function21)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(22, Servers0, function22)
+IMPLEMENT_FUNCTION(22, Waiter1, function22)
if (savepoint.action == kActionDefault) {
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
getData()->car = kCarRestaurant;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(23, Servers0, chapter2)
+IMPLEMENT_FUNCTION(23, Waiter1, chapter2)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter2Handler();
+ setup_inKitchen();
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -434,28 +434,28 @@ IMPLEMENT_FUNCTION(23, Servers0, chapter2)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(24, Servers0, chapter2Handler)
+IMPLEMENT_FUNCTION(24, Waiter1, inKitchen)
switch (savepoint.action) {
default:
break;
case kActionNone:
- if (!getEntities()->isInKitchen(kEntityServers0) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
- HANDLE_TABLE(1, 3, 1, setup_function25);
- HANDLE_TABLE(1, 4, 2, setup_function26);
+ HANDLE_TABLE(1, 3, 1, setup_augustComeHere2);
+ HANDLE_TABLE(1, 4, 2, setup_augustClearTable2);
break;
case kActionCallback:
if (getCallback() == 1)
- HANDLE_TABLE(1, 4, 2, setup_function26);
+ HANDLE_TABLE(1, 4, 2, setup_augustClearTable2);
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(25, Servers0, function25)
+IMPLEMENT_FUNCTION(25, Waiter1, augustComeHere2)
switch (savepoint.action) {
default:
break;
@@ -474,13 +474,13 @@ IMPLEMENT_FUNCTION(25, Servers0, function25)
break;
case 1:
- getSavePoints()->push(kEntityServers0, kEntityAugust, kAction123712592);
- getEntities()->drawSequenceLeft(kEntityServers0, "BLANK");
+ getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction123712592);
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK");
break;
case 2:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
ENTITY_PARAM(1, 3) = 0;
callbackAction();
@@ -496,22 +496,22 @@ IMPLEMENT_FUNCTION(25, Servers0, function25)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(26, Servers0, function26)
+IMPLEMENT_FUNCTION(26, Waiter1, augustClearTable2)
serveTable(savepoint, "957", kEntityTables0, "016E", "016D", "959", &ENTITY_PARAM(1, 4));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(27, Servers0, chapter3)
+IMPLEMENT_FUNCTION(27, Waiter1, chapter3)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter3Handler();
+ setup_serving3();
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -530,53 +530,53 @@ IMPLEMENT_FUNCTION(27, Servers0, chapter3)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(28, Servers0, chapter3Handler)
+IMPLEMENT_FUNCTION(28, Waiter1, serving3)
switch (savepoint.action) {
default:
break;
case kActionNone:
- if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
if (ENTITY_PARAM(1, 5)) {
setCallback(1);
- setup_augustAnnaDateOrder();
+ setup_annaComeHere3();
break;
}
label_callback_1:
if (ENTITY_PARAM(1, 6)) {
setCallback(2);
- setup_function9();
+ setup_abbotCheckMe();
break;
}
label_callback_2:
if (ENTITY_PARAM(2, 4)) {
setCallback(3);
- setup_function30();
+ setup_abbotServeLunch3();
break;
}
label_callback_3:
if (ENTITY_PARAM(2, 3)) {
setCallback(4);
- setup_function10();
+ setup_abbotClearTable();
break;
}
label_callback_4:
if (ENTITY_PARAM(0, 3)) {
setCallback(5);
- setup_function7();
+ setup_rebeccaFeedUs();
break;
}
label_callback_5:
if (ENTITY_PARAM(1, 2)) {
setCallback(6);
- setup_function8();
+ setup_rebeccaClearOurTable();
break;
}
break;
@@ -606,7 +606,8 @@ label_callback_5:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder)
+IMPLEMENT_FUNCTION(29, Waiter1, annaComeHere3)
+ // August and Anna order dinner
switch (savepoint.action) {
default:
break;
@@ -625,15 +626,15 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder)
break;
case 1:
- getSavePoints()->push(kEntityServers0, kEntityAnna, kAction122358304);
- getEntities()->drawSequenceLeft(kEntityServers0, "026D");
+ getSavePoints()->push(kEntityWaiter1, kEntityAnna, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "026D");
setCallback(2);
setup_playSound("Ann3138");
break;
case 2:
- getSavePoints()->push(kEntityServers0, kEntityAnna, kAction122288808);
+ getSavePoints()->push(kEntityWaiter1, kEntityAnna, kAction122288808);
setCallback(3);
setup_draw("913");
@@ -641,7 +642,7 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder)
case 3:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
ENTITY_PARAM(1, 5) = 0;
callbackAction();
@@ -652,7 +653,7 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(30, Servers0, function30)
+IMPLEMENT_FUNCTION(30, Waiter1, abbotServeLunch3)
switch (savepoint.action) {
default:
break;
@@ -671,15 +672,15 @@ IMPLEMENT_FUNCTION(30, Servers0, function30)
break;
case 1:
- getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122358304);
- getEntities()->drawSequenceLeft(kEntityServers0, "029D");
+ getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122358304);
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "029D");
setCallback(2);
setup_playSound("Abb3016a");
break;
case 2:
- getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122288808);
+ getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122288808);
setCallback(3);
setup_draw("918");
@@ -687,7 +688,7 @@ IMPLEMENT_FUNCTION(30, Servers0, function30)
case 3:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
ENTITY_PARAM(2, 4) = 0;
callbackAction();
@@ -698,17 +699,17 @@ IMPLEMENT_FUNCTION(30, Servers0, function30)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(31, Servers0, chapter4)
+IMPLEMENT_FUNCTION(31, Waiter1, chapter4)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter4Handler();
+ setup_serving4();
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -727,7 +728,7 @@ IMPLEMENT_FUNCTION(31, Servers0, chapter4)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler)
+IMPLEMENT_FUNCTION(32, Waiter1, serving4)
switch (savepoint.action) {
default:
break;
@@ -738,47 +739,47 @@ IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler)
params->param1 = 0;
}
- if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
if (ENTITY_PARAM(1, 7)) {
setCallback(1);
- setup_augustOrderSteak();
+ setup_augustOrder4();
break;
}
label_callback_1:
if (ENTITY_PARAM(1, 8)) {
setCallback(2);
- setup_augustServeDuck();
+ setup_serveAugust4();
break;
}
label_callback_2:
if (ENTITY_PARAM(2, 1)) {
setCallback(3);
- setup_function35();
+ setup_augustClearTable();
break;
}
label_callback_3:
if (ENTITY_PARAM(2, 2)) {
setCallback(4);
- setup_function9();
+ setup_abbotCheckMe();
break;
}
label_callback_4:
if (ENTITY_PARAM(2, 3)) {
setCallback(5);
- setup_function10();
+ setup_abbotClearTable();
break;
}
label_callback_5:
if (ENTITY_PARAM(0, 3)) {
setCallback(6);
- setup_function7();
+ setup_rebeccaFeedUs();
break;
}
break;
@@ -821,7 +822,8 @@ label_callback_5:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
+IMPLEMENT_FUNCTION(33, Waiter1, augustOrder4)
+ // August orders a steak
switch (savepoint.action) {
default:
break;
@@ -837,7 +839,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
break;
case 1:
- getEntities()->drawSequenceLeft(kEntityServers0, "010F3");
+ getEntities()->drawSequenceLeft(kEntityWaiter1, "010F3");
getEntities()->drawSequenceLeft(kEntityAugust, "010D3");
setCallback(2);
@@ -845,7 +847,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
break;
case 2:
- getSavePoints()->push(kEntityServers0, kEntityAugust, kAction122288808);
+ getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction122288808);
setCallback(3);
setup_draw("913");
@@ -853,7 +855,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
case 3:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
ENTITY_PARAM(1, 7) = 0;
callbackAction();
@@ -864,7 +866,8 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck)
+IMPLEMENT_FUNCTION(34, Waiter1, serveAugust4)
+ // August is being served
switch (savepoint.action) {
default:
break;
@@ -880,15 +883,15 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck)
break;
case 1:
- getSavePoints()->push(kEntityServers0, kEntityAugust, kAction122358304);
- getSound()->playSound(kEntityServers0, "AUG1053");
+ getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction122358304);
+ getSound()->playSound(kEntityWaiter1, "AUG1053");
setCallback(2);
setup_draw("010G3");
break;
case 2:
- getSavePoints()->push(kEntityServers0, kEntityAugust, kAction201964801);
+ getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction201964801);
setCallback(3);
setup_draw("914");
@@ -896,7 +899,7 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck)
case 3:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
ENTITY_PARAM(1, 8) = 0;
callbackAction();
@@ -907,12 +910,12 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(35, Servers0, function35)
+IMPLEMENT_FUNCTION(35, Waiter1, augustClearTable)
serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "914", &ENTITY_PARAM(2, 1), false, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(36, Servers0, chapter5)
+IMPLEMENT_FUNCTION(36, Waiter1, chapter5)
switch (savepoint.action) {
default:
break;
@@ -922,7 +925,7 @@ IMPLEMENT_FUNCTION(36, Servers0, chapter5)
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
getData()->entityPosition = kPosition_3969;
getData()->location = kLocationInsideCompartment;
@@ -933,19 +936,19 @@ IMPLEMENT_FUNCTION(36, Servers0, chapter5)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(37, Servers0, chapter5Handler)
+IMPLEMENT_FUNCTION(37, Waiter1, chapter5Handler)
if (savepoint.action == kActionProceedChapter5)
setup_nullfunction();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_NULL_FUNCTION(38, Servers0)
+IMPLEMENT_NULL_FUNCTION(38, Waiter1)
//////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////
-void Servers0::handleServer(const SavePoint &savepoint, const char *name, EntityIndex entity, ActionIndex action, uint *parameter, const char *name2) {
+void Waiter1::handleServer(const SavePoint &savepoint, const char *name, EntityIndex entity, ActionIndex action, uint *parameter, const char *name2) {
switch (savepoint.action) {
default:
break;
@@ -962,11 +965,11 @@ void Servers0::handleServer(const SavePoint &savepoint, const char *name, Entity
if (getCallback() == 1) {
// Prepare or draw sequences depending of value of string
if (strcmp(name2, ""))
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
else
- getEntities()->drawSequenceLeft(kEntityServers0, name2);
+ getEntities()->drawSequenceLeft(kEntityWaiter1, name2);
- getSavePoints()->push(kEntityServers0, entity, action);
+ getSavePoints()->push(kEntityWaiter1, entity, action);
*parameter = 0;
callbackAction();
@@ -976,7 +979,7 @@ void Servers0::handleServer(const SavePoint &savepoint, const char *name, Entity
}
//////////////////////////////////////////////////////////////////////////
-void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, bool shouldUpdatePosition, bool pushSavepoint, Position position) {
+void Waiter1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, bool shouldUpdatePosition, bool pushSavepoint, Position position) {
switch (savepoint.action) {
default:
break;
@@ -998,9 +1001,9 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
case 1:
if (position)
- getEntities()->updatePositionEnter(kEntityServers0, kCarRestaurant, position);
+ getEntities()->updatePositionEnter(kEntityWaiter1, kCarRestaurant, position);
- getSavePoints()->push(kEntityServers0, entity, kAction136455232);
+ getSavePoints()->push(kEntityWaiter1, entity, kAction136455232);
setCallback(2);
setup_callSavepoint(seq2, entity, kActionDrawTablesWithChairs, seq3);
@@ -1008,7 +1011,7 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
case 2:
if (position)
- getEntities()->updatePositionExit(kEntityServers0, kCarRestaurant, position);
+ getEntities()->updatePositionExit(kEntityWaiter1, kCarRestaurant, position);
setCallback(3);
setup_draw(seq4);
@@ -1019,9 +1022,9 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
// Special case for functions 19 & 35
if (pushSavepoint)
- getSavePoints()->push(kEntityServers0, kEntityRebecca, kAction224253538);
+ getSavePoints()->push(kEntityWaiter1, kEntityRebecca, kAction224253538);
- getEntities()->clearSequences(kEntityServers0);
+ getEntities()->clearSequences(kEntityWaiter1);
*parameter = 0;
callbackAction();
diff --git a/engines/lastexpress/entities/servers0.h b/engines/lastexpress/entities/waiter1.h
index 70f06596b0..64c66550af 100644
--- a/engines/lastexpress/entities/servers0.h
+++ b/engines/lastexpress/entities/waiter1.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef LASTEXPRESS_SERVERS0_H
-#define LASTEXPRESS_SERVERS0_H
+#ifndef LASTEXPRESS_WAITER1_H
+#define LASTEXPRESS_WAITER1_H
#include "lastexpress/entities/entity.h"
@@ -29,10 +29,10 @@ namespace LastExpress {
class LastExpressEngine;
-class Servers0 : public Entity {
+class Waiter1 : public Entity {
public:
- Servers0(LastExpressEngine *engine);
- ~Servers0() {}
+ Waiter1(LastExpressEngine *engine);
+ ~Waiter1() {}
/**
* Call a savepoint (or draw sequence in default case)
@@ -80,29 +80,24 @@ public:
*/
DECLARE_FUNCTION_1(playSound, const char *filename)
- DECLARE_FUNCTION(function7)
- DECLARE_FUNCTION(function8)
- DECLARE_FUNCTION(function9)
- DECLARE_FUNCTION(function10)
+ DECLARE_FUNCTION(rebeccaFeedUs)
+ DECLARE_FUNCTION(rebeccaClearOurTable)
+ DECLARE_FUNCTION(abbotCheckMe)
+ DECLARE_FUNCTION(abbotClearTable)
/**
* Setup Chapter 1
*/
DECLARE_FUNCTION(chapter1)
- DECLARE_FUNCTION(function12)
- DECLARE_FUNCTION(function13)
- DECLARE_FUNCTION(function14)
- DECLARE_FUNCTION(function15)
- DECLARE_FUNCTION(function16)
- DECLARE_FUNCTION(function17)
- DECLARE_FUNCTION(function18)
- DECLARE_FUNCTION(function19)
-
- /**
- * Handle Chapter 1 events
- */
- DECLARE_FUNCTION(chapter1Handler)
-
+ DECLARE_FUNCTION(annaOrder)
+ DECLARE_FUNCTION(augustOrder)
+ DECLARE_FUNCTION(serveAnna)
+ DECLARE_FUNCTION(serveAugust)
+ DECLARE_FUNCTION(clearAnna)
+ DECLARE_FUNCTION(clearTatiana)
+ DECLARE_FUNCTION(clearAugust1)
+ DECLARE_FUNCTION(clearAugust2)
+ DECLARE_FUNCTION(servingDinner)
DECLARE_FUNCTION(function21)
DECLARE_FUNCTION(function22)
@@ -110,41 +105,26 @@ public:
* Setup Chapter 2
*/
DECLARE_FUNCTION(chapter2)
-
- /**
- * Handle Chapter 2 events
- */
- DECLARE_FUNCTION(chapter2Handler)
-
- DECLARE_FUNCTION(function25)
- DECLARE_FUNCTION(function26)
+ DECLARE_FUNCTION(inKitchen)
+ DECLARE_FUNCTION(augustComeHere2)
+ DECLARE_FUNCTION(augustClearTable2)
/**
* Setup Chapter 3
*/
DECLARE_FUNCTION(chapter3)
-
- /**
- * Handle Chapter 3 events
- */
- DECLARE_FUNCTION(chapter3Handler)
-
- DECLARE_FUNCTION(augustAnnaDateOrder)
- DECLARE_FUNCTION(function30)
+ DECLARE_FUNCTION(serving3)
+ DECLARE_FUNCTION(annaComeHere3)
+ DECLARE_FUNCTION(abbotServeLunch3)
/**
* Setup Chapter 4
*/
DECLARE_FUNCTION(chapter4)
-
- /**
- * Handle Chapter 4 events
- */
- DECLARE_FUNCTION(chapter4Handler)
-
- DECLARE_FUNCTION(augustOrderSteak)
- DECLARE_FUNCTION(augustServeDuck)
- DECLARE_FUNCTION(function35)
+ DECLARE_FUNCTION(serving4)
+ DECLARE_FUNCTION(augustOrder4)
+ DECLARE_FUNCTION(serveAugust4)
+ DECLARE_FUNCTION(augustClearTable)
/**
* Setup Chapter 5
@@ -165,4 +145,4 @@ private:
} // End of namespace LastExpress
-#endif // LASTEXPRESS_SERVERS0_H
+#endif // LASTEXPRESS_WAITER1_H
diff --git a/engines/lastexpress/entities/servers1.cpp b/engines/lastexpress/entities/waiter2.cpp
index 153c2b66da..52a48a77d5 100644
--- a/engines/lastexpress/entities/servers1.cpp
+++ b/engines/lastexpress/entities/waiter2.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "lastexpress/entities/servers1.h"
+#include "lastexpress/entities/waiter2.h"
#include "lastexpress/game/entities.h"
#include "lastexpress/game/logic.h"
@@ -32,61 +32,61 @@
namespace LastExpress {
-Servers1::Servers1(LastExpressEngine *engine) : Entity(engine, kEntityServers1) {
- ADD_CALLBACK_FUNCTION(Servers1, updateFromTime);
- ADD_CALLBACK_FUNCTION(Servers1, draw);
- ADD_CALLBACK_FUNCTION(Servers1, updatePosition);
- ADD_CALLBACK_FUNCTION(Servers1, callbackActionOnDirection);
- ADD_CALLBACK_FUNCTION(Servers1, callSavepoint);
- ADD_CALLBACK_FUNCTION(Servers1, playSound);
- ADD_CALLBACK_FUNCTION(Servers1, function7);
- ADD_CALLBACK_FUNCTION(Servers1, chapter1);
- ADD_CALLBACK_FUNCTION(Servers1, function9);
- ADD_CALLBACK_FUNCTION(Servers1, function10);
- ADD_CALLBACK_FUNCTION(Servers1, function11);
- ADD_CALLBACK_FUNCTION(Servers1, function12);
- ADD_CALLBACK_FUNCTION(Servers1, function13);
- ADD_CALLBACK_FUNCTION(Servers1, chapter1Handler);
- ADD_CALLBACK_FUNCTION(Servers1, function15);
- ADD_CALLBACK_FUNCTION(Servers1, function16);
- ADD_CALLBACK_FUNCTION(Servers1, chapter2);
- ADD_CALLBACK_FUNCTION(Servers1, chapter2Handler);
- ADD_CALLBACK_FUNCTION(Servers1, function19);
- ADD_CALLBACK_FUNCTION(Servers1, function20);
- ADD_CALLBACK_FUNCTION(Servers1, function21);
- ADD_CALLBACK_FUNCTION(Servers1, chapter3);
- ADD_CALLBACK_FUNCTION(Servers1, chapter3Handler);
- ADD_CALLBACK_FUNCTION(Servers1, function24);
- ADD_CALLBACK_FUNCTION(Servers1, chapter4);
- ADD_CALLBACK_FUNCTION(Servers1, chapter4Handler);
- ADD_CALLBACK_FUNCTION(Servers1, function27);
- ADD_CALLBACK_FUNCTION(Servers1, function28);
- ADD_CALLBACK_FUNCTION(Servers1, function29);
- ADD_CALLBACK_FUNCTION(Servers1, chapter5);
- ADD_CALLBACK_FUNCTION(Servers1, chapter5Handler);
+Waiter2::Waiter2(LastExpressEngine *engine) : Entity(engine, kEntityWaiter2) {
+ ADD_CALLBACK_FUNCTION(Waiter2, updateFromTime);
+ ADD_CALLBACK_FUNCTION(Waiter2, draw);
+ ADD_CALLBACK_FUNCTION(Waiter2, updatePosition);
+ ADD_CALLBACK_FUNCTION(Waiter2, callbackActionOnDirection);
+ ADD_CALLBACK_FUNCTION(Waiter2, callSavepoint);
+ ADD_CALLBACK_FUNCTION(Waiter2, playSound);
+ ADD_CALLBACK_FUNCTION(Waiter2, monsieurServeUs);
+ ADD_CALLBACK_FUNCTION(Waiter2, chapter1);
+ ADD_CALLBACK_FUNCTION(Waiter2, milosOrder);
+ ADD_CALLBACK_FUNCTION(Waiter2, monsieurOrder);
+ ADD_CALLBACK_FUNCTION(Waiter2, clearAlexei);
+ ADD_CALLBACK_FUNCTION(Waiter2, clearMilos);
+ ADD_CALLBACK_FUNCTION(Waiter2, clearMonsieur);
+ ADD_CALLBACK_FUNCTION(Waiter2, servingDinner);
+ ADD_CALLBACK_FUNCTION(Waiter2, function15);
+ ADD_CALLBACK_FUNCTION(Waiter2, function16);
+ ADD_CALLBACK_FUNCTION(Waiter2, chapter2);
+ ADD_CALLBACK_FUNCTION(Waiter2, inKitchen);
+ ADD_CALLBACK_FUNCTION(Waiter2, tatianaClearTableB);
+ ADD_CALLBACK_FUNCTION(Waiter2, ivoComeHere);
+ ADD_CALLBACK_FUNCTION(Waiter2, ivoClearTableC);
+ ADD_CALLBACK_FUNCTION(Waiter2, chapter3);
+ ADD_CALLBACK_FUNCTION(Waiter2, serving3);
+ ADD_CALLBACK_FUNCTION(Waiter2, annaBringTea3);
+ ADD_CALLBACK_FUNCTION(Waiter2, chapter4);
+ ADD_CALLBACK_FUNCTION(Waiter2, serving4);
+ ADD_CALLBACK_FUNCTION(Waiter2, augustNeedsADrink);
+ ADD_CALLBACK_FUNCTION(Waiter2, serveAugustADrink);
+ ADD_CALLBACK_FUNCTION(Waiter2, annaNeedsADrink);
+ ADD_CALLBACK_FUNCTION(Waiter2, chapter5);
+ ADD_CALLBACK_FUNCTION(Waiter2, chapter5Handler);
ADD_NULL_FUNCTION()
}
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_NOSETUP(1, Servers1, updateFromTime)
+IMPLEMENT_FUNCTION_NOSETUP(1, Waiter2, updateFromTime)
Entity::updateFromTime(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(2, Servers1, draw)
+IMPLEMENT_FUNCTION_S(2, Waiter2, draw)
Entity::draw(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_SII(3, Servers1, updatePosition, CarIndex, Position)
+IMPLEMENT_FUNCTION_SII(3, Waiter2, updatePosition, CarIndex, Position)
Entity::updatePosition(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(4, Servers1, callbackActionOnDirection)
+IMPLEMENT_FUNCTION(4, Waiter2, callbackActionOnDirection)
if (savepoint.action == kActionExcuseMeCath) {
if (!params->param1) {
- getSound()->excuseMe(kEntityServers1);
+ getSound()->excuseMe(kEntityWaiter2);
params->param1 = 1;
}
}
@@ -95,17 +95,17 @@ IMPLEMENT_FUNCTION(4, Servers1, callbackActionOnDirection)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_SIIS(5, Servers1, callSavepoint, EntityIndex, ActionIndex)
+IMPLEMENT_FUNCTION_SIIS(5, Waiter2, callSavepoint, EntityIndex, ActionIndex)
Entity::callSavepoint(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION_S(6, Servers1, playSound)
+IMPLEMENT_FUNCTION_S(6, Waiter2, playSound)
Entity::playSound(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(7, Servers1, function7)
+IMPLEMENT_FUNCTION(7, Waiter2, monsieurServeUs)
switch (savepoint.action) {
default:
break;
@@ -124,19 +124,19 @@ IMPLEMENT_FUNCTION(7, Servers1, function7)
break;
case 1:
- getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction122358304);
+ getSavePoints()->push(kEntityWaiter2, kEntityBoutarel, kAction122358304);
setCallback(2);
setup_draw("008C");
break;
case 2:
- getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction122288808);
+ getSavePoints()->push(kEntityWaiter2, kEntityBoutarel, kAction122288808);
setCallback(2);
setup_draw("926");
break;
case 3:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(1, 2) = 0;
@@ -148,27 +148,27 @@ IMPLEMENT_FUNCTION(7, Servers1, function7)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(8, Servers1, chapter1)
+IMPLEMENT_FUNCTION(8, Waiter2, chapter1)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter1Handler();
+ setup_servingDinner();
break;
case kActionDefault:
- getSavePoints()->addData(kEntityServers1, kAction223002560, 0);
- getSavePoints()->addData(kEntityServers1, kAction302996448, 2);
- getSavePoints()->addData(kEntityServers1, kAction269485588, 3);
- getSavePoints()->addData(kEntityServers1, kAction326144276, 4);
- getSavePoints()->addData(kEntityServers1, kAction302203328, 5);
- getSavePoints()->addData(kEntityServers1, kAction189688608, 6);
- getSavePoints()->addData(kEntityServers1, kAction236237423, 7);
- getSavePoints()->addData(kEntityServers1, kAction219377792, 8);
- getSavePoints()->addData(kEntityServers1, kAction256200848, 9);
- getSavePoints()->addData(kEntityServers1, kAction291721418, 10);
- getSavePoints()->addData(kEntityServers1, kAction258136010, 11);
+ getSavePoints()->addData(kEntityWaiter2, kAction223002560, 0);
+ getSavePoints()->addData(kEntityWaiter2, kAction302996448, 2);
+ getSavePoints()->addData(kEntityWaiter2, kAction269485588, 3);
+ getSavePoints()->addData(kEntityWaiter2, kAction326144276, 4);
+ getSavePoints()->addData(kEntityWaiter2, kAction302203328, 5);
+ getSavePoints()->addData(kEntityWaiter2, kAction189688608, 6);
+ getSavePoints()->addData(kEntityWaiter2, kAction236237423, 7);
+ getSavePoints()->addData(kEntityWaiter2, kAction219377792, 8);
+ getSavePoints()->addData(kEntityWaiter2, kAction256200848, 9);
+ getSavePoints()->addData(kEntityWaiter2, kAction291721418, 10);
+ getSavePoints()->addData(kEntityWaiter2, kAction258136010, 11);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -178,7 +178,7 @@ IMPLEMENT_FUNCTION(8, Servers1, chapter1)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(9, Servers1, function9)
+IMPLEMENT_FUNCTION(9, Waiter2, milosOrder)
switch (savepoint.action) {
default:
break;
@@ -198,7 +198,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9)
case 1:
getEntities()->drawSequenceLeft(kEntityMilos, "BLANK");
- getEntities()->drawSequenceLeft(kEntityServers1, "009B");
+ getEntities()->drawSequenceLeft(kEntityWaiter2, "009B");
setCallback(2);
setup_playSound("WAT1001");
@@ -212,7 +212,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9)
break;
case 3:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 1) = 0;
@@ -224,7 +224,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(10, Servers1, function10)
+IMPLEMENT_FUNCTION(10, Waiter2, monsieurOrder)
switch (savepoint.action) {
default:
break;
@@ -244,21 +244,21 @@ IMPLEMENT_FUNCTION(10, Servers1, function10)
case 1:
getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK");
- getEntities()->drawSequenceLeft(kEntityServers1, "008C");
+ getEntities()->drawSequenceLeft(kEntityWaiter2, "008C");
setCallback(2);
setup_playSound("MRB1077");
break;
case 2:
- getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction168717392);
+ getSavePoints()->push(kEntityWaiter2, kEntityBoutarel, kAction168717392);
setCallback(3);
setup_draw("926");
break;
case 3:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
ENTITY_PARAM(0, 2) = 0;
@@ -270,63 +270,63 @@ IMPLEMENT_FUNCTION(10, Servers1, function10)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(11, Servers1, function11)
+IMPLEMENT_FUNCTION(11, Waiter2, clearAlexei)
serveTable(savepoint, "919", kEntityTables1, "005H", "005J", "921", &ENTITY_PARAM(0, 3), 63);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(12, Servers1, function12)
+IMPLEMENT_FUNCTION(12, Waiter2, clearMilos)
serveTable(savepoint, "923", kEntityTables2, "009F", "009G", "926", &ENTITY_PARAM(0, 4));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(13, Servers1, function13)
+IMPLEMENT_FUNCTION(13, Waiter2, clearMonsieur)
serveTable(savepoint, "923", kEntityTables2, "009F", "009G", "926", &ENTITY_PARAM(0, 5));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(14, Servers1, chapter1Handler)
+IMPLEMENT_FUNCTION(14, Waiter2, servingDinner)
switch (savepoint.action) {
default:
break;
case kActionDefault:
- if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
if (ENTITY_PARAM(0, 1)) {
setCallback(1);
- setup_function9();
+ setup_milosOrder();
break;
}
if (ENTITY_PARAM(1, 2)) {
setCallback(2);
- setup_function10();
+ setup_monsieurOrder();
break;
}
if (ENTITY_PARAM(0, 3)) {
setCallback(3);
- setup_function11();
+ setup_clearAlexei();
break;
}
if (ENTITY_PARAM(0, 4)) {
setCallback(4);
- setup_function12();
+ setup_clearMilos();
break;
}
if (ENTITY_PARAM(0, 5)) {
setCallback(5);
- setup_function13();
+ setup_clearMonsieur();
}
break;
case kActionCallback:
if (getCallback() == 5) {
- getSavePoints()->push(kEntityServers1, kEntityPascale, kAction352768896);
+ getSavePoints()->push(kEntityWaiter2, kEntityPascale, kAction352768896);
setup_function15();
}
break;
@@ -334,7 +334,7 @@ switch (savepoint.action) {
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(15, Servers1, function15)
+IMPLEMENT_FUNCTION(15, Waiter2, function15)
switch (savepoint.action) {
default:
break;
@@ -350,28 +350,28 @@ IMPLEMENT_FUNCTION(15, Servers1, function15)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(16, Servers1, function16)
+IMPLEMENT_FUNCTION(16, Waiter2, function16)
if (savepoint.action == kActionDefault) {
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
getData()->car = kCarRestaurant;
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(17, Servers1, chapter2)
+IMPLEMENT_FUNCTION(17, Waiter2, chapter2)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter2Handler();
+ setup_inKitchen();
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -387,32 +387,32 @@ IMPLEMENT_FUNCTION(17, Servers1, chapter2)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(18, Servers1, chapter2Handler)
+IMPLEMENT_FUNCTION(18, Waiter2, inKitchen)
switch (savepoint.action) {
default:
break;
case kActionNone:
- if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
if (ENTITY_PARAM(0, 6)) {
setCallback(1);
- setup_function19();
+ setup_tatianaClearTableB();
break;
}
label_callback_1:
if (ENTITY_PARAM(0, 7)) {
setCallback(2);
- setup_function20();
+ setup_ivoComeHere();
break;
}
label_callback_2:
if (ENTITY_PARAM(0, 8) || ENTITY_PARAM(0, 5)) {
setCallback(3);
- setup_function21();
+ setup_ivoClearTableC();
}
break;
@@ -428,7 +428,7 @@ label_callback_2:
goto label_callback_2;
case 4:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
break;
}
@@ -442,12 +442,12 @@ label_callback_2:
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(19, Servers1, function19)
+IMPLEMENT_FUNCTION(19, Waiter2, tatianaClearTableB)
serveTable(savepoint, "969", kEntityTables1, "005H2", "018A", "971", &ENTITY_PARAM(0, 6), 63);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(20, Servers1, function20)
+IMPLEMENT_FUNCTION(20, Waiter2, ivoComeHere)
switch (savepoint.action) {
default:
break;
@@ -462,8 +462,8 @@ IMPLEMENT_FUNCTION(20, Servers1, function20)
case kActionCallback:
if (getCallback() == 1) {
- getSavePoints()->push(kEntityServers1, kEntityIvo, kAction123712592);
- getEntities()->drawSequenceLeft(kEntityServers1, "BLANK");
+ getSavePoints()->push(kEntityWaiter2, kEntityIvo, kAction123712592);
+ getEntities()->drawSequenceLeft(kEntityWaiter2, "BLANK");
ENTITY_PARAM(0, 7) = 0;
callbackAction();
@@ -473,22 +473,22 @@ IMPLEMENT_FUNCTION(20, Servers1, function20)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(21, Servers1, function21)
+IMPLEMENT_FUNCTION(21, Waiter2, ivoClearTableC)
serveTable(savepoint, "974", kEntityTables2, "009F2", "009G", "976", &ENTITY_PARAM(0, 8), 0, true, &ENTITY_PARAM(0, 5));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(22, Servers1, chapter3)
+IMPLEMENT_FUNCTION(22, Waiter2, chapter3)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter3Handler();
+ setup_serving3();
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
@@ -503,49 +503,49 @@ IMPLEMENT_FUNCTION(22, Servers1, chapter3)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(23, Servers1, chapter3Handler)
+IMPLEMENT_FUNCTION(23, Waiter2, serving3)
if (savepoint.action != kActionNone)
return;
- if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
return;
if (ENTITY_PARAM(1, 1)) {
setCallback(1);
- setup_function24();
+ setup_annaBringTea3();
return;
}
if (ENTITY_PARAM(1, 2)) {
setCallback(2);
- setup_function7();
+ setup_monsieurServeUs();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(24, Servers1, function24)
+IMPLEMENT_FUNCTION(24, Waiter2, annaBringTea3)
serveSalon(savepoint, "927", "Ann3143A", kEntityAnna, "Ann31444", "112C", kAction122288808, "928", &ENTITY_PARAM(1, 1));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(25, Servers1, chapter4)
+IMPLEMENT_FUNCTION(25, Waiter2, chapter4)
switch (savepoint.action) {
default:
break;
case kActionNone:
- setup_chapter4Handler();
+ setup_serving4();
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
getData()->location = kLocationOutsideCompartment;
getData()->car = kCarRestaurant;
getData()->inventoryItem = kItemNone;
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
ENTITY_PARAM(1, 2) = 0;
ENTITY_PARAM(1, 3) = 0;
@@ -556,7 +556,7 @@ IMPLEMENT_FUNCTION(25, Servers1, chapter4)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler)
+IMPLEMENT_FUNCTION(26, Waiter2, serving4)
switch (savepoint.action) {
default:
break;
@@ -569,24 +569,30 @@ IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler)
}
}
- if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
+ if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon())
break;
+ if (ENTITY_PARAM(1, 3)) {
+ setCallback(1);
+ setup_augustNeedsADrink();
+ break;
+ }
+
if (ENTITY_PARAM(1, 5)) {
setCallback(2);
- setup_function28();
+ setup_serveAugustADrink();
break;
}
if (ENTITY_PARAM(1, 4)) {
setCallback(3);
- setup_function29();
+ setup_annaNeedsADrink();
break;
}
if (ENTITY_PARAM(1, 2)) {
setCallback(4);
- setup_function7();
+ setup_monsieurServeUs();
}
break;
@@ -608,22 +614,22 @@ IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(27, Servers1, function27)
+IMPLEMENT_FUNCTION(27, Waiter2, augustNeedsADrink)
serveSalon(savepoint, "929", "", kEntityAugust, "Aug4003", "122D", kAction134486752, "930", &ENTITY_PARAM(1, 3));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(28, Servers1, function28)
+IMPLEMENT_FUNCTION(28, Waiter2, serveAugustADrink)
serveSalon(savepoint, "931", "", kEntityAugust, "Aug4004", "122E", kAction125826561, "930", &ENTITY_PARAM(1, 5));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(29, Servers1, function29)
+IMPLEMENT_FUNCTION(29, Waiter2, annaNeedsADrink)
serveSalon(savepoint, "932", "", kEntityAnna, "Ann4151", "127D", kAction122288808, "930", &ENTITY_PARAM(1, 4));
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(30, Servers1, chapter5)
+IMPLEMENT_FUNCTION(30, Waiter2, chapter5)
switch (savepoint.action) {
default:
break;
@@ -633,7 +639,7 @@ IMPLEMENT_FUNCTION(30, Servers1, chapter5)
break;
case kActionDefault:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_3969;
getData()->location = kLocationInsideCompartment;
@@ -644,19 +650,19 @@ IMPLEMENT_FUNCTION(30, Servers1, chapter5)
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_FUNCTION(31, Servers1, chapter5Handler)
+IMPLEMENT_FUNCTION(31, Waiter2, chapter5Handler)
if (savepoint.action == kActionProceedChapter5)
setup_nullfunction();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
-IMPLEMENT_NULL_FUNCTION(32, Servers1)
+IMPLEMENT_NULL_FUNCTION(32, Waiter2)
//////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////
-void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, Position position, bool shouldUpdatePosition, uint *parameter2) {
+void Waiter2::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, Position position, bool shouldUpdatePosition, uint *parameter2) {
switch (savepoint.action) {
default:
break;
@@ -678,9 +684,9 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
case 1:
if (position)
- getEntities()->updatePositionEnter(kEntityServers1, kCarRestaurant, position);
+ getEntities()->updatePositionEnter(kEntityWaiter2, kCarRestaurant, position);
- getSavePoints()->push(kEntityServers1, entity, kAction136455232);
+ getSavePoints()->push(kEntityWaiter2, entity, kAction136455232);
setCallback(2);
setup_callSavepoint(seq2, entity, kActionDrawTablesWithChairs, seq3);
@@ -688,7 +694,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
case 2:
if (position)
- getEntities()->updatePositionExit(kEntityServers1, kCarRestaurant, position);
+ getEntities()->updatePositionExit(kEntityWaiter2, kCarRestaurant, position);
setCallback(3);
setup_draw(seq4);
@@ -696,7 +702,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
case 3:
getData()->entityPosition = kPosition_5900;
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
*parameter = 0;
if (parameter2 != NULL)
@@ -710,7 +716,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn
}
//////////////////////////////////////////////////////////////////////////
-void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const char *snd1, EntityIndex entity, const char *snd2, const char *seq2, ActionIndex action, const char *seq3, uint *parameter) {
+void Waiter2::serveSalon(const SavePoint &savepoint, const char *seq1, const char *snd1, EntityIndex entity, const char *snd2, const char *seq2, ActionIndex action, const char *seq3, uint *parameter) {
switch (savepoint.action) {
default:
break;
@@ -729,46 +735,46 @@ void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const ch
break;
case 1:
- getEntities()->drawSequenceRight(kEntityServers1, seq1);
+ getEntities()->drawSequenceRight(kEntityWaiter2, seq1);
if (getEntities()->isInRestaurant(kEntityPlayer))
- getEntities()->updateFrame(kEntityServers1);
+ getEntities()->updateFrame(kEntityWaiter2);
if (!strcmp(snd1, ""))
- getSound()->playSound(kEntityServers1, snd1);
+ getSound()->playSound(kEntityWaiter2, snd1);
setCallback(2);
setup_callbackActionOnDirection();
break;
case 2:
- getSavePoints()->push(kEntityServers1, entity, kAction122358304);
+ getSavePoints()->push(kEntityWaiter2, entity, kAction122358304);
- getSound()->playSound(kEntityServers1, snd2);
+ getSound()->playSound(kEntityWaiter2, snd2);
setCallback(3);
setup_updatePosition(seq2, kCarRestaurant, 57);
break;
case 3:
- getSavePoints()->push(kEntityServers1, entity, action);
+ getSavePoints()->push(kEntityWaiter2, entity, action);
setCallback(4);
setup_draw(seq3);
break;
case 4:
- getEntities()->drawSequenceRight(kEntityServers1, "816UD");
+ getEntities()->drawSequenceRight(kEntityWaiter2, "816UD");
if (getEntities()->isInSalon(kEntityPlayer))
- getEntities()->updateFrame(kEntityServers1);
+ getEntities()->updateFrame(kEntityWaiter2);
setCallback(5);
setup_callbackActionOnDirection();
break;
case 5:
- getEntities()->clearSequences(kEntityServers1);
+ getEntities()->clearSequences(kEntityWaiter2);
getData()->entityPosition = kPosition_5900;
*parameter = 0;
diff --git a/engines/lastexpress/entities/servers1.h b/engines/lastexpress/entities/waiter2.h
index 58566cd4d3..e8dc8f48e0 100644
--- a/engines/lastexpress/entities/servers1.h
+++ b/engines/lastexpress/entities/waiter2.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef LASTEXPRESS_SERVERS1_H
-#define LASTEXPRESS_SERVERS1_H
+#ifndef LASTEXPRESS_WAITER2_H
+#define LASTEXPRESS_WAITER2_H
#include "lastexpress/entities/entity.h"
@@ -29,10 +29,10 @@ namespace LastExpress {
class LastExpressEngine;
-class Servers1 : public Entity {
+class Waiter2 : public Entity {
public:
- Servers1(LastExpressEngine *engine);
- ~Servers1() {}
+ Waiter2(LastExpressEngine *engine);
+ ~Waiter2() {}
/**
* Updates parameter 2 using time value
@@ -80,24 +80,19 @@ public:
*/
DECLARE_FUNCTION_1(playSound, const char *filename)
- DECLARE_FUNCTION(function7)
+ DECLARE_FUNCTION(monsieurServeUs)
/**
* Setup Chapter 1
*/
DECLARE_FUNCTION(chapter1)
- DECLARE_FUNCTION(function9)
- DECLARE_FUNCTION(function10)
- DECLARE_FUNCTION(function11)
- DECLARE_FUNCTION(function12)
- DECLARE_FUNCTION(function13)
-
- /**
- * Handle Chapter 1 events
- */
- DECLARE_FUNCTION(chapter1Handler)
-
+ DECLARE_FUNCTION(milosOrder)
+ DECLARE_FUNCTION(monsieurOrder)
+ DECLARE_FUNCTION(clearAlexei)
+ DECLARE_FUNCTION(clearMilos)
+ DECLARE_FUNCTION(clearMonsieur)
+ DECLARE_FUNCTION(servingDinner)
DECLARE_FUNCTION(function15)
DECLARE_FUNCTION(function16)
@@ -105,41 +100,26 @@ public:
* Setup Chapter 2
*/
DECLARE_FUNCTION(chapter2)
-
- /**
- * Handle Chapter 2 events
- */
- DECLARE_FUNCTION(chapter2Handler)
-
- DECLARE_FUNCTION(function19)
- DECLARE_FUNCTION(function20)
- DECLARE_FUNCTION(function21)
+ DECLARE_FUNCTION(inKitchen)
+ DECLARE_FUNCTION(tatianaClearTableB)
+ DECLARE_FUNCTION(ivoComeHere)
+ DECLARE_FUNCTION(ivoClearTableC)
/**
* Setup Chapter 3
*/
DECLARE_FUNCTION(chapter3)
-
- /**
- * Handle Chapter 3 events
- */
- DECLARE_FUNCTION(chapter3Handler)
-
- DECLARE_FUNCTION(function24)
+ DECLARE_FUNCTION(serving3)
+ DECLARE_FUNCTION(annaBringTea3)
/**
* Setup Chapter 4
*/
DECLARE_FUNCTION(chapter4)
-
- /**
- * Handle Chapter 4 events
- */
- DECLARE_FUNCTION(chapter4Handler)
-
- DECLARE_FUNCTION(function27)
- DECLARE_FUNCTION(function28)
- DECLARE_FUNCTION(function29)
+ DECLARE_FUNCTION(serving4)
+ DECLARE_FUNCTION(augustNeedsADrink)
+ DECLARE_FUNCTION(serveAugustADrink)
+ DECLARE_FUNCTION(annaNeedsADrink)
/**
* Setup Chapter 5
@@ -160,4 +140,4 @@ private:
} // End of namespace LastExpress
-#endif // LASTEXPRESS_SERVERS1_H
+#endif // LASTEXPRESS_WAITER2_H
diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp
index 986c56cb1b..96b97db939 100644
--- a/engines/lastexpress/game/action.cpp
+++ b/engines/lastexpress/game/action.cpp
@@ -1456,7 +1456,7 @@ IMPLEMENT_ACTION(playMusicChapterSetupTrain)
if (!getSoundQueue()->isBuffered(filename) && hotspot.param3 & id) {
getSound()->playSound(kEntityPlayer, filename, kFlagDefault);
- getSavePoints()->call(kEntityPlayer, kEntityTrain, kAction203863200, filename.c_str());
+ getSavePoints()->call(kEntityPlayer, kEntityTrain, kAction203863200, filename);
getSavePoints()->push(kEntityPlayer, kEntityTrain, kAction222746496, hotspot.param2);
}
diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp
index b4b5527f8d..b881d34ebe 100644
--- a/engines/lastexpress/game/entities.cpp
+++ b/engines/lastexpress/game/entities.cpp
@@ -51,8 +51,6 @@
#include "lastexpress/entities/pascale.h"
#include "lastexpress/entities/rebecca.h"
#include "lastexpress/entities/salko.h"
-#include "lastexpress/entities/servers0.h"
-#include "lastexpress/entities/servers1.h"
#include "lastexpress/entities/sophie.h"
#include "lastexpress/entities/tables.h"
#include "lastexpress/entities/tatiana.h"
@@ -60,6 +58,8 @@
#include "lastexpress/entities/vassili.h"
#include "lastexpress/entities/verges.h"
#include "lastexpress/entities/vesna.h"
+#include "lastexpress/entities/waiter1.h"
+#include "lastexpress/entities/waiter2.h"
#include "lastexpress/entities/yasmin.h"
// Game
@@ -134,8 +134,8 @@ Entities::Entities(LastExpressEngine *engine) : _engine(engine) {
ADD_ENTITY(Mertens);
ADD_ENTITY(Coudert);
ADD_ENTITY(Pascale);
- ADD_ENTITY(Servers0);
- ADD_ENTITY(Servers1);
+ ADD_ENTITY(Waiter1);
+ ADD_ENTITY(Waiter2);
ADD_ENTITY(Cooks);
ADD_ENTITY(Verges);
ADD_ENTITY(Tatiana);
@@ -389,7 +389,6 @@ void Entities::resetState(EntityIndex entityIndex) {
getLogic()->updateCursor();
}
-
void Entities::updateFields() const {
if (!getFlags()->isGameRunning)
return;
@@ -897,7 +896,6 @@ void Entities::computeCurrentFrame(EntityIndex entityIndex) const {
}
break;
-
case kDirectionLeft:
if (data->currentFrame == -1 || data->currentFrame >= (int32)data->sequence->count()) {
data->currentFrame = 0;
@@ -1772,8 +1770,7 @@ void Entities::enterCompartment(EntityIndex entity, ObjectIndex compartment, boo
// Update compartments
int index = (compartment < 32 ? compartment - 1 : compartment - 24);
- if (index >= 16)
- error("[Entities::enterCompartment] Invalid compartment index");
+ assert(index < 16);
if (useCompartment1)
_compartments1[index] |= STORE_VALUE(entity);
@@ -1858,8 +1855,7 @@ void Entities::exitCompartment(EntityIndex entity, ObjectIndex compartment, bool
// Update compartments
int index = (compartment < 32 ? compartment - 1 : compartment - 24);
- if (index >= 16)
- error("[Entities::exitCompartment] Invalid compartment index");
+ assert(index < 16);
if (useCompartment1)
_compartments1[index] &= ~STORE_VALUE(entity);
diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp
index 9e02b3bc1d..622d547542 100644
--- a/engines/lastexpress/game/inventory.cpp
+++ b/engines/lastexpress/game/inventory.cpp
@@ -40,7 +40,6 @@
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
-
namespace LastExpress {
Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem(kItemNone), _highlightedItemIndex(0), _itemsShown(0),
@@ -534,18 +533,18 @@ Common::String Inventory::toString() {
// Private methods
//////////////////////////////////////////////////////////////////////////
InventoryItem Inventory::getFirstExaminableItem() const {
-
int index = 0;
- InventoryEntry entry = _entries[index];
- while (!entry.inPocket || !entry.cursor || entry.floating) {
- index++;
- entry = _entries[index];
+ do {
+ InventoryEntry entry = _entries[index];
- if (index >= kPortraitOriginal)
- return kItemNone;
- }
+ // Check if it is an examinable item
+ if (entry.inPocket && entry.cursor && !entry.floating)
+ return (InventoryItem)index;
+
+ index++;
+ } while (index < kPortraitOriginal);
- return (InventoryItem)index;
+ return kItemNone;
}
bool Inventory::isItemSceneParameter(InventoryItem item) const {
diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp
index b0186a4ccc..a8483e6d5c 100644
--- a/engines/lastexpress/game/savepoint.cpp
+++ b/engines/lastexpress/game/savepoint.cpp
@@ -28,7 +28,6 @@
#include "lastexpress/lastexpress.h"
-
namespace LastExpress {
SavePoints::SavePoints(LastExpressEngine *engine) : _engine(engine) {
@@ -57,7 +56,7 @@ void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex acti
_savepoints.push_back(point);
}
-void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) {
+void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param) {
if (_savepoints.size() >= _savePointsMaxSize)
return;
@@ -65,7 +64,9 @@ void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex acti
point.entity1 = entity1;
point.action = action;
point.entity2 = entity2;
- strcpy((char *)&point.param.charValue, param);
+
+ assert(param.size() <= 5);
+ strncpy((char *)&point.param.charValue, param.c_str(), 5);
_savepoints.push_back(point);
}
@@ -76,7 +77,6 @@ SavePoint SavePoints::pop() {
return point;
}
-
void SavePoints::pushAll(EntityIndex entity, ActionIndex action, uint32 param) {
for (uint32 index = 1; index < 40; index++) {
if ((EntityIndex)index != entity)
@@ -156,16 +156,18 @@ void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex acti
}
}
-void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const {
+void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param) const {
SavePoint point;
point.entity1 = entity1;
point.action = action;
point.entity2 = entity2;
- strcpy((char *)&point.param.charValue, param);
+
+ assert(param.size() <= 5);
+ strncpy((char *)&point.param.charValue, param.c_str(), 5);
Callback *callback = getCallback(entity1);
if (callback != NULL && callback->isValid()) {
- debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%s", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param);
+ debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%s", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param.c_str());
(*callback)(point);
}
}
diff --git a/engines/lastexpress/game/savepoint.h b/engines/lastexpress/game/savepoint.h
index 068c54eb0f..ab6490796b 100644
--- a/engines/lastexpress/game/savepoint.h
+++ b/engines/lastexpress/game/savepoint.h
@@ -101,7 +101,7 @@ public:
// Savepoints
void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0);
- void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param);
+ void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param);
void pushAll(EntityIndex entity, ActionIndex action, uint32 param = 0);
void process();
void reset();
@@ -113,7 +113,7 @@ public:
void setCallback(EntityIndex index, Callback *callback);
Callback *getCallback(EntityIndex entity) const;
void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0) const;
- void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const;
+ void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param) const;
void callAndProcess();
// Serializable
diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp
index 293c3ab725..90b684ab0b 100644
--- a/engines/lastexpress/lastexpress.cpp
+++ b/engines/lastexpress/lastexpress.cpp
@@ -48,7 +48,7 @@
const char *g_actionNames[] = {"None", "Action1", "Action2", "ExitCompartment", "Action4", "ExcuseMeCath", "ExcuseMe", "INVALID", "Knock", "OpenDoor", "Action10", "Action11", "Default", "INVALID", "INVALID", "INVALID", "Action16", "DrawScene", "Callback"};
const char *g_directionNames[] = { "None", "Up", "Down", "Left", "Right", "Switch"};
-const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert", "Pascale", "Servers0", "Servers1", "Cooks", "Verges", "Tatiana", "Vassili", "Alexei", "Abbot", "Milos", "Vesna", "Ivo", "Salko", "Kronos", "Kahina", "Francois", "MmeBoutarel", "Boutarel", "Rebecca", "Sophie", "Mahmud", "Yasmin", "Hadija", "Alouan", "Gendarmes", "Max", "Chapters", "Train", "Tables0", "Tables1", "Tables2", "Tables3", "Tables4", "Tables5", "Entity39"};
+const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert", "Pascale", "Waiter1", "Waiter2", "Cooks", "Verges", "Tatiana", "Vassili", "Alexei", "Abbot", "Milos", "Vesna", "Ivo", "Salko", "Kronos", "Kahina", "Francois", "MmeBoutarel", "Boutarel", "Rebecca", "Sophie", "Mahmud", "Yasmin", "Hadija", "Alouan", "Gendarmes", "Max", "Chapters", "Train", "Tables0", "Tables1", "Tables2", "Tables3", "Tables4", "Tables5", "Entity39"};
namespace LastExpress {
diff --git a/engines/lastexpress/module.mk b/engines/lastexpress/module.mk
index 8b3287d5d7..afce0b0749 100644
--- a/engines/lastexpress/module.mk
+++ b/engines/lastexpress/module.mk
@@ -35,8 +35,6 @@ MODULE_OBJS := \
entities/pascale.o \
entities/rebecca.o \
entities/salko.o \
- entities/servers0.o \
- entities/servers1.o \
entities/sophie.o \
entities/tables.o \
entities/tatiana.o \
@@ -44,6 +42,8 @@ MODULE_OBJS := \
entities/vassili.o \
entities/verges.o \
entities/vesna.o \
+ entities/waiter1.o \
+ entities/waiter2.o \
entities/yasmin.o \
fight/fight.o \
fight/fighter.o \
diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h
index c0099db7ac..724c4b3fb4 100644
--- a/engines/lastexpress/shared.h
+++ b/engines/lastexpress/shared.h
@@ -1006,8 +1006,8 @@ enum EntityIndex {
kEntityMertens,
kEntityCoudert,
kEntityPascale, // 5
- kEntityServers0,
- kEntityServers1,
+ kEntityWaiter1,
+ kEntityWaiter2,
kEntityCooks,
kEntityVerges,
kEntityTatiana, // 10
@@ -1409,7 +1409,7 @@ enum ActionIndex {
kAction169032608 = 169032608,
kAction189426612 = 189426612,
kAction203859488 = 203859488,
- kAction219522616 = 219522616, // Servers0
+ kAction219522616 = 219522616, // Waiter1
kAction225182640 = 225182640,
kAction235257824 = 235257824,
@@ -1520,7 +1520,7 @@ enum ActionIndex {
kAction71277948 = 71277948,
kAction158007856 = 158007856,
kAction101687594 = 101687594,
- kAction122358304 = 122358304, // also Servers1/Boutarel?
+ kAction122358304 = 122358304, // also Waiter2/Boutarel?
kActionMaxFreeFromCage = 135204609,
kAction156622016 = 156622016,
diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp
index 6bf1ebc9de..697e6e1269 100644
--- a/engines/lastexpress/sound/entry.cpp
+++ b/engines/lastexpress/sound/entry.cpp
@@ -33,7 +33,6 @@
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
-
namespace LastExpress {
#define SOUNDCACHE_ENTRY_SIZE 92160
@@ -267,6 +266,8 @@ void SoundEntry::update(uint val) {
}
bool SoundEntry::updateSound() {
+ assert(_name2.size() <= 16);
+
bool result;
char sub[16];
@@ -279,6 +280,7 @@ bool SoundEntry::updateSound() {
_status.status &= ~0x8000;
strcpy(sub, _name2.c_str());
+ // FIXME: Rewrite and document expected behavior
int l = strlen(sub) + 1;
if (l - 1 > 4)
sub[l - (1 + 4)] = 0;
@@ -361,7 +363,10 @@ void SoundEntry::showSubtitle(Common::String filename) {
}
void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) {
- if (_name2.matchString("NISSND?") && (_status.status & kFlagType7) != kFlag3) {
+ assert(_name1.size() <= 16);
+ assert(_name2.size() <= 16);
+
+ if (_name2.matchString("NISSND?") && (_status.status & kFlagType9) != kFlag3) {
s.syncAsUint32LE(_status.status);
s.syncAsUint32LE(_type);
s.syncAsUint32LE(_blockCount); // field_8;
diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp
index 5f55f4e74e..3a2d0c075c 100644
--- a/engines/lastexpress/sound/sound.cpp
+++ b/engines/lastexpress/sound/sound.cpp
@@ -984,22 +984,22 @@ void SoundManager::excuseMe(EntityIndex entity, EntityIndex entity2, SoundFlag f
playSound(kEntityPlayer, (rnd(2) ? "HDE1002" : "HED1002A"), flag);
break;
- case kEntityServers0:
- case kEntityServers1:
+ case kEntityWaiter1:
+ case kEntityWaiter2:
switch(rnd(3)) {
default:
break;
case 0:
- playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002" : "WAT1003", flag);
+ playSound(kEntityPlayer, (entity == kEntityWaiter1) ? "WAT1002" : "WAT1003", flag);
break;
case 1:
- playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002A" : "WAT1003A", flag);
+ playSound(kEntityPlayer, (entity == kEntityWaiter1) ? "WAT1002A" : "WAT1003A", flag);
break;
case 2:
- playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002B" : "WAT1003B", flag);
+ playSound(kEntityPlayer, (entity == kEntityWaiter1) ? "WAT1002B" : "WAT1003B", flag);
break;
}
break;
diff --git a/engines/made/database.cpp b/engines/made/database.cpp
index 85a8a5ca4a..a9855ba1fe 100644
--- a/engines/made/database.cpp
+++ b/engines/made/database.cpp
@@ -456,7 +456,7 @@ void GameDatabaseV2::load(Common::SeekableReadStream &sourceS) {
for (int section = 0; section < 2; section++) {
while (!sourceS.eos()) {
int16 objIndex = sourceS.readUint16LE();
- debug("objIndex = %04X; section = %d", objIndex, section);
+ debug(1, "objIndex = %04X; section = %d", objIndex, section);
if (objIndex == 0)
break;
Object *obj = new ObjectV1();
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index 1bb328c7a2..2c75965976 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -441,7 +441,8 @@ void ResourceReader::openResourceBlocks() {
}
void ResourceReader::openResourceBlock(const char *filename, Common::File *blockFile, uint32 resType) {
- blockFile->open(filename);
+ if (!blockFile->open(filename))
+ error("Failed to open '%s'", filename);
blockFile->readUint16LE(); // Skip unused
uint16 count = blockFile->readUint16LE();
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index c27b781dda..edccb68953 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -368,6 +368,9 @@ uint16 Screen::drawFlex(uint16 flexIndex, int16 x, int16 y, int16 flipX, int16 f
return 0;
PictureResource *flex = _vm->_res->getPicture(flexIndex);
+ if (!flex)
+ error("Failed to find picture %d", flexIndex);
+
Graphics::Surface *sourceSurface = flex->getPicture();
drawSurface(sourceSurface, x, y, flipX, flipY, mask, clipInfo);
diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp
index 1ff42c5e2b..6bc6cf572d 100644
--- a/engines/mads/debugger.cpp
+++ b/engines/mads/debugger.cpp
@@ -21,6 +21,7 @@
*/
#include "common/file.h"
+#include "mads/compression.h"
#include "mads/mads.h"
#include "mads/debugger.h"
@@ -169,8 +170,10 @@ bool Debugger::Cmd_ShowCodes(int argc, const char **argv) {
}
bool Debugger::Cmd_DumpFile(int argc, const char **argv) {
- if (argc != 2) {
- debugPrintf("Usage: %s <resource>\n", argv[0]);
+ if (argc < 2) {
+ debugPrintf("Usage: %s <resource> <unpack>\n", argv[0]);
+ debugPrintf(" resource: the resource name\n");
+ debugPrintf(" unpack: optional, when specified, the FAB/MADSPACK compressed resource is unpacked\n");
} else {
Common::DumpFile outFile;
Common::File inFile;
@@ -179,10 +182,32 @@ bool Debugger::Cmd_DumpFile(int argc, const char **argv) {
debugPrintf("Specified resource does not exist\n");
} else {
outFile.open(argv[1]);
- byte *data = new byte[inFile.size()];
-
- inFile.read(data, inFile.size());
- outFile.write(data, inFile.size());
+ bool unpack = ((argc >= 3) && !scumm_stricmp(argv[2], "unpack"));
+
+ byte *data;
+ int totalSize = 0;
+
+ if (!unpack) {
+ totalSize = inFile.size();
+ data = new byte[totalSize];
+ inFile.read(data, totalSize);
+ } else {
+ MadsPack dataPack(&inFile);
+ int count = dataPack.getCount();
+ for (int i = 0; i < count; i++) {
+ totalSize += dataPack.getItem(i)._size;
+ }
+ data = new byte[totalSize];
+ byte *ptr = data;
+
+ for (int i = 0; i < count; i++) {
+ Common::SeekableReadStream *readStream = dataPack.getItemStream(i);
+ readStream->read(ptr, readStream->size());
+ ptr += readStream->size();
+ }
+ }
+
+ outFile.write(data, totalSize);
outFile.flush();
delete[] data;
diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h
index aad29f6551..c586a6f1fe 100644
--- a/engines/mads/dialogs.h
+++ b/engines/mads/dialogs.h
@@ -201,7 +201,9 @@ public:
enum DialogId {
DIALOG_NONE = 0, DIALOG_GAME_MENU = 1, DIALOG_SAVE = 2, DIALOG_RESTORE = 3,
- DIALOG_OPTIONS = 4, DIALOG_DIFFICULTY = 5, DIALOG_ERROR = 6
+ DIALOG_OPTIONS = 4, DIALOG_DIFFICULTY = 5, DIALOG_ERROR = 6,
+ DIALOG_MAIN_MENU = 7, DIALOG_TEXTVIEW = 8, DIALOG_ANIMVIEW = 9,
+ DIALOG_ADVERT = 10
};
class Dialogs {
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index 59d7914378..f32d17d9c9 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -201,9 +201,10 @@ Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
- File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
+ Common::String ext = Common::String::format(".WW%d", variant);
+ File f(Resources::formatName(RESPREFIX_RM, _sceneId, ext));
MadsPack codesPack(&f);
- Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
+ Common::SeekableReadStream *stream = codesPack.getItemStream(0);
loadCodes(depthSurface, stream);
@@ -213,22 +214,20 @@ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = depthSurface.getData();
- byte *endP = depthSurface.getBasePtr(0, depthSurface.h);
-
- byte runLength = stream->readByte();
- while (destP < endP && runLength > 0) {
- byte runValue = stream->readByte();
-
- // Write out the run length
- Common::fill(destP, destP + runLength, runValue);
- destP += runLength;
-
- // Get the next run length
- runLength = stream->readByte();
+ byte *walkMap = new byte[stream->size()];
+ stream->read(walkMap, stream->size());
+
+ for (int y = 0; y < 156; ++y) {
+ for (int x = 0; x < 320; ++x) {
+ int offset = x + (y * 320);
+ if ((walkMap[offset / 8] << (offset % 8)) & 0x80)
+ *destP++ = 1; // walkable
+ else
+ *destP++ = 0;
+ }
}
- if (destP < endP)
- Common::fill(destP, endP, 0);
+ delete[] walkMap;
}
} // End of namespace Dragonsphere
diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp
index 9d9b48dd66..3836adb6d2 100644
--- a/engines/mads/dragonsphere/game_dragonsphere.cpp
+++ b/engines/mads/dragonsphere/game_dragonsphere.cpp
@@ -42,6 +42,10 @@ GameDragonsphere::GameDragonsphere(MADSEngine *vm)
}
void GameDragonsphere::startGame() {
+ _scene._priorSceneId = 0;
+ _scene._currentSceneId = -1;
+ _scene._nextSceneId = 101;
+
initializeGlobals();
}
diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp
index c3e6d5c122..de4dc3c070 100644
--- a/engines/mads/events.cpp
+++ b/engines/mads/events.cpp
@@ -46,6 +46,7 @@ EventsManager::EventsManager(MADSEngine *vm) {
_mouseMoved = false;
_vD8 = 0;
_rightMousePressed = false;
+ _eventTarget = nullptr;
}
EventsManager::~EventsManager() {
@@ -138,6 +139,12 @@ void EventsManager::pollEvents() {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
+ // If an event target is specified, pass the event to it
+ if (_eventTarget) {
+ _eventTarget->onEvent(event);
+ continue;
+ }
+
// Handle keypress
switch (event.type) {
case Common::EVENT_QUIT:
@@ -191,7 +198,7 @@ void EventsManager::pollEvents() {
}
}
-void EventsManager::checkForNextFrameCounter() {
+bool EventsManager::checkForNextFrameCounter() {
// Check for next game frame
uint32 milli = g_system->getMillis();
if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
@@ -209,7 +216,11 @@ void EventsManager::checkForNextFrameCounter() {
// Signal the ScummVM debugger
_vm->_debugger->onFrame();
+
+ return true;
}
+
+ return false;
}
void EventsManager::delay(int cycles) {
diff --git a/engines/mads/events.h b/engines/mads/events.h
index 3d7504c0bd..54df337efd 100644
--- a/engines/mads/events.h
+++ b/engines/mads/events.h
@@ -39,6 +39,12 @@ enum CursorType { CURSOR_NONE = 0, CURSOR_ARROW = 1, CURSOR_WAIT = 2, CURSOR_GO_
class MADSEngine;
+class EventTarget {
+public:
+ virtual ~EventTarget() {}
+ virtual bool onEvent(Common::Event &event) { return false; }
+};
+
class EventsManager {
private:
MADSEngine *_vm;
@@ -46,16 +52,12 @@ private:
uint32 _priorFrameTime;
Common::Point _mousePos;
Common::Point _currentPos;
+ EventTarget *_eventTarget;
/**
* Updates the cursor image when the current cursor changes
*/
void changeCursor();
-
- /**
- * Checks for whether the next game frame number has been reached.
- */
- void checkForNextFrameCounter();
public:
SpriteAsset *_cursorSprites;
CursorType _cursorId;
@@ -127,6 +129,11 @@ public:
void pollEvents();
/**
+ * Sets an event handler other than the events manager
+ */
+ void setEventTarget(EventTarget *target) { _eventTarget = target; }
+
+ /**
* Return the current mouse position
*/
Common::Point mousePos() const { return _mousePos; }
@@ -147,6 +154,11 @@ public:
void waitForNextFrame();
/**
+ * Checks for whether the next game frame number has been reached.
+ */
+ bool checkForNextFrameCounter();
+
+ /**
* Gets the current frame counter
*/
uint32 getFrameCounter() const { return _frameCounter; }
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
index 8639f59418..b544eff2db 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -64,6 +64,7 @@ Game::Game(MADSEngine *vm)
_loadGameSlot = -1;
_lastSave = -1;
_saveFile = nullptr;
+ _saveThumb = nullptr;
_statusFlag = 0;
_sectionHandler = nullptr;
_sectionNumber = 1;
@@ -93,6 +94,11 @@ Game::Game(MADSEngine *vm)
}
Game::~Game() {
+ if (_saveThumb) {
+ _saveThumb->free();
+ delete _saveThumb;
+ }
+
delete _saveFile;
delete _surface;
delete _sectionHandler;
@@ -548,16 +554,14 @@ void Game::writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &hea
out->write(header._saveName.c_str(), header._saveName.size());
out->writeByte('\0');
- // Get the active palette
- uint8 thumbPalette[256 * 3];
- g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
-
- // Create a thumbnail and save it
- Graphics::Surface *thumb = new Graphics::Surface();
- ::createThumbnail(thumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette);
- Graphics::saveThumbnail(*out, *thumb);
- thumb->free();
- delete thumb;
+ // Handle the thumbnail. If there's already one set by the game, create one
+ if (!_saveThumb)
+ createThumbnail();
+ Graphics::saveThumbnail(*out, *_saveThumb);
+
+ _saveThumb->free();
+ delete _saveThumb;
+ _saveThumb = nullptr;
// Write out the save date/time
TimeDate td;
@@ -570,4 +574,16 @@ void Game::writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &hea
out->writeUint32LE(_vm->_events->getFrameCounter());
}
+void Game::createThumbnail() {
+ if (_saveThumb) {
+ _saveThumb->free();
+ delete _saveThumb;
+ }
+
+ uint8 thumbPalette[PALETTE_SIZE];
+ _vm->_palette->grabPalette(thumbPalette, 0, PALETTE_COUNT);
+ _saveThumb = new Graphics::Surface();
+ ::createThumbnail(_saveThumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette);
+}
+
} // End of namespace MADS
diff --git a/engines/mads/game.h b/engines/mads/game.h
index 08cd7e7843..1a61fc8ac8 100644
--- a/engines/mads/game.h
+++ b/engines/mads/game.h
@@ -82,6 +82,7 @@ protected:
int _lastSave;
Common::String _saveName;
Common::InSaveFile *_saveFile;
+ Graphics::Surface *_saveThumb;
/**
* Constructor
@@ -226,6 +227,11 @@ public:
* Read in a savegame header
*/
static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header);
+
+ /**
+ * Creates a temporary thumbnail for use in saving games
+ */
+ void createThumbnail();
};
} // End of namespace MADS
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
index 59eec40bcc..d56994ab8e 100644
--- a/engines/mads/mads.cpp
+++ b/engines/mads/mads.cpp
@@ -55,6 +55,7 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
_resources = nullptr;
_sound = nullptr;
_audio = nullptr;
+ _opl = nullptr;
}
MADSEngine::~MADSEngine() {
@@ -68,6 +69,9 @@ MADSEngine::~MADSEngine() {
delete _resources;
delete _sound;
delete _audio;
+
+ _mixer->stopAll();
+ delete _opl;
}
void MADSEngine::initialize() {
@@ -76,6 +80,9 @@ void MADSEngine::initialize() {
DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling");
+ _opl = OPL::Config::create();
+ _opl->init(11025);
+
// Initial sub-system engine references
MSurface::setVm(this);
MSprite::setVm(this);
@@ -89,7 +96,7 @@ void MADSEngine::initialize() {
Font::init(this);
_font = new Font();
_screen.init();
- _sound = new SoundManager(this, _mixer);
+ _sound = new SoundManager(this, _mixer, _opl);
_audio = new AudioPlayer(_mixer, getGameID());
_game = Game::init(this);
@@ -103,9 +110,6 @@ Common::Error MADSEngine::run() {
// Run the game
_game->run();
- // Dummy loop to keep application active
- _events->delay(9999);
-
return Common::kNoError;
}
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
index 9a8f2152a1..8fc2788c28 100644
--- a/engines/mads/mads.h
+++ b/engines/mads/mads.h
@@ -99,6 +99,7 @@ public:
ScreenSurface _screen;
SoundManager *_sound;
AudioPlayer *_audio;
+ FM_OPL *_opl;
bool _easyMouse;
bool _invObjectsAnimated;
bool _textWindowStill;
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index 9b2d6f3114..e83b69d210 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -546,10 +546,9 @@ void TextDisplayList::draw(MSurface *s) {
for (uint idx = 0; idx < size(); ++idx) {
TextDisplay &td = (*this)[idx];
if (td._active && (td._expire >= 0)) {
+ Common::Point destPos(td._bounds.left, td._bounds.top);
td._font->setColors(0xFF, td._color1, td._color2, 0);
- td._font->writeString(s, td._msg,
- Common::Point(td._bounds.left, td._bounds.top),
- td._spacing, td._bounds.width());
+ td._font->writeString(s, td._msg, destPos, td._spacing, td._bounds.width());
}
}
}
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 61e810e215..96353e9ae5 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS := \
nebular/dialogs_nebular.o \
nebular/game_nebular.o \
nebular/globals_nebular.o \
+ nebular/menu_nebular.o \
nebular/sound_nebular.o \
nebular/nebular_scenes.o \
nebular/nebular_scenes1.o \
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index 18a9a4f547..349f4a5f23 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -527,7 +527,7 @@ MSurface *MSurface::flipHorizontal() const {
/*------------------------------------------------------------------------*/
int DepthSurface::getDepth(const Common::Point &pt) {
- if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) {
+ if (_depthStyle == 2) {
int bits = (3 - (pt.x % 4)) * 2;
byte v = *getBasePtr(pt.x >> 2, pt.y);
return v >> bits;
@@ -540,7 +540,7 @@ int DepthSurface::getDepth(const Common::Point &pt) {
}
int DepthSurface::getDepthHighBit(const Common::Point &pt) {
- if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) {
+ if (_depthStyle == 2) {
int bits = (3 - (pt.x % 4)) * 2;
byte v = *getBasePtr(pt.x >> 2, pt.y);
return (v >> bits) & 2;
@@ -552,5 +552,4 @@ int DepthSurface::getDepthHighBit(const Common::Point &pt) {
}
}
-
} // End of namespace MADS
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index ef2bbd6784..3a5bf22eed 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -51,10 +51,9 @@ struct SpriteInfo {
* MADS graphics surface
*/
class MSurface : public Graphics::Surface {
-private:
- bool _freeFlag;
protected:
static MADSEngine *_vm;
+ bool _freeFlag;
public:
/**
* Sets the engine refrence used all surfaces
@@ -223,9 +222,14 @@ private:
MADSEngine *_vm;
public:
/**
+ * Depth style
+ */
+ int _depthStyle;
+
+ /**
* Constructor
*/
- DepthSurface(MADSEngine *vm) : _vm(vm) {}
+ DepthSurface(MADSEngine *vm) : _vm(vm), _depthStyle(0) {}
/**
* Returns the depth at a given position
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
index 99fa01c34f..35a7d3bdc6 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -23,12 +23,17 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/util.h"
+#include "common/translation.h"
+
+#include "gui/saveload.h"
+
#include "mads/mads.h"
#include "mads/screen.h"
#include "mads/msurface.h"
#include "mads/staticres.h"
#include "mads/nebular/dialogs_nebular.h"
#include "mads/nebular/game_nebular.h"
+#include "mads/nebular/menu_nebular.h"
namespace MADS {
@@ -265,20 +270,99 @@ bool DialogsNebular::commandCheck(const char *idStr, Common::String &valStr,
}
void DialogsNebular::showDialog() {
- switch (_pendingDialog) {
- case DIALOG_GAME_MENU:
- //GameMenuDialog::show();
- break;
- case DIALOG_DIFFICULTY: {
-/*
- DifficultyDialog *dlg = new DifficultyDialog(_vm);
- dlg->show();
- delete dlg;
-*/
- break;
+ while (_pendingDialog != DIALOG_NONE && !_vm->shouldQuit()) {
+ DialogId dialogId = _pendingDialog;
+ _pendingDialog = DIALOG_NONE;
+
+ switch (dialogId) {
+ case DIALOG_MAIN_MENU: {
+ MainMenu *menu = new MainMenu(_vm);
+ menu->show();
+ delete menu;
+ break;
+ }
+ case DIALOG_DIFFICULTY: {
+ DifficultyDialog *dlg = new DifficultyDialog(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ case DIALOG_GAME_MENU: {
+ GameMenuDialog *dlg = new GameMenuDialog(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ case DIALOG_SAVE: {
+ showScummVMSaveDialog();
+ break;
+ }
+ case DIALOG_RESTORE: {
+ showScummVMRestoreDialog();
+ break;
+ }
+ case DIALOG_OPTIONS: {
+ OptionsDialog *dlg = new OptionsDialog(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ case DIALOG_ADVERT: {
+ AdvertView *dlg = new AdvertView(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ case DIALOG_TEXTVIEW: {
+ TextView *dlg = new TextView(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ case DIALOG_ANIMVIEW: {
+ AnimationView *dlg = new AnimationView(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ default:
+ break;
+ }
}
- default:
- break;
+}
+
+void DialogsNebular::showScummVMSaveDialog() {
+ Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game;
+ Scene *scene = &(game._scene);
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ Common::String desc = dialog->getResultString();
+
+ if (desc.empty()) {
+ // create our own description for the saved game, the user didn't enter it
+ desc = dialog->createDefaultSaveDescription(slot);
+ }
+
+ scene->_spriteSlots.reset();
+ scene->loadScene(scene->_currentSceneId, game._aaName, true);
+ scene->_userInterface.noInventoryAnim();
+ game._scene.drawElements(kTransitionFadeIn, false);
+
+ game.saveGame(slot, desc);
+ }
+}
+
+void DialogsNebular::showScummVMRestoreDialog() {
+ Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game;
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+
+ int slot = dialog->runModalWithCurrentTarget();
+ if (slot >= 0) {
+ game._loadGameSlot = slot;
+ game._scene._currentSceneId = -1;
+ game._currentSectionNumber = -1;
}
}
@@ -469,15 +553,78 @@ void PictureDialog::restore() {
/*------------------------------------------------------------------------*/
-ScreenDialog::DialogLine::DialogLine() {
+FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
+ _screenId = 990;
+ _palFlag = true;
+}
+
+FullScreenDialog::~FullScreenDialog() {
+ _vm->_screen.resetClipBounds();
+ _vm->_game->_scene.restrictScene();
+}
+
+void FullScreenDialog::display() {
+ Game &game = *_vm->_game;
+ Scene &scene = game._scene;
+
+ int nextSceneId = scene._nextSceneId;
+ int currentSceneId = scene._currentSceneId;
+ int priorSceneId = scene._priorSceneId;
+
+ if (_screenId > 0) {
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(_screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
+ }
+
+ scene._priorSceneId = priorSceneId;
+ scene._currentSceneId = currentSceneId;
+ scene._nextSceneId = nextSceneId;
+
+ _vm->_events->initVars();
+ game._kernelMode = KERNEL_ROOM_INIT;
+
+ byte pal[768];
+ if (_vm->_screenFade) {
+ Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
+ _vm->_palette->setFullPalette(pal);
+ } else {
+ _vm->_palette->getFullPalette(pal);
+ _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
+ }
+
+ // Set Fx state and palette entries
+ game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
+ game._trigger = 0;
+
+ // Clear the screen and draw the upper and lower horizontal lines
+ _vm->_screen.empty();
+ _vm->_palette->setLowRange();
+ _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+
+ // Restrict the screen to the area between the two lines
+ _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH,
+ DIALOG_TOP + MADS_SCENE_HEIGHT));
+ _vm->_game->_scene.restrictScene();
+
+ if (_screenId > 0)
+ scene._spriteSlots.fullRefresh();
+}
+
+/*------------------------------------------------------------------------*/
+
+GameDialog::DialogLine::DialogLine() {
_active = true;
_state = DLGSTATE_UNSELECTED;
_textDisplayIndex = -1;
_font = nullptr;
_widthAdjust = 0;
+ _msg = "";
}
-ScreenDialog::DialogLine::DialogLine(const Common::String &s) {
+GameDialog::DialogLine::DialogLine(const Common::String &s) {
+ _active = true;
_state = DLGSTATE_UNSELECTED;
_textDisplayIndex = -1;
_font = nullptr;
@@ -487,16 +634,17 @@ ScreenDialog::DialogLine::DialogLine(const Common::String &s) {
/*------------------------------------------------------------------------*/
-ScreenDialog::ScreenDialog(MADSEngine *vm) : _vm(vm) {
+GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) {
Game &game = *_vm->_game;
Scene &scene = game._scene;
- _v1 = 0;
- _v2 = 0;
- _v3 = false;
- _selectedLine = 0;
+ _tempLine = 0;
+ _movedFlag = false;
+ _redrawFlag = false;
+ _selectedLine = -1;
_dirFlag = false;
_textLineCount = 0;
+ _lineIndex = -1;
_screenId = 920;
chooseBackground();
@@ -508,64 +656,42 @@ ScreenDialog::ScreenDialog(MADSEngine *vm) : _vm(vm) {
scene.clearVocab();
scene._dynamicHotspots.clear();
_vm->_dialogs->_defaultPosition = Common::Point(-1, -1);
+ _menuSpritesIndex = 0;
+}
- bool palFlag = false;
- int nextSceneId = scene._nextSceneId;
- int currentSceneId = scene._currentSceneId;
- int priorSceneId = scene._priorSceneId;
-
- if (_vm->_dialogs->_pendingDialog == DIALOG_DIFFICULTY) {
- palFlag = true;
- } else {
- _vm->_palette->initPalette();
- }
- scene.loadScene(_screenId, game._aaName, palFlag);
+void GameDialog::display() {
+ FullScreenDialog::display();
- scene._priorSceneId = priorSceneId;
- scene._currentSceneId = currentSceneId;
- scene._nextSceneId = nextSceneId;
- scene._posAdjust.y = 22;
- _vm->_sound->pauseNewCommands();
- _vm->_events->initVars();
- game._kernelMode = KERNEL_ROOM_INIT;
+ Palette &palette = *_vm->_palette;
+ palette.setEntry(10, 0, 63, 0);
+ palette.setEntry(11, 0, 45, 0);
+ palette.setEntry(12, 63, 63, 0);
+ palette.setEntry(13, 45, 45, 0);
+ palette.setEntry(14, 63, 63, 63);
+ palette.setEntry(15, 45, 45, 45);
+ Scene &scene = _vm->_game->_scene;
SpriteAsset *menuSprites = new SpriteAsset(_vm, "*MENU", 0);
_menuSpritesIndex = scene._sprites.add(menuSprites);
- byte pal[768];
- if (_vm->_screenFade) {
- Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
- _vm->_palette->setFullPalette(pal);
- } else {
- _vm->_palette->getFullPalette(pal);
- _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
- }
-
- _vm->_screen.empty();
- _vm->_screen.hLine(0, 0, MADS_SCREEN_WIDTH, 2);
+ _lineIndex = -1;
+ setClickableLines();
- game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
- game._trigger = 0;
_vm->_events->setCursor(CURSOR_ARROW);
+}
- _vm->_palette->setEntry(10, 0, 63, 0);
- _vm->_palette->setEntry(11, 0, 45, 0);
- _vm->_palette->setEntry(12, 63, 63, 0);
- _vm->_palette->setEntry(13, 45, 45, 0);
- _vm->_palette->setEntry(14, 63, 63, 63);
- _vm->_palette->setEntry(15, 45, 45, 45);
-
- _lineIndex = -1;
+GameDialog::~GameDialog() {
+ _vm->_screen.resetClipBounds();
}
-void ScreenDialog::clearLines() {
+void GameDialog::clearLines() {
Scene &scene = _vm->_game->_scene;
- _v2 = 0;
+ _movedFlag = false;
_lines.clear();
scene._spriteSlots.fullRefresh(true);
}
-void ScreenDialog::setClickableLines() {
+void GameDialog::setClickableLines() {
ScreenObjects &screenObjects = _vm->_game->_screenObjects;
for (uint idx = 0; idx < _lines.size(); ++idx) {
@@ -586,19 +712,17 @@ void ScreenDialog::setClickableLines() {
}
}
-void ScreenDialog::addQuote(int id1, int id2, DialogTextAlign align,
+void GameDialog::addQuote(int id1, int id2, DialogTextAlign align,
const Common::Point &pt, Font *font) {
- Common::String msg = _vm->_game->getQuote(id1);
+ Common::String msg = _vm->_game->getQuote(id1).c_str(); // c_str() because we need a copy
- if (id2 > 0) {
- msg += " ";
+ if (id2 > 0)
msg += _vm->_game->getQuote(id2);
- }
addLine(msg, align, pt, font);
}
-void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align,
+void GameDialog::addLine(const Common::String &msg, DialogTextAlign align,
const Common::Point &pt, Font *font) {
Scene &scene = _vm->_game->_scene;
DialogLine *line;
@@ -641,6 +765,10 @@ void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align,
int xOffset;
switch (align) {
+ case ALIGN_NONE:
+ // No adjustment
+ break;
+
case ALIGN_CENTER:
xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(msg, -1) / 2;
line->_pos.x += xOffset;
@@ -653,6 +781,10 @@ void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align,
xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(
Common::String(msgP, ch), line->_widthAdjust);
line->_pos.x += xOffset;
+
+ Common::String newMsg = msg.c_str();
+ newMsg.deleteChar(ch - msgP);
+ line->_msg = newMsg;
}
break;
}
@@ -669,14 +801,14 @@ void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align,
++_lineIndex;
}
-void ScreenDialog::initVars() {
- _v1 = -1;
+void GameDialog::initVars() {
+ _tempLine = -1;
_selectedLine = -1;
_lineIndex = 0;
_textLineCount = 0;
}
-void ScreenDialog::chooseBackground() {
+void GameDialog::chooseBackground() {
switch (_vm->_game->_currentSectionNumber) {
case 1:
case 2:
@@ -700,27 +832,35 @@ void ScreenDialog::chooseBackground() {
}
}
-void ScreenDialog::setFrame(int frameNumber, int depth) {
+void GameDialog::setFrame(int frameNumber, int depth) {
Scene &scene = _vm->_game->_scene;
+ SpriteAsset *menuSprites = scene._sprites[_menuSpritesIndex];
+ MSprite *frame = menuSprites->getFrame(frameNumber - 1);
+
SpriteSlot &spriteSlot = scene._spriteSlots[scene._spriteSlots.add()];
spriteSlot._flags = IMG_UPDATE;
spriteSlot._seqIndex = 1;
spriteSlot._spritesIndex = _menuSpritesIndex;
spriteSlot._frameNumber = frameNumber;
+ spriteSlot._position = frame->_offset;
+ spriteSlot._depth = depth;
+ spriteSlot._scale = 100;
}
-void ScreenDialog::show() {
+void GameDialog::show() {
+ display();
+
Scene &scene = _vm->_game->_scene;
while (_selectedLine < 1 && !_vm->shouldQuit()) {
handleEvents();
- if (_v3) {
- if (!_v1)
- _v1 = -1;
+ if (_redrawFlag) {
+ if (!_tempLine)
+ _tempLine = -1;
refreshText();
scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
- _v3 = false;
+ _redrawFlag = false;
}
_vm->_events->waitForNextFrame();
@@ -728,11 +868,11 @@ void ScreenDialog::show() {
}
}
-void ScreenDialog::handleEvents() {
+void GameDialog::handleEvents() {
ScreenObjects &screenObjects = _vm->_game->_screenObjects;
EventsManager &events = *_vm->_events;
Nebular::DialogsNebular &dialogs = *(Nebular::DialogsNebular *)_vm->_dialogs;
- int v1 = _v1;
+ int tempLine = _tempLine;
// Mark all the lines as initially unselected
for (uint i = 0; i < _lines.size(); ++i)
@@ -742,10 +882,11 @@ void ScreenDialog::handleEvents() {
_vm->_events->pollEvents();
// Scan for objects in the dialog
- int objIndex = screenObjects.scan(events.currentPos() - _vm->_screen._offset, LAYER_GUI);
+ Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP);
+ int objIndex = screenObjects.scan(mousePos, LAYER_GUI);
- if (_v2) {
- int yp = events.currentPos().y - _vm->_screen._offset.y;
+ if (_movedFlag) {
+ int yp = mousePos.y;
if (yp < screenObjects[1]._bounds.top) {
if (!events._mouseReleased)
_lines[1]._state = DLGSTATE_SELECTED;
@@ -760,7 +901,7 @@ void ScreenDialog::handleEvents() {
}
int line = -1;
- if (objIndex > 0 || events._mouseButtons) {
+ if (objIndex > 0 && (events._mouseStatus || events._mouseReleased)) {
line = screenObjects[objIndex]._descId;
if (dialogs._pendingDialog == DIALOG_SAVE || dialogs._pendingDialog == DIALOG_RESTORE) {
if (line > 7 && line <= 14) {
@@ -768,9 +909,9 @@ void ScreenDialog::handleEvents() {
line -= 7;
}
- int v2 = (line > 0 && line < 8) ? 1 : 0;
+ bool movedFlag = line > 0 && line < 8;
if (events._mouseMoved)
- _v2 = v2;
+ _movedFlag = movedFlag;
}
if (screenObjects[objIndex]._category == CAT_COMMAND) {
@@ -784,17 +925,17 @@ void ScreenDialog::handleEvents() {
line = -1;
if (events._mouseReleased) {
- if (!_v2 || line <= 18)
+ if (!_movedFlag || line <= 18)
_selectedLine = line;
- _v3 = true;
+ _redrawFlag = true;
}
- _v1 = line;
- if (v1 == line || _selectedLine >= 0)
- _v3 = true;
+ _tempLine = line;
+ if (tempLine != line || _selectedLine >= 0)
+ _redrawFlag = true;
}
-void ScreenDialog::refreshText() {
+void GameDialog::refreshText() {
Scene &scene = _vm->_game->_scene;
for (uint i = 0; i < _lines.size(); ++i) {
@@ -834,10 +975,9 @@ void ScreenDialog::refreshText() {
/*------------------------------------------------------------------------*/
-DifficultyDialog::DifficultyDialog(MADSEngine *vm) : ScreenDialog(vm) {
- setFrame(8, 2);
+DifficultyDialog::DifficultyDialog(MADSEngine *vm) : GameDialog(vm) {
setLines();
- setClickableLines();
+ _vm->_palette->resetGamePalette(18, 10);
}
void DifficultyDialog::setLines() {
@@ -853,19 +993,24 @@ void DifficultyDialog::setLines() {
}
}
+void DifficultyDialog::display() {
+ GameDialog::display();
+ setFrame(8, 2);
+}
+
void DifficultyDialog::show() {
- ScreenDialog::show();
+ GameDialog::show();
Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game;
switch (_selectedLine) {
case 1:
- game._difficulty = Nebular::DIFFICULTY_HARD;
+ game._difficulty = Nebular::DIFFICULTY_EASY;
break;
case 2:
game._difficulty = Nebular::DIFFICULTY_MEDIUM;
break;
case 3:
- game._difficulty = Nebular::DIFFICULTY_EASY;
+ game._difficulty = Nebular::DIFFICULTY_HARD;
break;
default:
_vm->quitGame();
@@ -874,16 +1019,161 @@ void DifficultyDialog::show() {
/*------------------------------------------------------------------------*/
-GameMenuDialog::GameMenuDialog(MADSEngine *vm) : ScreenDialog(vm) {
+GameMenuDialog::GameMenuDialog(MADSEngine *vm) : GameDialog(vm) {
+ setLines();
+}
+
+void GameMenuDialog::setLines() {
+ Font *font = _vm->_font->getFont(FONT_CONVERSATION);
+
+ int yp = 64 - ((font->getHeight() + 1) * 4 + 6) / 2;
+
+ addQuote(10, 0, ALIGN_CENTER, Common::Point(0, yp), font);
+ yp += 6;
+
+ for (int id = 11; id <= 15; ++id) {
+ yp += font->getHeight();
+ addQuote(id, 0, ALIGN_CENTER, Common::Point(0, yp));
+ }
+}
+
+void GameMenuDialog::display() {
+ GameDialog::display();
setFrame(1, 2);
}
-void GameMenuDialog::addLines() {
- initVars();
+void GameMenuDialog::show() {
+ GameDialog::show();
+
+ switch (_selectedLine) {
+ case 1:
+ _vm->_dialogs->_pendingDialog = DIALOG_SAVE;
+ _vm->_dialogs->showDialog();
+ break;
+ case 2:
+ _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
+ _vm->_dialogs->showDialog();
+ break;
+ case 3:
+ _vm->_dialogs->_pendingDialog = DIALOG_OPTIONS;
+ _vm->_dialogs->showDialog();
+ break;
+ case 4:
+ // Resume game
+ break;
+ case 5:
+ default:
+ _vm->quitGame();
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+OptionsDialog::OptionsDialog(MADSEngine *vm) : GameDialog(vm) {
+ setLines();
+}
+
+int OptionsDialog::getOptionQuote(int option) {
+ Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game;
+
+ // TODO: Hook the rest of the options to the current config
+ switch (option) {
+ case 17: // Music
+ return 24; // 24: ON, 25: OFF
+ case 18: // Sound
+ return 26; // 26: ON, 27: OFF
+ case 19: // Interface
+ return !_vm->_easyMouse ? 28 : 29; // 28: Standard, 29: Easy
+ case 20: // Inventory
+ return _vm->_invObjectsAnimated ? 30 : 31; // 30: Spinning, 31: Still
+ case 21: // Text window
+ return !_vm->_textWindowStill ? 32 : 33; // 32: Animated, 33: Still
+ case 22: // Screen fade
+ return 34 + _vm->_screenFade; // 34: Smooth, 35: Medium, 36: Fast
+ case 23: // Storyline
+ return (game._storyMode == STORYMODE_NAUGHTY) ? 37 : 38; // 37: Naughty, 38: Nice
+ default:
+ error("getOptionQuote: Unknown option");
+ }
+}
+
+void OptionsDialog::setLines() {
Font *font = _vm->_font->getFont(FONT_CONVERSATION);
- int top = 78 - (font->getHeight() + 2) * 12;
- addQuote(10, 0, ALIGN_CENTER, Common::Point(0, top), font);
- // TODO
+
+ int yp = 40 - ((font->getHeight() + 1) * 4 + 6) / 2;
+
+ addQuote(16, 0, ALIGN_CENTER, Common::Point(0, yp), font);
+ yp += 6;
+
+ for (int id = 17; id <= 23; ++id) {
+ yp += font->getHeight();
+ addQuote(id, getOptionQuote(id), ALIGN_AT_CENTER, Common::Point(0, yp));
+ }
+
+ yp += 28;
+ addQuote(1, 0, ALIGN_NONE, Common::Point(90, yp));
+ addQuote(2, 0, ALIGN_NONE, Common::Point(190, yp));
+}
+
+void OptionsDialog::display() {
+ GameDialog::display();
+ setFrame(2, 2);
+}
+
+void OptionsDialog::show() {
+ Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game;
+ do {
+ _selectedLine = 0;
+ GameDialog::show();
+
+ switch (_selectedLine) {
+ case 1: // Music
+ warning("STUB: Music toggle");
+ break;
+ case 2: // Sound
+ warning("STUB: Sound toggle");
+ break;
+ case 3: // Interface
+ _vm->_easyMouse = !_vm->_easyMouse;
+ break;
+ case 4: // Inventory
+ _vm->_invObjectsAnimated = !_vm->_invObjectsAnimated;
+ break;
+ case 5: // Text window
+ _vm->_textWindowStill = !_vm->_textWindowStill;
+ break;
+ case 6: // Screen fade
+ if (_vm->_screenFade == SCREEN_FADE_FAST)
+ _vm->_screenFade = SCREEN_FADE_MEDIUM;
+ else if (_vm->_screenFade == SCREEN_FADE_MEDIUM)
+ _vm->_screenFade = SCREEN_FADE_SMOOTH;
+ else
+ _vm->_screenFade = SCREEN_FADE_FAST;
+ break;
+ case 7: // Storyline
+ game._storyMode = (game._storyMode == STORYMODE_NAUGHTY) ? STORYMODE_NICE : STORYMODE_NAUGHTY;
+ break;
+ default:
+ break;
+ }
+
+ // Reload menu
+ _lineIndex = -1;
+ clearLines();
+ setLines();
+ setClickableLines();
+ } while (_selectedLine <= 7);
+
+ switch (_selectedLine) {
+ case 8: // Done
+ // TODO: Copy from temporary config
+ break;
+ case 9: // Cancel
+ // TODO: Ignore all changes to temporary config
+ break;
+ default:
+ break;
+ }
}
} // End of namespace Nebular
diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h
index a144ee9d83..f64f992611 100644
--- a/engines/mads/nebular/dialogs_nebular.h
+++ b/engines/mads/nebular/dialogs_nebular.h
@@ -31,6 +31,8 @@ namespace MADS {
namespace Nebular {
+#define DIALOG_TOP 22
+
enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 };
class DialogsNebular : public Dialogs {
@@ -46,6 +48,10 @@ private:
bool textNoun(Common::String &dest, int nounId, const Common::String &source);
bool commandCheck(const char *idStr, Common::String &valStr, const Common::String &command);
+
+ void showScummVMSaveDialog();
+ void showScummVMRestoreDialog();
+
public:
virtual void showDialog();
@@ -99,11 +105,41 @@ public:
virtual ~PictureDialog();
};
-enum DialogTextAlign { ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 };
+enum DialogTextAlign { ALIGN_NONE = 0, ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 };
enum DialogState { DLGSTATE_UNSELECTED = 0, DLGSTATE_SELECTED = 1, DLGSTATE_FOCUSED = 2 };
-class ScreenDialog {
+class FullScreenDialog: public EventTarget {
+protected:
+ /**
+ * Engine reference
+ */
+ MADSEngine *_vm;
+
+ /**
+ * Screen/scene to show background from
+ */
+ int _screenId;
+
+ /**
+ * Flag for palette initialization
+ */
+ bool _palFlag;
+
+ /**
+ * Handles displaying the screen background and dialog
+ */
+ virtual void display();
+public:
+ /**
+ * Constructor
+ */
+ FullScreenDialog(MADSEngine *vm);
+
+ virtual ~FullScreenDialog();
+};
+
+class GameDialog: public FullScreenDialog {
struct DialogLine {
bool _active;
DialogState _state;
@@ -112,22 +148,25 @@ class ScreenDialog {
Common::String _msg;
Font *_font;
int _widthAdjust;
-
+
DialogLine();
DialogLine(const Common::String &s);
};
protected:
- MADSEngine *_vm;
Common::Array<DialogLine> _lines;
- int _v1;
- int _v2;
- bool _v3;
+ int _tempLine;
+ bool _movedFlag;
+ bool _redrawFlag;
int _selectedLine;
bool _dirFlag;
- int _screenId;
int _menuSpritesIndex;
int _lineIndex;
int _textLineCount;
+
+ /**
+ * Display the dialog
+ */
+ virtual void display();
/**
* Reset the lines list for the dialog
@@ -177,12 +216,12 @@ public:
/**
* Constructor
*/
- ScreenDialog(MADSEngine *vm);
+ GameDialog(MADSEngine *vm);
/**
* Destructor
*/
- virtual ~ScreenDialog() {}
+ virtual ~GameDialog();
/**
* Show the dialog
@@ -190,30 +229,69 @@ public:
virtual void show();
};
-class DifficultyDialog : public ScreenDialog {
+class DifficultyDialog : public GameDialog {
private:
/**
- * Set the lines for the dialog
+ * Set the lines for the dialog
*/
void setLines();
public:
DifficultyDialog(MADSEngine *vm);
/**
+ * Display the dialog
+ */
+ virtual void display();
+
+ /**
* Show the dialog
*/
virtual void show();
};
-class GameMenuDialog : public ScreenDialog {
+class GameMenuDialog : public GameDialog {
private:
/**
- * Add the lines for the Game Menu dialog
+ * Set the lines for the dialog
*/
- void addLines();
+ void setLines();
public:
GameMenuDialog(MADSEngine *vm);
+ /**
+ * Display the dialog
+ */
+ virtual void display();
+
+ /**
+ * Show the dialog
+ */
+ virtual void show();
+};
+
+class OptionsDialog : public GameDialog {
+private:
+ /**
+ * Set the lines for the dialog
+ */
+ void setLines();
+
+ /**
+ * Gets the quote to be shown for an option
+ */
+ int getOptionQuote(int option);
+public:
+ OptionsDialog(MADSEngine *vm);
+
+ /**
+ * Display the dialog
+ */
+ virtual void display();
+
+ /**
+ * Show the dialog
+ */
+ virtual void show();
};
} // End of namespace Nebular
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index d6d7a07e52..902f42507a 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -22,6 +22,7 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
+#include "graphics/scaler.h"
#include "mads/mads.h"
#include "mads/game.h"
#include "mads/screen.h"
@@ -59,9 +60,7 @@ ProtectionResult GameNebular::checkCopyProtection() {
}
void GameNebular::startGame() {
- // Show the main menu
- // TODO: Show the main menu here
-
+ /*
// Check copy protection
ProtectionResult protectionResult = checkCopyProtection();
switch (protectionResult) {
@@ -79,11 +78,13 @@ void GameNebular::startGame() {
// Copy protection check succeeded
break;
}
+ */
initSection(_sectionNumber);
_statusFlag = true;
- _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY;
+ // Show the main menu
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
_vm->_dialogs->showDialog();
_vm->_dialogs->_pendingDialog = DIALOG_NONE;
@@ -310,6 +311,11 @@ void GameNebular::setSectionHandler() {
void GameNebular::checkShowDialog() {
if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[kCopyProtectFailed]) {
_player.releasePlayerSprites();
+
+ // Make a thumbnail in case it's needed for making a savegame
+ _vm->_game->createThumbnail();
+
+ // Show the dialog
_vm->_dialogs->showDialog();
_vm->_dialogs->_pendingDialog = DIALOG_NONE;
}
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
new file mode 100644
index 0000000000..4d3beb3382
--- /dev/null
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -0,0 +1,986 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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/scummsys.h"
+#include "mads/game.h"
+#include "mads/mads.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/screen.h"
+#include "mads/nebular/menu_nebular.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+#define NEBULAR_MENUSCREEN 990
+#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
+#define MADS_MENU_ANIM_DELAY 70
+
+MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
+ _breakFlag = false;
+ _redrawFlag = true;
+ _palFlag = false;
+}
+
+void MenuView::show() {
+ Scene &scene = _vm->_game->_scene;
+ EventsManager &events = *_vm->_events;
+ _vm->_screenFade = SCREEN_FADE_FAST;
+
+ scene._spriteSlots.reset(true);
+ display();
+
+ events.setEventTarget(this);
+ events.hideCursor();
+
+ while (!_breakFlag && !_vm->shouldQuit()) {
+ if (_redrawFlag) {
+ _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
+ _redrawFlag = false;
+ }
+
+ _vm->_events->waitForNextFrame();
+ _vm->_game->_fx = kTransitionNone;
+ doFrame();
+ }
+
+ events.setEventTarget(nullptr);
+ _vm->_sound->stop();
+}
+
+void MenuView::display() {
+ _vm->_palette->resetGamePalette(4, 8);
+
+ FullScreenDialog::display();
+}
+
+bool MenuView::onEvent(Common::Event &event) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+ return true;
+ }
+
+ return false;
+}
+
+/*------------------------------------------------------------------------*/
+
+MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
+ Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr);
+ Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1);
+ _delayTimeout = 0;
+ _menuItemIndex = -1;
+ _frameIndex = 0;
+ _skipFlag = false;
+ _highlightedIndex = -1;
+ _selectedIndex = -1;
+ _buttonDown = false;
+
+ for (int i = 0; i < 7; ++i)
+ _menuItems[i] = nullptr;
+}
+
+MainMenu::~MainMenu() {
+ Scene &scene = _vm->_game->_scene;
+ for (int i = 0; i < 7; ++i) {
+ if (_menuItemIndexes[i] != -1)
+ scene._sprites.remove(_menuItemIndexes[i]);
+ }
+
+ scene._spriteSlots.reset();
+}
+
+void MainMenu::display() {
+ MenuView::display();
+ Scene &scene = _vm->_game->_scene;
+ ScreenObjects &screenObjects = _vm->_game->_screenObjects;
+ screenObjects.clear();
+
+ // Load each of the menu item assets and add to the scene sprites list
+ for (int i = 0; i < 7; ++i) {
+ Common::String spritesName = Resources::formatName(NEBULAR_MENUSCREEN,
+ 'A', i + 1, EXT_SS, "");
+ _menuItems[i] = new SpriteAsset(_vm, spritesName, 0);
+ _menuItemIndexes[i] = scene._sprites.add(_menuItems[i]);
+
+ // Register the menu item area in the screen objects
+ MSprite *frame0 = _menuItems[i]->getFrame(0);
+ Common::Point pt(frame0->_offset.x - (frame0->w / 2),
+ frame0->_offset.y - frame0->h);
+ screenObjects.add(
+ Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w,
+ pt.y + frame0->h + DIALOG_TOP), LAYER_GUI, CAT_COMMAND, i);
+ }
+
+ // Set the cursor for when it's shown
+ _vm->_events->setCursor(CURSOR_ARROW);
+}
+
+void MainMenu::doFrame() {
+ // Delay between animation frames on the menu
+ uint32 currTime = g_system->getMillis();
+ if (currTime < _delayTimeout)
+ return;
+ _delayTimeout = currTime + MADS_MENU_ANIM_DELAY;
+
+ // If an item has already been selected, handle rotating out the other menu items
+ if (_selectedIndex != -1) {
+ if (_frameIndex == _menuItems[0]->getCount()) {
+ handleAction((MADSGameAction)_selectedIndex);
+ } else {
+ for (_menuItemIndex = 0; _menuItemIndex < 6; ++_menuItemIndex) {
+ if (_menuItemIndex != _selectedIndex) {
+ addSpriteSlot();
+ }
+ }
+
+ // Move the menu items to the next frame
+ ++_frameIndex;
+ }
+ return;
+ }
+
+ // If we've alerady reached the end of the menuitem animation, exit immediately
+ if (_menuItemIndex == 6)
+ return;
+
+ // If the user has chosen to skip the animation, show the full menu immediately
+ if (_skipFlag && _menuItemIndex >= 0) {
+ // Quickly loop through all the menu items to display each's final frame
+ for (; _menuItemIndex < 6; ++_menuItemIndex) {
+ // Draw the final frame of the menuitem
+ _frameIndex = 0;
+ addSpriteSlot();
+ }
+
+ _vm->_events->showCursor();
+ } else {
+ if ((_menuItemIndex == -1) || (_frameIndex == 0)) {
+ if (++_menuItemIndex == 6) {
+ // Reached end of display animation
+ _vm->_events->showCursor();
+ return;
+ }
+
+ _frameIndex = _menuItems[_menuItemIndex]->getCount() - 1;
+ } else {
+ --_frameIndex;
+ }
+
+ // Move to the next menuitem frame
+ addSpriteSlot();
+ }
+}
+
+void MainMenu::addSpriteSlot() {
+ Scene &scene = _vm->_game->_scene;
+ SpriteSlots &spriteSlots = scene._spriteSlots;
+
+ int seqIndex = (_menuItemIndex < 6) ? _menuItemIndex : _frameIndex;
+ spriteSlots.deleteTimer(seqIndex);
+
+ SpriteAsset *menuItem = _menuItems[_menuItemIndex];
+ MSprite *spr = menuItem->getFrame(_frameIndex);
+
+ SpriteSlot &slot = spriteSlots[spriteSlots.add()];
+ slot._flags = IMG_UPDATE;
+ slot._seqIndex = seqIndex;
+ slot._spritesIndex = _menuItemIndexes[_menuItemIndex];
+ slot._frameNumber = _frameIndex + 1;
+ slot._position = spr->_offset;
+ slot._depth = 1;
+ slot._scale = 100;
+
+ _redrawFlag = true;
+}
+
+bool MainMenu::onEvent(Common::Event &event) {
+ Scene &scene = _vm->_game->_scene;
+ if (_selectedIndex != -1)
+ return false;
+
+ // Handle keypresses - these can be done at any time, even when the menu items are being drawn
+ if (event.type == Common::EVENT_KEYDOWN) {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_F6:
+ handleAction(EXIT);
+ break;
+
+ case Common::KEYCODE_F1:
+ handleAction(START_GAME);
+ break;
+
+ case Common::KEYCODE_F2:
+ handleAction(RESUME_GAME);
+ break;
+
+ case Common::KEYCODE_F3:
+ handleAction(SHOW_INTRO);
+ break;
+
+ case Common::KEYCODE_F4:
+ handleAction(CREDITS);
+ break;
+
+ case Common::KEYCODE_F5:
+ handleAction(QUOTES);
+ break;
+
+ case Common::KEYCODE_s: {
+ // Goodness knows why, but Rex has a key to restart the menuitem animations
+ // Restart the animation
+ _menuItemIndex = -1;
+ for (int i = 0; i < 6; ++i)
+ scene._spriteSlots.deleteTimer(i);
+
+ _skipFlag = false;
+ _vm->_events->hideCursor();
+ break;
+ }
+
+ default:
+ // Any other key skips the menu animation
+ _skipFlag = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ switch (event.type) {
+ case Common::EVENT_LBUTTONDOWN:
+ if (_vm->_events->isCursorVisible()) {
+ _buttonDown = true;
+ int menuIndex = getHighlightedItem(event.mouse);
+
+ if (menuIndex != _highlightedIndex) {
+ scene._spriteSlots.deleteTimer(menuIndex);
+
+ _highlightedIndex = menuIndex;
+ if (_highlightedIndex != -1) {
+ _frameIndex = _highlightedIndex;
+ addSpriteSlot();
+ }
+ }
+ } else {
+ // Skip the menu animation
+ _skipFlag = true;
+ }
+ return true;
+
+ case Common::EVENT_MOUSEMOVE:
+ if (_buttonDown) {
+ int menuIndex = getHighlightedItem(event.mouse);
+ if (menuIndex != _highlightedIndex) {
+ if (_highlightedIndex != -1) {
+ // Revert to the unselected menu item
+ unhighlightItem();
+ }
+
+ if (menuIndex != -1) {
+ // Highlight new item
+ _highlightedIndex = menuIndex;
+ _frameIndex = _highlightedIndex;
+ addSpriteSlot();
+ }
+ }
+ }
+ break;
+
+ case Common::EVENT_LBUTTONUP:
+ _buttonDown = false;
+ if (_highlightedIndex != -1) {
+ _selectedIndex = _highlightedIndex;
+ unhighlightItem();
+ _frameIndex = 0;
+ }
+
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+int MainMenu::getHighlightedItem(const Common::Point &pt) {
+ return _vm->_game->_screenObjects.scan(pt, LAYER_GUI) - 1;
+}
+
+void MainMenu::unhighlightItem() {
+ // Revert to the unselected menu item
+ _vm->_game->_scene._spriteSlots.deleteTimer(_highlightedIndex);
+ _menuItemIndex = _highlightedIndex;
+ _frameIndex = 0;
+ addSpriteSlot();
+
+ _menuItemIndex = 6;
+ _highlightedIndex = -1;
+}
+
+void MainMenu::handleAction(MADSGameAction action) {
+ _vm->_events->hideCursor();
+ _breakFlag = true;
+
+ switch (action) {
+ case START_GAME:
+ // Show the difficulty dialog
+ _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY;
+ break;
+
+ case RESUME_GAME:
+ // The original resumed the most recently saved game. Instead,
+ // just show the load game scren
+ _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
+ return;
+
+ case SHOW_INTRO:
+ AnimationView::execute(_vm, "rexopen");
+ break;
+
+ case CREDITS:
+ TextView::execute(_vm, "credits");
+ return;
+
+ case QUOTES:
+ TextView::execute(_vm, "quotes");
+ return;
+
+ case EXIT:
+ _vm->_dialogs->_pendingDialog = DIALOG_ADVERT;
+ break;
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+AdvertView::AdvertView(MADSEngine *vm): EventTarget(), _vm(vm) {
+ _breakFlag = false;
+}
+
+void AdvertView::show() {
+ bool altAdvert = _vm->getRandomNumber(1000) >= 500;
+ int screenId = altAdvert ? 995 : 996;
+ uint32 expiryTime = g_system->getMillis() + 10 * 1000;
+
+ _vm->_palette->resetGamePalette(4, 8);
+
+ // Load the advert background onto the screen
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface,
+ _vm->_screen);
+ _vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
+ _vm->_palette->setFullPalette(_vm->_palette->_mainPalette);
+
+ delete sceneInfo;
+
+ EventsManager &events = *_vm->_events;
+ events.setEventTarget(this);
+ events.hideCursor();
+
+ while (!_breakFlag && !_vm->shouldQuit()) {
+ _vm->_events->waitForNextFrame();
+ _vm->_game->_fx = kTransitionNone;
+
+ _breakFlag |= g_system->getMillis() >= expiryTime;
+ }
+
+ events.setEventTarget(nullptr);
+ _vm->quitGame();
+ events.pollEvents();
+}
+
+bool AdvertView::onEvent(Common::Event &event) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _breakFlag = true;
+ return true;
+ }
+
+ return false;
+}
+
+/*------------------------------------------------------------------------*/
+
+char TextView::_resourceName[100];
+#define TEXTVIEW_LINE_SPACING 2
+#define TEXT_ANIMATION_DELAY 100
+#define TV_NUM_FADE_STEPS 40
+#define TV_FADE_DELAY_MILLI 50
+
+void TextView::execute(MADSEngine *vm, const Common::String &resName) {
+ assert(resName.size() < 100);
+ strncpy(_resourceName, resName.c_str(), sizeof(_resourceName));
+ vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
+}
+
+TextView::TextView(MADSEngine *vm) : MenuView(vm) {
+ _animating = false;
+ _panSpeed = 0;
+ _spareScreen = nullptr;
+ _scrollCount = 0;
+ _lineY = -1;
+ _scrollTimeout = 0;
+ _panCountdown = 0;
+ _translationX = 0;
+ _screenId = -1;
+
+ _font = _vm->_font->getFont(FONT_CONVERSATION);
+ _vm->_palette->resetGamePalette(4, 0);
+ load();
+}
+
+TextView::~TextView() {
+}
+
+void TextView::load() {
+ Common::String scriptName(_resourceName);
+ scriptName += ".txr";
+
+ if (!_script.open(scriptName))
+ error("Could not open resource %s", _resourceName);
+
+ processLines();
+}
+
+void TextView::processLines() {
+ if (_script.eos())
+ error("Attempted to read past end of response file");
+
+ while (!_script.eos()) {
+ // Read in the next line
+ _script.readLine(_currentLine, 79);
+ char *p = _currentLine + strlen(_currentLine) - 1;
+ if (*p == '\n')
+ *p = '\0';
+
+ // Commented out line, so go loop for another
+ if (_currentLine[0] == '#')
+ continue;
+
+ // Process the line
+ char *cStart = strchr(_currentLine, '[');
+ if (cStart) {
+ while (cStart) {
+ // Loop for possible multiple commands on one line
+ char *cEnd = strchr(_currentLine, ']');
+ if (!cEnd)
+ error("Unterminated command '%s' in response file", _currentLine);
+
+ *cEnd = '\0';
+ processCommand();
+
+ // Copy rest of line (if any) to start of buffer
+ strncpy(_currentLine, cEnd + 1, sizeof(_currentLine));
+
+ cStart = strchr(_currentLine, '[');
+ }
+
+ if (_currentLine[0]) {
+ processText();
+ break;
+ }
+
+ } else {
+ processText();
+ break;
+ }
+ }
+}
+
+void TextView::processCommand() {
+ Scene &scene = _vm->_game->_scene;
+ Common::String scriptLine(_currentLine + 1);
+ scriptLine.toUppercase();
+ const char *paramP;
+ const char *commandStr = scriptLine.c_str();
+
+ if (!strncmp(commandStr, "BACKGROUND", 10)) {
+ // Set the background
+ paramP = commandStr + 10;
+ resetPalette();
+ int screenId = getParameter(&paramP);
+
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
+ scene._spriteSlots.fullRefresh();
+ _redrawFlag = true;
+
+ } else if (!strncmp(commandStr, "GO", 2)) {
+ _animating = true;
+
+ } else if (!strncmp(commandStr, "PAN", 3)) {
+ // Set panning values
+ paramP = commandStr + 3;
+ int panX = getParameter(&paramP);
+ int panY = getParameter(&paramP);
+ int panSpeed = getParameter(&paramP);
+
+ if ((panX != 0) || (panY != 0)) {
+ _pan = Common::Point(panX, panY);
+ _panSpeed = panSpeed;
+ }
+
+ } else if (!strncmp(commandStr, "DRIVER", 6)) {
+ // Set the driver to use
+ paramP = commandStr + 7;
+
+ if (!strncmp(paramP, "#SOUND.00", 9)) {
+ int driverNum = paramP[9] - '0';
+ _vm->_sound->init(driverNum);
+ }
+ } else if (!strncmp(commandStr, "SOUND", 5)) {
+ // Set sound number
+ paramP = commandStr + 5;
+ int soundId = getParameter(&paramP);
+ _vm->_sound->command(soundId);
+
+ } else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') ||
+ (commandStr[5] == '1'))) {
+ // Set the text colors
+ int index = commandStr[5] - '0';
+ paramP = commandStr + 6;
+
+ byte r = getParameter(&paramP);
+ byte g = getParameter(&paramP);
+ byte b = getParameter(&paramP);
+
+ _vm->_palette->setEntry(5 + index, r, g, b);
+
+ } else if (!strncmp(commandStr, "SPARE", 5)) {
+ // Sets a secondary background number that can be later switched in with a PAGE command
+ paramP = commandStr + 6;
+ int spareIndex = commandStr[5] - '0';
+ assert(spareIndex < 4);
+ int screenId = getParameter(&paramP);
+
+ // Load the spare background
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->_width = MADS_SCREEN_WIDTH;
+ sceneInfo->_height = MADS_SCENE_HEIGHT;
+ _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
+ _spareScreens[spareIndex]);
+ delete sceneInfo;
+
+ } else if (!strncmp(commandStr, "PAGE", 4)) {
+ // Signals to change to a previous specified secondary background
+ paramP = commandStr + 4;
+ int spareIndex = getParameter(&paramP);
+
+ // Only allow background switches if one isn't currently in progress
+ if (!_spareScreen && _spareScreens[spareIndex].getPixels() != nullptr) {
+ _spareScreen = &_spareScreens[spareIndex];
+ _translationX = 0;
+ }
+
+ } else {
+ error("Unknown response command: '%s'", commandStr);
+ }
+}
+
+int TextView::getParameter(const char **paramP) {
+ if ((**paramP != '=') && (**paramP != ','))
+ return 0;
+
+ int result = 0;
+ ++*paramP;
+ while ((**paramP >= '0') && (**paramP <= '9')) {
+ result = result * 10 + (**paramP - '0');
+ ++*paramP;
+ }
+
+ return result;
+}
+
+void TextView::processText() {
+ int lineWidth, xStart;
+
+ if (!strcmp(_currentLine, "***")) {
+ // Special signifier for end of script
+ _scrollCount = _font->getHeight() * 13;
+ _lineY = -1;
+ return;
+ }
+
+ _lineY = 0;
+
+ // Lines are always centered, except if line contains a '@', in which case the
+ // '@' marks the position that must be horizontally centered
+ char *centerP = strchr(_currentLine, '@');
+ if (centerP) {
+ *centerP = '\0';
+ xStart = (MADS_SCREEN_WIDTH / 2) - _font->getWidth(_currentLine);
+
+ // Delete the @ character and shift back the remainder of the string
+ char *p = centerP + 1;
+ if (*p == ' ') ++p;
+ strcpy(centerP, p);
+
+ } else {
+ lineWidth = _font->getWidth(_currentLine);
+ xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
+ }
+
+ // Add the new line to the list of pending lines
+ TextLine tl;
+ tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT);
+ tl._line = _currentLine;
+ tl._textDisplayIndex = -1;
+ _textLines.push_back(tl);
+}
+
+void TextView::display() {
+ FullScreenDialog::display();
+ _sceneChanged = true;
+}
+
+void TextView::resetPalette() {
+ _vm->_palette->resetGamePalette(8, 8);
+ _vm->_palette->setEntry(5, 0, 63, 63);
+ _vm->_palette->setEntry(6, 0, 45, 45);
+}
+
+void TextView::doFrame() {
+ Scene &scene = _vm->_game->_scene;
+ if (!_animating)
+ return;
+
+ // Only update state if wait period has expired
+ uint32 currTime = g_system->getMillis();
+
+ // If a screen transition is in progress and it's time for another column, handle it
+ if (_spareScreen) {
+ byte *srcP = _spareScreen->getBasePtr(_translationX, 0);
+ byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0);
+ byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0);
+
+ for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
+ bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
+ *bgP = *srcP;
+ *screenP = *srcP;
+ }
+
+ // Flag the column of the screen is modified
+ _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0,
+ _translationX + 1, MADS_SCENE_HEIGHT));
+
+ // Keep moving the column to copy to the right
+ if (++_translationX == MADS_SCREEN_WIDTH) {
+ // Surface transition is complete
+ _spareScreen = nullptr;
+ }
+ }
+
+ // Make sure it's time for an update
+ if (currTime < _scrollTimeout)
+ return;
+ _scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
+ _redrawFlag = true;
+
+ // If any panning values are set, pan the background surface
+ if ((_pan.x != 0) || (_pan.y != 0)) {
+ if (_panCountdown > 0) {
+ --_panCountdown;
+ return;
+ }
+
+ // Handle horizontal panning
+ if (_pan.x != 0) {
+ byte *lineTemp = new byte[_pan.x];
+ for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) {
+ byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
+
+ // Copy the first X pixels into temp buffer, move the rest of the line
+ // to the start of the line, and then move temp buffer pixels to end of line
+ Common::copy(pixelsP, pixelsP + _pan.x, lineTemp);
+ Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP);
+ Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x);
+ }
+
+ delete[] lineTemp;
+ }
+
+ // Handle vertical panning
+ if (_pan.y != 0) {
+ // Store the bottom Y lines into a temp buffer, move the rest of the lines down,
+ // and then copy the stored lines back to the top of the screen
+ byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH];
+ byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y);
+ Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp);
+
+ for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) {
+ byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
+ byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y);
+ Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP);
+ }
+
+ Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH,
+ (byte *)scene._backgroundSurface.getPixels());
+ delete[] linesTemp;
+ }
+
+ // Flag for a full screen refresh
+ scene._spriteSlots.fullRefresh();
+ }
+
+ // Scroll all active text lines up
+ for (int i = _textLines.size() - 1; i >= 0; --i) {
+ TextLine &tl = _textLines[i];
+ if (tl._textDisplayIndex != -1)
+ // Expire the text line that's already on-screen
+ scene._textDisplay.expire(tl._textDisplayIndex);
+
+ tl._pos.y--;
+ if (tl._pos.y < 0) {
+ _textLines.remove_at(i);
+ } else {
+ tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y,
+ 0x605, -1, tl._line, _font);
+ }
+ }
+
+ if (_scrollCount > 0) {
+ // Handling final scrolling of text off of screen
+ if (--_scrollCount == 0) {
+ scriptDone();
+ return;
+ }
+ } else {
+ // Handling a text row
+ if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING))
+ processLines();
+ }
+}
+
+void TextView::scriptDone() {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+}
+
+/*------------------------------------------------------------------------*/
+
+char AnimationView::_resourceName[100];
+
+void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
+ assert(resName.size() < 100);
+ strncpy(_resourceName, resName.c_str(), sizeof(_resourceName));
+ vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
+}
+
+AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
+ _soundDriverLoaded = false;
+ _previousUpdate = 0;
+ _screenId = -1;
+ _showWhiteBars = true;
+ _resetPalette = false;
+ _resyncMode = NEVER;
+
+ load();
+}
+
+void AnimationView::load() {
+ Common::String resName(_resourceName);
+ if (!resName.hasSuffix("."))
+ resName += ".res";
+
+ if (!_script.open(resName))
+ error("Could not open resource %s", resName.c_str());
+
+ processLines();
+}
+
+bool AnimationView::onEvent(Common::Event &event) {
+ // Wait for the Escape key or a mouse press
+ if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) ||
+ (event.type == Common::EVENT_RBUTTONUP)) {
+ scriptDone();
+ return true;
+ }
+
+ return false;
+}
+
+void AnimationView::doFrame() {
+ Scene &scene = _vm->_game->_scene;
+ int bgNumber = 0;
+
+ // Only update state if wait period has expired
+ if (_previousUpdate > 0) {
+ if (g_system->getMillis() - _previousUpdate < 3000) {
+ return;
+ } else {
+ // time for an update
+ _previousUpdate = g_system->getMillis();
+ }
+ } else {
+ _previousUpdate = g_system->getMillis();
+ return;
+ }
+ /*
+ char bgFile[10];
+ strncpy(bgFile, _currentFile, 5);
+ bgFile[0] = bgFile[2];
+ bgFile[1] = bgFile[3];
+ bgFile[2] = bgFile[4];
+ bgFile[3] = '\0';
+ bgNumber = atoi(bgFile);
+ sprintf(bgFile, "rm%i.art", bgNumber);
+
+ // Not all scenes have a background. If there is one, refresh it
+ if (Common::File::exists(bgFile)) {
+ _vm->_palette->resetGamePalette(4, 8);
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(bgNumber, 0, Common::String(), 0, scene._depthSurface,
+ scene._backgroundSurface);
+ }
+ */
+}
+
+void AnimationView::scriptDone() {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+}
+
+void AnimationView::processLines() {
+ if (_script.eos()) {
+ // end of script, end animation
+ scriptDone();
+ return;
+ }
+
+ char c;
+ while (!_script.eos()) {
+ // Get in next line
+ _currentLine.empty();
+ while (!_script.eos() && (c = _script.readByte()) != '\n') {
+ if (c != '\r')
+ _currentLine += c;
+ }
+
+ // Process the line
+ while (!_currentLine.empty()) {
+ if (_currentLine.hasPrefix("-")) {
+ _currentLine.deleteChar(0);
+
+ processCommand();
+ } else {
+ // Get resource name
+ Common::String resName;
+ while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') {
+ _currentLine.deleteChar(0);
+ resName += c;
+ }
+
+ _resources.push_back(ResourceEntry(resName, _sfx));
+ _sfx = 0;
+ }
+
+ // Skip any spaces
+ while (_currentLine.hasPrefix(" "))
+ _currentLine.deleteChar(0);
+ }
+ }
+}
+
+void AnimationView::processCommand() {
+ // Get the command character
+ char commandChar = toupper(_currentLine[0]);
+ _currentLine.deleteChar(0);
+
+ // Handle the command
+ switch (commandChar) {
+ case 'H':
+ // -h[:ex] Disable EMS / XMS high memory support
+ if (_currentLine.hasPrefix(":"))
+ _currentLine.deleteChar(0);
+ while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x"))
+ _currentLine.deleteChar(0);
+ break;
+ case 'O':
+ // -o:xxx Specify opening special effect
+ assert(_currentLine[0] == ':');
+ _currentLine.deleteChar(0);
+ _sfx = getParameter();
+ break;
+ case 'P':
+ // Switch to CONCAT mode, which is ignored anyway
+ break;
+ case 'R': {
+ // Resynch timer (always, beginning, never)
+ assert(_currentLine[0] == ':');
+ _currentLine.deleteChar(0);
+
+ char v = toupper(_currentLine[0]);
+ _currentLine.deleteChar(0);
+ if (v == 'N')
+ _resyncMode = NEVER;
+ else if (v == 'A')
+ _resyncMode = ALWAYS;
+ else if (v == 'B')
+ _resyncMode = BEGINNING;
+ else
+ error("Unknown parameter");
+ break;
+ }
+ case 'W':
+ // Switch white bars being visible
+ _showWhiteBars = !_showWhiteBars;
+ break;
+ case 'X':
+ // Exit after animation finishes. Ignore
+ break;
+ case 'Y':
+ // Reset palette on startup
+ _resetPalette = true;
+ break;
+ default:
+ error("Unknown command char: '%c'", commandChar);
+ }
+}
+
+int AnimationView::getParameter() {
+ int result = 0;
+
+ while (!_currentLine.empty()) {
+ char c = _currentLine[0];
+
+ if (c >= '0' && c <= '9') {
+ _currentLine.deleteChar(0);
+ result = result * 10 + (c - '0');
+ } else {
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h
new file mode 100644
index 0000000000..7abe3c8892
--- /dev/null
+++ b/engines/mads/nebular/menu_nebular.h
@@ -0,0 +1,287 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 MADS_MENU_NEBULAR_H
+#define MADS_MENU_NEBULAR_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/msurface.h"
+#include "mads/nebular/dialogs_nebular.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+namespace Nebular {
+
+enum MADSGameAction { START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT };
+
+class MenuView: public FullScreenDialog {
+protected:
+ bool _breakFlag;
+ bool _redrawFlag;
+
+ virtual void doFrame() = 0;
+
+ virtual void display();
+
+ /**
+ * Event handler
+ */
+ virtual bool onEvent(Common::Event &event);
+public:
+ MenuView(MADSEngine *vm);
+
+ virtual ~MenuView() {}
+
+ virtual void show();
+};
+
+class MainMenu: public MenuView {
+private:
+ SpriteAsset *_menuItems[7];
+ int _menuItemIndexes[7];
+ int _menuItemIndex;
+ int _frameIndex;
+ uint32 _delayTimeout;
+ bool _skipFlag;
+
+ /**
+ * Currently highlighted menu item
+ */
+ int _highlightedIndex;
+
+ /**
+ * Flag for mouse button being pressed
+ */
+ bool _buttonDown;
+
+ /**
+ * Stores menu item selection
+ */
+ int _selectedIndex;
+
+ /**
+ * Get the highlighted menu item under the cursor
+ */
+ int getHighlightedItem(const Common::Point &pt);
+
+ /**
+ * Un-highlight a currently highlighted item
+ */
+ void unhighlightItem();
+
+ /**
+ * Execute a given menuitem
+ */
+ void handleAction(MADSGameAction action);
+
+ /**
+ * Add a sprite slot for the current menuitem frame
+ */
+ void addSpriteSlot();
+protected:
+ /**
+ * Display the menu
+ */
+ virtual void display();
+
+ /**
+ * Handle the menu item animations
+ */
+ virtual void doFrame();
+
+ /**
+ * Event handler
+ */
+ virtual bool onEvent(Common::Event &event);
+public:
+ MainMenu(MADSEngine *vm);
+
+ virtual ~MainMenu();
+};
+
+class AdvertView : public EventTarget {
+private:
+ /**
+ * Engine reference
+ */
+ MADSEngine *_vm;
+
+ /**
+ * Signals when to close the dialog
+ */
+ bool _breakFlag;
+protected:
+ /**
+ * Event handler
+ */
+ virtual bool onEvent(Common::Event &event);
+public:
+ AdvertView(MADSEngine *vm);
+
+ virtual ~AdvertView() {}
+
+ /**
+ * Show the dialog
+ */
+ void show();
+};
+
+struct TextLine {
+ Common::Point _pos;
+ Common::String _line;
+ int _textDisplayIndex;
+};
+
+/**
+ * Scrolling text view
+ */
+class TextView : public MenuView {
+private:
+ static char _resourceName[100];
+
+ bool _animating;
+ bool _sceneChanged;
+ Common::Array<TextLine> _textLines;
+ Common::Point _pan;
+ int _panSpeed;
+ MSurface _spareScreens[4];
+ int _scrollCount;
+ int _lineY;
+ uint32 _scrollTimeout;
+ int _panCountdown;
+ int _translationX;
+ Common::File _script;
+ char _currentLine[80];
+ MSurface *_spareScreen;
+ Font *_font;
+private:
+ /**
+ * Load the text resource
+ */
+ void load();
+
+ /**
+ * Process the lines
+ */
+ void processLines();
+
+ /**
+ * Process a command from the script file
+ */
+ void processCommand();
+
+ /**
+ * Process text from the script file
+ */
+ void processText();
+
+ /**
+ * Get a parameter from line
+ */
+ int getParameter(const char **paramP);
+
+ /**
+ * Called when the script is finished
+ */
+ void scriptDone();
+
+ /**
+ * Reset the game palette
+ */
+ void resetPalette();
+protected:
+ virtual void display();
+
+ virtual void doFrame();
+public:
+ /**
+ * Queue the given text resource for display
+ */
+ static void execute(MADSEngine *vm, const Common::String &resName);
+
+ TextView(MADSEngine *vm);
+
+ virtual ~TextView();
+};
+
+enum ResyncMode { NEVER, ALWAYS, BEGINNING };
+
+struct ResourceEntry {
+ Common::String _resourceName;
+ int _sfx;
+
+ ResourceEntry() {}
+ ResourceEntry(const Common::String &resName, int sfx) {
+ _resourceName = resName;
+ _sfx = sfx;
+ }
+};
+
+/**
+* Animation cutscene view
+*/
+class AnimationView : public MenuView {
+private:
+ static char _resourceName[100];
+
+ Common::File _script;
+ uint32 _previousUpdate;
+ Common::String _currentLine;
+ bool _soundDriverLoaded;
+ bool _showWhiteBars;
+ bool _resetPalette;
+ ResyncMode _resyncMode;
+ int _sfx;
+ Common::Array<ResourceEntry> _resources;
+private:
+ void load();
+
+ void processLines();
+
+ void processCommand();
+
+ int getParameter();
+
+ void scriptDone();
+protected:
+ virtual void doFrame();
+
+ virtual bool onEvent(Common::Event &event);
+public:
+ /**
+ * Queue the given text resource for display
+ */
+ static void execute(MADSEngine *vm, const Common::String &resName);
+
+ AnimationView(MADSEngine *vm);
+
+ virtual ~AnimationView() {}
+};
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_MENU_NEBULAR_H */
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index c71512ed4c..b5e2491624 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -331,7 +331,7 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStr
byte runValue = stream->readByte();
// Write out the run length
- Common::fill(destP, destP + runLength, runValue);
+ Common::fill(destP, MIN(endP, destP + runLength), runValue);
destP += runLength;
// Get the next run length
diff --git a/engines/mads/nebular/nebular_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp
index a81f11b8a5..ab072c1d3c 100644
--- a/engines/mads/nebular/nebular_scenes1.cpp
+++ b/engines/mads/nebular/nebular_scenes1.cpp
@@ -1033,7 +1033,7 @@ void Scene102::actions() {
_action._inProgress = false;
return;
}
- } else if (_action.isAction(VERB_LOOK) || (_game._difficulty != DIFFICULTY_EASY)) {
+ } else if (_action.isAction(VERB_LOOK) || (_game._difficulty != DIFFICULTY_HARD)) {
_vm->_dialogs->show(10222);
_action._inProgress = false;
return;
diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp
index 6039135794..14f36756de 100644
--- a/engines/mads/nebular/nebular_scenes8.cpp
+++ b/engines/mads/nebular/nebular_scenes8.cpp
@@ -1121,8 +1121,6 @@ void Scene804::actions() {
} else {
_action._inProgress = false;
- //saveGame("REX000.SAV");
-
_vm->_dialogs->show(80424);
_pullThrottleReally = true;
_scene->_kernelMessages.add(Common::Point(78, 75), 0x1110, 0, 0,
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index fc2755db2f..5ce362e053 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -149,7 +149,7 @@ AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
/*-----------------------------------------------------------------------*/
-ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset) {
+ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset) {
// Open up the appropriate sound file
if (!_soundFile.open(filename))
error("Could not open file - %s", filename.c_str());
@@ -197,8 +197,7 @@ ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffs
// Store passed parameters, and setup OPL
_dataOffset = dataOffset;
_mixer = mixer;
- _opl = OPL::Config::create();
- assert(_opl);
+ _opl = opl;
_opl->init(getRate());
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1,
@@ -217,7 +216,6 @@ ASound::~ASound() {
delete[] (*i)._data;
_mixer->stopHandle(_soundHandle);
- delete _opl;
}
void ASound::adlibInit() {
@@ -941,8 +939,8 @@ const ASound1::CommandPtr ASound1::_commandList[42] = {
&ASound1::command40, &ASound1::command41
};
-ASound1::ASound1(Audio::Mixer *mixer)
- : ASound(mixer, "asound.001", 0x1520) {
+ASound1::ASound1(Audio::Mixer *mixer, FM_OPL *opl)
+ : ASound(mixer, opl, "asound.001", 0x1520) {
_cmd23Toggle = false;
// Load sound samples
@@ -1242,7 +1240,7 @@ const ASound2::CommandPtr ASound2::_commandList[44] = {
&ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43
};
-ASound2::ASound2(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) {
+ASound2::ASound2(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
_command12Param = 0xFD;
// Load sound samples
@@ -1613,7 +1611,7 @@ const ASound3::CommandPtr ASound3::_commandList[61] = {
&ASound3::command60
};
-ASound3::ASound3(Audio::Mixer *mixer) : ASound(mixer, "asound.003", 0x15B0) {
+ASound3::ASound3(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
_command39Flag = false;
// Load sound samples
@@ -2017,7 +2015,7 @@ const ASound4::CommandPtr ASound4::_commandList[61] = {
&ASound4::command60
};
-ASound4::ASound4(Audio::Mixer *mixer) : ASound(mixer, "asound.004", 0x14F0) {
+ASound4::ASound4(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 210; ++i)
@@ -2273,7 +2271,7 @@ const ASound5::CommandPtr ASound5::_commandList[42] = {
&ASound5::command40, &ASound5::command41
};
-ASound5::ASound5(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) {
+ASound5::ASound5(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x144);
for (int i = 0; i < 164; ++i)
@@ -2514,7 +2512,7 @@ const ASound6::CommandPtr ASound6::_commandList[30] = {
&ASound6::nullCommand, &ASound6::command29
};
-ASound6::ASound6(Audio::Mixer *mixer) : ASound(mixer, "asound.006", 0x1390) {
+ASound6::ASound6(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 200; ++i)
@@ -2670,7 +2668,7 @@ const ASound7::CommandPtr ASound7::_commandList[38] = {
&ASound7::command36, &ASound7::command37
};
-ASound7::ASound7(Audio::Mixer *mixer) : ASound(mixer, "asound.007", 0x1460) {
+ASound7::ASound7(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 214; ++i)
@@ -2876,7 +2874,7 @@ const ASound8::CommandPtr ASound8::_commandList[38] = {
&ASound8::command36, &ASound8::command37
};
-ASound8::ASound8(Audio::Mixer *mixer) : ASound(mixer, "asound.008", 0x1490) {
+ASound8::ASound8(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 174; ++i)
@@ -3114,6 +3112,313 @@ int ASound8::command37() {
return 0;
}
+/*-----------------------------------------------------------------------*/
+
+const ASound9::CommandPtr ASound9::_commandList[52] = {
+ &ASound9::command0, &ASound9::command1, &ASound9::command2, &ASound9::command3,
+ &ASound9::command4, &ASound9::command5, &ASound9::command6, &ASound9::command7,
+ &ASound9::command8, &ASound9::command9, &ASound9::command10, &ASound9::command11,
+ &ASound9::command12, &ASound9::command13, &ASound9::command14, &ASound9::command15,
+ &ASound9::command16, &ASound9::command17, &ASound9::command18, &ASound9::command19,
+ &ASound9::command20, &ASound9::command21, &ASound9::command22, &ASound9::command23,
+ &ASound9::command24, &ASound9::command25, &ASound9::command26, &ASound9::command27,
+ &ASound9::command28, &ASound9::command29, &ASound9::command30, &ASound9::command31,
+ &ASound9::command32, &ASound9::command33, &ASound9::command34, &ASound9::command35,
+ &ASound9::command36, &ASound9::command37, &ASound9::command38, &ASound9::command39,
+ &ASound9::command40, &ASound9::command41, &ASound9::command42, &ASound9::command43,
+ &ASound9::command44_46, &ASound9::command45, &ASound9::command44_46, &ASound9::command47,
+ &ASound9::command48, &ASound9::command49, &ASound9::command50, &ASound9::command51
+};
+
+ASound9::ASound9(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
+ _v1 = _v2 = 0;
+ _soundPtr = nullptr;
+
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x50);
+ for (int i = 0; i < 94; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound9::command(int commandId, int param) {
+ if (commandId > 60)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound9::command9() {
+ _v1 = 1848;
+ _v2 = 84;
+ _channels[0].load(loadData(0xAA4, 470));
+ _channels[1].load(loadData(0xE4C, 450));
+ _channels[2].load(loadData(0x1466, 702));
+ _channels[3].load(loadData(0x137E, 232));
+ _channels[4].load(loadData(0x1014, 65));
+ _channels[5].load(loadData(0x11C4, 44));
+ _channels[6].load(loadData(0XC7A, 466));
+ return 0;
+}
+
+int ASound9::command10() {
+ _channels[0].load(loadData(0x1724, 24));
+ _channels[1].load(loadData(0x173C, 24));
+ _channels[2].load(loadData(0x1754, 20));
+ _channels[3].load(loadData(0x1768, 20));
+ _channels[4].load(loadData(0x177C, 20));
+ _channels[5].load(loadData(0x1790, 20));
+ return 0;
+}
+
+int ASound9::command11() {
+ playSound(0x8232, 168);
+ playSound(0x82DA, 170);
+ return 0;
+}
+
+int ASound9::command12() {
+ playSound(0x80DA, 12);
+ playSound(0x80E6, 12);
+ return 0;
+}
+
+int ASound9::command13() {
+ playSound(0x80F2, 38);
+ playSound(0x8118, 42);
+ return 0;
+}
+
+int ASound9::command14() {
+ playSound(0x81F6, 22);
+ return 0;
+}
+
+int ASound9::command15() {
+ playSound(0x818A, 32);
+ playSound(0x81AA, 32);
+ return 0;
+}
+
+int ASound9::command16() {
+ playSound(0x8022, 36);
+ playSound(0x8046, 42);
+ return 0;
+}
+
+int ASound9::command17() {
+ command29();
+ playSound(0x858C, 11);
+ return 0;
+}
+
+int ASound9::command18() {
+ playSound(0x80C2, 24);
+ return 0;
+}
+
+int ASound9::command19() {
+ playSound(0x80A0, 34);
+ return 0;
+}
+
+int ASound9::command20() {
+ int v = (getRandomNumber() & 0x10) | 0x4D;
+ byte *pData = loadData(0x8142, 8);
+ pData[4] = v & 0x7F;
+ playSoundData(pData);
+ return 0;
+}
+
+int ASound9::command21() {
+ playSound(0x815A, 16);
+ return 0;
+}
+
+int ASound9::command22() {
+ playSound(0x816A, 16);
+ return 0;
+}
+
+int ASound9::command23() {
+ playSound(0x814A, 16);
+ return 0;
+}
+
+int ASound9::command24() {
+ playSound(0x7FE2, 34);
+ return 0;
+}
+
+int ASound9::command25() {
+ playSound(0x8004, 30);
+ return 0;
+}
+
+int ASound9::command26() {
+ _channels[6].load(loadData(0x8384, 156));
+ _channels[7].load(loadData(0x8420, 160));
+ return 0;
+}
+
+int ASound9::command27() {
+ playSound(0x84C0, 140);
+ return 0;
+}
+
+int ASound9::command28() {
+ playSound(0x81CA, 10);
+ return 0;
+}
+
+int ASound9::command29() {
+ playSound(0x81D4, 10);
+ return 0;
+}
+
+int ASound9::command30() {
+ playSound(0x817A, 16);
+ return 0;
+}
+
+int ASound9::command31() {
+ playSound(0x820C, 14);
+ playSound(0x821A, 24);
+ return 0;
+}
+
+int ASound9::command32() {
+ playSound(0x8070, 8);
+ return 0;
+}
+
+int ASound9::command33() {
+ playSound(0x8078, 16);
+ playSound(0x8088, 16);
+ return 0;
+}
+
+int ASound9::command34() {
+ // Skipped stuff in original
+ _channels[0].load(loadData(0x17A4, 24));
+ _channels[1].load(loadData(0x1CDE, 62));
+ _channels[2].load(loadData(0x2672, 980));
+ _channels[3].load(loadData(0x3336, 1000));
+ _channels[4].load(loadData(0x469E, 176));
+ _channels[5].load(loadData(0x57F2, 138));
+
+ return 0;
+}
+
+int ASound9::command35() {
+ playSound(0x854C, 64);
+ return 0;
+}
+
+int ASound9::command36() {
+ playSound(0x81DE, 10);
+ playSound(0x81E8, 14);
+ return 0;
+}
+
+int ASound9::command37() {
+ byte *pData = loadData(0x8098, 8);
+ int v = getRandomNumber();
+ if ((v &= 0x40) != 0)
+ v |= 8;
+ else
+ v += 0x4A;
+
+ pData[6] = v;
+ playSoundData(pData);
+ return 0;
+}
+
+int ASound9::command38() {
+ playSound(0x100E, 6);
+ return 0;
+}
+
+int ASound9::command39() {
+ _soundPtr = loadData(0x1055, 128);
+ return 0;
+}
+
+int ASound9::command40() {
+ _soundPtr = loadData(0x118C, 50);
+ return 0;
+}
+
+int ASound9::command41() {
+ _soundPtr = loadData(0x11BE, 6);
+ return 0;
+}
+
+int ASound9::command42() {
+ _soundPtr = loadData(0x11F0, 50);
+ return 0;
+}
+
+int ASound9::command43() {
+ _v1 = _v2 = 80;
+ _channels[0].load(loadData(0x626A, 90));
+ _channels[1].load(loadData(0x67F2, 92));
+ _channels[2].load(loadData(0x6CFE, 232));
+ _channels[3].load(loadData(0x7146, 236));
+
+ return 0;
+}
+
+int ASound9::command44_46() {
+ _soundPtr = loadData(0x10D5, 38);
+ return 0;
+}
+
+int ASound9::command45() {
+ _soundPtr = loadData(0x10FB, 38);
+ return 0;
+}
+
+int ASound9::command47() {
+ _soundPtr = loadData(0x1121, 107);
+ return 0;
+}
+
+int ASound9::command48() {
+ playSound(0x7FD0, 8);
+ playSound(0x7FD8, 10);
+ return 0;
+}
+
+int ASound9::command49() {
+ _channels[0].load(loadData(0x7AD6, 92));
+ _channels[1].load(loadData(0x7B32, 90));
+ _channels[2].load(loadData(0x7B8C, 738));
+ _channels[3].load(loadData(0x7E6E, 28));
+ _channels[4].load(loadData(0x7E8A, 30));
+ _channels[5].load(loadData(0x7EA8, 30));
+ _channels[6].load(loadData(0x7EC6, 195));
+ return 0;
+}
+
+int ASound9::command50() {
+ _soundPtr = loadData(0x1222, 348);
+ return 0;
+}
+
+int ASound9::command51() {
+ // Skipped stuff in original
+ _channels[0].load(loadData(0x17BC, 1282));
+ _channels[1].load(loadData(0x1CFC, 2422));
+ _channels[2].load(loadData(0x2A46, 2288));
+ _channels[3].load(loadData(0x371E, 3964));
+ _channels[4].load(loadData(0x474E, 1863));
+ _channels[5].load(loadData(0x587C, 2538));
+ return 0;
+}
+
+
} // End of namespace Nebular
} // End of namespace MADS
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index c485bd7955..abb6516030 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -305,10 +305,12 @@ public:
public:
/**
* Constructor
+ * @param mixer Mixer
+ * @param opl OPL
* @param filename Specifies the adlib sound player file to use
* @param dataOffset Offset in the file of the data segment
*/
- ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset);
+ ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset);
/**
* Destructor
@@ -408,7 +410,7 @@ private:
void command111213();
int command2627293032();
public:
- ASound1(Audio::Mixer *mixer);
+ ASound1(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -460,7 +462,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound2(Audio::Mixer *mixer);
+ ASound2(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -520,7 +522,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound3(Audio::Mixer *mixer);
+ ASound3(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -558,7 +560,7 @@ private:
void method1();
public:
- ASound4(Audio::Mixer *mixer);
+ ASound4(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -604,7 +606,7 @@ private:
int command42();
int command43();
public:
- ASound5(Audio::Mixer *mixer);
+ ASound5(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -633,7 +635,7 @@ private:
int command25();
int command29();
public:
- ASound6(Audio::Mixer *mixer);
+ ASound6(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -665,7 +667,7 @@ private:
int command36();
int command37();
public:
- ASound7(Audio::Mixer *mixer);
+ ASound7(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -708,7 +710,66 @@ private:
void method1(byte *pData);
void adjustRange(byte *pData, byte v, int incr);
public:
- ASound8(Audio::Mixer *mixer);
+ ASound8(Audio::Mixer *mixer, FM_OPL *opl);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound9 : public ASound {
+private:
+ int _v1, _v2;
+ byte *_soundPtr;
+
+ typedef int (ASound9::*CommandPtr)();
+ static const CommandPtr _commandList[52];
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+ int command41();
+ int command42();
+ int command43();
+ int command44_46();
+ int command45();
+ int command47();
+ int command48();
+ int command49();
+ int command50();
+ int command51();
+ int command57();
+ int command59();
+ int command60();
+public:
+ ASound9(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
diff --git a/engines/mads/palette.h b/engines/mads/palette.h
index 975167a458..9b8b7146db 100644
--- a/engines/mads/palette.h
+++ b/engines/mads/palette.h
@@ -297,7 +297,7 @@ public:
/**
* Resets the game palette
*/
- void resetGamePalette(int v1, int v2);
+ void resetGamePalette(int lowRange, int highRange);
/**
* Initializes the main palette
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
index b0b1bf7836..ba2179fcbf 100644
--- a/engines/mads/phantom/game_phantom.cpp
+++ b/engines/mads/phantom/game_phantom.cpp
@@ -42,6 +42,10 @@ GamePhantom::GamePhantom(MADSEngine *vm)
}
void GamePhantom::startGame() {
+ _scene._priorSceneId = 0;
+ _scene._currentSceneId = -1;
+ _scene._nextSceneId = 101;
+
initializeGlobals();
}
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
index dbce014525..7fd7ce642d 100644
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -169,9 +169,10 @@ Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
- File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
+ Common::String ext = Common::String::format(".WW%d", variant);
+ File f(Resources::formatName(RESPREFIX_RM, _sceneId, ext));
MadsPack codesPack(&f);
- Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
+ Common::SeekableReadStream *stream = codesPack.getItemStream(0);
loadCodes(depthSurface, stream);
@@ -181,22 +182,20 @@ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = depthSurface.getData();
- byte *endP = depthSurface.getBasePtr(0, depthSurface.h);
-
- byte runLength = stream->readByte();
- while (destP < endP && runLength > 0) {
- byte runValue = stream->readByte();
-
- // Write out the run length
- Common::fill(destP, destP + runLength, runValue);
- destP += runLength;
-
- // Get the next run length
- runLength = stream->readByte();
+ byte *walkMap = new byte[stream->size()];
+ stream->read(walkMap, stream->size());
+
+ for (int y = 0; y < 156; ++y) {
+ for (int x = 0; x < 320; ++x) {
+ int offset = x + (y * 320);
+ if ((walkMap[offset / 8] << (offset % 8)) & 0x80)
+ *destP++ = 1; // walkable
+ else
+ *destP++ = 0;
+ }
}
- if (destP < endP)
- Common::fill(destP, endP, 0);
+ delete[] walkMap;
}
} // End of namespace Phantom
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
index ffeed6cda8..ad24dd4f60 100644
--- a/engines/mads/scene.cpp
+++ b/engines/mads/scene.cpp
@@ -63,8 +63,7 @@ Scene::Scene(MADSEngine *vm)
_paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF));
// Set up a scene surface that maps to our physical screen drawing surface
- _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
- _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
+ restrictScene();
// Set up the verb list
_verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE));
@@ -82,6 +81,12 @@ Scene::Scene(MADSEngine *vm)
Scene::~Scene() {
delete _sceneLogic;
delete _sceneInfo;
+ delete _animationData;
+}
+
+void Scene::restrictScene() {
+ _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
+ _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
}
void Scene::clearVocab() {
@@ -196,21 +201,24 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) {
}
void Scene::loadHotspots() {
- File f(Resources::formatName(RESPREFIX_RM, _currentSceneId, ".HH"));
- MadsPack madsPack(&f);
- bool isV2 = (_vm->getGameID() != GType_RexNebular);
+ _hotspots.clear();
- Common::SeekableReadStream *stream = madsPack.getItemStream(0);
- int count = stream->readUint16LE();
- delete stream;
+ Common::File f;
+ if (f.open(Resources::formatName(RESPREFIX_RM, _currentSceneId, ".HH"))) {
+ MadsPack madsPack(&f);
+ bool isV2 = (_vm->getGameID() != GType_RexNebular);
- stream = madsPack.getItemStream(1);
- _hotspots.clear();
- for (int i = 0; i < count; ++i)
- _hotspots.push_back(Hotspot(*stream, isV2));
+ Common::SeekableReadStream *stream = madsPack.getItemStream(0);
+ int count = stream->readUint16LE();
+ delete stream;
- delete stream;
- f.close();
+ stream = madsPack.getItemStream(1);
+ for (int i = 0; i < count; ++i)
+ _hotspots.push_back(Hotspot(*stream, isV2));
+
+ delete stream;
+ f.close();
+ }
}
void Scene::loadVocab() {
@@ -346,7 +354,7 @@ void Scene::loop() {
// Handle drawing a game frame
doFrame();
- // TODO: Verify correctness of frame wait
+ // Wait for the next frame
_vm->_events->waitForNextFrame();
if (_vm->_dialogs->_pendingDialog != DIALOG_NONE && !_vm->_game->_trigger
@@ -507,7 +515,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
_vm->_sound->startQueuedCommands();
} else {
// Copy dirty areas to the screen
- _dirtyAreas.copyToScreen(_vm->_screen._offset);
+ _dirtyAreas.copyToScreen();
}
_spriteSlots.cleanUp();
diff --git a/engines/mads/scene.h b/engines/mads/scene.h
index 407d70dc85..ee7864cfee 100644
--- a/engines/mads/scene.h
+++ b/engines/mads/scene.h
@@ -142,6 +142,8 @@ public:
*/
~Scene();
+ void restrictScene();
+
/**
* Clear the vocabulary list
*/
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index 1494f62d7a..174579a624 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -151,30 +151,34 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
_sceneId = sceneId;
}
- // TODO: The following isn't quite right for V2 games (it's all 0)
- _artFileNum = infoStream->readUint16LE();
- _depthStyle = infoStream->readUint16LE();
- _width = infoStream->readUint16LE();
- _height = infoStream->readUint16LE();
-
- // HACK for V2 games (for now)
- if (_vm->getGameID() != GType_RexNebular) {
+ int nodeCount = 20;
+
+ if (_vm->getGameID() == GType_RexNebular) {
+ _artFileNum = infoStream->readUint16LE();
+ _depthStyle = infoStream->readUint16LE();
+ _width = infoStream->readUint16LE();
+ _height = infoStream->readUint16LE();
+
+ infoStream->skip(24);
+
+ nodeCount = infoStream->readUint16LE();
+ _yBandsEnd = infoStream->readUint16LE();
+ _yBandsStart = infoStream->readUint16LE();
+ _maxScale = infoStream->readUint16LE();
+ _minScale = infoStream->readUint16LE();
+ for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
+ _depthList[i] = infoStream->readUint16LE();
+ _field4A = infoStream->readUint16LE();
+ } else {
+ _artFileNum = sceneId;
+ _depthStyle = 0;
_width = 320;
_height = 156;
- }
- infoStream->skip(24);
-
- int nodeCount = infoStream->readUint16LE();
- _yBandsEnd = infoStream->readUint16LE();
- _yBandsStart = infoStream->readUint16LE();
- _maxScale = infoStream->readUint16LE();
- _minScale = infoStream->readUint16LE();
- for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
- _depthList[i] = infoStream->readUint16LE();
- _field4A = infoStream->readUint16LE();
+ infoStream->skip(140);
+ }
- // Load the set of objects that are associated with the scene
+ // Load the scene's walk nodes
for (int i = 0; i < 20; ++i) {
WalkNode node;
node.load(infoStream);
@@ -223,21 +227,16 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
depthSurface.setSize(width, height);
}
- if (_vm->getGameID() == GType_RexNebular) {
- // Load the depth surface with the scene codes
- Common::SeekableReadStream *depthStream = infoPack.getItemStream(variant + 1);
- loadCodes(depthSurface, depthStream);
- delete depthStream;
- }
-
+ loadCodes(depthSurface, variant);
+ depthSurface._depthStyle = _depthStyle;
infoFile.close();
if (_vm->getGameID() == GType_RexNebular) {
- loadMadsV1Background(sceneId, resName, flags, bgSurface);
- loadPalette(sceneId, _artFileNum, resName, flags, bgSurface);
+ loadMadsV1Background(_sceneId, resName, flags, bgSurface);
+ loadPalette(_sceneId, _artFileNum, resName, flags, bgSurface);
} else {
- loadMadsV2Background(sceneId, resName, flags, bgSurface);
- loadPalette(sceneId, sceneId, resName, flags, bgSurface);
+ loadMadsV2Background(_sceneId, resName, flags, bgSurface);
+ loadPalette(_sceneId, _sceneId, resName, flags, bgSurface);
}
Common::Array<SpriteAsset *> spriteSets;
@@ -334,7 +333,7 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
// Get the ART resource
if (sceneFlag) {
- resourceName = Resources::formatName(RESPREFIX_RM, _artFileNum, ".ART");
+ resourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".ART");
} else {
resourceName = "*" + Resources::formatResource(resName, resName);
}
@@ -347,9 +346,27 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
assert(_width == bgSurface.w && _height == bgSurface.h);
stream = artResource.getItemStream(1);
stream->read(bgSurface.getPixels(), bgSurface.w * bgSurface.h);
+ delete stream;
+
+ if (flags & SCENEFLAG_TRANSLATE) {
+ // Load in the palette and translate it
+ Common::SeekableReadStream *palStream = artResource.getItemStream(0);
+ Common::Array<RGB6> palette;
+
+ palStream->skip(4); // Skip width and height
+ int numColors = palStream->readUint16LE();
+ assert(numColors <= 252);
+ palette.resize(numColors);
+ for (int i = 0; i < numColors; ++i)
+ palette[i].load(palStream);
+ delete palStream;
+
+ // Translate the surface
+ _vm->_palette->_paletteUsage.process(palette, 0);
+ bgSurface.translate(palette);
+ }
// Close the ART file
- delete stream;
artFile.close();
}
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
index 783a9ab8a9..41e094b8f5 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/scene_data.h
@@ -55,7 +55,8 @@ class SpriteSlot;
enum {
SCENEFLAG_DITHER = 0x01, // Dither to 16 colors
- SCENEFLAG_LOAD_SHADOW = 0x10 // Load hard shadows
+ SCENEFLAG_LOAD_SHADOW = 0x10, // Load hard shadows
+ SCENEFLAG_TRANSLATE = 0x10000 // Translate palette of loaded background
};
class VerbInit {
diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp
index 7e8710db56..590e63ac9e 100644
--- a/engines/mads/screen.cpp
+++ b/engines/mads/screen.cpp
@@ -212,24 +212,22 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common:
Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
+ Common::Point destPos(bounds.left, bounds.top);
if ((*this)[i]._active && bounds.isValidRect()) {
- srcSurface->copyTo(destSurface, bounds, Common::Point(bounds.left, bounds.top));
+ srcSurface->copyTo(destSurface, bounds, destPos);
}
}
}
-void DirtyAreas::copyToScreen(const Common::Point &posAdjust) {
+void DirtyAreas::copyToScreen() {
for (uint i = 0; i < size(); ++i) {
- const Common::Rect &srcBounds = (*this)[i]._bounds;
+ const Common::Rect &bounds = (*this)[i]._bounds;
// Check if this is a sane rectangle before attempting to create it
- if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom)
+ if (bounds.left >= bounds.right || bounds.top >= bounds.bottom)
continue;
- Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
- srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
-
if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) {
_vm->_screen.copyRectToScreen(bounds);
}
@@ -559,23 +557,32 @@ void ScreenObjects::synchronize(Common::Serializer &s) {
ScreenSurface::ScreenSurface() {
_shakeCountdown = -1;
_random = 0x4D2;
+ _surfacePixels = nullptr;
}
void ScreenSurface::init() {
- setSize(g_system->getWidth(), g_system->getHeight());
-}
+ // Set the size for the screen
+ setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
-void ScreenSurface::copyRectToScreen(const Common::Point &destPos,
- const Common::Rect &bounds) {
- const byte *buf = getBasePtr(destPos.x, destPos.y);
+ // Store a copy of the raw pixels pointer for the screen, since the surface
+ // itself may be later changed to only a subset of the screen
+ _surfacePixels = (byte *)getPixels();
+ _freeFlag = false;
+}
- if (bounds.width() != 0 && bounds.height() != 0)
- g_system->copyRectToScreen(buf, this->pitch, bounds.left, bounds.top,
- bounds.width(), bounds.height());
+ScreenSurface::~ScreenSurface() {
+ delete[] _surfacePixels;
}
void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) {
- copyRectToScreen(Common::Point(bounds.left, bounds.top), bounds);
+ const byte *buf = getBasePtr(bounds.left, bounds.top);
+
+ Common::Rect destBounds = bounds;
+ destBounds.translate(_clipBounds.left, _clipBounds.top);
+
+ if (bounds.width() != 0 && bounds.height() != 0)
+ g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top,
+ destBounds.width(), destBounds.height());
}
void ScreenSurface::updateScreen() {
@@ -628,21 +635,28 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag
case kTransitionBoxInBottomRight:
case kTransitionBoxInTopLeft:
case kTransitionBoxInTopRight:
- error("TODO: transition");
+ warning("TODO: box transition");
+ transition(kTransitionFadeIn, surfaceFlag);
break;
case kTransitionPanLeftToRight:
case kTransitionPanRightToLeft:
- error("TODO: transition");
+ warning("TODO: pan transition");
+ transition(kTransitionFadeIn, surfaceFlag);
+ break;
case kTransitionCircleIn1:
case kTransitionCircleIn2:
case kTransitionCircleIn3:
case kTransitionCircleIn4:
- error("TODO circle transition");
+ warning("TODO circle transition");
+ transition(kTransitionFadeIn, surfaceFlag);
+ break;
case kCenterVertTransition:
- error("TODO: center vert transition");
+ warning("TODO: center vert transition");
+ transition(kTransitionFadeIn, surfaceFlag);
+ break;
default:
// Quick transitions
@@ -650,4 +664,15 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag
}
}
+void ScreenSurface::setClipBounds(const Common::Rect &r) {
+ _clipBounds = r;
+ setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height());
+ this->pitch = MADS_SCREEN_WIDTH;
+}
+
+void ScreenSurface::resetClipBounds() {
+ setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+}
+
+
} // End of namespace MADS
diff --git a/engines/mads/screen.h b/engines/mads/screen.h
index 7937e15456..9d01ca82e3 100644
--- a/engines/mads/screen.h
+++ b/engines/mads/screen.h
@@ -117,8 +117,8 @@ public:
/**
* Use the lsit of dirty areas to copy areas of the screen surface to
* the physical screen
- * @param posAdjust Position adjustment */
- void copyToScreen(const Common::Point &posAdjust);
+ */
+ void copyToScreen();
void reset();
};
@@ -205,8 +205,9 @@ public:
class ScreenSurface : public MSurface {
private:
uint16 _random;
+ byte *_surfacePixels;
+ Common::Rect _clipBounds;
public:
- Common::Point _offset;
int _shakeCountdown;
public:
/**
@@ -215,17 +216,14 @@ public:
ScreenSurface();
/**
- * Initialize the surface
+ * Destructor
*/
- void init();
+ ~ScreenSurface();
/**
- * Copys an area of the screen surface to a given destination position on
- * the ScummVM physical screen buffer
- * @param destPos Destination position
- * @param bounds Area of screen surface to copy
+ * Initialize the surface
*/
- void copyRectToScreen(const Common::Point &destPos, const Common::Rect &bounds);
+ void init();
/**
* Copys an area of the screen surface to the ScmmVM physical screen buffer
@@ -239,6 +237,12 @@ public:
void updateScreen();
void transition(ScreenTransition transitionType, bool surfaceFlag);
+
+ void setClipBounds(const Common::Rect &r);
+
+ void resetClipBounds();
+
+ const Common::Rect &getClipBounds() { return _clipBounds; }
};
} // End of namespace MADS
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
index bd99aed2f4..12109895b5 100644
--- a/engines/mads/sound.cpp
+++ b/engines/mads/sound.cpp
@@ -29,9 +29,10 @@
namespace MADS {
-SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
+SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer, FM_OPL *opl) {
_vm = vm;
_mixer = mixer;
+ _opl = opl;
_driver = nullptr;
_pollSoundEnabled = false;
_soundPollFlag = false;
@@ -49,31 +50,32 @@ void SoundManager::init(int sectionNumber) {
case GType_RexNebular:
switch (sectionNumber) {
case 1:
- _driver = new Nebular::ASound1(_mixer);
+ _driver = new Nebular::ASound1(_mixer, _opl);
break;
case 2:
- _driver = new Nebular::ASound2(_mixer);
+ _driver = new Nebular::ASound2(_mixer, _opl);
break;
case 3:
- _driver = new Nebular::ASound3(_mixer);
+ _driver = new Nebular::ASound3(_mixer, _opl);
break;
case 4:
- _driver = new Nebular::ASound4(_mixer);
+ _driver = new Nebular::ASound4(_mixer, _opl);
break;
case 5:
- _driver = new Nebular::ASound5(_mixer);
+ _driver = new Nebular::ASound5(_mixer, _opl);
break;
case 6:
- _driver = new Nebular::ASound6(_mixer);
+ _driver = new Nebular::ASound6(_mixer, _opl);
break;
case 7:
- _driver = new Nebular::ASound7(_mixer);
+ _driver = new Nebular::ASound7(_mixer, _opl);
break;
case 8:
- _driver = new Nebular::ASound8(_mixer);
+ _driver = new Nebular::ASound8(_mixer, _opl);
break;
case 9:
- error("Sound driver 9 not implemented");
+ _driver = new Nebular::ASound9(_mixer, _opl);
+ break;
default:
_driver = nullptr;
break;
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
index 9a251f9dd0..b2af7e2346 100644
--- a/engines/mads/sound.h
+++ b/engines/mads/sound.h
@@ -37,13 +37,14 @@ class SoundManager {
private:
MADSEngine *_vm;
Audio::Mixer *_mixer;
+ FM_OPL *_opl;
Nebular::ASound *_driver;
bool _pollSoundEnabled;
bool _soundPollFlag;
bool _newSoundsPaused;
Common::Queue<int> _queuedCommands;
public:
- SoundManager(MADSEngine *vm, Audio::Mixer *mixer);
+ SoundManager(MADSEngine *vm, Audio::Mixer *mixer, FM_OPL *opl);
~SoundManager();
/**
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 8a9c0f70fa..7632cde294 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -294,7 +294,7 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version 1.? (5CD)
+ // Version 1.? (5CD) - Spanish
// From jvprat
{
{
@@ -312,6 +312,24 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.0 (5CD) - Italian
+ // From dodomorandi on bug #6629
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1("a_Data.MHK", "0e21e89df7788f32056b6521abf2e81a"),
+ Common::IT_ITA,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.? (DVD, From "Myst 10th Anniversary Edition")
// From Clone2727
{
diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp
index 710c36ac8d..d8dbeef641 100644
--- a/engines/mohawk/myst_stacks/stoneship.cpp
+++ b/engines/mohawk/myst_stacks/stoneship.cpp
@@ -42,6 +42,7 @@ Stoneship::Stoneship(MohawkEngine_Myst *vm) :
_tunnelRunning = false;
+ _state.lightState = 0;
_state.generatorDepletionTime = 0;
_state.generatorDuration = 0;
_cabinMystBookPresent = 0;
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index d07aa9d5ec..3e54017df8 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -100,6 +100,9 @@ bool MystGameState::load(const Common::String &filename) {
syncGameState(s, size == 664);
delete loadFile;
+ // Set Channelwood elevator state to down, because we start on the lower level
+ _channelwood.elevatorState = 0;
+
// Switch us back to the intro stack, to the linking book
_vm->changeToStack(kIntroStack, 5, 0, 0);
diff --git a/engines/mortevielle/detection_tables.h b/engines/mortevielle/detection_tables.h
index 3e1e5aaefe..0aa27b89eb 100644
--- a/engines/mortevielle/detection_tables.h
+++ b/engines/mortevielle/detection_tables.h
@@ -57,21 +57,21 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = {
},
// German, improved translation
- {
- {
- "mortevielle",
- "Improved Translation",
- {
- {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144},
- {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO0()
- }, Common::DE_DEU, kUseEngineDataFile
- },
+// {
+// {
+// "mortevielle",
+// "Improved Translation",
+// {
+// {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144},
+// {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744},
+// AD_LISTEND
+// },
+// Common::DE_DEU,
+// Common::kPlatformDOS,
+// ADGF_NO_FLAGS,
+// GUIO0()
+// }, Common::DE_DEU, kUseEngineDataFile
+// },
// DOS English version doesn't exist. Technically, they are French or German versions,
// using English strings stored mort.dat
diff --git a/engines/neverhood/graphics.cpp b/engines/neverhood/graphics.cpp
index 939428ed19..89792d2659 100644
--- a/engines/neverhood/graphics.cpp
+++ b/engines/neverhood/graphics.cpp
@@ -114,7 +114,15 @@ void BaseSurface::drawMouseCursorResource(MouseCursorResource &mouseCursorResour
}
void BaseSurface::copyFrom(Graphics::Surface *sourceSurface, int16 x, int16 y, NDrawRect &sourceRect) {
- // Copy a rectangle from sourceSurface, no clipping is performed, 0 is the transparent color
+ // Copy a rectangle from sourceSurface, 0 is the transparent color
+ // Clipping is performed against the right/bottom border since x, y will always be >= 0
+
+ if (x + sourceRect.width > _surface->w)
+ sourceRect.width = _surface->w - x - 1;
+
+ if (y + sourceRect.height > _surface->h)
+ sourceRect.height = _surface->h - y - 1;
+
byte *source = (byte*)sourceSurface->getBasePtr(sourceRect.x, sourceRect.y);
byte *dest = (byte*)_surface->getBasePtr(x, y);
int height = sourceRect.height;
diff --git a/engines/neverhood/modules/module1400.cpp b/engines/neverhood/modules/module1400.cpp
index 551b6874ff..465ad5909a 100644
--- a/engines/neverhood/modules/module1400.cpp
+++ b/engines/neverhood/modules/module1400.cpp
@@ -709,13 +709,14 @@ Scene1405::Scene1405(NeverhoodEngine *vm, Module *parentModule)
void Scene1405::update() {
Scene::update();
+ // Check if the player chose a wrong tile, in which case the whole grid gets reset
if (_countdown != 0 && (--_countdown == 0)) {
_tilesLeft = 48;
- _tiles[_firstTileIndex]->hide();
- _tiles[_secondTileIndex]->hide();
+ _tiles[_firstTileIndex]->hide(true);
+ _tiles[_secondTileIndex]->hide(false);
for (uint32 i = 0; i < 48; i++) {
if (getSubVar(VA_IS_TILE_MATCH, i)) {
- _tiles[i]->hide();
+ _tiles[i]->hide(false);
setSubVar(VA_IS_TILE_MATCH, i, 0);
}
}
diff --git a/engines/neverhood/modules/module1400_sprites.cpp b/engines/neverhood/modules/module1400_sprites.cpp
index 30a5c340c9..99a2a314a7 100644
--- a/engines/neverhood/modules/module1400_sprites.cpp
+++ b/engines/neverhood/modules/module1400_sprites.cpp
@@ -873,10 +873,11 @@ void AsScene1405Tile::show() {
}
}
-void AsScene1405Tile::hide() {
+void AsScene1405Tile::hide(bool playClickSound) {
if (_isShowing) {
_isShowing = false;
- playSound(0);
+ if (playClickSound)
+ playSound(0);
setVisible(false);
}
}
diff --git a/engines/neverhood/modules/module1400_sprites.h b/engines/neverhood/modules/module1400_sprites.h
index fe0db66d27..e709193aab 100644
--- a/engines/neverhood/modules/module1400_sprites.h
+++ b/engines/neverhood/modules/module1400_sprites.h
@@ -155,7 +155,7 @@ class AsScene1405Tile : public AnimatedSprite {
public:
AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 tileIndex);
void show();
- void hide();
+ void hide(bool playClickSound);
protected:
Scene1405 *_parentScene;
bool _isShowing;
diff --git a/engines/neverhood/modules/module1600_sprites.cpp b/engines/neverhood/modules/module1600_sprites.cpp
index 09e3d0afe1..6a4de86517 100644
--- a/engines/neverhood/modules/module1600_sprites.cpp
+++ b/engines/neverhood/modules/module1600_sprites.cpp
@@ -30,6 +30,8 @@ AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16
createSurface(200, 556, 328);
_x = x;
_y = y;
+ _destX = x;
+ _destY = y;
_inMainArea = false;
_exitDirection = 0;
@@ -48,6 +50,7 @@ AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16
_soundCounter = 0;
_pathPoints = NULL;
_currMoveDirection = 0;
+ _newMoveDirection = 0;
startAnimation(0xD4220027, 0, -1);
setDoDeltaX(getGlobalVar(V_CAR_DELTA_X));
diff --git a/engines/neverhood/sprite.cpp b/engines/neverhood/sprite.cpp
index a566b8ee3b..3611ce1ba2 100644
--- a/engines/neverhood/sprite.cpp
+++ b/engines/neverhood/sprite.cpp
@@ -31,8 +31,20 @@ Sprite::Sprite(NeverhoodEngine *vm, int objectPriority)
: Entity(vm, objectPriority), _x(0), _y(0), _spriteUpdateCb(NULL), _filterXCb(NULL), _filterYCb(NULL),
_dataResource(vm), _doDeltaX(false), _doDeltaY(false), _needRefresh(false), _flags(0), _surface(NULL) {
- SetMessageHandler(&Sprite::handleMessage);
+ _drawOffset.x = 0;
+ _drawOffset.y = 0;
+ _drawOffset.width = 0;
+ _drawOffset.height = 0;
+ _collisionBounds.x1 = 0;
+ _collisionBounds.y1 = 0;
+ _collisionBounds.x2 = 0;
+ _collisionBounds.y2 = 0;
+ _collisionBoundsOffset.x = 0;
+ _collisionBoundsOffset.y = 0;
+ _collisionBoundsOffset.width = 0;
+ _collisionBoundsOffset.height = 0;
+ SetMessageHandler(&Sprite::handleMessage);
}
Sprite::~Sprite() {
diff --git a/engines/pegasus/energymonitor.cpp b/engines/pegasus/energymonitor.cpp
index 40e54afb89..d3cc208e41 100644
--- a/engines/pegasus/energymonitor.cpp
+++ b/engines/pegasus/energymonitor.cpp
@@ -68,7 +68,9 @@ void Blinker::timeChanged(const TimeValue time) {
}
}
-static const NotificationFlags kEnergyExpiredFlag = 1;
+enum {
+ kEnergyExpiredFlag = 1
+};
EnergyMonitor *g_energyMonitor = 0;
diff --git a/engines/pegasus/interaction.cpp b/engines/pegasus/interaction.cpp
new file mode 100644
index 0000000000..143bdebaba
--- /dev/null
+++ b/engines/pegasus/interaction.cpp
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/interaction.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+GameInteraction::GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler(nextHandler) {
+ _isInteracting = false;
+ _savedHandler = 0;
+ _owner = nextHandler;
+}
+
+} // End of namespace Pegasus
+
diff --git a/engines/pegasus/interaction.h b/engines/pegasus/interaction.h
index 293ee6be83..ca168b4cb7 100644
--- a/engines/pegasus/interaction.h
+++ b/engines/pegasus/interaction.h
@@ -37,11 +37,7 @@ class Neighborhood;
class GameInteraction : public IDObject, public InputHandler {
public:
- GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler((InputHandler *)nextHandler) {
- _isInteracting = false;
- _savedHandler = 0;
- _owner = nextHandler;
- }
+ GameInteraction(const InteractionID id, Neighborhood *nextHandler);
// If the interaction is open (_isInteracting == true), it's too late to do anything
// about it here.
diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk
index cb44a04171..6d69d6ea58 100644
--- a/engines/pegasus/module.mk
+++ b/engines/pegasus/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS = \
graphics.o \
hotspot.o \
input.o \
+ interaction.o \
interface.o \
menu.o \
movie.o \
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
index 9d2d6723a9..ed52851338 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -42,109 +42,119 @@
namespace Pegasus {
-static const int16 kVidPhoneAngle = 30;
-static const int16 kReplicatorAngle = 50;
-static const int16 kDrawersAngle = -30;
-static const int16 kCaldoria53Angle = 45;
-static const int16 kCaldoria55Angle = -45;
+enum {
+ kVidPhoneAngle = 30,
+ kReplicatorAngle = 50,
+ kDrawersAngle = -30,
+ kCaldoria53Angle = 45,
+ kCaldoria55Angle = -45
+};
-static const TimeValue kSinclairInterruptionTime1 = 2955;
-static const TimeValue kSinclairInterruptionTime2 = 6835;
-static const TimeValue kSinclairInterruptionTime3 = 9835;
-static const TimeValue kSinclairInterruptionTime4 = 12555;
+enum {
+ kSinclairInterruptionTime1 = 2955,
+ kSinclairInterruptionTime2 = 6835,
+ kSinclairInterruptionTime3 = 9835,
+ kSinclairInterruptionTime4 = 12555
+};
-static const InputBits kPullbackInterruptFilter = kFilterAllInput;
-static const InputBits kRecalibrationInterruptFilter = kFilterAllInput;
+enum {
+ kPullbackInterruptFilter = kFilterAllInput,
+ kRecalibrationInterruptFilter = kFilterAllInput
+};
-static const TimeValue kCaldoriaReplicatorIntroIn = 4933;
-static const TimeValue kCaldoriaReplicatorIntroOut = 6557;
+enum {
+ kCaldoriaReplicatorIntroIn = 4933,
+ kCaldoriaReplicatorIntroOut = 6557,
-static const TimeValue kCaldoriaReplicatorWrongChoiceIn = 6557;
-static const TimeValue kCaldoriaReplicatorWrongChoiceOut = 8586;
+ kCaldoriaReplicatorWrongChoiceIn = 6557,
+ kCaldoriaReplicatorWrongChoiceOut = 8586,
-static const TimeValue kCaldoriaReplicatorOJChoiceIn = 8586;
-static const TimeValue kCaldoriaReplicatorOJChoiceOut = 11687;
+ kCaldoriaReplicatorOJChoiceIn = 8586,
+ kCaldoriaReplicatorOJChoiceOut = 11687,
-static const TimeValue kCaldoriaMessagesIntroIn = 11687;
-static const TimeValue kCaldoriaMessagesIntroOut = 13641;
+ kCaldoriaMessagesIntroIn = 11687,
+ kCaldoriaMessagesIntroOut = 13641,
-static const TimeValue kCaldoriaFirstMessageIn = 13641;
-static const TimeValue kCaldoriaFirstMessageOut = 14203;
+ kCaldoriaFirstMessageIn = 13641,
+ kCaldoriaFirstMessageOut = 14203,
-static const TimeValue kCaldoriaSecondMessageIn = 14203;
-static const TimeValue kCaldoriaSecondMessageOut = 14750;
+ kCaldoriaSecondMessageIn = 14203,
+ kCaldoriaSecondMessageOut = 14750,
-static const TimeValue kCaldoriaDoorCloseIn = 14750;
-static const TimeValue kCaldoriaDoorCloseOut = 15472;
+ kCaldoriaDoorCloseIn = 14750,
+ kCaldoriaDoorCloseOut = 15472,
-static const TimeValue kCaldoriaElevatorCloseIn = 15472;
-static const TimeValue kCaldoriaElevatorCloseOut = 16336;
+ kCaldoriaElevatorCloseIn = 15472,
+ kCaldoriaElevatorCloseOut = 16336,
-static const TimeValue kCaldoriaShowerCloseIn = 16336;
-static const TimeValue kCaldoriaShowerCloseOut = 17101;
+ kCaldoriaShowerCloseIn = 16336,
+ kCaldoriaShowerCloseOut = 17101,
-static const TimeValue kCaldoriaGTDoorCloseIn = 17101;
-static const TimeValue kCaldoriaGTDoorCloseOut = 18523;
+ kCaldoriaGTDoorCloseIn = 17101,
+ kCaldoriaGTDoorCloseOut = 18523,
-static const TimeValue kCaldoriaNobodyHomeIn = 18523;
-static const TimeValue kCaldoriaNobodyHomeOut = 21469;
+ kCaldoriaNobodyHomeIn = 18523,
+ kCaldoriaNobodyHomeOut = 21469,
-static const TimeValue kCaldoriaNoOtherFloorIn = 21469;
-static const TimeValue kCaldoriaNoOtherFloorOut = 28013;
+ kCaldoriaNoOtherFloorIn = 21469,
+ kCaldoriaNoOtherFloorOut = 28013,
-static const TimeValue kCaldoria4DInstructionsIn = 28013;
-static const TimeValue kCaldoria4DInstructionsOut = 29730;
+ kCaldoria4DInstructionsIn = 28013,
+ kCaldoria4DInstructionsOut = 29730,
-static const TimeValue kCaldoriaDrinkOJIn = 33910;
-static const TimeValue kCaldoriaDrinkOJOut = 35846;
+ kCaldoriaDrinkOJIn = 33910,
+ kCaldoriaDrinkOJOut = 35846,
-static const TimeValue kCaldoriaNoOtherDestinationIn = 35846;
-static const TimeValue kCaldoriaNoOtherDestinationOut = 37877;
+ kCaldoriaNoOtherDestinationIn = 35846,
+ kCaldoriaNoOtherDestinationOut = 37877,
-static const TimeValue kCaldoriaUhghIn = 37877;
-static const TimeValue kCaldoriaUhghOut = 38025;
+ kCaldoriaUhghIn = 37877,
+ kCaldoriaUhghOut = 38025,
-static const TimeValue kCaldoriaSinclairShootsOSIn = 38025;
-static const TimeValue kCaldoriaSinclairShootsOSOut = 40649;
+ kCaldoriaSinclairShootsOSIn = 38025,
+ kCaldoriaSinclairShootsOSOut = 40649,
-static const TimeValue kCaldoriaScreamingAfterIn = 40649;
-static const TimeValue kCaldoriaScreamingAfterOut = 47661;
+ kCaldoriaScreamingAfterIn = 40649,
+ kCaldoriaScreamingAfterOut = 47661
+};
-static const TimeValue k4FloorTime = 0;
+enum {
+ k4FloorTime = 0,
-static const TimeValue k4To1Start = 40;
-static const TimeValue k4To1Stop = 7720;
+ k4To1Start = 40,
+ k4To1Stop = 7720,
-static const TimeValue k4To5Start = 7720;
-static const TimeValue k4To5Stop = 10280;
+ k4To5Start = 7720,
+ k4To5Stop = 10280,
-static const TimeValue k4To2Time = 10280;
+ k4To2Time = 10280,
-static const TimeValue k4To3Time = 10320;
+ k4To3Time = 10320,
-static const TimeValue k1FloorTime = 10360;
+ k1FloorTime = 10360,
-static const TimeValue k1To4Start = 10400;
-static const TimeValue k1To4Stop = 18080;
+ k1To4Start = 10400,
+ k1To4Stop = 18080,
-static const TimeValue k1To5Start = 18080;
-static const TimeValue k1To5Stop = 28320;
+ k1To5Start = 18080,
+ k1To5Stop = 28320,
-static const TimeValue k1To2Time = 28320;
+ k1To2Time = 28320,
-static const TimeValue k1To3Time = 28360;
+ k1To3Time = 28360,
-static const TimeValue k5FloorTime = 28400;
+ k5FloorTime = 28400,
-static const TimeValue k5To1Start = 28440;
-static const TimeValue k5To1Stop = 38680;
+ k5To1Start = 28440,
+ k5To1Stop = 38680,
-static const TimeValue k5To4Start = 38680;
-static const TimeValue k5To4Stop = 41240;
+ k5To4Start = 38680,
+ k5To4Stop = 41240,
-static const TimeValue k5To2Time = 41240;
+ k5To2Time = 41240,
-static const TimeValue k5To3Time = 41280;
+ k5To3Time = 41280
+};
// FuseFunction functions...
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
index 0494753661..688fb7860d 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
@@ -30,34 +30,36 @@
namespace Pegasus {
-static const TimeValue kSwitchableSlop = 3 * kCaldoriaFrameDuration;
-// Two seconds - some slop
-static const TimeValue kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop;
-// Twelve frames + some slop
-static const TimeValue kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop;
+enum {
+ kSwitchableSlop = 3 * kCaldoriaFrameDuration,
+ // Two seconds - some slop
+ kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop,
+ // Twelve frames + some slop
+ kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop,
-static const TimeValue kSwitchable1Start = 0;
-static const TimeValue kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration;
+ kSwitchable1Start = 0,
+ kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration,
-static const TimeValue kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration;
-static const TimeValue kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration;
+ kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration,
+ kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration,
-static const TimeValue kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration;
-static const TimeValue kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration;
+ kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration,
+ kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration,
-static const NotificationFlags kVidPhoneDoneFlag = 1;
+ kVidPhoneDoneFlag = 1,
-static const TimeValue kRockMusicLoopIn = 0;
-static const TimeValue kRockMusicLoopOut = 2088;
+ kRockMusicLoopIn = 0,
+ kRockMusicLoopOut = 2088,
-static const TimeValue kOrchestralMusicLoopIn = 2088;
-static const TimeValue kOrchestralMusicLoopOut = 4985;
+ kOrchestralMusicLoopIn = 2088,
+ kOrchestralMusicLoopOut = 4985,
-static const TimeValue kRhythmsMusicLoopIn = 4985;
-static const TimeValue kRhythmsMusicLoopOut = 6824;
+ kRhythmsMusicLoopIn = 4985,
+ kRhythmsMusicLoopOut = 6824,
-static const TimeValue kAcousticMusicLoopIn = 6824;
-static const TimeValue kAcousticMusicLoopOut = 9387;
+ kAcousticMusicLoopIn = 6824,
+ kAcousticMusicLoopOut = 9387
+};
enum {
k4DVideoMenu,
diff --git a/engines/pegasus/neighborhood/mars/shuttlehud.cpp b/engines/pegasus/neighborhood/mars/shuttlehud.cpp
index 11e826278b..2d894f7b95 100644
--- a/engines/pegasus/neighborhood/mars/shuttlehud.cpp
+++ b/engines/pegasus/neighborhood/mars/shuttlehud.cpp
@@ -30,26 +30,28 @@
namespace Pegasus {
-static const CoordType kHUDTargetGridLeft = kShuttleWindowLeft + 16;
-static const CoordType kHUDTargetGridTop = kShuttleWindowTop + 8;
-static const CoordType kHUDTargetGridWidth = 328;
-static const CoordType kHUDTargetGridHeight = 206;
-
-static const CoordType kHUDRS232Left = kHUDTargetGridLeft + 264;
-static const CoordType kHUDRS232Top = kHUDTargetGridTop + 2;
-
-static const CoordType kHUDLockLeft = kShuttleWindowLeft + 101;
-static const CoordType kHUDLockTop = kShuttleWindowTop + 49;
-static const CoordType kHUDLockWidth = 145;
-static const CoordType kHUDLockHeight = 124;
-
-static const CoordType kTractorLockWidth = 50;
-static const CoordType kTractorLockHeight = 30;
-
-static const CoordType kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2;
-static const CoordType kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2;
-static const CoordType kTractorLockRight = kTractorLockLeft + kTractorLockWidth;
-static const CoordType kTractorLockBottom = kTractorLockTop + kTractorLockHeight;
+enum {
+ kHUDTargetGridLeft = kShuttleWindowLeft + 16,
+ kHUDTargetGridTop = kShuttleWindowTop + 8,
+ kHUDTargetGridWidth = 328,
+ kHUDTargetGridHeight = 206,
+
+ kHUDRS232Left = kHUDTargetGridLeft + 264,
+ kHUDRS232Top = kHUDTargetGridTop + 2,
+
+ kHUDLockLeft = kShuttleWindowLeft + 101,
+ kHUDLockTop = kShuttleWindowTop + 49,
+ kHUDLockWidth = 145,
+ kHUDLockHeight = 124,
+
+ kTractorLockWidth = 50,
+ kTractorLockHeight = 30,
+
+ kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2,
+ kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2,
+ kTractorLockRight = kTractorLockLeft + kTractorLockWidth,
+ kTractorLockBottom = kTractorLockTop + kTractorLockHeight
+};
static const uint16 s_RS232Data[] = {
0xF0E1, 0xCE70,
diff --git a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
index e2a0267231..1478a74744 100644
--- a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
@@ -45,7 +45,9 @@ static const TimeValue kSection2Start = 26;
static const TimeValue kSection2Stop = 1000;
// Seems to be a good value for a 20 second pan.
-static const CoordType kPanPixelsPerFrame = 8;
+enum {
+ kPanPixelsPerFrame = 8
+};
// Interesting times are in seconds.
static const TimeValue s_ECRInterestingTimes[] = {
diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
index 3491f161c7..e85a3e699f 100644
--- a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
@@ -65,64 +65,66 @@ static const ItemID kCO2Item = 10000;
static const ItemID kHeItem = 10001;
// Interactive points.
-static const TimeValue kFSPowerUpStartStart = 0;
-static const TimeValue kFSPowerUpStartStop = 600;
-static const TimeValue kFSSplashStart = 600;
-static const TimeValue kFSSplashStop = 7800;
-static const TimeValue kFSSplashIntakeStart = 7800;
-static const TimeValue kFSSplashIntakeStop = 18600;
-
-static const TimeValue kFSMainMenu = 18600;
-static const TimeValue kFSIntakeHiliteStart = 19200;
-static const TimeValue kFSIntakeHiliteStop = 19800;
-static const TimeValue kFSDispenseHiliteStart = 19800;
-static const TimeValue kFSDispenseHiliteStop = 20400;
-
-static const TimeValue kFSDispenseMenu = 20400;
-
-static const TimeValue kFSArHiliteStart = 21000;
-static const TimeValue kFSArHiliteStop = 21600;
-static const TimeValue kFSArAttach = 21600;
-static const TimeValue kFSArFilledStart = 22200;
-static const TimeValue kFSArFilledStop = 25200;
-static const TimeValue kFSArIncompatibleStart = 25200;
-static const TimeValue kFSArIncompatibleStop = 30000;
-
-static const TimeValue kFSCO2HiliteStart = 30000;
-static const TimeValue kFSCO2HiliteStop = 30600;
-static const TimeValue kFSCO2Attach = 30600;
-static const TimeValue kFSCO2FilledStart = 31200;
-static const TimeValue kFSCO2FilledStop = 34200;
-static const TimeValue kFSCO2IncompatibleStart = 34200;
-static const TimeValue kFSCO2IncompatibleStop = 39000;
-
-static const TimeValue kFSHeHiliteStart = 39000;
-static const TimeValue kFSHeHiliteStop = 39600;
-static const TimeValue kFSHeAttach = 39600;
-static const TimeValue kFSHeFilledStart = 40200;
-static const TimeValue kFSHeFilledStop = 43200;
-static const TimeValue kFSHeIncompatibleStart = 43200;
-static const TimeValue kFSHeIncompatibleStop = 48000;
-
-static const TimeValue kFSOHiliteStart = 48000;
-static const TimeValue kFSOHiliteStop = 48600;
-static const TimeValue kFSOAttach = 48600;
-static const TimeValue kFSOFilledStart = 49200;
-static const TimeValue kFSOFilledStop = 52200;
-static const TimeValue kFSOIncompatibleStart = 52200;
-static const TimeValue kFSOIncompatibleStop = 57000;
-
-static const TimeValue kFSNHiliteStart = 57000;
-static const TimeValue kFSNHiliteStop = 57600;
-static const TimeValue kFSNAttach = 57600;
-static const TimeValue kFSNFilledStart = 58200;
-static const TimeValue kFSNFilledStop = 61200;
-static const TimeValue kFSNIncompatibleStart = 61200;
-static const TimeValue kFSNIncompatibleStop = 66000;
-
-static const TimeValue kFSIntakeMenu = 66000;
-static const TimeValue kFSIntakeInProgressStart = 66600;
-static const TimeValue kFSIntakeInProgressStop = 69600;
+enum {
+ kFSPowerUpStartStart = 0,
+ kFSPowerUpStartStop = 600,
+ kFSSplashStart = 600,
+ kFSSplashStop = 7800,
+ kFSSplashIntakeStart = 7800,
+ kFSSplashIntakeStop = 18600,
+
+ kFSMainMenu = 18600,
+ kFSIntakeHiliteStart = 19200,
+ kFSIntakeHiliteStop = 19800,
+ kFSDispenseHiliteStart = 19800,
+ kFSDispenseHiliteStop = 20400,
+
+ kFSDispenseMenu = 20400,
+
+ kFSArHiliteStart = 21000,
+ kFSArHiliteStop = 21600,
+ kFSArAttach = 21600,
+ kFSArFilledStart = 22200,
+ kFSArFilledStop = 25200,
+ kFSArIncompatibleStart = 25200,
+ kFSArIncompatibleStop = 30000,
+
+ kFSCO2HiliteStart = 30000,
+ kFSCO2HiliteStop = 30600,
+ kFSCO2Attach = 30600,
+ kFSCO2FilledStart = 31200,
+ kFSCO2FilledStop = 34200,
+ kFSCO2IncompatibleStart = 34200,
+ kFSCO2IncompatibleStop = 39000,
+
+ kFSHeHiliteStart = 39000,
+ kFSHeHiliteStop = 39600,
+ kFSHeAttach = 39600,
+ kFSHeFilledStart = 40200,
+ kFSHeFilledStop = 43200,
+ kFSHeIncompatibleStart = 43200,
+ kFSHeIncompatibleStop = 48000,
+
+ kFSOHiliteStart = 48000,
+ kFSOHiliteStop = 48600,
+ kFSOAttach = 48600,
+ kFSOFilledStart = 49200,
+ kFSOFilledStop = 52200,
+ kFSOIncompatibleStart = 52200,
+ kFSOIncompatibleStop = 57000,
+
+ kFSNHiliteStart = 57000,
+ kFSNHiliteStop = 57600,
+ kFSNAttach = 57600,
+ kFSNFilledStart = 58200,
+ kFSNFilledStop = 61200,
+ kFSNIncompatibleStart = 61200,
+ kFSNIncompatibleStop = 66000,
+
+ kFSIntakeMenu = 66000,
+ kFSIntakeInProgressStart = 66600,
+ kFSIntakeInProgressStop = 69600
+};
NoradAlphaFillingStation::NoradAlphaFillingStation(Neighborhood *owner) : GameInteraction(kNoradFillingStationInteractionID, owner),
_rightSideMovie(kN01RightSideID), _rightSideNotification(kNoradFillingStationNotificationID, ((PegasusEngine *)g_engine)) {
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
index 5c321a8e8a..9ea3036024 100644
--- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
@@ -394,20 +394,22 @@ static const NotificationFlags kGlobeNotificationFlags = kGlobeSplash1Finished |
kGlobeTimerExpired |
kMaxDeactivatedFinished;
-static const int16 kSplash1End = 4;
-static const int16 kSplash2End = 5;
-static const int16 kSplash3Start = 8;
-static const int16 kSplash3Stop = 9;
-static const int16 kSplash4Start = 9;
-static const int16 kSplash4Stop = 10;
-static const int16 kNewLaunchSiloTime = 10;
-static const int16 kSiloDeactivatedTime = 11;
-static const int16 kMissileLaunchedTime = 12;
-static const int16 kMaxDeactivatedStart = 13;
-static const int16 kMaxDeactivatedStop = 23;
-
-static const int16 kGamePlaying = 1;
-static const int16 kGameOver = 2;
+enum {
+ kSplash1End = 4,
+ kSplash2End = 5,
+ kSplash3Start = 8,
+ kSplash3Stop = 9,
+ kSplash4Start = 9,
+ kSplash4Stop = 10,
+ kNewLaunchSiloTime = 10,
+ kSiloDeactivatedTime = 11,
+ kMissileLaunchedTime = 12,
+ kMaxDeactivatedStart = 13,
+ kMaxDeactivatedStop = 23,
+
+ kGamePlaying = 1,
+ kGameOver = 2
+};
enum {
kGameIntro,
diff --git a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
index d48481e925..1b14c529d8 100644
--- a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
+++ b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
@@ -34,110 +34,113 @@ namespace Pegasus {
// Right Monitor times
-static const TimeValue kAlphaClawSplashStart = 0;
-static const TimeValue kAlphaClawSplashStop = 4000;
-
-static const TimeValue kDeltaClawSplashStart = 4000;
-static const TimeValue kDeltaClawSplashStop = 8000;
-
-static const TimeValue kClawAtATime = 8000;
-static const TimeValue kClawAtAPinchedTime = 8600;
-static const TimeValue kClawAtATurnedTime = 9200;
-static const TimeValue kClawAtAWithRobotPinchedTime = 9800;
-
-static const TimeValue kClawAtBTime = 10400;
-static const TimeValue kClawAtBPinchedTime = 11000;
-static const TimeValue kClawAtBTurnedTime = 11600;
-static const TimeValue kClawAtBWithRobotTime = 12200;
-static const TimeValue kClawAtBWithRobotPinchedTime = 12800;
-
-static const TimeValue kClawAtCTime = 13400;
-static const TimeValue kClawAtCPinchedTime = 14000;
-static const TimeValue kClawAtCTurnedTime = 14600;
-
-static const TimeValue kClawAtDTime = 15200;
-static const TimeValue kClawAtDPinchedTime = 15800;
-static const TimeValue kClawAtDTurnedTime = 16400;
-
-static const TimeValue kAToBStart = 17000;
-static const TimeValue kAToBStop = 18680;
-static const TimeValue kAPinchStart = 18680;
-static const TimeValue kAPinchStop = 20200;
-static const TimeValue kACCWStart = 20200;
-static const TimeValue kACCWStop = 21600;
-static const TimeValue kACWStart = 21600;
-static const TimeValue kACWStop = 23000;
-
-static const TimeValue kBToAStart = 23000;
-static const TimeValue kBToAStop = 24680;
-static const TimeValue kBToCStart = 24680;
-static const TimeValue kBToCStop = 26520;
-static const TimeValue kBToDStart = 26520;
-static const TimeValue kBToDStop = 28320;
-static const TimeValue kBPinchStart = 28320;
-static const TimeValue kBPinchStop = 29680;
-static const TimeValue kBCCWStart = 29680;
-static const TimeValue kBCCWStop = 31200;
-static const TimeValue kBCWStart = 31200;
-static const TimeValue kBCWStop = 32720;
-
-static const TimeValue kCToBStart = 32720;
-static const TimeValue kCToBStop = 34560;
-static const TimeValue kCPinchStart = 34560;
-static const TimeValue kCPinchStop = 36400;
-static const TimeValue kCCCWStart = 36400;
-static const TimeValue kCCCWStop = 37840;
-static const TimeValue kCCWStart = 37840;
-static const TimeValue kCCWStop = 39280;
-
-static const TimeValue kDToBStart = 39280;
-static const TimeValue kDToBStop = 41080;
-static const TimeValue kDPinchStart = 41080;
-static const TimeValue kDPinchStop = 42600;
-static const TimeValue kDCCWStart = 42600;
-static const TimeValue kDCCWStop = 44000;
-static const TimeValue kDCWStart = 44000;
-static const TimeValue kDCWStop = 45400;
-
-static const TimeValue kRobotApproachStart = 45400;
-static const TimeValue kRobotApproachStop = 56800;
-
-static const TimeValue kCToBWithRobotStart = 56800;
-static const TimeValue kCToBWithRobotStop = 58600;
-
-static const TimeValue kBPinchWithRobotStart = 58600;
-static const TimeValue kBPinchWithRobotStop = 60400;
-static const TimeValue kBToAWithRobotStart = 60400;
-static const TimeValue kBToAWithRobotStop = 62240;
+enum {
+ kAlphaClawSplashStart = 0,
+ kAlphaClawSplashStop = 4000,
+
+ kDeltaClawSplashStart = 4000,
+ kDeltaClawSplashStop = 8000,
+
+ kClawAtATime = 8000,
+ kClawAtAPinchedTime = 8600,
+ kClawAtATurnedTime = 9200,
+ kClawAtAWithRobotPinchedTime = 9800,
+
+ kClawAtBTime = 10400,
+ kClawAtBPinchedTime = 11000,
+ kClawAtBTurnedTime = 11600,
+ kClawAtBWithRobotTime = 12200,
+ kClawAtBWithRobotPinchedTime = 12800,
+
+ kClawAtCTime = 13400,
+ kClawAtCPinchedTime = 14000,
+ kClawAtCTurnedTime = 14600,
+
+ kClawAtDTime = 15200,
+ kClawAtDPinchedTime = 15800,
+ kClawAtDTurnedTime = 16400,
+
+ kAToBStart = 17000,
+ kAToBStop = 18680,
+ kAPinchStart = 18680,
+ kAPinchStop = 20200,
+ kACCWStart = 20200,
+ kACCWStop = 21600,
+ kACWStart = 21600,
+ kACWStop = 23000,
+
+ kBToAStart = 23000,
+ kBToAStop = 24680,
+ kBToCStart = 24680,
+ kBToCStop = 26520,
+ kBToDStart = 26520,
+ kBToDStop = 28320,
+ kBPinchStart = 28320,
+ kBPinchStop = 29680,
+ kBCCWStart = 29680,
+ kBCCWStop = 31200,
+ kBCWStart = 31200,
+ kBCWStop = 32720,
+
+ kCToBStart = 32720,
+ kCToBStop = 34560,
+ kCPinchStart = 34560,
+ kCPinchStop = 36400,
+ kCCCWStart = 36400,
+ kCCCWStop = 37840,
+ kCCWStart = 37840,
+ kCCWStop = 39280,
+
+ kDToBStart = 39280,
+ kDToBStop = 41080,
+ kDPinchStart = 41080,
+ kDPinchStop = 42600,
+ kDCCWStart = 42600,
+ kDCCWStop = 44000,
+ kDCWStart = 44000,
+ kDCWStop = 45400,
+
+ kRobotApproachStart = 45400,
+ kRobotApproachStop = 56800,
+
+ kCToBWithRobotStart = 56800,
+ kCToBWithRobotStop = 58600,
+
+ kBPinchWithRobotStart = 58600,
+ kBPinchWithRobotStop = 60400,
+ kBToAWithRobotStart = 60400,
+ kBToAWithRobotStop = 62240
+};
// As usual, times here are in seconds.
// Left monitor times.
+enum {
+ kAlphaSplashStart = 0,
+ kAlphaSplashStop = 2,
-static const TimeValue kAlphaSplashStart = 0;
-static const TimeValue kAlphaSplashStop = 2;
-
-static const TimeValue kMainMenuTime = 2;
-static const TimeValue kLaunchPrepRolloverTime = 3;
-static const TimeValue kLaunchPrepHighlightStart = 4;
-static const TimeValue kLaunchPrepHighlightStop = 5;
-static const TimeValue kClawControlRolloverTime = 5;
-static const TimeValue kClawControlHighlightStart = 6;
-static const TimeValue kClawControlHighlightStop = 7;
+ kMainMenuTime = 2,
+ kLaunchPrepRolloverTime = 3,
+ kLaunchPrepHighlightStart = 4,
+ kLaunchPrepHighlightStop = 5,
+ kClawControlRolloverTime = 5,
+ kClawControlHighlightStart = 6,
+ kClawControlHighlightStop = 7,
-static const TimeValue kAlphaLaunchPrepStart = 7;
-static const TimeValue kAlphaLaunchPrepStop = 17;
+ kAlphaLaunchPrepStart = 7,
+ kAlphaLaunchPrepStop = 17,
-static const TimeValue kClawMenuStart = 17;
-static const TimeValue kClawMenuStop = 18;
+ kClawMenuStart = 17,
+ kClawMenuStop = 18,
-static const TimeValue kClawMenuTime = 18;
+ kClawMenuTime = 18,
-static const TimeValue kDeltaSplashStart = 19;
-static const TimeValue kDeltaSplashStop = 21;
+ kDeltaSplashStart = 19,
+ kDeltaSplashStop = 21,
-static const TimeValue kDeltaLaunchPrepStart = 21;
-static const TimeValue kDeltaLaunchPrepStop = 30;
+ kDeltaLaunchPrepStart = 21,
+ kDeltaLaunchPrepStop = 30
+};
// Right monitor times.
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
index 92b79c038e..f7996fabf5 100644
--- a/engines/pegasus/neighborhood/tsa/fulltsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
@@ -41,41 +41,45 @@ namespace Pegasus {
// TSA PICTs:
-static const ResIDType kTBPCloseBoxPICTID = 800;
-static const ResIDType kTBPRewindPICTID = 801;
-static const ResIDType kUnresolvedPICTID = 802;
-static const ResIDType kResolvedPICTID = 803;
-static const ResIDType kJumpMenuPICTID = 804;
-static const ResIDType kJumpMenuHilitedPICTID = 805;
-static const ResIDType kExitPICTID = 806;
-static const ResIDType kExitHilitedPICTID = 807;
-static const ResIDType kLeftRipPICTID = 808;
-static const ResIDType kComparisonCloseBoxPICTID = 809;
-static const ResIDType kComparisonLeftRewindPICTID = 810;
-static const ResIDType kComparisonRightRewindPICTID = 811;
-static const ResIDType kComparisonHiliteNoradPICTID = 812;
-static const ResIDType kComparisonHiliteMarsPICTID = 813;
-static const ResIDType kComparisonHiliteCaldoriaPICTID = 814;
-static const ResIDType kComparisonHiliteWSCPICTID = 815;
-static const ResIDType kComparisonChancesNoradPICTID = 816;
-static const ResIDType kComparisonChancesMarsPICTID = 817;
-static const ResIDType kComparisonChancesCaldoriaPICTID = 818;
-static const ResIDType kComparisonChancesWSCPICTID = 819;
-static const ResIDType kRedirectionCCRolloverPICTID = 820;
-static const ResIDType kRedirectionRRRolloverPICTID = 821;
-static const ResIDType kRedirectionFDRolloverPICTID = 822;
-static const ResIDType kRedirectionCCDoorPICTID = 823;
-static const ResIDType kRedirectionRRDoorPICTID = 824;
-static const ResIDType kRedirectionFDDoorPICTID = 825;
-static const ResIDType kRedirectionSecuredPICTID = 826;
-static const ResIDType kRedirectionNewTargetPICTID = 827;
-static const ResIDType kRedirectionClosePICTID = 828;
+enum {
+ kTBPCloseBoxPICTID = 800,
+ kTBPRewindPICTID = 801,
+ kUnresolvedPICTID = 802,
+ kResolvedPICTID = 803,
+ kJumpMenuPICTID = 804,
+ kJumpMenuHilitedPICTID = 805,
+ kExitPICTID = 806,
+ kExitHilitedPICTID = 807,
+ kLeftRipPICTID = 808,
+ kComparisonCloseBoxPICTID = 809,
+ kComparisonLeftRewindPICTID = 810,
+ kComparisonRightRewindPICTID = 811,
+ kComparisonHiliteNoradPICTID = 812,
+ kComparisonHiliteMarsPICTID = 813,
+ kComparisonHiliteCaldoriaPICTID = 814,
+ kComparisonHiliteWSCPICTID = 815,
+ kComparisonChancesNoradPICTID = 816,
+ kComparisonChancesMarsPICTID = 817,
+ kComparisonChancesCaldoriaPICTID = 818,
+ kComparisonChancesWSCPICTID = 819,
+ kRedirectionCCRolloverPICTID = 820,
+ kRedirectionRRRolloverPICTID = 821,
+ kRedirectionFDRolloverPICTID = 822,
+ kRedirectionCCDoorPICTID = 823,
+ kRedirectionRRDoorPICTID = 824,
+ kRedirectionFDDoorPICTID = 825,
+ kRedirectionSecuredPICTID = 826,
+ kRedirectionNewTargetPICTID = 827,
+ kRedirectionClosePICTID = 828
+};
static const int16 kCompassShift = 15;
-static const TimeScale kFullTSAMovieScale = 600;
-static const TimeScale kFullTSAFramesPerSecond = 15;
-static const TimeScale kFullTSAFrameDuration = 40;
+enum {
+ kFullTSAMovieScale = 600,
+ kFullTSAFramesPerSecond = 15,
+ kFullTSAFrameDuration = 40
+};
// Alternate IDs.
static const AlternateID kAltTSANormal = 0;
@@ -84,416 +88,425 @@ static const AlternateID kAltTSARobotsAtFrontDoor = 2;
static const AlternateID kAltTSARedAlert = 3;
// Room IDs.
-static const RoomID kTSA01 = 1;
-static const RoomID kTSA02 = 2;
-static const RoomID kTSA03 = 3;
-static const RoomID kTSA04 = 4;
-static const RoomID kTSA05 = 5;
-static const RoomID kTSA0A = 6;
-static const RoomID kTSA06 = 7;
-static const RoomID kTSA07 = 8;
-static const RoomID kTSA08 = 9;
-static const RoomID kTSA09 = 10;
-static const RoomID kTSA10 = 11;
-static const RoomID kTSA11 = 12;
-static const RoomID kTSA12 = 13;
-static const RoomID kTSA13 = 14;
-static const RoomID kTSA14 = 15;
-static const RoomID kTSA15 = 16;
-static const RoomID kTSA16 = 17;
-static const RoomID kTSA17 = 18;
-static const RoomID kTSA18 = 19;
-static const RoomID kTSA19 = 20;
-static const RoomID kTSA0B = 21;
-static const RoomID kTSA21Cyan = 22;
-static const RoomID kTSA22Cyan = 23;
-static const RoomID kTSA23Cyan = 24;
-static const RoomID kTSA24Cyan = 25;
-static const RoomID kTSA25Cyan = 26;
-static const RoomID kTSA21Red = 27;
-static const RoomID kTSA23Red = 29;
-static const RoomID kTSA24Red = 30;
-static const RoomID kTSA25Red = 31;
-static const RoomID kTSA26 = 32;
-static const RoomID kTSA27 = 33;
-static const RoomID kTSA28 = 34;
-static const RoomID kTSA29 = 35;
-static const RoomID kTSA30 = 36;
-static const RoomID kTSA31 = 37;
-static const RoomID kTSA32 = 38;
-static const RoomID kTSA33 = 39;
-static const RoomID kTSA34 = 40;
-static const RoomID kTSA35 = 41;
-static const RoomID kTSADeathRoom = 43;
+enum {
+ kTSA01 = 1,
+ kTSA02 = 2,
+ kTSA03 = 3,
+ kTSA04 = 4,
+ kTSA05 = 5,
+ kTSA0A = 6,
+ kTSA06 = 7,
+ kTSA07 = 8,
+ kTSA08 = 9,
+ kTSA09 = 10,
+ kTSA10 = 11,
+ kTSA11 = 12,
+ kTSA12 = 13,
+ kTSA13 = 14,
+ kTSA14 = 15,
+ kTSA15 = 16,
+ kTSA16 = 17,
+ kTSA17 = 18,
+ kTSA18 = 19,
+ kTSA19 = 20,
+ kTSA0B = 21,
+ kTSA21Cyan = 22,
+ kTSA22Cyan = 23,
+ kTSA23Cyan = 24,
+ kTSA24Cyan = 25,
+ kTSA25Cyan = 26,
+ kTSA21Red = 27,
+ kTSA23Red = 29,
+ kTSA24Red = 30,
+ kTSA25Red = 31,
+ kTSA26 = 32,
+ kTSA27 = 33,
+ kTSA28 = 34,
+ kTSA29 = 35,
+ kTSA30 = 36,
+ kTSA31 = 37,
+ kTSA32 = 38,
+ kTSA33 = 39,
+ kTSA34 = 40,
+ kTSA35 = 41,
+ kTSADeathRoom = 43
+};
// Hot Spot Activation IDs.
-static const HotSpotActivationID kActivateTSAReadyForCard = 1;
-static const HotSpotActivationID kActivateTSAReadyToTransport = 2;
-static const HotSpotActivationID kActivateTSARobotsAwake = 3;
-static const HotSpotActivationID kActivateTSA0BZoomedOut = 4;
-static const HotSpotActivationID kActivateTSA0BZoomedIn = 5;
-static const HotSpotActivationID kActivateTSA0BComparisonVideo = 6;
-static const HotSpotActivationID kActivationLogReaderOpen = 7;
-static const HotSpotActivationID kActivateTSA0BTBPVideo = 8;
-static const HotSpotActivationID kActivationDoesntHaveKey = 9;
-static const HotSpotActivationID kActivationKeyVaultOpen = 10;
-static const HotSpotActivationID kActivationDoesntHaveChips = 11;
-static const HotSpotActivationID kActivationChipVaultOpen = 12;
-static const HotSpotActivationID kActivationJumpToPrehistoric = 13;
-static const HotSpotActivationID kActivationJumpToNorad = 14;
-static const HotSpotActivationID kActivationJumpToMars = 15;
-static const HotSpotActivationID kActivationJumpToWSC = 16;
-static const HotSpotActivationID kActivationReadyToExit = 17;
-static const HotSpotActivationID kActivationReadyForJumpMenu = 18;
-static const HotSpotActivationID kActivationMainJumpMenu = 19;
+enum {
+ kActivateTSAReadyForCard = 1,
+ kActivateTSAReadyToTransport = 2,
+ kActivateTSARobotsAwake = 3,
+ kActivateTSA0BZoomedOut = 4,
+ kActivateTSA0BZoomedIn = 5,
+ kActivateTSA0BComparisonVideo = 6,
+ kActivationLogReaderOpen = 7,
+ kActivateTSA0BTBPVideo = 8,
+ kActivationDoesntHaveKey = 9,
+ kActivationKeyVaultOpen = 10,
+ kActivationDoesntHaveChips = 11,
+ kActivationChipVaultOpen = 12,
+ kActivationJumpToPrehistoric = 13,
+ kActivationJumpToNorad = 14,
+ kActivationJumpToMars = 15,
+ kActivationJumpToWSC = 16,
+ kActivationReadyToExit = 17,
+ kActivationReadyForJumpMenu = 18,
+ kActivationMainJumpMenu = 19
+};
// Hot Spot IDs.
-static const HotSpotID kTSAGTCardDropSpotID = 5000;
-static const HotSpotID kTSAGTTokyoSpotID = 5001;
-static const HotSpotID kTSAGTCaldoriaSpotID = 5002;
-static const HotSpotID kTSAGTBeachSpotID = 5003;
-static const HotSpotID kTSAGTOtherSpotID = 5004;
-static const HotSpotID kTSA02DoorSpotID = 5005;
-static const HotSpotID kTSA03EastJimenezSpotID = 5006;
-static const HotSpotID kTSA03WestCrenshawSpotID = 5007;
-static const HotSpotID kTSA04EastMatsumotoSpotID = 5008;
-static const HotSpotID kTSA04WestCastilleSpotID = 5009;
-static const HotSpotID kTSA05EastSinclairSpotID = 5010;
-static const HotSpotID kTSA05WestWhiteSpotID = 5011;
-static const HotSpotID kTSA0AEastSpotID = 5012;
-static const HotSpotID kTSA0AWastSpotID = 5013;
-static const HotSpotID kTSA0BEastMonitorSpotID = 5014;
-static const HotSpotID kTSA0BEastMonitorOutSpotID = 5015;
-static const HotSpotID kTSA0BEastCompareNoradSpotID = 5016;
-static const HotSpotID kTSA0BEastCompareMarsSpotID = 5017;
-static const HotSpotID kTSA0BEastCompareCaldoriaSpotID = 5018;
-static const HotSpotID kTSA0BEastCompareWSCSpotID = 5019;
-static const HotSpotID kTSA0BEastLeftRewindSpotID = 5020;
-static const HotSpotID kTSA0BEastLeftPlaySpotID = 5021;
-static const HotSpotID kTSA0BEastRightRewindSpotID = 5022;
-static const HotSpotID kTSA0BEastRightPlaySpotID = 5023;
-static const HotSpotID kTSA0BEastCloseVideoSpotID = 5024;
-static const HotSpotID kTSA0BNorthMonitorSpotID = 5025;
-static const HotSpotID kTSA0BNorthMonitorOutSpotID = 5026;
-static const HotSpotID kTSA0BNorthHistLogSpotID = 5027;
-static const HotSpotID kTSA0BNorthRobotsToCommandCenterSpotID = 5028;
-static const HotSpotID kTSA0BNorthRobotsToReadyRoomSpotID = 5029;
-static const HotSpotID kTSA0BNorthRobotsToFrontDoorSpotID = 5030;
-static const HotSpotID kTSA0BWestMonitorSpotID = 5031;
-static const HotSpotID kTSA0BWestMonitorOutSpotID = 5032;
-static const HotSpotID kTSA0BWestTheorySpotID = 5033;
-static const HotSpotID kTSA0BWestBackgroundSpotID = 5034;
-static const HotSpotID kTSA0BWestProcedureSpotID = 5035;
-static const HotSpotID kTSA0BWestCloseVideoSpotID = 5036;
-static const HotSpotID kTSA0BWestPlayVideoSpotID = 5037;
-static const HotSpotID kTSA0BWestRewindVideoSpotID = 5038;
-static const HotSpotID kTSA22EastMonitorSpotID = 5039;
-static const HotSpotID kTSA22EastKeySpotID = 5040;
-static const HotSpotID kTSA23WestMonitorSpotID = 5041;
-static const HotSpotID kTSA23WestChipsSpotID = 5042;
-static const HotSpotID kTSA34NorthDoorSpotID = 5043;
-static const HotSpotID kTSA37NorthJumpToPrehistoricSpotID = 5044;
-static const HotSpotID kTSA37NorthJumpToNoradSpotID = 5045;
-static const HotSpotID kTSA37NorthCancelNoradSpotID = 5046;
-static const HotSpotID kTSA37NorthJumpToMarsSpotID = 5047;
-static const HotSpotID kTSA37NorthCancelMarsSpotID = 5048;
-static const HotSpotID kTSA37NorthJumpToWSCSpotID = 5049;
-static const HotSpotID kTSA37NorthCancelWSCSpotID = 5050;
-static const HotSpotID kTSA37NorthExitSpotID = 5051;
-static const HotSpotID kTSA37NorthJumpMenuSpotID = 5052;
-static const HotSpotID kTSA37NorthNoradMenuSpotID = 5053;
-static const HotSpotID kTSA37NorthMarsMenuSpotID = 5054;
-static const HotSpotID kTSA37NorthWSCMenuSpotID = 5055;
+enum {
+ kTSAGTCardDropSpotID = 5000,
+ kTSAGTTokyoSpotID = 5001,
+ kTSAGTCaldoriaSpotID = 5002,
+ kTSAGTBeachSpotID = 5003,
+ kTSAGTOtherSpotID = 5004,
+ kTSA02DoorSpotID = 5005,
+ kTSA03EastJimenezSpotID = 5006,
+ kTSA03WestCrenshawSpotID = 5007,
+ kTSA04EastMatsumotoSpotID = 5008,
+ kTSA04WestCastilleSpotID = 5009,
+ kTSA05EastSinclairSpotID = 5010,
+ kTSA05WestWhiteSpotID = 5011,
+ kTSA0AEastSpotID = 5012,
+ kTSA0AWastSpotID = 5013,
+ kTSA0BEastMonitorSpotID = 5014,
+ kTSA0BEastMonitorOutSpotID = 5015,
+ kTSA0BEastCompareNoradSpotID = 5016,
+ kTSA0BEastCompareMarsSpotID = 5017,
+ kTSA0BEastCompareCaldoriaSpotID = 5018,
+ kTSA0BEastCompareWSCSpotID = 5019,
+ kTSA0BEastLeftRewindSpotID = 5020,
+ kTSA0BEastLeftPlaySpotID = 5021,
+ kTSA0BEastRightRewindSpotID = 5022,
+ kTSA0BEastRightPlaySpotID = 5023,
+ kTSA0BEastCloseVideoSpotID = 5024,
+ kTSA0BNorthMonitorSpotID = 5025,
+ kTSA0BNorthMonitorOutSpotID = 5026,
+ kTSA0BNorthHistLogSpotID = 5027,
+ kTSA0BNorthRobotsToCommandCenterSpotID = 5028,
+ kTSA0BNorthRobotsToReadyRoomSpotID = 5029,
+ kTSA0BNorthRobotsToFrontDoorSpotID = 5030,
+ kTSA0BWestMonitorSpotID = 5031,
+ kTSA0BWestMonitorOutSpotID = 5032,
+ kTSA0BWestTheorySpotID = 5033,
+ kTSA0BWestBackgroundSpotID = 5034,
+ kTSA0BWestProcedureSpotID = 5035,
+ kTSA0BWestCloseVideoSpotID = 5036,
+ kTSA0BWestPlayVideoSpotID = 5037,
+ kTSA0BWestRewindVideoSpotID = 5038,
+ kTSA22EastMonitorSpotID = 5039,
+ kTSA22EastKeySpotID = 5040,
+ kTSA23WestMonitorSpotID = 5041,
+ kTSA23WestChipsSpotID = 5042,
+ kTSA34NorthDoorSpotID = 5043,
+ kTSA37NorthJumpToPrehistoricSpotID = 5044,
+ kTSA37NorthJumpToNoradSpotID = 5045,
+ kTSA37NorthCancelNoradSpotID = 5046,
+ kTSA37NorthJumpToMarsSpotID = 5047,
+ kTSA37NorthCancelMarsSpotID = 5048,
+ kTSA37NorthJumpToWSCSpotID = 5049,
+ kTSA37NorthCancelWSCSpotID = 5050,
+ kTSA37NorthExitSpotID = 5051,
+ kTSA37NorthJumpMenuSpotID = 5052,
+ kTSA37NorthNoradMenuSpotID = 5053,
+ kTSA37NorthMarsMenuSpotID = 5054,
+ kTSA37NorthWSCMenuSpotID = 5055
+};
// Extra sequence IDs.
-static const ExtraID kTSATransporterArrowLoop = 0;
-static const ExtraID kTSAArriveFromCaldoria = 1;
-static const ExtraID kTSAGTOtherChoice = 2;
-static const ExtraID kTSAGTCardSwipe = 3;
-static const ExtraID kTSAGTSelectCaldoria = 4;
-static const ExtraID kTSAGTGoToCaldoria = 5;
-static const ExtraID kTSAGTSelectBeach = 6;
-static const ExtraID kTSAGTGoToBeach = 7;
-static const ExtraID kTSAGTArriveAtBeach = 8;
-static const ExtraID kTSAGTSelectTokyo = 9;
-static const ExtraID kTSAGTGoToTokyo = 10;
-static const ExtraID kTSAGTArriveAtTokyo = 11;
-static const ExtraID kTSA02NorthZoomIn = 12;
-static const ExtraID kTSA02NorthTenSecondDoor = 13;
-static const ExtraID kTSA02NorthZoomOut = 14;
-static const ExtraID kTSA02NorthDoorWithAgent3 = 15;
-static const ExtraID kTSA03JimenezZoomIn = 16;
-static const ExtraID kTSA03JimenezSpeech = 17;
-static const ExtraID kTSA03JimenezZoomOut = 18;
-static const ExtraID kTSA03CrenshawZoomIn = 19;
-static const ExtraID kTSA03CrenshawSpeech = 20;
-static const ExtraID kTSA03CrenshawZoomOut = 21;
-static const ExtraID kTSA03SouthRobotDeath = 22;
-static const ExtraID kTSA04NorthRobotGreeting = 23;
-static const ExtraID kTSA04MatsumotoZoomIn = 24;
-static const ExtraID kTSA04MatsumotoSpeech = 25;
-static const ExtraID kTSA04MatsumotoZoomOut = 26;
-static const ExtraID kTSA04CastilleZoomIn = 27;
-static const ExtraID kTSA04CastilleSpeech = 28;
-static const ExtraID kTSA04CastilleZoomOut = 29;
-static const ExtraID kTSA05SinclairZoomIn = 30;
-static const ExtraID kTSA05SinclairSpeech = 31;
-static const ExtraID kTSA05SinclairZoomOut = 32;
-static const ExtraID kTSA05WhiteZoomIn = 33;
-static const ExtraID kTSA05WhiteSpeech = 34;
-static const ExtraID kTSA05WhiteZoomOut = 35;
-static const ExtraID kTSA0AEastRobot = 36;
-static const ExtraID kTSA0AWestRobot = 37;
-static const ExtraID kTSA16NorthRobotDeath = 38;
-static const ExtraID kTSA0BEastZoomIn = 39;
-static const ExtraID kTSA0BEastZoomedView = 40;
-static const ExtraID kTSA0BEastZoomOut = 41;
-static const ExtraID kTSA0BEastTurnLeft = 42;
-static const ExtraID kTSA0BComparisonStartup = 43;
-static const ExtraID kTSA0BComparisonView0000 = 44;
-static const ExtraID kTSA0BComparisonView0002 = 45;
-static const ExtraID kTSA0BComparisonView0020 = 46;
-static const ExtraID kTSA0BComparisonView0022 = 47;
-static const ExtraID kTSA0BComparisonView0200 = 48;
-static const ExtraID kTSA0BComparisonView0202 = 49;
-static const ExtraID kTSA0BComparisonView0220 = 50;
-static const ExtraID kTSA0BComparisonView0222 = 51;
-static const ExtraID kTSA0BComparisonView2000 = 52;
-static const ExtraID kTSA0BComparisonView2002 = 53;
-static const ExtraID kTSA0BComparisonView2020 = 54;
-static const ExtraID kTSA0BComparisonView2022 = 55;
-static const ExtraID kTSA0BComparisonView2200 = 56;
-static const ExtraID kTSA0BComparisonView2202 = 57;
-static const ExtraID kTSA0BComparisonView2220 = 58;
-static const ExtraID kTSA0BComparisonView2222 = 59;
-static const ExtraID kTSA0BNoradComparisonView = 60;
-static const ExtraID kTSA0BNoradUnaltered = 61;
-static const ExtraID kTSA0BNoradAltered = 62;
-static const ExtraID kTSA0BMarsComparisonView = 63;
-static const ExtraID kTSA0BMarsUnaltered = 64;
-static const ExtraID kTSA0BMarsAltered = 65;
-static const ExtraID kTSA0BWSCComparisonView = 66;
-static const ExtraID kTSA0BWSCUnaltered = 67;
-static const ExtraID kTSA0BWSCAltered = 68;
-static const ExtraID kTSA0BCaldoriaComparisonView = 69;
-static const ExtraID kTSA0BCaldoriaUnaltered = 70;
-static const ExtraID kTSA0BCaldoriaAltered = 71;
-static const ExtraID kTSA0BNorthZoomIn = 72;
-static const ExtraID kTSA0BNorthZoomedView = 73;
-static const ExtraID kTSA0BNorthZoomOut = 74;
-static const ExtraID kTSA0BNorthTurnLeft = 75;
-static const ExtraID kTSA0BNorthTurnRight = 76;
-static const ExtraID kTSA0BNorthHistLogOpen = 77;
-static const ExtraID kTSA0BNorthHistLogClose = 78;
-static const ExtraID kTSA0BNorthHistLogCloseWithLog = 79;
-static const ExtraID kTSA0BNorthCantChangeHistory = 80;
-static const ExtraID kTSA0BNorthYoureBusted = 81;
-static const ExtraID kTSA0BNorthFinallyHappened = 82;
-static const ExtraID kTSA0BShowRip1 = 83;
-static const ExtraID kTSA0BNorthRipView1 = 84;
-static const ExtraID kTSA0BShowRip2 = 85;
-static const ExtraID kTSA0BShowGuardRobots = 86;
-static const ExtraID kTSA0BAIInterruption = 87;
-static const ExtraID kTSA0BRobotsToCommandCenter = 88;
-static const ExtraID kTSA0BNorthRobotsAtCCView = 89;
-static const ExtraID kTSA0BNorthRobotsAtRRView = 90;
-static const ExtraID kTSA0BNorthRobotsAtFDView = 91;
-static const ExtraID kTSA0BRobotsFromCommandCenterToReadyRoom = 92;
-static const ExtraID kTSA0BRobotsFromReadyRoomToCommandCenter = 93;
-static const ExtraID kTSA0BRobotsFromCommandCenterToFrontDoor = 94;
-static const ExtraID kTSA0BRobotsFromFrontDoorToCommandCenter = 95;
-static const ExtraID kTSA0BRobotsFromFrontDoorToReadyRoom = 96;
-static const ExtraID kTSA0BRobotsFromReadyRoomToFrontDoor = 97;
-static const ExtraID kTSA0BWestZoomIn = 98;
-static const ExtraID kTSA0BWestZoomedView = 99;
-static const ExtraID kTSA0BWestZoomOut = 100;
-static const ExtraID kTSA0BWestTurnRight = 101;
-static const ExtraID kTSA0BTBPTheoryHighlight = 102;
-static const ExtraID kTSA0BTBPBackgroundHighlight = 103;
-static const ExtraID kTSA0BTBPProcedureHighlight = 104;
-static const ExtraID kTSA0BTBPTheory = 105;
-static const ExtraID kTSA0BTBPBackground = 106;
-static const ExtraID kTSA0BTBPProcedure = 107;
-static const ExtraID kTSA0BRipAlarmScreen = 108;
-static const ExtraID kTSA22RedEastZoomInSequence = 109;
-static const ExtraID kTSA22RedEastVaultViewWithKey = 110;
-static const ExtraID kTSA22RedEastVaultViewNoKey = 111;
-static const ExtraID kTSA23RedWestVaultZoomInSequence = 112;
-static const ExtraID kTSA23RedWestVaultViewWithChips = 113;
-static const ExtraID kTSA23RedWestVaultViewNoChips = 114;
-static const ExtraID kTSA25NorthDeniedNoKey = 115;
-static const ExtraID kTSA25NorthDeniedNoChip = 116;
-static const ExtraID kTSA25NorthPutOnSuit = 117;
-static const ExtraID kTSA25NorthAlreadyHaveSuit = 118;
-static const ExtraID kTSA25NorthDescending1 = 119;
-static const ExtraID kTSA25NorthDescending2 = 120;
-static const ExtraID kTSA37HorseToAI1 = 121;
-static const ExtraID kTSA37PegasusAI1 = 122;
-static const ExtraID kTSA37AI1ToCommissioner1 = 123;
-static const ExtraID kTSA37Commissioner1 = 124;
-static const ExtraID kTSA37Commissioner1ToZoom = 125;
-static const ExtraID kTSA37ZoomToPrehistoric = 126;
-static const ExtraID kTSA37PrehistoricToAI2 = 127;
-static const ExtraID kTSA37PegasusAI2 = 128;
-static const ExtraID kTSA37AI2ToPrehistoric = 129;
-static const ExtraID kTSA37PrehistoricToDepart = 130;
-static const ExtraID kTSA37PegasusDepart = 131;
-static const ExtraID kTSA37TimeJumpToPegasus = 132;
-static const ExtraID kTSA37RecallToDownload = 133;
-static const ExtraID kTSA37DownloadToColonel1 = 134;
-static const ExtraID kTSA37Colonel1 = 135;
-static const ExtraID kTSA37Colonel1ToReviewRequired = 136;
-static const ExtraID kTSA37ReviewRequiredToExit = 137;
-static const ExtraID kTSA37ExitHilited = 138;
-static const ExtraID kTSA37ExitToHorse = 139;
-static const ExtraID kTSA37HorseToColonel2 = 140;
-static const ExtraID kTSA37Colonel2 = 141;
-static const ExtraID kTSA37PegasusAI3 = 142;
-static const ExtraID kTSA37AI3ToHorse = 143;
-static const ExtraID kTSA37HorseToZoom = 144;
-static const ExtraID kTSA37ZoomToMainMenu = 145;
-static const ExtraID kTSA37MainMenuToAI4 = 146;
-static const ExtraID kTSA37PegasusAI4 = 147;
-static const ExtraID kTSA37AI4ToMainMenu = 148;
-static const ExtraID kTSA37JumpMenu000 = 149;
-static const ExtraID kTSA37JumpMenu001 = 150;
-static const ExtraID kTSA37JumpMenu010 = 151;
-static const ExtraID kTSA37JumpMenu011 = 152;
-static const ExtraID kTSA37JumpMenu100 = 153;
-static const ExtraID kTSA37JumpMenu101 = 154;
-static const ExtraID kTSA37JumpMenu110 = 155;
-static const ExtraID kTSA37JumpMenu111 = 156;
-static const ExtraID kTSA37JumpToWSCMenu = 157;
-static const ExtraID kTSA37CancelWSC = 158;
-static const ExtraID kTSA37JumpToWSC = 159;
-static const ExtraID kTSA37WSCToAI5 = 160;
-static const ExtraID kTSA37PegasusAI5 = 161;
-static const ExtraID kTSA37AI5ToWSC = 162;
-static const ExtraID kTSA37WSCToDepart = 163;
-static const ExtraID kTSA37JumpToMarsMenu = 164;
-static const ExtraID kTSA37CancelMars = 165;
-static const ExtraID kTSA37JumpToMars = 166;
-static const ExtraID kTSA37MarsToAI6 = 167;
-static const ExtraID kTSA37PegasusAI6 = 168;
-static const ExtraID kTSA37AI6ToMars = 169;
-static const ExtraID kTSA37MarsToDepart = 170;
-static const ExtraID kTSA37JumpToNoradMenu = 171;
-static const ExtraID kTSA37CancelNorad = 172;
-static const ExtraID kTSA37JumpToNorad = 173;
-static const ExtraID kTSA37NoradToAI7 = 174;
-static const ExtraID kTSA37PegasusAI7 = 175;
-static const ExtraID kTSA37AI7ToNorad = 176;
-static const ExtraID kTSA37NoradToDepart = 177;
-static const ExtraID kTSA37EnvironmentalScan = 178;
-static const ExtraID kTSA37DownloadToMainMenu = 179;
-static const ExtraID kTSA37DownloadToOpMemReview = 180;
-static const ExtraID kTSA37OpMemReviewToMainMenu = 181;
-static const ExtraID kTSA37OpMemReviewToAllClear = 182;
-static const ExtraID kTSA37AllClearToCongratulations = 183;
-static const ExtraID kTSA37Congratulations = 184;
-static const ExtraID kTSA37CongratulationsToExit = 185;
+enum {
+ kTSATransporterArrowLoop = 0,
+ kTSAArriveFromCaldoria = 1,
+ kTSAGTOtherChoice = 2,
+ kTSAGTCardSwipe = 3,
+ kTSAGTSelectCaldoria = 4,
+ kTSAGTGoToCaldoria = 5,
+ kTSAGTSelectBeach = 6,
+ kTSAGTGoToBeach = 7,
+ kTSAGTArriveAtBeach = 8,
+ kTSAGTSelectTokyo = 9,
+ kTSAGTGoToTokyo = 10,
+ kTSAGTArriveAtTokyo = 11,
+ kTSA02NorthZoomIn = 12,
+ kTSA02NorthTenSecondDoor = 13,
+ kTSA02NorthZoomOut = 14,
+ kTSA02NorthDoorWithAgent3 = 15,
+ kTSA03JimenezZoomIn = 16,
+ kTSA03JimenezSpeech = 17,
+ kTSA03JimenezZoomOut = 18,
+ kTSA03CrenshawZoomIn = 19,
+ kTSA03CrenshawSpeech = 20,
+ kTSA03CrenshawZoomOut = 21,
+ kTSA03SouthRobotDeath = 22,
+ kTSA04NorthRobotGreeting = 23,
+ kTSA04MatsumotoZoomIn = 24,
+ kTSA04MatsumotoSpeech = 25,
+ kTSA04MatsumotoZoomOut = 26,
+ kTSA04CastilleZoomIn = 27,
+ kTSA04CastilleSpeech = 28,
+ kTSA04CastilleZoomOut = 29,
+ kTSA05SinclairZoomIn = 30,
+ kTSA05SinclairSpeech = 31,
+ kTSA05SinclairZoomOut = 32,
+ kTSA05WhiteZoomIn = 33,
+ kTSA05WhiteSpeech = 34,
+ kTSA05WhiteZoomOut = 35,
+ kTSA0AEastRobot = 36,
+ kTSA0AWestRobot = 37,
+ kTSA16NorthRobotDeath = 38,
+ kTSA0BEastZoomIn = 39,
+ kTSA0BEastZoomedView = 40,
+ kTSA0BEastZoomOut = 41,
+ kTSA0BEastTurnLeft = 42,
+ kTSA0BComparisonStartup = 43,
+ kTSA0BComparisonView0000 = 44,
+ kTSA0BComparisonView0002 = 45,
+ kTSA0BComparisonView0020 = 46,
+ kTSA0BComparisonView0022 = 47,
+ kTSA0BComparisonView0200 = 48,
+ kTSA0BComparisonView0202 = 49,
+ kTSA0BComparisonView0220 = 50,
+ kTSA0BComparisonView0222 = 51,
+ kTSA0BComparisonView2000 = 52,
+ kTSA0BComparisonView2002 = 53,
+ kTSA0BComparisonView2020 = 54,
+ kTSA0BComparisonView2022 = 55,
+ kTSA0BComparisonView2200 = 56,
+ kTSA0BComparisonView2202 = 57,
+ kTSA0BComparisonView2220 = 58,
+ kTSA0BComparisonView2222 = 59,
+ kTSA0BNoradComparisonView = 60,
+ kTSA0BNoradUnaltered = 61,
+ kTSA0BNoradAltered = 62,
+ kTSA0BMarsComparisonView = 63,
+ kTSA0BMarsUnaltered = 64,
+ kTSA0BMarsAltered = 65,
+ kTSA0BWSCComparisonView = 66,
+ kTSA0BWSCUnaltered = 67,
+ kTSA0BWSCAltered = 68,
+ kTSA0BCaldoriaComparisonView = 69,
+ kTSA0BCaldoriaUnaltered = 70,
+ kTSA0BCaldoriaAltered = 71,
+ kTSA0BNorthZoomIn = 72,
+ kTSA0BNorthZoomedView = 73,
+ kTSA0BNorthZoomOut = 74,
+ kTSA0BNorthTurnLeft = 75,
+ kTSA0BNorthTurnRight = 76,
+ kTSA0BNorthHistLogOpen = 77,
+ kTSA0BNorthHistLogClose = 78,
+ kTSA0BNorthHistLogCloseWithLog = 79,
+ kTSA0BNorthCantChangeHistory = 80,
+ kTSA0BNorthYoureBusted = 81,
+ kTSA0BNorthFinallyHappened = 82,
+ kTSA0BShowRip1 = 83,
+ kTSA0BNorthRipView1 = 84,
+ kTSA0BShowRip2 = 85,
+ kTSA0BShowGuardRobots = 86,
+ kTSA0BAIInterruption = 87,
+ kTSA0BRobotsToCommandCenter = 88,
+ kTSA0BNorthRobotsAtCCView = 89,
+ kTSA0BNorthRobotsAtRRView = 90,
+ kTSA0BNorthRobotsAtFDView = 91,
+ kTSA0BRobotsFromCommandCenterToReadyRoom = 92,
+ kTSA0BRobotsFromReadyRoomToCommandCenter = 93,
+ kTSA0BRobotsFromCommandCenterToFrontDoor = 94,
+ kTSA0BRobotsFromFrontDoorToCommandCenter = 95,
+ kTSA0BRobotsFromFrontDoorToReadyRoom = 96,
+ kTSA0BRobotsFromReadyRoomToFrontDoor = 97,
+ kTSA0BWestZoomIn = 98,
+ kTSA0BWestZoomedView = 99,
+ kTSA0BWestZoomOut = 100,
+ kTSA0BWestTurnRight = 101,
+ kTSA0BTBPTheoryHighlight = 102,
+ kTSA0BTBPBackgroundHighlight = 103,
+ kTSA0BTBPProcedureHighlight = 104,
+ kTSA0BTBPTheory = 105,
+ kTSA0BTBPBackground = 106,
+ kTSA0BTBPProcedure = 107,
+ kTSA0BRipAlarmScreen = 108,
+ kTSA22RedEastZoomInSequence = 109,
+ kTSA22RedEastVaultViewWithKey = 110,
+ kTSA22RedEastVaultViewNoKey = 111,
+ kTSA23RedWestVaultZoomInSequence = 112,
+ kTSA23RedWestVaultViewWithChips = 113,
+ kTSA23RedWestVaultViewNoChips = 114,
+ kTSA25NorthDeniedNoKey = 115,
+ kTSA25NorthDeniedNoChip = 116,
+ kTSA25NorthPutOnSuit = 117,
+ kTSA25NorthAlreadyHaveSuit = 118,
+ kTSA25NorthDescending1 = 119,
+ kTSA25NorthDescending2 = 120,
+ kTSA37HorseToAI1 = 121,
+ kTSA37PegasusAI1 = 122,
+ kTSA37AI1ToCommissioner1 = 123,
+ kTSA37Commissioner1 = 124,
+ kTSA37Commissioner1ToZoom = 125,
+ kTSA37ZoomToPrehistoric = 126,
+ kTSA37PrehistoricToAI2 = 127,
+ kTSA37PegasusAI2 = 128,
+ kTSA37AI2ToPrehistoric = 129,
+ kTSA37PrehistoricToDepart = 130,
+ kTSA37PegasusDepart = 131,
+ kTSA37TimeJumpToPegasus = 132,
+ kTSA37RecallToDownload = 133,
+ kTSA37DownloadToColonel1 = 134,
+ kTSA37Colonel1 = 135,
+ kTSA37Colonel1ToReviewRequired = 136,
+ kTSA37ReviewRequiredToExit = 137,
+ kTSA37ExitHilited = 138,
+ kTSA37ExitToHorse = 139,
+ kTSA37HorseToColonel2 = 140,
+ kTSA37Colonel2 = 141,
+ kTSA37PegasusAI3 = 142,
+ kTSA37AI3ToHorse = 143,
+ kTSA37HorseToZoom = 144,
+ kTSA37ZoomToMainMenu = 145,
+ kTSA37MainMenuToAI4 = 146,
+ kTSA37PegasusAI4 = 147,
+ kTSA37AI4ToMainMenu = 148,
+ kTSA37JumpMenu000 = 149,
+ kTSA37JumpMenu001 = 150,
+ kTSA37JumpMenu010 = 151,
+ kTSA37JumpMenu011 = 152,
+ kTSA37JumpMenu100 = 153,
+ kTSA37JumpMenu101 = 154,
+ kTSA37JumpMenu110 = 155,
+ kTSA37JumpMenu111 = 156,
+ kTSA37JumpToWSCMenu = 157,
+ kTSA37CancelWSC = 158,
+ kTSA37JumpToWSC = 159,
+ kTSA37WSCToAI5 = 160,
+ kTSA37PegasusAI5 = 161,
+ kTSA37AI5ToWSC = 162,
+ kTSA37WSCToDepart = 163,
+ kTSA37JumpToMarsMenu = 164,
+ kTSA37CancelMars = 165,
+ kTSA37JumpToMars = 166,
+ kTSA37MarsToAI6 = 167,
+ kTSA37PegasusAI6 = 168,
+ kTSA37AI6ToMars = 169,
+ kTSA37MarsToDepart = 170,
+ kTSA37JumpToNoradMenu = 171,
+ kTSA37CancelNorad = 172,
+ kTSA37JumpToNorad = 173,
+ kTSA37NoradToAI7 = 174,
+ kTSA37PegasusAI7 = 175,
+ kTSA37AI7ToNorad = 176,
+ kTSA37NoradToDepart = 177,
+ kTSA37EnvironmentalScan = 178,
+ kTSA37DownloadToMainMenu = 179,
+ kTSA37DownloadToOpMemReview = 180,
+ kTSA37OpMemReviewToMainMenu = 181,
+ kTSA37OpMemReviewToAllClear = 182,
+ kTSA37AllClearToCongratulations = 183,
+ kTSA37Congratulations = 184,
+ kTSA37CongratulationsToExit = 185
+};
const DisplayOrder kRipTimerOrder = kMonitorLayer;
+enum {
+ kUnresolvedLeft = kNavAreaLeft + 14,
+ kUnresolvedTop = kNavAreaTop + 236,
-const CoordType kUnresolvedLeft = kNavAreaLeft + 14;
-const CoordType kUnresolvedTop = kNavAreaTop + 236;
-
-const CoordType kResolvedLeft = kNavAreaLeft + 36;
-const CoordType kResolvedTop = kNavAreaTop + 236;
+ kResolvedLeft = kNavAreaLeft + 36,
+ kResolvedTop = kNavAreaTop + 236,
-const CoordType kJumpMenuLeft = kNavAreaLeft + 360;
-const CoordType kJumpMenuTop = kNavAreaTop + 202;
+ kJumpMenuLeft = kNavAreaLeft + 360,
+ kJumpMenuTop = kNavAreaTop + 202,
-const CoordType kJumpMenuHilitedLeft = kNavAreaLeft + 354;
-const CoordType kJumpMenuHilitedTop = kNavAreaTop + 196;
+ kJumpMenuHilitedLeft = kNavAreaLeft + 354,
+ kJumpMenuHilitedTop = kNavAreaTop + 196,
-const CoordType kExitLeft = kNavAreaLeft + 360;
-const CoordType kExitTop = kNavAreaTop + 216;
+ kExitLeft = kNavAreaLeft + 360,
+ kExitTop = kNavAreaTop + 216,
-const CoordType kExitHilitedLeft = kNavAreaLeft + 354;
-const CoordType kExitHilitedTop = kNavAreaTop + 210;
+ kExitHilitedLeft = kNavAreaLeft + 354,
+ kExitHilitedTop = kNavAreaTop + 210,
-const CoordType kRipTimerLeft = kNavAreaLeft + 95;
-const CoordType kRipTimerTop = kNavAreaTop + 87;
+ kRipTimerLeft = kNavAreaLeft + 95,
+ kRipTimerTop = kNavAreaTop + 87,
-const CoordType kTBPCloseLeft = kNavAreaLeft + 30;
-const CoordType kTBPCloseTop = kNavAreaTop + 16;
+ kTBPCloseLeft = kNavAreaLeft + 30,
+ kTBPCloseTop = kNavAreaTop + 16,
-const CoordType kTBPRewindLeft = kNavAreaLeft + 86;
-const CoordType kTBPRewindTop = kNavAreaTop + 218;
+ kTBPRewindLeft = kNavAreaLeft + 86,
+ kTBPRewindTop = kNavAreaTop + 218,
-const CoordType kComparisonCloseLeft = kNavAreaLeft + 50;
-const CoordType kComparisonCloseTop = kNavAreaTop + 14;
+ kComparisonCloseLeft = kNavAreaLeft + 50,
+ kComparisonCloseTop = kNavAreaTop + 14,
-const CoordType kComparisonLeftRewindLeft = kNavAreaLeft + 96;
-const CoordType kComparisonLeftRewindTop = kNavAreaTop + 190;
+ kComparisonLeftRewindLeft = kNavAreaLeft + 96,
+ kComparisonLeftRewindTop = kNavAreaTop + 190,
-const CoordType kComparisonRightRewindLeft = kNavAreaLeft + 282;
-const CoordType kComparisonRightRewindTop = kNavAreaTop + 190;
+ kComparisonRightRewindLeft = kNavAreaLeft + 282,
+ kComparisonRightRewindTop = kNavAreaTop + 190,
-const CoordType kComparisonHiliteSpriteLeft = kNavAreaLeft + 45;
-const CoordType kComparisonHiliteSpriteTop = kNavAreaTop + 65;
+ kComparisonHiliteSpriteLeft = kNavAreaLeft + 45,
+ kComparisonHiliteSpriteTop = kNavAreaTop + 65,
-const CoordType kComparisonHiliteNoradLeft = kNavAreaLeft + 45;
-const CoordType kComparisonHiliteNoradTop = kNavAreaTop + 65;
+ kComparisonHiliteNoradLeft = kNavAreaLeft + 45,
+ kComparisonHiliteNoradTop = kNavAreaTop + 65,
-const CoordType kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4;
-const CoordType kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23;
+ kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4,
+ kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23,
-const CoordType kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7;
-const CoordType kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46;
+ kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7,
+ kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46,
-const CoordType kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11;
-const CoordType kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68;
+ kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11,
+ kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68,
-const CoordType kComparisonChancesSpriteLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesSpriteTop = kNavAreaTop + 162;
+ kComparisonChancesSpriteLeft = kNavAreaLeft + 148,
+ kComparisonChancesSpriteTop = kNavAreaTop + 162,
-const CoordType kComparisonChancesNoradLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesNoradTop = kNavAreaTop + 162;
+ kComparisonChancesNoradLeft = kNavAreaLeft + 148,
+ kComparisonChancesNoradTop = kNavAreaTop + 162,
-const CoordType kComparisonChancesMarsLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesMarsTop = kNavAreaTop + 162;
+ kComparisonChancesMarsLeft = kNavAreaLeft + 148,
+ kComparisonChancesMarsTop = kNavAreaTop + 162,
-const CoordType kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1;
+ kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148,
+ kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1,
-const CoordType kComparisonChancesWSCLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesWSCTop = kNavAreaTop + 162;
+ kComparisonChancesWSCLeft = kNavAreaLeft + 148,
+ kComparisonChancesWSCTop = kNavAreaTop + 162,
-const CoordType kRedirectionSprite1Left = kNavAreaLeft + 58;
-const CoordType kRedirectionSprite1Top = kNavAreaTop + 16;
+ kRedirectionSprite1Left = kNavAreaLeft + 58,
+ kRedirectionSprite1Top = kNavAreaTop + 16,
-const CoordType kRedirectionSprite2Left = kNavAreaLeft + 36;
-const CoordType kRedirectionSprite2Top = kNavAreaTop + 166;
+ kRedirectionSprite2Left = kNavAreaLeft + 36,
+ kRedirectionSprite2Top = kNavAreaTop + 166,
-const CoordType kRedirectionCCRolloverLeft = kNavAreaLeft + 58;
-const CoordType kRedirectionCCRolloverTop = kNavAreaTop + 16;
+ kRedirectionCCRolloverLeft = kNavAreaLeft + 58,
+ kRedirectionCCRolloverTop = kNavAreaTop + 16,
-const CoordType kRedirectionRRRolloverLeft = kNavAreaLeft + 430;
-const CoordType kRedirectionRRRolloverTop = kNavAreaTop + 30;
+ kRedirectionRRRolloverLeft = kNavAreaLeft + 430,
+ kRedirectionRRRolloverTop = kNavAreaTop + 30,
-const CoordType kRedirectionFDRolloverLeft = kNavAreaLeft + 278;
-const CoordType kRedirectionFDRolloverTop = kNavAreaTop + 160;
+ kRedirectionFDRolloverLeft = kNavAreaLeft + 278,
+ kRedirectionFDRolloverTop = kNavAreaTop + 160,
-const CoordType kRedirectionCCDoorLeft = kNavAreaLeft + 174;
-const CoordType kRedirectionCCDoorTop = kNavAreaTop + 36;
+ kRedirectionCCDoorLeft = kNavAreaLeft + 174,
+ kRedirectionCCDoorTop = kNavAreaTop + 36,
-const CoordType kRedirectionRRDoorLeft = kNavAreaLeft + 418;
-const CoordType kRedirectionRRDoorTop = kNavAreaTop + 32;
+ kRedirectionRRDoorLeft = kNavAreaLeft + 418,
+ kRedirectionRRDoorTop = kNavAreaTop + 32,
-const CoordType kRedirectionFDDoorLeft = kNavAreaLeft + 298;
-const CoordType kRedirectionFDDoorTop = kNavAreaTop + 240;
+ kRedirectionFDDoorLeft = kNavAreaLeft + 298,
+ kRedirectionFDDoorTop = kNavAreaTop + 240,
-const CoordType kRedirectionSecuredLeft = kNavAreaLeft + 36;
-const CoordType kRedirectionSecuredTop = kNavAreaTop + 166;
+ kRedirectionSecuredLeft = kNavAreaLeft + 36,
+ kRedirectionSecuredTop = kNavAreaTop + 166,
-const CoordType kRedirectionNewTargetLeft = kNavAreaLeft + 36;
-const CoordType kRedirectionNewTargetTop = kNavAreaTop + 166;
+ kRedirectionNewTargetLeft = kNavAreaLeft + 36,
+ kRedirectionNewTargetTop = kNavAreaTop + 166,
-const CoordType kRedirectionCloseLeft = kNavAreaLeft + 56;
-const CoordType kRedirectionCloseTop = kNavAreaTop + 220;
+ kRedirectionCloseLeft = kNavAreaLeft + 56,
+ kRedirectionCloseTop = kNavAreaTop + 220
+};
static const TimeValue kTSABumpIntoWallIn = 0;
static const TimeValue kTSABumpIntoWallOut = 148;
@@ -516,10 +529,12 @@ static const TimeValue kTSAVaultCloseOut = 5388;
static const TimeValue kTSAPegasusDoorCloseIn = 5388;
static const TimeValue kTSAPegasusDoorCloseOut = 6457;
-static const bool kPegasusUnresolved = false;
-static const bool kPegasusResolved = true;
-static const bool kPegasusCantExit = false;
-static const bool kPegasusCanExit = true;
+enum {
+ kPegasusUnresolved = false,
+ kPegasusResolved = true,
+ kPegasusCantExit = false,
+ kPegasusCanExit = true
+};
// Monitor modes
enum {
@@ -582,15 +597,17 @@ static const ExtraID s_historicalLogViews[16] = {
kTSA0BComparisonView2222
};
-static const int kRedirectionCCRolloverSprite = 0;
-static const int kRedirectionRRRolloverSprite = 1;
-static const int kRedirectionFDRolloverSprite = 2;
-static const int kRedirectionCCDoorSprite = 3;
-static const int kRedirectionRRDoorSprite = 4;
-static const int kRedirectionFDDoorSprite = 5;
-static const int kRedirectionCloseSprite = 6;
-static const int kRedirectionSecuredSprite = 0;
-static const int kRedirectionNewTargetSprite = 1;
+enum {
+ kRedirectionCCRolloverSprite = 0,
+ kRedirectionRRRolloverSprite = 1,
+ kRedirectionFDRolloverSprite = 2,
+ kRedirectionCCDoorSprite = 3,
+ kRedirectionRRDoorSprite = 4,
+ kRedirectionFDDoorSprite = 5,
+ kRedirectionCloseSprite = 6,
+ kRedirectionSecuredSprite = 0,
+ kRedirectionNewTargetSprite = 1
+};
void RipTimer::initImage() {
_middle = -1;
diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.cpp b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
index c808325b0f..0c29e06f41 100644
--- a/engines/pegasus/neighborhood/tsa/tinytsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
@@ -38,71 +38,81 @@ namespace Pegasus {
static const int16 kCompassShift = 30;
-static const TimeScale kTinyTSAMovieScale = 600;
-static const TimeScale kTinyTSAFramesPerSecond = 15;
-static const TimeScale kTinyTSAFrameDuration = 40;
+enum {
+ kTinyTSAMovieScale = 600,
+ kTinyTSAFramesPerSecond = 15,
+ kTinyTSAFrameDuration = 40
+};
// Alternate IDs.
-static const AlternateID kAltTinyTSANormal = 0;
+enum {
+ kAltTinyTSANormal = 0
+};
// Hot Spot Activation IDs.
-static const HotSpotActivationID kActivationTinyTSAJumpToNorad = 1;
-static const HotSpotActivationID kActivationTinyTSAJumpToMars = 2;
-static const HotSpotActivationID kActivationTinyTSAJumpToWSC = 3;
-static const HotSpotActivationID kActivationTinyTSAReadyForJumpMenu = 4;
-static const HotSpotActivationID kActivationTinyTSAMainJumpMenu = 5;
+enum {
+ kActivationTinyTSAJumpToNorad = 1,
+ kActivationTinyTSAJumpToMars = 2,
+ kActivationTinyTSAJumpToWSC = 3,
+ kActivationTinyTSAReadyForJumpMenu = 4,
+ kActivationTinyTSAMainJumpMenu = 5
+};
// Hot Spot IDs.
-static const HotSpotID kTinyTSA37NorthJumpToNoradSpotID = 5000;
-static const HotSpotID kTinyTSA37NorthCancelNoradSpotID = 5001;
-static const HotSpotID kTinyTSA37NorthJumpToMarsSpotID = 5002;
-static const HotSpotID kTinyTSA37NorthCancelMarsSpotID = 5003;
-static const HotSpotID kTinyTSA37NorthJumpToWSCSpotID = 5004;
-static const HotSpotID kTinyTSA37NorthCancelWSCSpotID = 5005;
-static const HotSpotID kTinyTSA37NorthJumpMenuSpotID = 5006;
-static const HotSpotID kTinyTSA37NorthNoradMenuSpotID = 5007;
-static const HotSpotID kTinyTSA37NorthMarsMenuSpotID = 5008;
-static const HotSpotID kTinyTSA37NorthWSCMenuSpotID = 5009;
+enum {
+ kTinyTSA37NorthJumpToNoradSpotID = 5000,
+ kTinyTSA37NorthCancelNoradSpotID = 5001,
+ kTinyTSA37NorthJumpToMarsSpotID = 5002,
+ kTinyTSA37NorthCancelMarsSpotID = 5003,
+ kTinyTSA37NorthJumpToWSCSpotID = 5004,
+ kTinyTSA37NorthCancelWSCSpotID = 5005,
+ kTinyTSA37NorthJumpMenuSpotID = 5006,
+ kTinyTSA37NorthNoradMenuSpotID = 5007,
+ kTinyTSA37NorthMarsMenuSpotID = 5008,
+ kTinyTSA37NorthWSCMenuSpotID = 5009
+};
// Extra sequence IDs.
-static const ExtraID kTinyTSA37PegasusDepart = 0;
-static const ExtraID kTinyTSA37TimeJumpToPegasus = 1;
-static const ExtraID kTinyTSA37RecallToDownload = 2;
-static const ExtraID kTinyTSA37ExitHilited = 3;
-static const ExtraID kTinyTSA37ExitToHorse = 4;
-static const ExtraID kTinyTSA37JumpMenu000 = 5;
-static const ExtraID kTinyTSA37JumpMenu001 = 6;
-static const ExtraID kTinyTSA37JumpMenu010 = 7;
-static const ExtraID kTinyTSA37JumpMenu011 = 8;
-static const ExtraID kTinyTSA37JumpMenu100 = 9;
-static const ExtraID kTinyTSA37JumpMenu101 = 10;
-static const ExtraID kTinyTSA37JumpMenu110 = 11;
-static const ExtraID kTinyTSA37JumpMenu111 = 12;
-static const ExtraID kTinyTSA37JumpToWSCMenu = 13;
-static const ExtraID kTinyTSA37CancelWSC = 14;
-static const ExtraID kTinyTSA37JumpToWSC = 15;
-static const ExtraID kTinyTSA37WSCToAI5 = 16;
-static const ExtraID kTinyTSA37PegasusAI5 = 17;
-static const ExtraID kTinyTSA37AI5ToWSC = 18;
-static const ExtraID kTinyTSA37WSCToDepart = 19;
-static const ExtraID kTinyTSA37JumpToMarsMenu = 20;
-static const ExtraID kTinyTSA37CancelMars = 21;
-static const ExtraID kTinyTSA37JumpToMars = 22;
-static const ExtraID kTinyTSA37MarsToAI6 = 23;
-static const ExtraID kTinyTSA37PegasusAI6 = 24;
-static const ExtraID kTinyTSA37AI6ToMars = 25;
-static const ExtraID kTinyTSA37MarsToDepart = 26;
-static const ExtraID kTinyTSA37JumpToNoradMenu = 27;
-static const ExtraID kTinyTSA37CancelNorad = 28;
-static const ExtraID kTinyTSA37JumpToNorad = 29;
-static const ExtraID kTinyTSA37NoradToAI7 = 30;
-static const ExtraID kTinyTSA37PegasusAI7 = 31;
-static const ExtraID kTinyTSA37AI7ToNorad = 32;
-static const ExtraID kTinyTSA37NoradToDepart = 33;
-static const ExtraID kTinyTSA37EnvironmentalScan = 34;
-static const ExtraID kTinyTSA37DownloadToMainMenu = 35;
-static const ExtraID kTinyTSA37DownloadToOpMemReview = 36;
-static const ExtraID kTinyTSA37OpMemReviewToMainMenu = 37;
+enum {
+ kTinyTSA37PegasusDepart = 0,
+ kTinyTSA37TimeJumpToPegasus = 1,
+ kTinyTSA37RecallToDownload = 2,
+ kTinyTSA37ExitHilited = 3,
+ kTinyTSA37ExitToHorse = 4,
+ kTinyTSA37JumpMenu000 = 5,
+ kTinyTSA37JumpMenu001 = 6,
+ kTinyTSA37JumpMenu010 = 7,
+ kTinyTSA37JumpMenu011 = 8,
+ kTinyTSA37JumpMenu100 = 9,
+ kTinyTSA37JumpMenu101 = 10,
+ kTinyTSA37JumpMenu110 = 11,
+ kTinyTSA37JumpMenu111 = 12,
+ kTinyTSA37JumpToWSCMenu = 13,
+ kTinyTSA37CancelWSC = 14,
+ kTinyTSA37JumpToWSC = 15,
+ kTinyTSA37WSCToAI5 = 16,
+ kTinyTSA37PegasusAI5 = 17,
+ kTinyTSA37AI5ToWSC = 18,
+ kTinyTSA37WSCToDepart = 19,
+ kTinyTSA37JumpToMarsMenu = 20,
+ kTinyTSA37CancelMars = 21,
+ kTinyTSA37JumpToMars = 22,
+ kTinyTSA37MarsToAI6 = 23,
+ kTinyTSA37PegasusAI6 = 24,
+ kTinyTSA37AI6ToMars = 25,
+ kTinyTSA37MarsToDepart = 26,
+ kTinyTSA37JumpToNoradMenu = 27,
+ kTinyTSA37CancelNorad = 28,
+ kTinyTSA37JumpToNorad = 29,
+ kTinyTSA37NoradToAI7 = 30,
+ kTinyTSA37PegasusAI7 = 31,
+ kTinyTSA37AI7ToNorad = 32,
+ kTinyTSA37NoradToDepart = 33,
+ kTinyTSA37EnvironmentalScan = 34,
+ kTinyTSA37DownloadToMainMenu = 35,
+ kTinyTSA37DownloadToOpMemReview = 36,
+ kTinyTSA37OpMemReviewToMainMenu = 37
+};
TinyTSA::TinyTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Tiny TSA", kTinyTSAID) {
}
diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp
index f009b35cdc..5e35d8ccc1 100644
--- a/engines/pegasus/neighborhood/wsc/wsc.cpp
+++ b/engines/pegasus/neighborhood/wsc/wsc.cpp
@@ -87,81 +87,85 @@ static const int kTimerEventPlasmaHit = 0;
static const int kTimerEventPlayerGawkingAtRobot = 1;
static const int kTimerEventPlayerGawkingAtRobot2 = 2;
-static const TimeValue kWSCMolecule1In = 0;
-static const TimeValue kWSCMolecule1Out = 937;
+enum {
+ kWSCMolecule1In = 0,
+ kWSCMolecule1Out = 937,
-static const TimeValue kWSCMolecule2In = 937;
-static const TimeValue kWSCMolecule2Out = 1864;
+ kWSCMolecule2In = 937,
+ kWSCMolecule2Out = 1864,
-static const TimeValue kWSCMolecule3In = 1864;
-static const TimeValue kWSCMolecule3Out = 2790;
+ kWSCMolecule3In = 1864,
+ kWSCMolecule3Out = 2790,
-static const TimeValue kWSCClick1In = 2790;
-static const TimeValue kWSCClick1Out = 2890;
+ kWSCClick1In = 2790,
+ kWSCClick1Out = 2890,
-static const TimeValue kWSCClick2In = 2890;
-static const TimeValue kWSCClick2Out = 3059;
+ kWSCClick2In = 2890,
+ kWSCClick2Out = 3059,
-static const TimeValue kWSCClick3In = 3059;
-static const TimeValue kWSCClick3Out = 3156;
+ kWSCClick3In = 3059,
+ kWSCClick3Out = 3156,
-static const TimeValue kWSCFlashlightClickIn = 3156;
-static const TimeValue kWSCFlashlightClickOut = 3211;
+ kWSCFlashlightClickIn = 3156,
+ kWSCFlashlightClickOut = 3211,
-static const TimeValue kWSCBumpIntoWallIn = 3211;
-static const TimeValue kWSCBumpIntoWallOut = 3514;
+ kWSCBumpIntoWallIn = 3211,
+ kWSCBumpIntoWallOut = 3514,
-static const TimeValue kWSCCantTransportIn = 3514;
-static const TimeValue kWSCCantTransportOut = 7791;
+ kWSCCantTransportIn = 3514,
+ kWSCCantTransportOut = 7791,
-static const TimeValue kHernandezNotHomeIn = 7791;
-static const TimeValue kHernandezNotHomeOut = 10199;
+ kHernandezNotHomeIn = 7791,
+ kHernandezNotHomeOut = 10199,
-static const TimeValue kWashingtonNotHomeIn = 10199;
-static const TimeValue kWashingtonNotHomeOut = 12649;
+ kWashingtonNotHomeIn = 10199,
+ kWashingtonNotHomeOut = 12649,
-static const TimeValue kSullivanNotHomeIn = 12649;
-static const TimeValue kSullivanNotHomeOut = 15031;
+ kSullivanNotHomeIn = 12649,
+ kSullivanNotHomeOut = 15031,
-static const TimeValue kNakamuraNotHomeIn = 15031;
-static const TimeValue kNakamuraNotHomeOut = 17545;
+ kNakamuraNotHomeIn = 15031,
+ kNakamuraNotHomeOut = 17545,
-static const TimeValue kGrailisNotHomeIn = 17545;
-static const TimeValue kGrailisNotHomeOut = 19937;
+ kGrailisNotHomeIn = 17545,
+ kGrailisNotHomeOut = 19937,
-static const TimeValue kTheriaultNotHomeIn = 19937;
-static const TimeValue kTheriaultNotHomeOut = 22395;
+ kTheriaultNotHomeIn = 19937,
+ kTheriaultNotHomeOut = 22395,
-static const TimeValue kGlennerNotHomeIn = 22395;
-static const TimeValue kGlennerNotHomeOut = 24770;
+ kGlennerNotHomeIn = 22395,
+ kGlennerNotHomeOut = 24770,
-static const TimeValue kSinclairNotHomeIn = 24770;
-static const TimeValue kSinclairNotHomeOut = 27328;
+ kSinclairNotHomeIn = 24770,
+ kSinclairNotHomeOut = 27328,
-static const TimeValue kWSCLabClosedIn = 27328;
-static const TimeValue kWSCLabClosedOut = 28904;
+ kWSCLabClosedIn = 27328,
+ kWSCLabClosedOut = 28904,
-static const TimeValue kSlidingDoorCloseIn = 28904;
-static const TimeValue kSlidingDoorCloseOut = 29295;
+ kSlidingDoorCloseIn = 28904,
+ kSlidingDoorCloseOut = 29295,
-static const TimeValue kSlimyDoorCloseIn = 29295;
-static const TimeValue kSlimyDoorCloseOut = 29788;
+ kSlimyDoorCloseIn = 29295,
+ kSlimyDoorCloseOut = 29788,
-static const TimeValue kPaging1In = 29788;
-static const TimeValue kPaging1Out = 32501;
+ kPaging1In = 29788,
+ kPaging1Out = 32501,
-static const TimeValue kPaging2In = 32501;
-static const TimeValue kPaging2Out = 34892;
+ kPaging2In = 32501,
+ kPaging2Out = 34892,
-static const TimeValue kCheckInIn = 34892;
-static const TimeValue kCheckInOut = 37789;
+ kCheckInIn = 34892,
+ kCheckInOut = 37789,
-static const TimeValue kDrinkAntidoteIn = 37789;
-static const TimeValue kDrinkAntidoteOut = 39725;
+ kDrinkAntidoteIn = 37789,
+ kDrinkAntidoteOut = 39725
+};
-static const TimeScale kWSCMovieScale = 600;
-static const TimeScale kWSCFramesPerSecond = 15;
-static const TimeScale kWSCFrameDuration = 40;
+enum {
+ kWSCMovieScale = 600,
+ kWSCFramesPerSecond = 15,
+ kWSCFrameDuration = 40
+};
// Alternate IDs.
static const AlternateID kAltWSCNormal = 0;
@@ -170,304 +174,312 @@ static const AlternateID kAltWSCW0ZDoorOpen = 2;
static const AlternateID kAltWSCPeopleAtW19North = 3;
// Room IDs.
-static const RoomID kWSC02 = 1;
-static const RoomID kWSC03 = 4;
-static const RoomID kWSC04 = 5;
-static const RoomID kWSC06 = 6;
-static const RoomID kWSC07 = 7;
-static const RoomID kWSC08 = 8;
-static const RoomID kWSC09 = 9;
-static const RoomID kWSC10 = 10;
-static const RoomID kWSC11 = 11;
-static const RoomID kWSC13 = 12;
-static const RoomID kWSC14 = 13;
-static const RoomID kWSC15 = 14;
-static const RoomID kWSC16 = 15;
-static const RoomID kWSC17 = 16;
-static const RoomID kWSC18 = 17;
-static const RoomID kWSC19 = 18;
-static const RoomID kWSC20 = 19;
-static const RoomID kWSC21 = 20;
-static const RoomID kWSC22 = 21;
-static const RoomID kWSC23 = 22;
-static const RoomID kWSC24 = 23;
-static const RoomID kWSC25 = 24;
-static const RoomID kWSC26 = 25;
-static const RoomID kWSC27 = 26;
-static const RoomID kWSC28 = 27;
-static const RoomID kWSC29 = 28;
-static const RoomID kWSC31 = 29;
-static const RoomID kWSC32 = 30;
-static const RoomID kWSC33 = 31;
-static const RoomID kWSC34 = 32;
-static const RoomID kWSC35 = 33;
-static const RoomID kWSC36 = 34;
-static const RoomID kWSC37 = 35;
-static const RoomID kWSC38 = 36;
-static const RoomID kWSC39 = 37;
-static const RoomID kWSC40 = 38;
-static const RoomID kWSC41 = 39;
-static const RoomID kWSC42 = 40;
-static const RoomID kWSC43 = 41;
-static const RoomID kWSC44 = 42;
-static const RoomID kWSC45 = 43;
-static const RoomID kWSC46 = 44;
-static const RoomID kWSC47 = 45;
-static const RoomID kWSC48 = 46;
-static const RoomID kWSC49 = 47;
-static const RoomID kWSC50 = 48;
-static const RoomID kWSC52 = 49;
-static const RoomID kWSC53 = 50;
-static const RoomID kWSC54 = 51;
-static const RoomID kWSC55 = 52;
-static const RoomID kWSC56 = 53;
-static const RoomID kWSC57 = 54;
-static const RoomID kWSC58 = 55;
-static const RoomID kWSC60 = 56;
-static const RoomID kWSC60East = 57;
-static const RoomID kWSC60North = 58;
-static const RoomID kWSC61 = 59;
-static const RoomID kWSC61South = 60;
-static const RoomID kWSC61West = 61;
-static const RoomID kWSC63 = 63;
-static const RoomID kWSC64 = 64;
-static const RoomID kWSC65 = 65;
-static const RoomID kWSC65Screen = 66;
-static const RoomID kWSC66 = 67;
-static const RoomID kWSC67 = 68;
-static const RoomID kWSC68 = 69;
-static const RoomID kWSC69 = 70;
-static const RoomID kWSC70 = 71;
-static const RoomID kWSC71 = 72;
-static const RoomID kWSC72 = 73;
-static const RoomID kWSC73 = 74;
-static const RoomID kWSC74 = 75;
-static const RoomID kWSC75 = 76;
-static const RoomID kWSC0Z = 77;
-static const RoomID kWSC76 = 78;
-static const RoomID kWSC77 = 79;
-static const RoomID kWSC78 = 80;
-static const RoomID kWSC79 = 81;
-static const RoomID kWSC80 = 82;
-static const RoomID kWSC81 = 83;
-static const RoomID kWSC82 = 84;
-static const RoomID kWSC83 = 85;
-static const RoomID kWSC84 = 86;
-static const RoomID kWSC85 = 87;
-static const RoomID kWSC86 = 88;
-static const RoomID kWSC87 = 89;
-static const RoomID kWSC88 = 90;
-static const RoomID kWSC89 = 91;
-static const RoomID kWSC90 = 92;
-static const RoomID kWSC91 = 93;
-static const RoomID kWSC92 = 94;
-static const RoomID kWSC93 = 95;
-static const RoomID kWSC94 = 96;
-static const RoomID kWSC95 = 97;
-static const RoomID kWSC96 = 98;
-static const RoomID kWSC97 = 99;
-static const RoomID kWSC98 = 100;
-static const RoomID kWSCDeathRoom = 101;
+enum {
+ kWSC02 = 1,
+ kWSC03 = 4,
+ kWSC04 = 5,
+ kWSC06 = 6,
+ kWSC07 = 7,
+ kWSC08 = 8,
+ kWSC09 = 9,
+ kWSC10 = 10,
+ kWSC11 = 11,
+ kWSC13 = 12,
+ kWSC14 = 13,
+ kWSC15 = 14,
+ kWSC16 = 15,
+ kWSC17 = 16,
+ kWSC18 = 17,
+ kWSC19 = 18,
+ kWSC20 = 19,
+ kWSC21 = 20,
+ kWSC22 = 21,
+ kWSC23 = 22,
+ kWSC24 = 23,
+ kWSC25 = 24,
+ kWSC26 = 25,
+ kWSC27 = 26,
+ kWSC28 = 27,
+ kWSC29 = 28,
+ kWSC31 = 29,
+ kWSC32 = 30,
+ kWSC33 = 31,
+ kWSC34 = 32,
+ kWSC35 = 33,
+ kWSC36 = 34,
+ kWSC37 = 35,
+ kWSC38 = 36,
+ kWSC39 = 37,
+ kWSC40 = 38,
+ kWSC41 = 39,
+ kWSC42 = 40,
+ kWSC43 = 41,
+ kWSC44 = 42,
+ kWSC45 = 43,
+ kWSC46 = 44,
+ kWSC47 = 45,
+ kWSC48 = 46,
+ kWSC49 = 47,
+ kWSC50 = 48,
+ kWSC52 = 49,
+ kWSC53 = 50,
+ kWSC54 = 51,
+ kWSC55 = 52,
+ kWSC56 = 53,
+ kWSC57 = 54,
+ kWSC58 = 55,
+ kWSC60 = 56,
+ kWSC60East = 57,
+ kWSC60North = 58,
+ kWSC61 = 59,
+ kWSC61South = 60,
+ kWSC61West = 61,
+ kWSC63 = 63,
+ kWSC64 = 64,
+ kWSC65 = 65,
+ kWSC65Screen = 66,
+ kWSC66 = 67,
+ kWSC67 = 68,
+ kWSC68 = 69,
+ kWSC69 = 70,
+ kWSC70 = 71,
+ kWSC71 = 72,
+ kWSC72 = 73,
+ kWSC73 = 74,
+ kWSC74 = 75,
+ kWSC75 = 76,
+ kWSC0Z = 77,
+ kWSC76 = 78,
+ kWSC77 = 79,
+ kWSC78 = 80,
+ kWSC79 = 81,
+ kWSC80 = 82,
+ kWSC81 = 83,
+ kWSC82 = 84,
+ kWSC83 = 85,
+ kWSC84 = 86,
+ kWSC85 = 87,
+ kWSC86 = 88,
+ kWSC87 = 89,
+ kWSC88 = 90,
+ kWSC89 = 91,
+ kWSC90 = 92,
+ kWSC91 = 93,
+ kWSC92 = 94,
+ kWSC93 = 95,
+ kWSC94 = 96,
+ kWSC95 = 97,
+ kWSC96 = 98,
+ kWSC97 = 99,
+ kWSC98 = 100,
+ kWSCDeathRoom = 101
+};
// Hot Spot Activation IDs.
-static const HotSpotActivationID kActivationZoomedInToAnalyzer = 1;
-static const HotSpotActivationID kActivationShotByRobot = 2;
-static const HotSpotActivationID kActivationWarnedAboutPoison = 3;
-static const HotSpotActivationID kActivationMorphScreenOff = 4;
-static const HotSpotActivationID kActivationReadyForMorph = 5;
-static const HotSpotActivationID kActivationMorphLooping = 6;
-static const HotSpotActivationID kActivationMorphInterrupted = 7;
-static const HotSpotActivationID kActivationW03NorthOff = 8;
-static const HotSpotActivationID kActivationW03NorthReadyForInstructions = 9;
-static const HotSpotActivationID kActivationW03NorthSawInstructions = 10;
-static const HotSpotActivationID kActivationW03NorthInGame = 11;
-static const HotSpotActivationID kActivationReadyForSynthesis = 12;
-static const HotSpotActivationID kActivationSynthesizerLooping = 13;
-static const HotSpotActivationID kActivationReadyForMap = 14;
-static const HotSpotActivationID kActivationSinclairOfficeLocked = 15;
-static const HotSpotActivationID kActivationW58SouthDoorLocked = 16;
-static const HotSpotActivationID kActivationW61SouthOff = 17;
-static const HotSpotActivationID kActivationW61SouthOn = 18;
-static const HotSpotActivationID kActivationW61MessagesOff = 19;
-static const HotSpotActivationID kActivationW61MessagesOn = 20;
-static const HotSpotActivationID kActivationWSCRobotHeadOpen = 21;
-static const HotSpotActivationID kActivationRobotTurning = 22;
-static const HotSpotActivationID kActivationRobotDead = 23;
-static const HotSpotActivationID kActivationRobotGone = 24;
+enum {
+ kActivationZoomedInToAnalyzer = 1,
+ kActivationShotByRobot = 2,
+ kActivationWarnedAboutPoison = 3,
+ kActivationMorphScreenOff = 4,
+ kActivationReadyForMorph = 5,
+ kActivationMorphLooping = 6,
+ kActivationMorphInterrupted = 7,
+ kActivationW03NorthOff = 8,
+ kActivationW03NorthReadyForInstructions = 9,
+ kActivationW03NorthSawInstructions = 10,
+ kActivationW03NorthInGame = 11,
+ kActivationReadyForSynthesis = 12,
+ kActivationSynthesizerLooping = 13,
+ kActivationReadyForMap = 14,
+ kActivationSinclairOfficeLocked = 15,
+ kActivationW58SouthDoorLocked = 16,
+ kActivationW61SouthOff = 17,
+ kActivationW61SouthOn = 18,
+ kActivationW61MessagesOff = 19,
+ kActivationW61MessagesOn = 20,
+ kActivationWSCRobotHeadOpen = 21,
+ kActivationRobotTurning = 22,
+ kActivationRobotDead = 23,
+ kActivationRobotGone = 24
+};
// Hot Spot IDs.
-static const HotSpotID kWSCDropDartSpotID = 5000;
-static const HotSpotID kWSCTurnOnAnalyzerSpotID = 5001;
-static const HotSpotID kWSCAnalyzerScreenSpotID = 5002;
-static const HotSpotID kWSCSpinRobotSpotID = 5003;
-static const HotSpotID kWSC01YesSpotID = 5004;
-static const HotSpotID kWSC01NoSpotID = 5005;
-static const HotSpotID kWSC01AcknowledgeWarningSpotID = 5006;
-static const HotSpotID kWSC02SouthMorphSpotID = 5007;
-static const HotSpotID kWSC02SouthMessagesSpotID = 5008;
-static const HotSpotID kWSC02SouthMorphOutSpotID = 5009;
-static const HotSpotID kWSC02ActivateMorphScreenSpotID = 5010;
-static const HotSpotID kWSC02SouthStartMorphSpotID = 5011;
-static const HotSpotID kWSC02SouthInterruptMorphSpotID = 5012;
-static const HotSpotID kWSC02SouthMorphFinishedSpotID = 5013;
-static const HotSpotID kWSC02SouthTakeArgonSpotID = 5014;
-static const HotSpotID kWSC02SouthMessagesOutSpotID = 5015;
-static const HotSpotID kWSC02SouthTakeNitrogenSpotID = 5016;
-static const HotSpotID kWSC02SouthPlayMessagesSpotID = 5017;
-static const HotSpotID kWSC03NorthActivateScreenSpotID = 5018;
-static const HotSpotID kWSC03NorthBuildMoleculeSpotID = 5019;
-static const HotSpotID kWSC03NorthProceedSpotID = 5020;
-static const HotSpotID kWSC03NorthMolecule1SpotID = 5021;
-static const HotSpotID kWSC03NorthMolecule2SpotID = 5022;
-static const HotSpotID kWSC03NorthMolecule3SpotID = 5023;
-static const HotSpotID kWSC03NorthMolecule4SpotID = 5024;
-static const HotSpotID kWSC03NorthMolecule5SpotID = 5025;
-static const HotSpotID kWSC03NorthMolecule6SpotID = 5026;
-static const HotSpotID kWSC03SouthActivateSynthesizerSpotID = 5027;
-static const HotSpotID kWSC03SouthPickUpAntidoteSpotID = 5028;
-static const HotSpotID kWSC07SouthMapSpotID = 5029;
-static const HotSpotID kW42EastUnlockDoorSpotID = 5030;
-static const HotSpotID kW56NorthMapSpotID = 5031;
-static const HotSpotID kW58SouthPryDoorSpotID = 5032;
-static const HotSpotID kWSC60EastSpotID = 5033;
-static const HotSpotID kWSC60NorthSpotID = 5034;
-static const HotSpotID kWSC60EastOutSpotID = 5035;
-static const HotSpotID kWSC60NorthOutSpotID = 5036;
-static const HotSpotID kWSC61EastSpotID = 5037;
-static const HotSpotID kWSC61SouthSpotID = 5038;
-static const HotSpotID kW61SouthMachineGunSpotID = 5039;
-static const HotSpotID kW61SouthDropMachineGunSpotID = 5040;
-static const HotSpotID kWSC61WestSpotID = 5041;
-static const HotSpotID kWSC61SouthOutSpotID = 5042;
-static const HotSpotID kW61SouthActivateSpotID = 5043;
-static const HotSpotID kW61SmartAlloysSpotID = 5044;
-static const HotSpotID kW61MorphingSpotID = 5045;
-static const HotSpotID kW61TimeBendingSpotID = 5046;
-static const HotSpotID kWSC61WestOutSpotID = 5047;
-static const HotSpotID kW61TurnOnMessagesSpotID = 5048;
-static const HotSpotID kW61WhiteMessageSpotID = 5049;
-static const HotSpotID kW61WalchekMessageSpotID = 5050;
-static const HotSpotID kWSC65SouthScreenSpotID = 5051;
-static const HotSpotID kWSC65SouthScreenOutSpotID = 5052;
-static const HotSpotID kW98RetinalChipSpotID = 5053;
-static const HotSpotID kW98MapChipSpotID = 5054;
-static const HotSpotID kW98OpticalChipSpotID = 5055;
-static const HotSpotID kW98DropArgonSpotID = 5056;
-static const HotSpotID kW98GrabCableSpotID = 5057;
-static const HotSpotID kW98OpenRobotSpotID = 5058;
-static const HotSpotID kW98StunGunSpotID = 5059;
+enum {
+ kWSCDropDartSpotID = 5000,
+ kWSCTurnOnAnalyzerSpotID = 5001,
+ kWSCAnalyzerScreenSpotID = 5002,
+ kWSCSpinRobotSpotID = 5003,
+ kWSC01YesSpotID = 5004,
+ kWSC01NoSpotID = 5005,
+ kWSC01AcknowledgeWarningSpotID = 5006,
+ kWSC02SouthMorphSpotID = 5007,
+ kWSC02SouthMessagesSpotID = 5008,
+ kWSC02SouthMorphOutSpotID = 5009,
+ kWSC02ActivateMorphScreenSpotID = 5010,
+ kWSC02SouthStartMorphSpotID = 5011,
+ kWSC02SouthInterruptMorphSpotID = 5012,
+ kWSC02SouthMorphFinishedSpotID = 5013,
+ kWSC02SouthTakeArgonSpotID = 5014,
+ kWSC02SouthMessagesOutSpotID = 5015,
+ kWSC02SouthTakeNitrogenSpotID = 5016,
+ kWSC02SouthPlayMessagesSpotID = 5017,
+ kWSC03NorthActivateScreenSpotID = 5018,
+ kWSC03NorthBuildMoleculeSpotID = 5019,
+ kWSC03NorthProceedSpotID = 5020,
+ kWSC03NorthMolecule1SpotID = 5021,
+ kWSC03NorthMolecule2SpotID = 5022,
+ kWSC03NorthMolecule3SpotID = 5023,
+ kWSC03NorthMolecule4SpotID = 5024,
+ kWSC03NorthMolecule5SpotID = 5025,
+ kWSC03NorthMolecule6SpotID = 5026,
+ kWSC03SouthActivateSynthesizerSpotID = 5027,
+ kWSC03SouthPickUpAntidoteSpotID = 5028,
+ kWSC07SouthMapSpotID = 5029,
+ kW42EastUnlockDoorSpotID = 5030,
+ kW56NorthMapSpotID = 5031,
+ kW58SouthPryDoorSpotID = 5032,
+ kWSC60EastSpotID = 5033,
+ kWSC60NorthSpotID = 5034,
+ kWSC60EastOutSpotID = 5035,
+ kWSC60NorthOutSpotID = 5036,
+ kWSC61EastSpotID = 5037,
+ kWSC61SouthSpotID = 5038,
+ kW61SouthMachineGunSpotID = 5039,
+ kW61SouthDropMachineGunSpotID = 5040,
+ kWSC61WestSpotID = 5041,
+ kWSC61SouthOutSpotID = 5042,
+ kW61SouthActivateSpotID = 5043,
+ kW61SmartAlloysSpotID = 5044,
+ kW61MorphingSpotID = 5045,
+ kW61TimeBendingSpotID = 5046,
+ kWSC61WestOutSpotID = 5047,
+ kW61TurnOnMessagesSpotID = 5048,
+ kW61WhiteMessageSpotID = 5049,
+ kW61WalchekMessageSpotID = 5050,
+ kWSC65SouthScreenSpotID = 5051,
+ kWSC65SouthScreenOutSpotID = 5052,
+ kW98RetinalChipSpotID = 5053,
+ kW98MapChipSpotID = 5054,
+ kW98OpticalChipSpotID = 5055,
+ kW98DropArgonSpotID = 5056,
+ kW98GrabCableSpotID = 5057,
+ kW98OpenRobotSpotID = 5058,
+ kW98StunGunSpotID = 5059
+};
// Extra sequence IDs.
-static const ExtraID kWSCArrivalFromTSA = 0;
-static const ExtraID kWSCShotByRobot = 1;
-static const ExtraID kWSCDartScan1 = 2;
-static const ExtraID kWSCDartScan2 = 3;
-static const ExtraID kWSCDartScanNo = 4;
-static const ExtraID kWSCDartScan3 = 5;
-static const ExtraID kWSCAnalyzerPowerUp = 6;
-static const ExtraID kWSCAnalyzerPowerUpWithDart = 7;
-static const ExtraID kWSCDropDartIntoAnalyzer = 8;
-static const ExtraID kWSCAnalyzeDart = 9;
-static const ExtraID kWSCZoomOutFromAnalyzer = 10;
-static const ExtraID kWSCSpinRobot = 11;
-static const ExtraID kWSC02MorphZoomNoArgon = 12;
-static const ExtraID kWSC02MessagesZoomNoNitrogen = 13;
-static const ExtraID kWSC02ZoomOutNoArgon = 14;
-static const ExtraID kWSC02TurnOnMorphScreen = 15;
-static const ExtraID kWSC02DropToMorphExperiment = 16;
-static const ExtraID kWSC02MorphLoop = 17;
-static const ExtraID kWSC02MorphInterruption = 18;
-static const ExtraID kWSC02MorphFinished = 19;
-static const ExtraID kWSC02TurnOffMorphScreen = 20;
-static const ExtraID kWSC02SouthViewNoArgon = 21;
-static const ExtraID kMessagesMovedToOffice = 22;
-static const ExtraID kMessagesOff = 23;
-static const ExtraID kMessagesZoomOutNoNitrogen = 24;
-static const ExtraID kMessagesMovedToOfficeNoNitrogen = 25;
-static const ExtraID kMessagesOffNoNitrogen = 26;
-static const ExtraID kMessagesViewNoNitrogen = 27;
-static const ExtraID kMessagesViewMachineOnNoNitrogen = 28;
-static const ExtraID kW03NorthActivate = 29;
-static const ExtraID kW03NorthGetData = 30;
-static const ExtraID kW03NorthInstructions = 31;
-static const ExtraID kW03NorthPrepMolecule1 = 32;
-static const ExtraID kW03NorthPrepMolecule2 = 33;
-static const ExtraID kW03NorthPrepMolecule3 = 34;
-static const ExtraID kW03NorthFinishSynthesis = 35;
-static const ExtraID kW03SouthCreateAntidote = 36;
-static const ExtraID kW03SouthAntidoteLoop = 37;
-static const ExtraID kW03SouthDeactivate = 38;
-static const ExtraID kW03SouthViewNoAntidote = 39;
-static const ExtraID kWSC07SouthMap = 40;
-static const ExtraID kW17WestPeopleCrossing = 41;
-static const ExtraID kW17WestPeopleCrossingView = 42;
-static const ExtraID kW21SouthPeopleCrossing = 43;
-static const ExtraID kW24SouthPeopleCrossing = 44;
-static const ExtraID kW34EastPeopleCrossing = 45;
-static const ExtraID kW36WestPeopleCrossing = 46;
-static const ExtraID kW38NorthPeopleCrossing = 47;
-static const ExtraID kW46SouthPeopleCrossing = 48;
-static const ExtraID kW49NorthPeopleCrossing = 49;
-static const ExtraID kW49NorthPeopleCrossingView = 50;
-static const ExtraID kWSC56SouthMap = 51;
-static const ExtraID kNerdAtTheDoor1 = 52;
-static const ExtraID kNerdAtTheDoor2 = 53;
-static const ExtraID kW61SouthZoomInNoGun = 54;
-static const ExtraID kW61Brochure = 55;
-static const ExtraID kW61SouthScreenOnWithGun = 56;
-static const ExtraID kW61SouthScreenOffWithGun = 57;
-static const ExtraID kW61SouthSmartAlloysWithGun = 58;
-static const ExtraID kW61SouthMorphingWithGun = 59;
-static const ExtraID kW61SouthTimeBendingWithGun = 60;
-static const ExtraID kW61SouthZoomOutNoGun = 61;
-static const ExtraID kW61SouthScreenOnNoGun = 62;
-static const ExtraID kW61SouthScreenOffNoGun = 63;
-static const ExtraID kW61SouthSmartAlloysNoGun = 64;
-static const ExtraID kW61SouthMorphingNoGun = 65;
-static const ExtraID kW61SouthTimeBendingNoGun = 66;
-static const ExtraID kW61MessagesOn = 67;
-static const ExtraID kW61MessagesOff = 68;
-static const ExtraID kW61WhiteMessage = 69;
-static const ExtraID kW61WalchekMessage = 70;
-static const ExtraID kW61WalchekEasterEgg1 = 71;
-static const ExtraID kW62SouthPlasmaRobotAppears = 72;
-static const ExtraID kW62ZoomToRobot = 73;
-static const ExtraID kW62ZoomOutFromRobot = 74;
-static const ExtraID kW62PlasmaDodgeSurvive = 75;
-static const ExtraID kW62PlasmaDodgeDie = 76;
-static const ExtraID kW65SouthSinclairLecture = 77;
-static const ExtraID kW73WestPeopleCrossing = 78;
-static const ExtraID kW73WestPeopleCrossingView = 79;
-static const ExtraID kW0ZSpottedByWomen = 80;
-static const ExtraID kW95RobotShoots = 81;
-static const ExtraID kW98MorphsToRobot = 82;
-static const ExtraID kW98RobotShoots = 83;
-static const ExtraID kW98RobotShocked = 84;
-static const ExtraID kW98RobotGassed = 85;
-static const ExtraID kW98RobotHeadOpensDark = 86;
-static const ExtraID kW98RobotHead000Dark = 87;
-static const ExtraID kW98RobotHead001Dark = 88;
-static const ExtraID kW98RobotHead010Dark = 89;
-static const ExtraID kW98RobotHead011Dark = 90;
-static const ExtraID kW98RobotHead100Dark = 91;
-static const ExtraID kW98RobotHead101Dark = 92;
-static const ExtraID kW98RobotHead110Dark = 93;
-static const ExtraID kW98RobotHead111Dark = 94;
-static const ExtraID kW98RobotHeadClosesDark = 95;
-static const ExtraID kW98WestViewWithGunDark = 96;
-static const ExtraID kW98WestViewNoGunDark = 97;
-static const ExtraID kW98RobotHeadOpensLight = 98;
-static const ExtraID kW98RobotHead000Light = 99;
-static const ExtraID kW98RobotHead001Light = 100;
-static const ExtraID kW98RobotHead010Light = 101;
-static const ExtraID kW98RobotHead011Light = 102;
-static const ExtraID kW98RobotHead100Light = 103;
-static const ExtraID kW98RobotHead101Light = 104;
-static const ExtraID kW98RobotHead110Light = 105;
-static const ExtraID kW98RobotHead111Light = 106;
-static const ExtraID kW98RobotHeadClosesLight = 107;
-static const ExtraID kW98WestViewWithGunLight = 108;
-static const ExtraID kW98WestViewNoGunLight = 109;
+enum {
+ kWSCArrivalFromTSA = 0,
+ kWSCShotByRobot = 1,
+ kWSCDartScan1 = 2,
+ kWSCDartScan2 = 3,
+ kWSCDartScanNo = 4,
+ kWSCDartScan3 = 5,
+ kWSCAnalyzerPowerUp = 6,
+ kWSCAnalyzerPowerUpWithDart = 7,
+ kWSCDropDartIntoAnalyzer = 8,
+ kWSCAnalyzeDart = 9,
+ kWSCZoomOutFromAnalyzer = 10,
+ kWSCSpinRobot = 11,
+ kWSC02MorphZoomNoArgon = 12,
+ kWSC02MessagesZoomNoNitrogen = 13,
+ kWSC02ZoomOutNoArgon = 14,
+ kWSC02TurnOnMorphScreen = 15,
+ kWSC02DropToMorphExperiment = 16,
+ kWSC02MorphLoop = 17,
+ kWSC02MorphInterruption = 18,
+ kWSC02MorphFinished = 19,
+ kWSC02TurnOffMorphScreen = 20,
+ kWSC02SouthViewNoArgon = 21,
+ kMessagesMovedToOffice = 22,
+ kMessagesOff = 23,
+ kMessagesZoomOutNoNitrogen = 24,
+ kMessagesMovedToOfficeNoNitrogen = 25,
+ kMessagesOffNoNitrogen = 26,
+ kMessagesViewNoNitrogen = 27,
+ kMessagesViewMachineOnNoNitrogen = 28,
+ kW03NorthActivate = 29,
+ kW03NorthGetData = 30,
+ kW03NorthInstructions = 31,
+ kW03NorthPrepMolecule1 = 32,
+ kW03NorthPrepMolecule2 = 33,
+ kW03NorthPrepMolecule3 = 34,
+ kW03NorthFinishSynthesis = 35,
+ kW03SouthCreateAntidote = 36,
+ kW03SouthAntidoteLoop = 37,
+ kW03SouthDeactivate = 38,
+ kW03SouthViewNoAntidote = 39,
+ kWSC07SouthMap = 40,
+ kW17WestPeopleCrossing = 41,
+ kW17WestPeopleCrossingView = 42,
+ kW21SouthPeopleCrossing = 43,
+ kW24SouthPeopleCrossing = 44,
+ kW34EastPeopleCrossing = 45,
+ kW36WestPeopleCrossing = 46,
+ kW38NorthPeopleCrossing = 47,
+ kW46SouthPeopleCrossing = 48,
+ kW49NorthPeopleCrossing = 49,
+ kW49NorthPeopleCrossingView = 50,
+ kWSC56SouthMap = 51,
+ kNerdAtTheDoor1 = 52,
+ kNerdAtTheDoor2 = 53,
+ kW61SouthZoomInNoGun = 54,
+ kW61Brochure = 55,
+ kW61SouthScreenOnWithGun = 56,
+ kW61SouthScreenOffWithGun = 57,
+ kW61SouthSmartAlloysWithGun = 58,
+ kW61SouthMorphingWithGun = 59,
+ kW61SouthTimeBendingWithGun = 60,
+ kW61SouthZoomOutNoGun = 61,
+ kW61SouthScreenOnNoGun = 62,
+ kW61SouthScreenOffNoGun = 63,
+ kW61SouthSmartAlloysNoGun = 64,
+ kW61SouthMorphingNoGun = 65,
+ kW61SouthTimeBendingNoGun = 66,
+ kW61MessagesOn = 67,
+ kW61MessagesOff = 68,
+ kW61WhiteMessage = 69,
+ kW61WalchekMessage = 70,
+ kW61WalchekEasterEgg1 = 71,
+ kW62SouthPlasmaRobotAppears = 72,
+ kW62ZoomToRobot = 73,
+ kW62ZoomOutFromRobot = 74,
+ kW62PlasmaDodgeSurvive = 75,
+ kW62PlasmaDodgeDie = 76,
+ kW65SouthSinclairLecture = 77,
+ kW73WestPeopleCrossing = 78,
+ kW73WestPeopleCrossingView = 79,
+ kW0ZSpottedByWomen = 80,
+ kW95RobotShoots = 81,
+ kW98MorphsToRobot = 82,
+ kW98RobotShoots = 83,
+ kW98RobotShocked = 84,
+ kW98RobotGassed = 85,
+ kW98RobotHeadOpensDark = 86,
+ kW98RobotHead000Dark = 87,
+ kW98RobotHead001Dark = 88,
+ kW98RobotHead010Dark = 89,
+ kW98RobotHead011Dark = 90,
+ kW98RobotHead100Dark = 91,
+ kW98RobotHead101Dark = 92,
+ kW98RobotHead110Dark = 93,
+ kW98RobotHead111Dark = 94,
+ kW98RobotHeadClosesDark = 95,
+ kW98WestViewWithGunDark = 96,
+ kW98WestViewNoGunDark = 97,
+ kW98RobotHeadOpensLight = 98,
+ kW98RobotHead000Light = 99,
+ kW98RobotHead001Light = 100,
+ kW98RobotHead010Light = 101,
+ kW98RobotHead011Light = 102,
+ kW98RobotHead100Light = 103,
+ kW98RobotHead101Light = 104,
+ kW98RobotHead110Light = 105,
+ kW98RobotHead111Light = 106,
+ kW98RobotHeadClosesLight = 107,
+ kW98WestViewWithGunLight = 108,
+ kW98WestViewNoGunLight = 109
+};
static const CoordType kMoleculesMovieLeft = kNavAreaLeft + 112;
static const CoordType kMoleculesMovieTop = kNavAreaTop + 40;
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 0010180d8d..0c8ea2e4ee 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -2514,7 +2514,7 @@ void PegasusEngine::initKeymap() {
{ Common::KEYCODE_t, "TMA", _("Toggle Center Data Display") },
{ Common::KEYCODE_i, "TIN", _("Display/Hide Info Screen") },
{ Common::KEYCODE_ESCAPE, "PM", _("Display/Hide Pause Menu") },
- { Common::KEYCODE_e, "WTF", _("???") } // easter egg key (without being completely upfront about it)
+ { Common::KEYCODE_e, "WTF", "???" } // easter egg key (without being completely upfront about it)
};
for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
diff --git a/engines/saga/console.cpp b/engines/saga/console.cpp
index 0b801eef3e..8ad7fd5aaa 100644
--- a/engines/saga/console.cpp
+++ b/engines/saga/console.cpp
@@ -25,8 +25,10 @@
#include "saga/saga.h"
#include "saga/actor.h"
#include "saga/animation.h"
+#include "saga/music.h"
#include "saga/scene.h"
#include "saga/script.h"
+#include "saga/sndres.h"
#include "saga/console.h"
@@ -45,6 +47,11 @@ Console::Console(SagaEngine *vm) : GUI::Debugger() {
registerCmd("cutaway_info", WRAP_METHOD(Console, cmdCutawayInfo));
registerCmd("play_cutaway", WRAP_METHOD(Console, cmdPlayCutaway));
+ // Sound commands
+ registerCmd("play_music", WRAP_METHOD(Console, cmdPlayMusic));
+ registerCmd("play_sound", WRAP_METHOD(Console, cmdPlaySound));
+ registerCmd("play_voice", WRAP_METHOD(Console, cmdPlayVoice));
+
// Game stuff
#if 0
@@ -117,6 +124,45 @@ bool Console::cmdPlayCutaway(int argc, const char **argv) {
return true;
}
+bool Console::cmdPlayMusic(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <Music number>\n", argv[0]);
+ } else {
+ if (_vm->getGameId() == GID_ITE)
+ _vm->_music->play(atoi(argv[1]) + 9);
+ else
+ _vm->_music->play(atoi(argv[1]));
+ }
+ return true;
+}
+
+bool Console::cmdPlaySound(int argc, const char **argv) {
+ if (argc != 2)
+ debugPrintf("Usage: %s <Sound number>\n", argv[0]);
+ else
+ _vm->_sndRes->playSound(atoi(argv[1]), 255, false);
+ return true;
+}
+
+bool Console::cmdPlayVoice(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: %s <Voice number> <Voice bank>\n", argv[0]);
+ } else {
+ int voiceBank = 0;
+
+ if (argc == 3) {
+ voiceBank = _vm->_sndRes->getVoiceBank();
+ _vm->_sndRes->setVoiceBank(atoi(argv[2]));
+ }
+
+ _vm->_sndRes->playVoice(atoi(argv[1]));
+
+ if (argc == 3)
+ _vm->_sndRes->setVoiceBank(voiceBank);
+ }
+ return true;
+}
+
bool Console::cmdCurrentScene(int argc, const char **argv) {
debugPrintf("Current Scene is: %i, scene resource id: %i\n",
_vm->_scene->currentSceneNumber(), _vm->_scene->currentSceneResourceId());
diff --git a/engines/saga/console.h b/engines/saga/console.h
index 625e6f57ad..cec964301c 100644
--- a/engines/saga/console.h
+++ b/engines/saga/console.h
@@ -41,6 +41,10 @@ private:
bool cmdCutawayInfo(int argc, const char **argv);
bool cmdPlayCutaway(int argc, const char **argv);
+ bool cmdPlayMusic(int argc, const char **argv);
+ bool cmdPlaySound(int argc, const char **argv);
+ bool cmdPlayVoice(int argc, const char **argv);
+
bool cmdCurrentScene(int argc, const char **argv);
bool cmdCurrentChapter(int argc, const char **argv);
bool cmdSceneChange(int argc, const char **argv);
diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h
index 72187a1a13..2f72e7a13c 100644
--- a/engines/saga/detection_tables.h
+++ b/engines/saga/detection_tables.h
@@ -595,6 +595,30 @@ static const SAGAGameDescription gameDescriptions[] = {
ITEPatch_Files,
},
+ // Inherit the earth - Chinese Disk version
+ {
+ {
+ "ite",
+ "Floppy",
+ {
+ {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", 8901704},
+ {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", 281071},
+ { NULL, 0, NULL, 0}
+ },
+ Common::ZH_CNA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOSPEECH)
+ },
+ GID_ITE,
+ GF_ITE_FLOPPY,
+ ITE_DEFAULT_SCENE,
+ &ITE_Resources,
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
+ ITEPatch_Files,
+ },
+
// ITE Amiga versions /////////////////////////////////////////////////////////////////////////////////////
// TODO: Add the Amiga versions here (not supported yet)
diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp
index 013b019c9f..b7c3fa4d6e 100644
--- a/engines/saga/events.cpp
+++ b/engines/saga/events.cpp
@@ -583,6 +583,18 @@ EventColumns *Events::chain(EventColumns *eventColumns, const Event &event) {
return eventColumns;
}
+EventColumns *Events::chainMusic(EventColumns *eventColumns, long musicId, bool loop, long time) {
+ Event event;
+
+ event.type = kEvTOneshot;
+ event.code = kMusicEvent;
+ event.param = musicId;
+ event.param2 = loop ? MUSIC_NORMAL : MUSIC_LOOP;
+ event.op = kEventPlay;
+ event.time = time;
+ return chain(eventColumns, event);
+}
+
void Events::initializeEvent(Event &event) {
switch (event.type) {
case kEvTOneshot:
diff --git a/engines/saga/events.h b/engines/saga/events.h
index 6c423abb8c..84a62f5a3a 100644
--- a/engines/saga/events.h
+++ b/engines/saga/events.h
@@ -172,9 +172,18 @@ class Events {
return chain(NULL, event);
}
+ // Schedules a music event in the event list; returns a pointer to the scheduled
+ // event columns suitable for chaining if desired.
+ EventColumns *queueMusic(long musicId, bool loop = false, long time = 0) {
+ return chainMusic(NULL, musicId, loop, time);
+ }
+
// Places a 'event' on the end of an event columns given by 'eventColumns'
EventColumns *chain(EventColumns *eventColumns, const Event &event);
+ // Places a music 'event' on the end of an event columns given by 'eventColumns'
+ EventColumns *chainMusic(EventColumns *eventColumns, long musicId, bool loop = false, long time = 0);
+
private:
int handleContinuous(Event *event);
int handleOneShot(Event *event);
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index 680b2274f5..44581f26fc 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -710,6 +710,11 @@ bool Interface::processAscii(Common::KeyState keystate) {
}
void Interface::setStatusText(const char *text, int statusColor) {
+ if (_vm->getGameId() == GID_FTA2 || _vm->getGameId() == GID_DINO) {
+ warning("setStatusText not implemented for SAGA2");
+ return;
+ }
+
if (_vm->getGameId() == GID_IHNM) {
// Don't show the status text for the IHNM chapter selection screens (chapter 8), or
// scene 0 (IHNM demo introduction)
diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp
index 91b1d3db95..0c1a2ce233 100644
--- a/engines/saga/introproc_ite.cpp
+++ b/engines/saga/introproc_ite.cpp
@@ -28,6 +28,7 @@
#include "saga/animation.h"
#include "saga/events.h"
#include "saga/font.h"
+#include "saga/itedata.h"
#include "saga/sndres.h"
#include "saga/palanim.h"
#include "saga/music.h"
@@ -37,10 +38,15 @@
namespace Saga {
-using Common::UNK_LANG;
-using Common::EN_ANY;
-using Common::DE_DEU;
-using Common::IT_ITA;
+#define INTRO_FRAMETIME 90
+#define INTRO_CAPTION_Y 170
+#define INTRO_DE_CAPTION_Y 160
+#define INTRO_IT_CAPTION_Y 160
+#define INTRO_VOICE_PAD 50
+#define INTRO_VOICE_LETTERLEN 90
+
+#define DISSOLVE_DURATION 3000
+#define LOGO_DISSOLVE_DURATION 1000
// Intro scenes
#define RID_ITE_INTRO_ANIM_SCENE 1538
@@ -54,8 +60,8 @@ using Common::IT_ITA;
#define RID_ITE_FAIRETENT_SCENE 1567
// ITE intro music
-#define MUSIC_1 9
-#define MUSIC_2 10
+#define MUSIC_INTRO 9
+#define MUSIC_TITLE_THEME 10
LoadSceneParams ITE_IntroList[] = {
{RID_ITE_INTRO_ANIM_SCENE, kLoadByResourceId, Scene::SC_ITEIntroAnimProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
@@ -98,11 +104,11 @@ int Scene::ITEStartProc() {
return SUCCESS;
}
-EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]) {
+EventColumns *Scene::queueIntroDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]) {
TextListEntry textEntry;
TextListEntry *entry;
Event event;
- int voice_len;
+ int voiceLength;
int i;
// Queue narrator dialogue list
@@ -132,7 +138,7 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = entry;
- event.time = (i == 0) ? 0 : VOICE_PAD;
+ event.time = (i == 0) ? 0 : INTRO_VOICE_PAD;
eventColumns = _vm->_events->chain(eventColumns, event);
}
@@ -146,9 +152,10 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue
_vm->_events->chain(eventColumns, event);
}
- voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn);
- if (voice_len < 0) {
- voice_len = strlen(dialogue[i].i_str) * VOICE_LETTERLEN;
+ voiceLength = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn);
+ if (voiceLength < 0) {
+ // Set a default length if no speech file is present
+ voiceLength = strlen(dialogue[i].i_str) * INTRO_VOICE_LETTERLEN;
}
// Remove text
@@ -156,31 +163,17 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue
event.code = kTextEvent;
event.op = kEventRemove;
event.data = entry;
- event.time = voice_len;
+ event.time = voiceLength;
_vm->_events->chain(eventColumns, event);
}
return eventColumns;
}
-enum {
- kCHeader,
- kCText
-};
-
-enum {
- kITEPC = (1 << 0),
- kITEPCCD = (1 << 1),
- kITEMac = (1 << 2),
- kITEWyrmKeep = (1 << 3),
- kITEAny = 0xffff,
- kITENotWyrmKeep = kITEAny & ~kITEWyrmKeep
-};
-
// Queue a page of credits text. The original interpreter did word-wrapping
// automatically. We currently don't.
-EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) {
+EventColumns *Scene::queueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) {
int game;
Common::Language lang;
bool hasWyrmkeepCredits = (Common::File::exists("credit3n.dlt") || // PC
@@ -192,13 +185,13 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits
lang = _vm->getLanguage();
if (hasWyrmkeepCredits)
- game = kITEWyrmKeep;
+ game = kITECreditsWyrmKeep;
else if (_vm->getPlatform() == Common::kPlatformMacintosh)
- game = kITEMac;
+ game = kITECreditsMac;
else if (_vm->getFeatures() & GF_EXTRA_ITE_CREDITS)
- game = kITEPCCD;
+ game = kITECreditsPCCD;
else
- game = kITEPC;
+ game = kITECreditsPC;
int line_spacing = 0;
int paragraph_spacing;
@@ -209,7 +202,7 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits
int credits_height = 0;
for (i = 0; i < n_credits; i++) {
- if (credits[i].lang != lang && credits[i].lang != UNK_LANG) {
+ if (credits[i].lang != lang && credits[i].lang != Common::UNK_LANG) {
continue;
}
@@ -218,12 +211,12 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits
}
switch (credits[i].type) {
- case kCHeader:
+ case kITECreditsHeader:
font = kKnownFontSmall;
line_spacing = 4;
n_paragraphs++;
break;
- case kCText:
+ case kITECreditsText:
font = kKnownFontMedium;
line_spacing = 2;
break;
@@ -250,7 +243,7 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits
textEntry.point.x = 160;
for (i = 0; i < n_credits; i++) {
- if (credits[i].lang != lang && credits[i].lang != UNK_LANG) {
+ if (credits[i].lang != lang && credits[i].lang != Common::UNK_LANG) {
continue;
}
@@ -259,12 +252,12 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits
}
switch (credits[i].type) {
- case kCHeader:
+ case kITECreditsHeader:
font = kKnownFontSmall;
line_spacing = 4;
y += paragraph_spacing;
break;
- case kCText:
+ case kITECreditsText:
font = kKnownFontMedium;
line_spacing = 2;
break;
@@ -328,7 +321,7 @@ int Scene::ITEIntroAnimProc(int param) {
debug(3, "Intro animation procedure started.");
debug(3, "Linking animation resources...");
- _vm->_anim->setFrameTime(0, ITE_INTRO_FRAMETIME);
+ _vm->_anim->setFrameTime(0, INTRO_FRAMETIME);
// Link this scene's animation resources for continuous
// playback
@@ -355,13 +348,7 @@ int Scene::ITEIntroAnimProc(int param) {
_vm->_events->chain(eventColumns, event);
// Queue intro music playback
- event.type = kEvTOneshot;
- event.code = kMusicEvent;
- event.param = MUSIC_1;
- event.param2 = MUSIC_LOOP;
- event.op = kEventPlay;
- event.time = 0;
- _vm->_events->chain(eventColumns, event);
+ _vm->_events->chainMusic(eventColumns, MUSIC_INTRO, true);
}
break;
case SCENE_END:
@@ -374,14 +361,11 @@ int Scene::ITEIntroAnimProc(int param) {
return 0;
}
-int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) {
- return ((Scene *)refCon)->ITEIntroCave1Proc(param);
-}
-
-// Handles first introductory cave painting scene
-int Scene::ITEIntroCave1Proc(int param) {
+int Scene::ITEIntroCaveCommonProc(int param, int caveScene) {
Event event;
- EventColumns *eventColumns;
+ EventColumns *eventColumns = NULL;
+ const IntroDialogue *dialogue;
+
int lang = 0;
if (_vm->getLanguage() == Common::DE_DEU)
@@ -389,202 +373,62 @@ int Scene::ITEIntroCave1Proc(int param) {
else if (_vm->getLanguage() == Common::IT_ITA)
lang = 2;
- static const IntroDialogue dialogue[][4] = {
- { { // English
- 0, // cave voice 0
- "We see the sky, we see the land, we see the water, "
- "and we wonder: Are we the only ones?"
- },
- {
- 1, // cave voice 1
- "Long before we came to exist, the humans ruled the "
- "Earth."
- },
- {
- 2, // cave voice 2
- "They made marvelous things, and moved whole "
- "mountains."
- },
- {
- 3, // cave voice 3
- "They knew the Secret of Flight, the Secret of "
- "Happiness, and other secrets beyond our imagining."
- } },
- // -----------------------------------------------------
- { { // German
- 0, // cave voice 0
- "Um uns sind der Himmel, das Land und die Seen; und "
- "wir fragen uns - sind wir die einzigen?"
- },
- {
- 1, // cave voice 1
- "Lange vor unserer Zeit herrschten die Menschen "
- "\201ber die Erde."
- },
- {
- 2, // cave voice 2
- "Sie taten wundersame Dinge und versetzten ganze "
- "Berge."
- },
- {
- 3, // cave voice 3
- "Sie kannten das Geheimnis des Fluges, das Geheimnis "
- "der Fr\224hlichkeit und andere Geheimnisse, die "
- "unsere Vorstellungskraft \201bersteigen."
- } },
- // -----------------------------------------------------
- { { // Italian fan translation
- 0, // cave voice 0
- "Guardiamo il cielo, guardiamo la terra, guardiamo "
- "l'acqua, e ci chiediamo: Siamo forse soli?"
- },
- {
- 1, // cave voice 1
- "Molto tempo prima che noi esistessimo, gli Umani "
- "dominavano la terra."
- },
- {
- 2, // cave voice 2
- "Fecero cose meravigliose, e mossero intere "
- "montagne."
- },
- {
- 3, // cave voice 3
- "Conoscevano il Segreto del Volo, il Segreto della "
- "Felicit\205, ed altri segreti oltre ogni nostra "
- "immaginazione."
- } }
- };
-
- int n_dialogues = ARRAYSIZE(dialogue[lang]);
-
- switch (param) {
- case SCENE_BEGIN:
- // Begin palette cycling animation for candles
- event.type = kEvTOneshot;
- event.code = kPalAnimEvent;
- event.op = kEventCycleStart;
- event.time = 0;
- eventColumns = _vm->_events->queue(event);
-
- // Queue narrator dialogue list
- ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
-
- // End scene after last dialogue over
- event.type = kEvTOneshot;
- event.code = kSceneEvent;
- event.op = kEventEnd;
- event.time = VOICE_PAD;
- _vm->_events->chain(eventColumns, event);
-
+ int n_dialogues = 0;
+
+ switch (caveScene) {
+ case 1:
+ n_dialogues = ARRAYSIZE(introDialogueCave1[lang]);
+ dialogue = introDialogueCave1[lang];
break;
- case SCENE_END:
+ case 2:
+ n_dialogues = ARRAYSIZE(introDialogueCave2[lang]);
+ dialogue = introDialogueCave2[lang];
break;
-
- default:
- warning("Illegal scene procedure parameter");
+ case 3:
+ n_dialogues = ARRAYSIZE(introDialogueCave3[lang]);
+ dialogue = introDialogueCave3[lang];
break;
+ case 4:
+ n_dialogues = ARRAYSIZE(introDialogueCave4[lang]);
+ dialogue = introDialogueCave4[lang];
+ break;
+ default:
+ error("Invalid cave scene");
}
- return 0;
-}
-
-int Scene::SC_ITEIntroCave2Proc(int param, void *refCon) {
- return ((Scene *)refCon)->ITEIntroCave2Proc(param);
-}
-
-// Handles second introductory cave painting scene
-int Scene::ITEIntroCave2Proc(int param) {
- Event event;
- EventColumns *eventColumns;
- int lang = 0;
-
- if (_vm->getLanguage() == Common::DE_DEU)
- lang = 1;
- else if (_vm->getLanguage() == Common::IT_ITA)
- lang = 2;
-
- static const IntroDialogue dialogue[][3] = {
- { { // English
- 4, // cave voice 4
- "The humans also knew the Secret of Life, and they "
- "used it to give us the Four Great Gifts:"
- },
- {
- 5, // cave voice 5
- "Thinking minds, feeling hearts, speaking mouths, and "
- "reaching hands."
- },
- {
- 6, // cave voice 6
- "We are their children."
- } },
- // -----------------------------------------------------
- { { // German
- 4, // cave voice 4
- "Au$erdem kannten die Menschen das Geheimnis des "
- "Lebens. Und sie nutzten es, um uns die vier gro$en "
- "Geschenke zu geben -"
- },
- {
- 5, // cave voice 5
- "den denkenden Geist, das f\201hlende Herz, den "
- "sprechenden Mund und die greifende Hand."
- },
- {
- 6, // cave voice 6
- "Wir sind ihre Kinder."
- } },
- // -----------------------------------------------------
- { { // Italian fan translation
- 4, // cave voice 4
- "Gli Umani conoscevano anche il Segreto della Vita, "
- "e lo usarono per darci i Quattro Grandi Doni:"
-
- },
- {
- 5, // cave voice 5
- "Il pensiero, le emozioni, la parola e la manualit\205."
-
- },
- {
- 6, // cave voice 6
- "Siamo i loro figli."
- } }
- };
-
- int n_dialogues = ARRAYSIZE(dialogue[lang]);
-
switch (param) {
case SCENE_BEGIN:
- // Start 'dissolve' transition to new scene background
- event.type = kEvTContinuous;
- event.code = kTransitionEvent;
- event.op = kEventDissolve;
- event.time = 0;
- event.duration = DISSOLVE_DURATION;
- eventColumns = _vm->_events->queue(event);
+ if (caveScene > 1) {
+ // Start 'dissolve' transition to new scene background
+ event.type = kEvTContinuous;
+ event.code = kTransitionEvent;
+ event.op = kEventDissolve;
+ event.time = 0;
+ event.duration = DISSOLVE_DURATION;
+ eventColumns = _vm->_events->queue(event);
+ }
// Begin palette cycling animation for candles
event.type = kEvTOneshot;
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
- _vm->_events->chain(eventColumns, event);
+ eventColumns = _vm->_events->chain(eventColumns, event);
// Queue narrator dialogue list
- ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
+ queueIntroDialogue(eventColumns, n_dialogues, dialogue);
// End scene after last dialogue over
event.type = kEvTOneshot;
event.code = kSceneEvent;
event.op = kEventEnd;
- event.time = VOICE_PAD;
+ event.time = INTRO_VOICE_PAD;
_vm->_events->chain(eventColumns, event);
break;
case SCENE_END:
break;
+
default:
warning("Illegal scene procedure parameter");
break;
@@ -593,227 +437,24 @@ int Scene::ITEIntroCave2Proc(int param) {
return 0;
}
-int Scene::SC_ITEIntroCave3Proc(int param, void *refCon) {
- return ((Scene *)refCon)->ITEIntroCave3Proc(param);
+// Handles first introductory cave painting scene
+int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) {
+ return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 1);
}
-// Handles third introductory cave painting scene
-int Scene::ITEIntroCave3Proc(int param) {
- Event event;
- EventColumns *eventColumns;
- int lang = 0;
-
- if (_vm->getLanguage() == Common::DE_DEU)
- lang = 1;
- else if (_vm->getLanguage() == Common::IT_ITA)
- lang = 2;
-
- static const IntroDialogue dialogue[][3] = {
- { { // English
- 7, // cave voice 7
- "They taught us how to use our hands, and how to "
- "speak."
- },
- {
- 8, // cave voice 8
- "They showed us the joy of using our minds."
- },
- {
- 9, // cave voice 9
- "They loved us, and when we were ready, they surely "
- "would have given us the Secret of Happiness."
- } },
- // -----------------------------------------------------
- { { // German
- 7, // cave voice 7
- "Sie lehrten uns zu sprechen und unsere H\204nde zu "
- "benutzen."
- },
- {
- 8, // cave voice 8
- "Sie zeigten uns die Freude am Denken."
- },
- {
- 9, // cave voice 9
- "Sie liebten uns, und w\204ren wir bereit gewesen, "
- "h\204tten sie uns sicherlich das Geheimnis der "
- "Fr\224hlichkeit offenbart."
- } },
- // -----------------------------------------------------
- { { // Italian fan translation
- 7, // cave voice 7
- "Ci insegnarono come usare le mani e come parlare. "
-
- },
- {
- 8, // cave voice 8
- "Ci mostrarono le gioie che l'uso della mente "
- "pu\225 dare. "
- },
- {
- 9, // cave voice 9
- "Ci amarono, ed una volta pronti, ci avrebbero "
- "sicuramente svelato il Segreto della Felicit\205."
-
- } }
- };
-
- int n_dialogues = ARRAYSIZE(dialogue[lang]);
-
- switch (param) {
- case SCENE_BEGIN:
- // Start 'dissolve' transition to new scene background
- event.type = kEvTContinuous;
- event.code = kTransitionEvent;
- event.op = kEventDissolve;
- event.time = 0;
- event.duration = DISSOLVE_DURATION;
- eventColumns = _vm->_events->queue(event);
-
- // Begin palette cycling animation for candles
- event.type = kEvTOneshot;
- event.code = kPalAnimEvent;
- event.op = kEventCycleStart;
- event.time = 0;
- _vm->_events->chain(eventColumns, event);
-
- // Queue narrator dialogue list
- ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
-
- // End scene after last dialogue over
- event.type = kEvTOneshot;
- event.code = kSceneEvent;
- event.op = kEventEnd;
- event.time = VOICE_PAD;
- _vm->_events->chain(eventColumns, event);
-
- break;
- case SCENE_END:
- break;
- default:
- warning("Illegal scene procedure parameter");
- break;
- }
-
- return 0;
+// Handles second introductory cave painting scene
+int Scene::SC_ITEIntroCave2Proc(int param, void *refCon) {
+ return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 2);
}
-int Scene::SC_ITEIntroCave4Proc(int param, void *refCon) {
- return ((Scene *)refCon)->ITEIntroCave4Proc(param);
+// Handles third introductory cave painting scene
+int Scene::SC_ITEIntroCave3Proc(int param, void *refCon) {
+ return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 3);
}
// Handles fourth introductory cave painting scene
-int Scene::ITEIntroCave4Proc(int param) {
- Event event;
- EventColumns *eventColumns;
- int lang = 0;
-
- if (_vm->getLanguage() == Common::DE_DEU)
- lang = 1;
- else if (_vm->getLanguage() == Common::IT_ITA)
- lang = 2;
-
- static const IntroDialogue dialogue[][4] = {
- { { // English
- 10, // cave voice 10
- "And now we see the sky, the land, and the water that "
- "we are heirs to, and we wonder: why did they leave?"
- },
- {
- 11, // cave voice 11
- "Do they live still, in the stars? In the oceans "
- "depths? In the wind?"
- },
- {
- 12, // cave voice 12
- "We wonder, was their fate good or evil?"
- },
- {
- 13, // cave voice 13
- "And will we also share the same fate one day?"
- } },
- // -----------------------------------------------------
- { { // German
- 10, // cave voice 10
- "Und nun sehen wir den Himmel, das Land und die "
- "Seen - unser Erbe. Und wir fragen uns - warum "
- "verschwanden sie?"
- },
- {
- 11, // cave voice 11
- "Leben sie noch in den Sternen? In den Tiefen des "
- "Ozeans? Im Wind?"
- },
- {
- 12, // cave voice 12
- "Wir fragen uns - war ihr Schicksal gut oder b\224se?"
- },
- {
- 13, // cave voice 13
- "Und wird uns eines Tages das gleiche Schicksal "
- "ereilen?"
- } },
- // -----------------------------------------------------
- { { // Italian fan translation
- 10, // cave voice 10
- "Ed ora che guardiamo il cielo, la terra e l'acqua "
- "che abbiamo ereditato, pensiamo: Perch\202 partirono?"
-
- },
- {
- 11, // cave voice 11
- "Vivono ancora, nelle stelle? Nelle profondit\205 "
- "dell'oceano? Nel vento?"
- },
- {
- 12, // cave voice 12
- "Ci domandiamo, il loro destino fu felice o nefasto?"
- },
- {
- 13, // cave voice 13
- "E un giorno, condivideremo anche noi lo stesso "
- "destino?"
- } }
- };
-
- int n_dialogues = ARRAYSIZE(dialogue[lang]);
-
- switch (param) {
- case SCENE_BEGIN:
- // Start 'dissolve' transition to new scene background
- event.type = kEvTContinuous;
- event.code = kTransitionEvent;
- event.op = kEventDissolve;
- event.time = 0;
- event.duration = DISSOLVE_DURATION;
- eventColumns = _vm->_events->queue(event);
-
- // Begin palette cycling animation for candles
- event.type = kEvTOneshot;
- event.code = kPalAnimEvent;
- event.op = kEventCycleStart;
- event.time = 0;
- _vm->_events->chain(eventColumns, event);
-
- // Queue narrator dialogue list
- ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]);
-
- // End scene after last dialogue over
- event.type = kEvTOneshot;
- event.code = kSceneEvent;
- event.op = kEventEnd;
- event.time = VOICE_PAD;
- _vm->_events->chain(eventColumns, event);
-
- break;
- case SCENE_END:
- break;
- default:
- warning("Illegal scene procedure parameter");
- break;
- }
-
- return 0;
+int Scene::SC_ITEIntroCave4Proc(int param, void *refCon) {
+ return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 4);
}
int Scene::SC_ITEIntroValleyProc(int param, void *refCon) {
@@ -825,23 +466,7 @@ int Scene::ITEIntroValleyProc(int param) {
Event event;
EventColumns *eventColumns;
- static const IntroCredit credits[] = {
- {EN_ANY, kITEAny, kCHeader, "Producer"},
- {DE_DEU, kITEAny, kCHeader, "Produzent"},
- {IT_ITA, kITEAny, kCHeader, "Produttore"},
- {UNK_LANG, kITEAny, kCText, "Walter Hochbrueckner"},
- {EN_ANY, kITEAny, kCHeader, "Executive Producer"},
- {DE_DEU, kITEAny, kCHeader, "Ausf\201hrender Produzent"},
- {IT_ITA, kITEAny, kCHeader, "Produttore Esecutivo"},
- {UNK_LANG, kITEAny, kCText, "Robert McNally"},
- {UNK_LANG, kITEWyrmKeep, kCHeader, "2nd Executive Producer"},
- {EN_ANY, kITENotWyrmKeep, kCHeader, "Publisher"},
- {DE_DEU, kITENotWyrmKeep, kCHeader, "Herausgeber"},
- {IT_ITA, kITENotWyrmKeep, kCHeader, "Editore"},
- {UNK_LANG, kITEAny, kCText, "Jon Van Caneghem"}
- };
-
- int n_credits = ARRAYSIZE(credits);
+ int n_credits = ARRAYSIZE(creditsValley);
switch (param) {
case SCENE_BEGIN:
@@ -858,13 +483,7 @@ int Scene::ITEIntroValleyProc(int param) {
// Begin ITE title theme music
_vm->_music->stop();
- event.type = kEvTOneshot;
- event.code = kMusicEvent;
- event.param = MUSIC_2;
- event.param2 = MUSIC_NORMAL;
- event.op = kEventPlay;
- event.time = 0;
- _vm->_events->chain(eventColumns, event);
+ _vm->_events->chainMusic(eventColumns, MUSIC_TITLE_THEME);
// Pause animation before logo
event.type = kEvTOneshot;
@@ -899,7 +518,7 @@ int Scene::ITEIntroValleyProc(int param) {
_vm->_events->chain(eventColumns, event);
// Queue game credits list
- eventColumns = ITEQueueCredits(9000, CREDIT_DURATION1, n_credits, credits);
+ eventColumns = queueCredits(9000, CREDIT_DURATION1, n_credits, creditsValley);
// End scene after credit display
event.type = kEvTOneshot;
@@ -928,47 +547,8 @@ int Scene::ITEIntroTreeHouseProc(int param) {
Event event;
EventColumns *eventColumns;
- static const IntroCredit credits1[] = {
- {EN_ANY, kITEAny, kCHeader, "Game Design"},
- {DE_DEU, kITEAny, kCHeader, "Spielentwurf"},
- {IT_ITA, kITEAny, kCHeader, "Progetto"},
- {UNK_LANG, kITEAny, kCText, "Talin, Joe Pearce, Robert McNally"},
- {EN_ANY, kITEAny, kCText, "and Carolly Hauksdottir"},
- {DE_DEU, kITEAny, kCText, "und Carolly Hauksdottir"},
- {IT_ITA, kITEAny, kCText, "e Carolly Hauksdottir"},
- {EN_ANY, kITEAny, kCHeader, "Screenplay and Dialog"},
- {EN_ANY, kITEAny, kCText, "Robert Leh, Len Wein, and Bill Rotsler"},
- {DE_DEU, kITEAny, kCHeader, "Geschichte und Dialoge"},
- {DE_DEU, kITEAny, kCText, "Robert Leh, Len Wein und Bill Rotsler"},
- {IT_ITA, kITEAny, kCHeader, "Sceneggiatura e Dialoghi"},
- {IT_ITA, kITEAny, kCText, "Robert Leh, Len Wein e Bill Rotsler"}
- };
-
- int n_credits1 = ARRAYSIZE(credits1);
-
- static const IntroCredit credits2[] = {
- {UNK_LANG, kITEWyrmKeep, kCHeader, "Art Direction"},
- {UNK_LANG, kITEWyrmKeep, kCText, "Allison Hershey"},
- {EN_ANY, kITEAny, kCHeader, "Art"},
- {DE_DEU, kITEAny, kCHeader, "Grafiken"},
- {IT_ITA, kITEAny, kCHeader, "Grafica"},
- {UNK_LANG, kITEWyrmKeep, kCText, "Ed Lacabanne, Glenn Price, April Lee,"},
- {UNK_LANG, kITENotWyrmKeep, kCText, "Edward Lacabanne, Glenn Price, April Lee,"},
- {UNK_LANG, kITEWyrmKeep, kCText, "Lisa Sample, Brian Dowrick, Reed Waller,"},
- {EN_ANY, kITEWyrmKeep, kCText, "Allison Hershey and Talin"},
- {DE_DEU, kITEWyrmKeep, kCText, "Allison Hershey und Talin"},
- {IT_ITA, kITEWyrmKeep, kCText, "Allison Hershey e Talin"},
- {EN_ANY, kITENotWyrmKeep, kCText, "Lisa Iennaco, Brian Dowrick, Reed"},
- {EN_ANY, kITENotWyrmKeep, kCText, "Waller, Allison Hershey and Talin"},
- {DE_DEU, kITEAny, kCText, "Waller, Allison Hershey und Talin"},
- {IT_ITA, kITEAny, kCText, "Waller, Allison Hershey e Talin"},
- {EN_ANY, kITENotWyrmKeep, kCHeader, "Art Direction"},
- {DE_DEU, kITENotWyrmKeep, kCHeader, "Grafische Leitung"},
- {IT_ITA, kITENotWyrmKeep, kCHeader, "Direzione Grafica"},
- {UNK_LANG, kITENotWyrmKeep, kCText, "Allison Hershey"}
- };
-
- int n_credits2 = ARRAYSIZE(credits2);
+ int n_credits1 = ARRAYSIZE(creditsTreeHouse1);
+ int n_credits2 = ARRAYSIZE(creditsTreeHouse2);
switch (param) {
case SCENE_BEGIN:
@@ -993,8 +573,8 @@ int Scene::ITEIntroTreeHouseProc(int param) {
}
// Queue game credits list
- ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1);
- eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2);
+ queueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, creditsTreeHouse1);
+ eventColumns = queueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, creditsTreeHouse2);
// End scene after credit display
event.type = kEvTOneshot;
@@ -1023,34 +603,8 @@ int Scene::ITEIntroFairePathProc(int param) {
Event event;
EventColumns *eventColumns;
- static const IntroCredit credits1[] = {
- {EN_ANY, kITEAny, kCHeader, "Programming"},
- {DE_DEU, kITEAny, kCHeader, "Programmiert von"},
- {IT_ITA, kITEAny, kCHeader, "Programmazione"},
- {UNK_LANG, kITEAny, kCText, "Talin, Walter Hochbrueckner,"},
- {EN_ANY, kITEAny, kCText, "Joe Burks and Robert Wiggins"},
- {DE_DEU, kITEAny, kCText, "Joe Burks und Robert Wiggins"},
- {IT_ITA, kITEAny, kCText, "Joe Burks e Robert Wiggins"},
- {EN_ANY, kITEPCCD | kITEWyrmKeep, kCHeader, "Additional Programming"},
- {EN_ANY, kITEPCCD | kITEWyrmKeep, kCText, "John Bolton"},
- {UNK_LANG, kITEMac, kCHeader, "Macintosh Version"},
- {UNK_LANG, kITEMac, kCText, "Michael McNally and Robert McNally"},
- {EN_ANY, kITEAny, kCHeader, "Music and Sound"},
- {DE_DEU, kITEAny, kCHeader, "Musik und Sound"},
- {IT_ITA, kITEAny, kCHeader, "Musica e Sonoro"},
- {UNK_LANG, kITEAny, kCText, "Matt Nathan"}
- };
-
- int n_credits1 = ARRAYSIZE(credits1);
-
- static const IntroCredit credits2[] = {
- {EN_ANY, kITEAny, kCHeader, "Directed by"},
- {DE_DEU, kITEAny, kCHeader, "Regie"},
- {IT_ITA, kITEAny, kCHeader, "Regia"},
- {UNK_LANG, kITEAny, kCText, "Talin"}
- };
-
- int n_credits2 = ARRAYSIZE(credits2);
+ int n_credits1 = ARRAYSIZE(creditsFairePath1);
+ int n_credits2 = ARRAYSIZE(creditsFairePath2);
switch (param) {
case SCENE_BEGIN:
@@ -1073,8 +627,8 @@ int Scene::ITEIntroFairePathProc(int param) {
_vm->_events->chain(eventColumns, event);
// Queue game credits list
- ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1);
- eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2);
+ queueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, creditsFairePath1);
+ eventColumns = queueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, creditsFairePath2);
// End scene after credit display
event.type = kEvTOneshot;
diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp
index 710236b0c4..0b773b03f0 100644
--- a/engines/saga/introproc_saga2.cpp
+++ b/engines/saga/introproc_saga2.cpp
@@ -43,9 +43,6 @@ int Scene::DinoStartProc() {
playMovie("testvid.smk");
- // HACK: Forcibly quit here
- _vm->quitGame();
-
return SUCCESS;
}
@@ -55,9 +52,6 @@ int Scene::FTA2StartProc() {
playMovie("trimark.smk");
playMovie("intro.smk");
- // HACK: Forcibly quit here
- _vm->quitGame();
-
return SUCCESS;
}
diff --git a/engines/saga/itedata.cpp b/engines/saga/itedata.cpp
index 87b71c2cb7..da70733f4e 100644
--- a/engines/saga/itedata.cpp
+++ b/engines/saga/itedata.cpp
@@ -444,111 +444,437 @@ const RawPoint pieceOrigins[PUZZLE_PIECES] = {
};
const char *pieceNames[][PUZZLE_PIECES] = {
- { "screwdriver", "pliers", "c-clamp", "wood clamp", "level",
- "twine", "wood plane", "claw hammer", "tape measure", "hatchet",
- "shears", "ruler", "saw", "mallet", "paint brush"
+ {
+ "screwdriver", "pliers", "c-clamp", "wood clamp", "level",
+ "twine", "wood plane", "claw hammer", "tape measure", "hatchet",
+ "shears", "ruler", "saw", "mallet", "paint brush"
},
- { "Schraubendreher", "Zange", "Schraubzwinge", "Holzzwinge", "Wasserwaage",
- "Bindfaden", "Hobel", "Schusterhammer", "Bandma$", "Beil",
- "Schere", "Winkel", "S\204ge", "Hammer", "Pinsel"
+ {
+ "Schraubendreher", "Zange", "Schraubzwinge", "Holzzwinge", "Wasserwaage",
+ "Bindfaden", "Hobel", "Schusterhammer", "Bandma$", "Beil",
+ "Schere", "Winkel", "S\204ge", "Hammer", "Pinsel"
},
- { "cacciavite", "pinze", "morsa", "morsa da legno", "livella",
- "spago", "pialla", "martello", "metro a nastro", "accetta",
- "cesoie", "righello", "sega", "mazza", "pennello"
+ {
+ "cacciavite", "pinze", "morsa", "morsa da legno", "livella",
+ "spago", "pialla", "martello", "metro a nastro", "accetta",
+ "cesoie", "righello", "sega", "mazza", "pennello"
}
};
const char *hintStr[][4] = {
- { "Check which pieces could fit in each corner first.",
- "Check which corner has the least number of pieces that can fit and start from there.",
- "Check each new corner and any new side for pieces that fit.",
- "I don't see anything out of place."
- },
- { "\232berpr\201fe zun\204chst, welche die Eckteile sein k\224nnten.",
- "Schau, in welche Ecke die wenigsten Teile passen, und fang dort an.",
- "Untersuche jede Ecke und jede Seite auf Teile, die dort passen k\224nnen.",
- "Ich sehe nichts an der falschen Stelle."
- },
- { "Controlla prima quali pezzi si inseriscono meglio in ogni angolo.",
- "Controlla quale angolo ha il minor numero di pezzi che combaciano, e parti da quello.",
- "Controlla ogni nuovo angolo e lato per ogni pezzo che combacia.",
- "Non vedo nulla fuori posto."
+ {
+ "Check which pieces could fit in each corner first.",
+ "Check which corner has the least number of pieces that can fit and start from there.",
+ "Check each new corner and any new side for pieces that fit.",
+ "I don't see anything out of place."
+ },
+ {
+ "\232berpr\201fe zun\204chst, welche die Eckteile sein k\224nnten.",
+ "Schau, in welche Ecke die wenigsten Teile passen, und fang dort an.",
+ "Untersuche jede Ecke und jede Seite auf Teile, die dort passen k\224nnen.",
+ "Ich sehe nichts an der falschen Stelle."
+ },
+ {
+ "Controlla prima quali pezzi si inseriscono meglio in ogni angolo.",
+ "Controlla quale angolo ha il minor numero di pezzi che combaciano, e parti da quello.",
+ "Controlla ogni nuovo angolo e lato per ogni pezzo che combacia.",
+ "Non vedo nulla fuori posto."
}
};
const char *solicitStr[][NUM_SOLICIT_REPLIES] = {
- { "Hey, Fox! Would you like a hint?",
- "Would you like some help?",
- "Umm...Umm...",
- "Psst! want a hint?",
- "I would have done this differently, you know."
- },
- { "Hey, Fuchs! Brauchst Du \047nen Tip?",
- "M\224chtest Du etwas Hilfe?"
- "\231hm...\216hm..."
- "Psst! \047n Tip vielleicht?"
- "Ja, wei$t Du... ich h\204tte das anders gemacht."
- },
- { "Hey, Volpe! Serve un suggerimento?",
- "Hai bisogno di aiuto?",
- "Umm...Umm...",
- "Psst! Serve un aiutino?",
- "Io, sai, l'avrei fatto diversamente."
+ {
+ "Hey, Fox! Would you like a hint?",
+ "Would you like some help?",
+ "Umm...Umm...",
+ "Psst! want a hint?",
+ "I would have done this differently, you know."
+ },
+ {
+ "Hey, Fuchs! Brauchst Du \047nen Tip?",
+ "M\224chtest Du etwas Hilfe?"
+ "\231hm...\216hm..."
+ "Psst! \047n Tip vielleicht?"
+ "Ja, wei$t Du... ich h\204tte das anders gemacht."
+ },
+ {
+ "Hey, Volpe! Serve un suggerimento?",
+ "Hai bisogno di aiuto?",
+ "Umm...Umm...",
+ "Psst! Serve un aiutino?",
+ "Io, sai, l'avrei fatto diversamente."
}
};
const char *sakkaStr[][NUM_SAKKA] = {
- { "Hey, you're not supposed to help the applicants!",
- "Guys! This is supposed to be a test!",
- "C'mon fellows, that's not in the rules!"
+ {
+ "Hey, you're not supposed to help the applicants!",
+ "Guys! This is supposed to be a test!",
+ "C'mon fellows, that's not in the rules!"
},
- { "Hey, Du darfst dem Pr\201fling nicht helfen!",
- "Hallo?! Dies soll eine Pr\201fung sein!",
- "Also, Jungs. Schummeln steht nicht in den Regeln!"
+ {
+ "Hey, Du darfst dem Pr\201fling nicht helfen!",
+ "Hallo?! Dies soll eine Pr\201fung sein!",
+ "Also, Jungs. Schummeln steht nicht in den Regeln!"
},
- { "Hey, non si dovrebbero aiutare i candidati!",
- "Ragazzi! Questo dovrebbe essere un test!",
- "Forza ragazzi, non si pu\225!"
+ {
+ "Hey, non si dovrebbero aiutare i candidati!",
+ "Ragazzi! Questo dovrebbe essere un test!",
+ "Forza ragazzi, non si pu\225!"
}
};
const char *whineStr[][NUM_WHINES] = {
- { "Aww, c'mon Sakka!",
- "One hint won't hurt, will it?",
- "Sigh...",
- "I think that clipboard has gone to your head, Sakka!",
- "Well, I don't recall any specific rule against hinting."
- },
- { "Och, sei nicht so, Sakka!"
- "EIN Tip wird schon nicht schaden, oder?",
- "Seufz..."
- "Ich glaube, Du hast ein Brett vor dem Kopf, Sakka!",
- "Hm, ich kann mich an keine Regel erinnern, die Tips verbietet."
- },
- { "Ooo, suvvia Sakka!",
- "Un indizio non guaster\205, no?",
- "Sigh...",
- "Credo che questa faccenda ti abbia dato alla testa, Sakka!",
- "Beh, non ricordo regole specifiche contro i suggerimenti."
+ {
+ "Aww, c'mon Sakka!",
+ "One hint won't hurt, will it?",
+ "Sigh...",
+ "I think that clipboard has gone to your head, Sakka!",
+ "Well, I don't recall any specific rule against hinting."
+ },
+ {
+ "Och, sei nicht so, Sakka!"
+ "EIN Tip wird schon nicht schaden, oder?",
+ "Seufz..."
+ "Ich glaube, Du hast ein Brett vor dem Kopf, Sakka!",
+ "Hm, ich kann mich an keine Regel erinnern, die Tips verbietet."
+ },
+ {
+ "Ooo, suvvia Sakka!",
+ "Un indizio non guaster\205, no?",
+ "Sigh...",
+ "Credo che questa faccenda ti abbia dato alla testa, Sakka!",
+ "Beh, non ricordo regole specifiche contro i suggerimenti."
}
};
const char *optionsStr[][4] = {
- { "\"I'll do this puzzle later.\"",
- "\"Yes, I'd like a hint please.\"",
- "\"No, thank you, I'd like to try and solve it myself.\"",
- "I think the %s is in the wrong place."
- },
- { "\"Ich l\224se das Puzzle sp\204ter.\"",
- "\"Ja, ich m\224chte einen Tip, bitte.\"",
- "\"Nein danke, ich m\224chte das alleine l\224sen.\"",
- "Pssst... %s... falsche Stelle..."
- },
- { "\"Far\225 questo puzzle pi\227 tardi.\"",
- "\"Si, grazie. Ne avrei bisogno.\"",
- "\"No, grazie, voglio provare a risolverlo da solo.\"",
- "Penso che la tessera %s sia nel posto sbagliato."
+ {
+ "\"I'll do this puzzle later.\"",
+ "\"Yes, I'd like a hint please.\"",
+ "\"No, thank you, I'd like to try and solve it myself.\"",
+ "I think the %s is in the wrong place."
+ },
+ {
+ "\"Ich l\224se das Puzzle sp\204ter.\"",
+ "\"Ja, ich m\224chte einen Tip, bitte.\"",
+ "\"Nein danke, ich m\224chte das alleine l\224sen.\"",
+ "Pssst... %s... falsche Stelle..."
+ },
+ {
+ "\"Far\225 questo puzzle pi\227 tardi.\"",
+ "\"Si, grazie. Ne avrei bisogno.\"",
+ "\"No, grazie, voglio provare a risolverlo da solo.\"",
+ "Penso che la tessera %s sia nel posto sbagliato."
}
};
+const IntroDialogue introDialogueCave1[][4] = {
+ { { // English
+ 0, // cave voice 0
+ "We see the sky, we see the land, we see the water, "
+ "and we wonder: Are we the only ones?"
+ },
+ {
+ 1, // cave voice 1
+ "Long before we came to exist, the humans ruled the "
+ "Earth."
+ },
+ {
+ 2, // cave voice 2
+ "They made marvelous things, and moved whole "
+ "mountains."
+ },
+ {
+ 3, // cave voice 3
+ "They knew the Secret of Flight, the Secret of "
+ "Happiness, and other secrets beyond our imagining."
+ } },
+ // -----------------------------------------------------
+ { { // German
+ 0, // cave voice 0
+ "Um uns sind der Himmel, das Land und die Seen; und "
+ "wir fragen uns - sind wir die einzigen?"
+ },
+ {
+ 1, // cave voice 1
+ "Lange vor unserer Zeit herrschten die Menschen "
+ "\201ber die Erde."
+ },
+ {
+ 2, // cave voice 2
+ "Sie taten wundersame Dinge und versetzten ganze "
+ "Berge."
+ },
+ {
+ 3, // cave voice 3
+ "Sie kannten das Geheimnis des Fluges, das Geheimnis "
+ "der Fr\224hlichkeit und andere Geheimnisse, die "
+ "unsere Vorstellungskraft \201bersteigen."
+ } },
+ // -----------------------------------------------------
+ { { // Italian fan translation
+ 0, // cave voice 0
+ "Guardiamo il cielo, guardiamo la terra, guardiamo "
+ "l'acqua, e ci chiediamo: Siamo forse soli?"
+ },
+ {
+ 1, // cave voice 1
+ "Molto tempo prima che noi esistessimo, gli Umani "
+ "dominavano la terra."
+ },
+ {
+ 2, // cave voice 2
+ "Fecero cose meravigliose, e mossero intere "
+ "montagne."
+ },
+ {
+ 3, // cave voice 3
+ "Conoscevano il Segreto del Volo, il Segreto della "
+ "Felicit\205, ed altri segreti oltre ogni nostra "
+ "immaginazione."
+ } }
+};
+
+const IntroDialogue introDialogueCave2[][3] = {
+ { { // English
+ 4, // cave voice 4
+ "The humans also knew the Secret of Life, and they "
+ "used it to give us the Four Great Gifts:"
+ },
+ {
+ 5, // cave voice 5
+ "Thinking minds, feeling hearts, speaking mouths, and "
+ "reaching hands."
+ },
+ {
+ 6, // cave voice 6
+ "We are their children."
+ } },
+ // -----------------------------------------------------
+ { { // German
+ 4, // cave voice 4
+ "Au$erdem kannten die Menschen das Geheimnis des "
+ "Lebens. Und sie nutzten es, um uns die vier gro$en "
+ "Geschenke zu geben -"
+ },
+ {
+ 5, // cave voice 5
+ "den denkenden Geist, das f\201hlende Herz, den "
+ "sprechenden Mund und die greifende Hand."
+ },
+ {
+ 6, // cave voice 6
+ "Wir sind ihre Kinder."
+ } },
+ // -----------------------------------------------------
+ { { // Italian fan translation
+ 4, // cave voice 4
+ "Gli Umani conoscevano anche il Segreto della Vita, "
+ "e lo usarono per darci i Quattro Grandi Doni:"
+
+ },
+ {
+ 5, // cave voice 5
+ "Il pensiero, le emozioni, la parola e la manualit\205."
+
+ },
+ {
+ 6, // cave voice 6
+ "Siamo i loro figli."
+ } }
+};
+
+const IntroDialogue introDialogueCave3[][3] = {
+ { { // English
+ 7, // cave voice 7
+ "They taught us how to use our hands, and how to "
+ "speak."
+ },
+ {
+ 8, // cave voice 8
+ "They showed us the joy of using our minds."
+ },
+ {
+ 9, // cave voice 9
+ "They loved us, and when we were ready, they surely "
+ "would have given us the Secret of Happiness."
+ } },
+ // -----------------------------------------------------
+ { { // German
+ 7, // cave voice 7
+ "Sie lehrten uns zu sprechen und unsere H\204nde zu "
+ "benutzen."
+ },
+ {
+ 8, // cave voice 8
+ "Sie zeigten uns die Freude am Denken."
+ },
+ {
+ 9, // cave voice 9
+ "Sie liebten uns, und w\204ren wir bereit gewesen, "
+ "h\204tten sie uns sicherlich das Geheimnis der "
+ "Fr\224hlichkeit offenbart."
+ } },
+ // -----------------------------------------------------
+ { { // Italian fan translation
+ 7, // cave voice 7
+ "Ci insegnarono come usare le mani e come parlare. "
+
+ },
+ {
+ 8, // cave voice 8
+ "Ci mostrarono le gioie che l'uso della mente "
+ "pu\225 dare. "
+ },
+ {
+ 9, // cave voice 9
+ "Ci amarono, ed una volta pronti, ci avrebbero "
+ "sicuramente svelato il Segreto della Felicit\205."
+
+ } }
+};
+
+const IntroDialogue introDialogueCave4[][4] = {
+ { { // English
+ 10, // cave voice 10
+ "And now we see the sky, the land, and the water that "
+ "we are heirs to, and we wonder: why did they leave?"
+ },
+ {
+ 11, // cave voice 11
+ "Do they live still, in the stars? In the oceans "
+ "depths? In the wind?"
+ },
+ {
+ 12, // cave voice 12
+ "We wonder, was their fate good or evil?"
+ },
+ {
+ 13, // cave voice 13
+ "And will we also share the same fate one day?"
+ } },
+ // -----------------------------------------------------
+ { { // German
+ 10, // cave voice 10
+ "Und nun sehen wir den Himmel, das Land und die "
+ "Seen - unser Erbe. Und wir fragen uns - warum "
+ "verschwanden sie?"
+ },
+ {
+ 11, // cave voice 11
+ "Leben sie noch in den Sternen? In den Tiefen des "
+ "Ozeans? Im Wind?"
+ },
+ {
+ 12, // cave voice 12
+ "Wir fragen uns - war ihr Schicksal gut oder b\224se?"
+ },
+ {
+ 13, // cave voice 13
+ "Und wird uns eines Tages das gleiche Schicksal "
+ "ereilen?"
+ } },
+ // -----------------------------------------------------
+ { { // Italian fan translation
+ 10, // cave voice 10
+ "Ed ora che guardiamo il cielo, la terra e l'acqua "
+ "che abbiamo ereditato, pensiamo: Perch\202 partirono?"
+
+ },
+ {
+ 11, // cave voice 11
+ "Vivono ancora, nelle stelle? Nelle profondit\205 "
+ "dell'oceano? Nel vento?"
+ },
+ {
+ 12, // cave voice 12
+ "Ci domandiamo, il loro destino fu felice o nefasto?"
+ },
+ {
+ 13, // cave voice 13
+ "E un giorno, condivideremo anche noi lo stesso "
+ "destino?"
+ } }
+};
+
+const IntroCredit creditsValley[] = {
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Producer"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Produzent"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Produttore"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Walter Hochbrueckner"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Executive Producer"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Ausf\201hrender Produzent"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Produttore Esecutivo"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Robert McNally"},
+ {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsHeader, "2nd Executive Producer"},
+ {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsHeader, "Publisher"},
+ {Common::DE_DEU, kITECreditsNotWyrmKeep, kITECreditsHeader, "Herausgeber"},
+ {Common::IT_ITA, kITECreditsNotWyrmKeep, kITECreditsHeader, "Editore"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Jon Van Caneghem"}
+};
+
+const IntroCredit creditsTreeHouse1[] = {
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Game Design"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Spielentwurf"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Progetto"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Talin, Joe Pearce, Robert McNally"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsText, "and Carolly Hauksdottir"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsText, "und Carolly Hauksdottir"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsText, "e Carolly Hauksdottir"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Screenplay and Dialog"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsText, "Robert Leh, Len Wein, and Bill Rotsler"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Geschichte und Dialoge"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsText, "Robert Leh, Len Wein und Bill Rotsler"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Sceneggiatura e Dialoghi"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsText, "Robert Leh, Len Wein e Bill Rotsler"}
+};
+
+const IntroCredit creditsTreeHouse2[] = {
+ {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsHeader, "Art Direction"},
+ {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Art"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Grafiken"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Grafica"},
+ {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsText, "Ed Lacabanne, Glenn Price, April Lee,"},
+ {Common::UNK_LANG, kITECreditsNotWyrmKeep, kITECreditsText, "Edward Lacabanne, Glenn Price, April Lee,"},
+ {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsText, "Lisa Sample, Brian Dowrick, Reed Waller,"},
+ {Common::EN_ANY, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey and Talin"},
+ {Common::DE_DEU, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey und Talin"},
+ {Common::IT_ITA, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey e Talin"},
+ {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsText, "Lisa Iennaco, Brian Dowrick, Reed"},
+ {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsText, "Waller, Allison Hershey and Talin"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsText, "Waller, Allison Hershey und Talin"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsText, "Waller, Allison Hershey e Talin"},
+ {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsHeader, "Art Direction"},
+ {Common::DE_DEU, kITECreditsNotWyrmKeep, kITECreditsHeader, "Grafische Leitung"},
+ {Common::IT_ITA, kITECreditsNotWyrmKeep, kITECreditsHeader, "Direzione Grafica"},
+ {Common::UNK_LANG, kITECreditsNotWyrmKeep, kITECreditsText, "Allison Hershey"}
+};
+
+const IntroCredit creditsFairePath1[] = {
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Programming"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Programmiert von"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Programmazione"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Talin, Walter Hochbrueckner,"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsText, "Joe Burks and Robert Wiggins"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsText, "Joe Burks und Robert Wiggins"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsText, "Joe Burks e Robert Wiggins"},
+ {Common::EN_ANY, kITECreditsPCCD | kITECreditsWyrmKeep, kITECreditsHeader, "Additional Programming"},
+ {Common::EN_ANY, kITECreditsPCCD | kITECreditsWyrmKeep, kITECreditsText, "John Bolton"},
+ {Common::UNK_LANG, kITECreditsMac, kITECreditsHeader, "Macintosh Version"},
+ {Common::UNK_LANG, kITECreditsMac, kITECreditsText, "Michael McNally and Robert McNally"},
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Music and Sound"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Musik und Sound"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Musica e Sonoro"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Matt Nathan"}
+};
+
+const IntroCredit creditsFairePath2[] = {
+ {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Directed by"},
+ {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Regie"},
+ {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Regia"},
+ {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Talin"}
+};
+
} // End of namespace Saga
diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h
index d27b84781f..f9416652bf 100644
--- a/engines/saga/itedata.h
+++ b/engines/saga/itedata.h
@@ -79,6 +79,32 @@ struct IteFxTable {
byte vol;
};
+struct IntroDialogue {
+ uint32 i_voice_rn;
+ const char *i_str;
+};
+
+struct IntroCredit {
+ Common::Language lang;
+ int game;
+ int type;
+ const char *string;
+};
+
+enum {
+ kITECreditsHeader,
+ kITECreditsText
+};
+
+enum {
+ kITECreditsPC = (1 << 0),
+ kITECreditsPCCD = (1 << 1),
+ kITECreditsMac = (1 << 2),
+ kITECreditsWyrmKeep = (1 << 3),
+ kITECreditsAny = 0xffff,
+ kITECreditsNotWyrmKeep = kITECreditsAny & ~kITECreditsWyrmKeep
+};
+
#define ITE_OBJECTCOUNT 39
#define ITE_SFXCOUNT 63
@@ -106,6 +132,17 @@ extern const char *hintStr[][4];
extern const char portraitList[];
extern const char *optionsStr[][4];
+extern const IntroDialogue introDialogueCave1[][4];
+extern const IntroDialogue introDialogueCave2[][3];
+extern const IntroDialogue introDialogueCave3[][3];
+extern const IntroDialogue introDialogueCave4[][4];
+
+extern const IntroCredit creditsValley[13];
+extern const IntroCredit creditsTreeHouse1[13];
+extern const IntroCredit creditsTreeHouse2[19];
+extern const IntroCredit creditsFairePath1[15];
+extern const IntroCredit creditsFairePath2[4];
+
} // End of namespace Saga
#endif
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index e444900967..d20882ca26 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -147,7 +147,7 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
if (!_musicContext) {
if (_vm->getGameId() == GID_ITE) {
_musicContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
- } else {
+ } else if (_vm->getGameId() == GID_IHNM) {
// I've listened to music from both the FM and the GM
// file, and I've tentatively reached the conclusion
// that they are both General MIDI. My guess is that
@@ -173,6 +173,8 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
// Note that the IHNM demo has only got one music file
// (music.rsc). It is assumed that it contains FM music
_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM);
+ } else if (_vm->getGameId() == GID_DINO || _vm->getGameId() == GID_FTA2) {
+ _musicContext = _vm->_resource->getContext(GAME_SOUNDFILE);
}
}
@@ -255,19 +257,18 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
_mixer->stopHandle(_musicHandle);
_player->stop();
- int realTrackNumber;
+ int realTrackNumber = 0;
if (_vm->getGameId() == GID_ITE) {
- if (flags == MUSIC_DEFAULT) {
- if (resourceId == 13 || resourceId == 19) {
- flags = MUSIC_NORMAL;
- } else {
- flags = MUSIC_LOOP;
- }
- }
+ if (flags == MUSIC_NORMAL && (resourceId == 13 || resourceId == 19))
+ flags = MUSIC_LOOP;
realTrackNumber = resourceId - 8;
- } else {
+ } else if (_vm->getGameId() == GID_IHNM) {
+ realTrackNumber = resourceId + 1;
+ } else if (_vm->getGameId() == GID_DINO || _vm->getGameId() == GID_FTA2) {
realTrackNumber = resourceId + 1;
+ uint32 musicTrackTag = MKTAG('X','M','I', (byte)(resourceId + 1));
+ resourceId = _musicContext->getEntryNum(musicTrackTag);
}
// Try to open standalone digital track
@@ -359,9 +360,6 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
return;
}
- if (flags == MUSIC_DEFAULT)
- flags = MUSIC_NORMAL;
-
// Load MIDI/XMI resource data
if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
// Load the external music file for Mac IHNM
diff --git a/engines/saga/music.h b/engines/saga/music.h
index ba44c3ca71..2106fb6fa6 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -37,8 +37,7 @@ namespace Saga {
enum MusicFlags {
MUSIC_NORMAL = 0,
- MUSIC_LOOP = 0x0001,
- MUSIC_DEFAULT = 0xffff
+ MUSIC_LOOP = 0x0001
};
class MusicDriver : public Audio::MidiPlayer {
@@ -72,7 +71,7 @@ public:
bool isPlaying();
bool hasDigitalMusic() { return _digitalMusic; }
- void play(uint32 resourceId, MusicFlags flags = MUSIC_DEFAULT);
+ void play(uint32 resourceId, MusicFlags flags = MUSIC_NORMAL);
void pause();
void resume();
void stop();
diff --git a/engines/saga/resource.cpp b/engines/saga/resource.cpp
index cdf674dc66..1fb9ac1c04 100644
--- a/engines/saga/resource.cpp
+++ b/engines/saga/resource.cpp
@@ -304,21 +304,13 @@ void Resource::clearContexts() {
}
void Resource::loadResource(ResourceContext *context, uint32 resourceId, ByteArray &resourceBuffer) {
- Common::File *file;
- uint32 resourceOffset;
- ResourceData *resourceData;
-
-
- resourceData = context->getResourceData(resourceId);
-
- file = context->getFile(resourceData);
-
- resourceOffset = resourceData->offset;
+ ResourceData *resourceData = context->getResourceData(resourceId);
+ Common::File *file = context->getFile(resourceData);
+ uint32 resourceOffset = resourceData->offset;
debug(8, "loadResource %d 0x%X:0x%X", resourceId, resourceOffset, uint(resourceData->size));
resourceBuffer.resize(resourceData->size);
-
file->seek((long)resourceOffset, SEEK_SET);
if (file->read(resourceBuffer.getBuffer(), resourceBuffer.size()) != resourceBuffer.size()) {
diff --git a/engines/saga/resource.h b/engines/saga/resource.h
index 252e92c967..2a1aaf3103 100644
--- a/engines/saga/resource.h
+++ b/engines/saga/resource.h
@@ -60,12 +60,13 @@ struct PatchData {
struct ResourceData {
uint32 id; // SAGA2
+ uint32 category; // SAGA2
size_t offset;
size_t size;
PatchData *patchData;
ResourceData() :
- id(0), offset(0), size(0), patchData(NULL) {
+ id(0), category(0), offset(0), size(0), patchData(NULL) {
}
~ResourceData() {
@@ -130,10 +131,15 @@ public:
// SAGA 2
int32 getEntryNum(uint32 id) {
int32 num = 0;
+ uint32 miloCategory = MKTAG('M', 'I', 'L', 'O');
+
for (ResourceDataArray::const_iterator i = _table.begin(); i != _table.end(); ++i) {
- if (i->id == id) {
+ //uint32 c = i->category;
+ //debug("%c%c%c%c, offset: %d, size: %d", (c >> 24), (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF, i->offset, i->size);
+ // Ignore low quality music resources (MILO)
+ if (i->id == id && i->category != miloCategory)
return num;
- }
+
num++;
}
return -1;
@@ -282,6 +288,10 @@ protected:
return loadResV2(contextSize);
}
bool loadResV2(uint32 contextSize);
+
+ void readCategory(ResourceData &element);
+ void readEntry(ResourceData &element);
+ uint32 getCategory(uint32 resourceOffset);
};
class Resource_HRS : public Resource {
diff --git a/engines/saga/resource_hrs.cpp b/engines/saga/resource_hrs.cpp
index 09da9cf0bb..ba58830269 100644
--- a/engines/saga/resource_hrs.cpp
+++ b/engines/saga/resource_hrs.cpp
@@ -39,13 +39,35 @@
namespace Saga {
-void readElement(Common::File &file, Saga::ResourceData &element) {
- element.id = file.readUint32BE();
- element.offset = file.readUint32LE();
- element.size = file.readUint32LE();
+void ResourceContext_HRS::readCategory(ResourceData &element) {
+ element.id = _file.readUint32BE();
+ element.offset = _file.readUint32LE();
+ element.size = _file.readUint32LE();
+ element.category = 0;
+ debug(3, "Category: id %u, offset %u, size %u", element.id, (uint)element.offset, (uint)element.size);
+}
+
+void ResourceContext_HRS::readEntry(ResourceData &element) {
+ element.id = _file.readUint32BE();
+ element.offset = _file.readUint32LE();
+ element.size = _file.readUint32LE();
+ element.category = getCategory(_file.pos());
debug(3, "Entry: id %u, offset %u, size %u", element.id, (uint)element.offset, (uint)element.size);
}
+uint32 ResourceContext_HRS::getCategory(uint32 resourceOffset) {
+ for (int i = _categories.size() - 1; i >= 0; --i) {
+ if (resourceOffset >= _categories[i].offset)
+ return _categories[i].id;
+ }
+
+ error("Unknown category for offset %d", resourceOffset);
+}
+
+static bool categorySortHelper(const ResourceData &r1, const ResourceData &r2) {
+ return r1.offset < r2.offset;
+}
+
bool ResourceContext_HRS::loadResV2(uint32 contextSize) {
ResourceData origin;
uint32 firstEntryOffset;
@@ -56,7 +78,7 @@ bool ResourceContext_HRS::loadResV2(uint32 contextSize) {
debug(3, "Context %s =====", _fileName);
_file.seek(0, SEEK_SET);
- readElement(_file, origin);
+ readCategory(origin);
// Check if the file is valid
if (origin.id != MKTAG('H','R','E','S')) { // header
@@ -74,18 +96,23 @@ bool ResourceContext_HRS::loadResV2(uint32 contextSize) {
// Read categories
count = origin.size / resourceSize;
- debug(3, "Categories: %d =====", count);
+ debug(3, "File: %s, categories: %d =====", _file.getName(), count);
for (i = 0; i < count; i++) {
- readElement(_file, _categories[i]);
+ readCategory(_categories[i]);
+ //uint32 id = _categories[i].id;
+ //debug("%i: %c%c%c%c, offset: %d, size: %d", i, (id >> 24), (id >> 16) & 0xFF, (id >> 8) & 0xFF, id & 0xFF, _categories[i].offset, _categories[i].size);
}
+ Common::sort(_categories.begin(), _categories.end(), categorySortHelper);
+
_file.seek(firstEntryOffset, SEEK_SET);
// Read table entries
count = tableSize / resourceSize;
- debug(3, "Entries: %d =====", count);
+ debug(3, "File: %s, entries: %d =====", _file.getName(), count);
for (i = 0; i < count; i++) {
- readElement(_file, _table[i]);
+ readEntry(_table[i]);
+ //debug("%i: offset: %d, size: %d", i, _table[i].offset, _table[i].size);
}
return true;
}
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index b15d161ba3..3d38b3ea52 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -341,7 +341,6 @@ Common::Error SagaEngine::run() {
syncSoundSettings();
} else {
_framesEsc = 0;
- //_sndRes->playVoice(0); // SAGA 2 sound test
_scene->startScene();
}
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index 04776bd5dc..f19645dd99 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -789,13 +789,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) {
if (_vm->getGameId() == GID_ITE) {
if (_sceneDescription.musicResourceId >= 0) {
- event.type = kEvTOneshot;
- event.code = kMusicEvent;
- event.param = _sceneDescription.musicResourceId;
- event.param2 = MUSIC_DEFAULT;
- event.op = kEventPlay;
- event.time = 0;
- _vm->_events->queue(event);
+ _vm->_events->queueMusic(_sceneDescription.musicResourceId);
} else {
event.type = kEvTOneshot;
event.code = kMusicEvent;
diff --git a/engines/saga/scene.h b/engines/saga/scene.h
index 0a3b98b33f..6a9571d282 100644
--- a/engines/saga/scene.h
+++ b/engines/saga/scene.h
@@ -182,34 +182,8 @@ typedef Common::List<LoadSceneParams> SceneQueueList;
#define IHNM_TITLE_TIME_GM 28750
#define IHNM_TITLE_TIME_FM 19500
-///// ITE-specific stuff
-#define ITE_INTRO_FRAMETIME 90
-
-#define INTRO_CAPTION_Y 170
-#define INTRO_DE_CAPTION_Y 160
-#define INTRO_IT_CAPTION_Y 160
-#define VOICE_PAD 50
-#define VOICE_LETTERLEN 90
-
-#define PALETTE_FADE_DURATION 1000
-#define DISSOLVE_DURATION 3000
-#define LOGO_DISSOLVE_DURATION 1000
-
#define CREDIT_DURATION1 4000
-struct IntroDialogue {
- uint32 i_voice_rn;
- const char *i_str;
-};
-
-struct IntroCredit {
- Common::Language lang;
- int game;
- int type;
- const char *string;
-};
-
-
class Scene {
public:
Scene(SagaEngine *vm);
@@ -431,13 +405,10 @@ class Scene {
static int SC_ITEIntroFaireTentProc(int param, void *refCon);
private:
- EventColumns *ITEQueueDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]);
- EventColumns *ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]);
+ EventColumns *queueIntroDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]);
+ EventColumns *queueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]);
int ITEIntroAnimProc(int param);
- int ITEIntroCave1Proc(int param);
- int ITEIntroCave2Proc(int param);
- int ITEIntroCave3Proc(int param);
- int ITEIntroCave4Proc(int param);
+ int ITEIntroCaveCommonProc(int param, int caveScene);
int ITEIntroValleyProc(int param);
int ITEIntroTreeHouseProc(int param);
int ITEIntroFairePathProc(int param);
diff --git a/engines/saga/sfuncs_ihnm.cpp b/engines/saga/sfuncs_ihnm.cpp
index 6957360942..e3e3c1ca11 100644
--- a/engines/saga/sfuncs_ihnm.cpp
+++ b/engines/saga/sfuncs_ihnm.cpp
@@ -421,14 +421,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTable.size() - 1);
} else {
_vm->_music->setVolume(_vm->_musicVolume, 1);
- event.type = kEvTOneshot;
- event.code = kMusicEvent;
- event.param = _vm->_music->_songTable[param1];
- event.param2 = param2 ? MUSIC_LOOP : MUSIC_NORMAL;
- event.op = kEventPlay;
- event.time = _vm->ticksToMSec(1000);
-
- _vm->_events->queue(event);
+ _vm->_events->queueMusic(_vm->_music->_songTable[param1], param2, _vm->ticksToMSec(1000));
if (!_vm->_scene->haveChapterPointsChanged()) {
_vm->_scene->setCurrentMusicTrack(param1);
diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp
index 426430c892..edb12a3dd9 100644
--- a/engines/saga/shorten.cpp
+++ b/engines/saga/shorten.cpp
@@ -29,6 +29,8 @@
// Based on etree's Shorten tool, version 3.6.1
// http://etree.org/shnutils/shorten/
+// and
+// https://github.com/soiaf/Java-Shorten-decoder
// FIXME: This doesn't work yet correctly
@@ -154,6 +156,7 @@ uint32 ShortenGolombReader::getUint32(uint32 numBits) {
byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, byte &flags) {
int32 *buffer[2], *offset[2]; // up to 2 channels
+ int32 *oldValues[2];
byte *unpackedBuffer = 0;
byte *pBuf = unpackedBuffer;
int prevSize = 0;
@@ -190,15 +193,18 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
switch (type) {
case kTypeS8:
+ mean = 0;
break;
case kTypeU8:
flags |= Audio::FLAG_UNSIGNED;
+ mean = 0x80;
break;
case kTypeS16LH:
flags |= Audio::FLAG_LITTLE_ENDIAN;
// fallthrough
case kTypeS16HL:
flags |= Audio::FLAG_16BITS;
+ mean = 0;
break;
case kTypeU16LH:
flags |= Audio::FLAG_LITTLE_ENDIAN;
@@ -206,6 +212,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
case kTypeU16HL:
flags |= Audio::FLAG_16BITS;
flags |= Audio::FLAG_UNSIGNED;
+ mean = 0x8000;
break;
case kTypeWAV:
// TODO: Perhaps implement this if we find WAV Shorten encoded files
@@ -264,8 +271,10 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
for (i = 0; i < channels; i++) {
buffer[i] = (int32 *)malloc((blockSize + wrap) * 4);
offset[i] = (int32 *)malloc((MAX<uint32>(1, mean)) * 4);
+ oldValues[i] = (int32 *)malloc(64 * 4);
memset(buffer[i], 0, (blockSize + wrap) * 4);
memset(offset[i], 0, (MAX<uint32>(1, mean)) * 4);
+ memset(oldValues[i], 0, 64 * 4);
}
if (maxLPC > 0)
@@ -329,9 +338,6 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
channelOffset = (channelOffset >> (bitShift - 1)) >> 1;
}
- // FIXME: The original code in this bit tries to modify memory outside of the array (negative indices)
- // in cases kCmdDiff1, kCmdDiff2 and kCmdDiff3
- // I've removed those invalid writes, since they happen all the time (even when curChannel is 0)
switch (cmd) {
case kCmdZero:
for (i = 0; i < blockSize; i++)
@@ -342,22 +348,34 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
buffer[curChannel][i] = gReader->getSRice(energy) + channelOffset;
break;
case kCmdDiff1:
- gReader->getSRice(energy); // i = 0 (to fix invalid table/memory access)
- for (i = 1; i < blockSize; i++)
- buffer[curChannel][i] = gReader->getSRice(energy) + buffer[curChannel][i - 1];
+ for (i = 0; i < blockSize; i++) {
+ if (i == 0)
+ buffer[curChannel][i] = gReader->getSRice(energy) + oldValues[curChannel][0];
+ else
+ buffer[curChannel][i] = gReader->getSRice(energy) + buffer[curChannel][i - 1];
+ }
break;
case kCmdDiff2:
- gReader->getSRice(energy); // i = 0 (to fix invalid table/memory access)
- gReader->getSRice(energy); // i = 1 (to fix invalid table/memory access)
- for (i = 2; i < blockSize; i++)
- buffer[curChannel][i] = gReader->getSRice(energy) + 2 * buffer[curChannel][i - 1] - buffer[curChannel][i - 2];
+ for (i = 0; i < blockSize; i++) {
+ if (i == 0)
+ buffer[curChannel][i] = gReader->getSRice(energy) + 2 * oldValues[curChannel][0] - oldValues[curChannel][1];
+ else if (i == 1)
+ buffer[curChannel][i] = gReader->getSRice(energy) + 2 * buffer[curChannel][0] - oldValues[curChannel][0];
+ else
+ buffer[curChannel][i] = gReader->getSRice(energy) + 2 * buffer[curChannel][i - 1] - buffer[curChannel][i - 2];
+ }
break;
case kCmdDiff3:
- gReader->getSRice(energy); // i = 0 (to fix invalid table/memory access)
- gReader->getSRice(energy); // i = 1 (to fix invalid table/memory access)
- gReader->getSRice(energy); // i = 2 (to fix invalid table/memory access)
- for (i = 3; i < blockSize; i++)
- buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][i - 1] - buffer[curChannel][i - 2]) + buffer[curChannel][i - 3];
+ for (i = 0; i < blockSize; i++) {
+ if (i == 0)
+ buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (oldValues[curChannel][0] - oldValues[curChannel][1]) + oldValues[curChannel][2];
+ else if (i == 1)
+ buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][0] - oldValues[curChannel][0]) + oldValues[curChannel][1];
+ else if (i == 2)
+ buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][1] - buffer[curChannel][0]) + oldValues[curChannel][0];
+ else
+ buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][i - 1] - buffer[curChannel][i - 2]) + buffer[curChannel][i - 3];
+ }
break;
case kCmdQLPC:
lpcNum = gReader->getURice(2);
@@ -417,10 +435,12 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
// Do the wrap
- // FIXME: removed for now, as this corrupts the heap, because it
- // accesses negative array indices
- //for (int32 k = -wrap; k < 0; k++)
- // buffer[curChannel][k] = buffer[curChannel][k + blockSize];
+ for (i = 0; i < 64; ++i)
+ oldValues[curChannel][i] = 0;
+
+ int arrayTerminator = MIN<int>(64, blockSize);
+ for (i = 0; i < arrayTerminator; ++i)
+ oldValues[curChannel][i] = buffer[curChannel][blockSize - (i + 1)];
// Fix bitshift
if (bitShift > 0) {
@@ -495,6 +515,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
for (i = 0; i < channels; i++) {
free(buffer[i]);
free(offset[i]);
+ free(oldValues[i]);
}
if (maxLPC > 0)
@@ -516,6 +537,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
for (i = 0; i < channels; i++) {
free(buffer[i]);
free(offset[i]);
+ free(oldValues[i]);
}
if (maxLPC > 0)
diff --git a/engines/saga/sndres.h b/engines/saga/sndres.h
index 554eed4a27..5115873d76 100644
--- a/engines/saga/sndres.h
+++ b/engines/saga/sndres.h
@@ -45,6 +45,7 @@ public:
void playVoice(uint32 resourceId);
int getVoiceLength(uint32 resourceId);
void setVoiceBank(int serial);
+ int getVoiceBank() { return _voiceSerial; }
Common::Array<FxTable> _fxTable;
diff --git a/engines/savestate.h b/engines/savestate.h
index 970e01485d..54eff0f8cb 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -140,7 +140,7 @@ public:
* Sets the time the game was played before the save state was created.
*
* @param hours How many hours the user played the game so far.
- * @param min How many minutes the user played the game so far.
+ * @param minutes How many minutes the user played the game so far.
*/
void setPlayTime(int hours, int minutes);
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 344298ce9a..91b3c45c6e 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -2607,6 +2607,25 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Phantasmagoria - French DOS
+ // Supplied by Kervala in bug #6574
+ {"phantasmagoria", "", {
+ {"resmap.001", 0, "4da82dd336d4b9cd8c16f3cc11f0c615", 11524},
+ {"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 69963685},
+ {"resmap.002", 0, "4f40f43f2b60bf765864433069752bb9", 12064},
+ {"ressci.002", 0, "3aae6559aa1df273bc542d5ac6330d75", 78362841},
+ {"resmap.003", 0, "6a392a86f14b6ddb4422978ee71e54ac", 12340},
+ {"ressci.003", 0, "3aae6559aa1df273bc542d5ac6330d75", 80431189},
+ {"resmap.004", 0, "df2e9462c41202de5f3843908c95a715", 12562},
+ {"ressci.004", 0, "3aae6559aa1df273bc542d5ac6330d75", 82542844},
+ {"resmap.005", 0, "43efd3fe834286c70a2c8b4cd747c1e2", 12616},
+ {"ressci.005", 0, "3aae6559aa1df273bc542d5ac6330d75", 83790486},
+ {"resmap.006", 0, "b3065e54a00190752a06dacd201b5058", 12538},
+ {"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 85415107},
+ {"resmap.007", 0, "5633960bc106c39ca91d2d8fce18fd2d", 7984},
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Phantasmagoria - English DOS Demo
// Executable scanning reports "2.100.002"
{"phantasmagoria", "Demo", {
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 31e7ca4931..be062dba64 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -344,9 +344,9 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
if (kFuncNum == 8) { // kDrawPic (SCI0 - SCI11)
// If kDrawPic is called with 6 parameters from the overlay
// selector, the game is using old graphics functions.
- // Otherwise, if it's called with 8 parameters, it's using new
- // graphics functions.
- _gfxFunctionsType = (argc == 8) ? SCI_VERSION_0_LATE : SCI_VERSION_0_EARLY;
+ // Otherwise, if it's called with 8 parameters (e.g. SQ3) or 4 parameters
+ // (e.g. Hoyle 1/2), it's using new graphics functions.
+ _gfxFunctionsType = (argc == 6) ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE;
return true;
}
}
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index fc46d16b8d..0c2fd4e3ea 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -468,7 +468,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(TimesSin), SIG_EVERYWHERE, "ii", NULL, NULL },
{ "SinMult", kTimesSin, SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(TimesTan), SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ri]", NULL, kUnLoad_workarounds },
+ { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ir!]", NULL, kUnLoad_workarounds },
+ // ^ We allow invalid references here (e.g. bug #6600), since they will be invalidated anyway by the call itself
{ MAP_CALL(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL },
{ MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL },
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 3738fd3dcb..58c2b8d3e3 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -371,7 +371,7 @@ void SegManager::freeHunkEntry(reg_t addr) {
HunkTable *ht = (HunkTable *)getSegment(addr.getSegment(), SEG_TYPE_HUNK);
if (!ht) {
- warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type", PRINT_REG(addr));
+ warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type %d", PRINT_REG(addr), getSegmentType(addr.getSegment()));
return;
}
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 37e46b7a96..ea4dc2fe71 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -44,7 +44,8 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = {
{ GID_MOTHERGOOSEHIRES,90, 90, 0, "newGameButton", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_ge: MUMG Deluxe, when selecting "New Game" in the main menu. It tries to compare an integer with a list. Needs to return false for the game to continue.
{ GID_PHANTASMAGORIA, 902, 0, 0, "", "export 7", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_shr: when starting a chapter in Phantasmagoria
{ GID_QFG1VGA, 301, 928, 0, "Blink", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_div: when entering the inn, gets called with 1 parameter, but 2nd parameter is used for div which happens to be an object
- { GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer bug #5152
+ { GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer - bug #5152
+ { GID_QFG3, 780, 999, 0, "", "export 6", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_add: trying to talk to yourself at the top of the giant tree - bug #6692
{ GID_QFG4, 710,64941, 0, "RandCycle", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when the tentacle appears in the third room of the caves
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index a322eb8e61..91b5b25e99 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -782,9 +782,13 @@ void GfxFrameout::kernelFrameout() {
// TODO: For some reason, the top left nsRect coordinates get
// swapped in the GK1 inventory screen, investigate why.
+ // This is also needed for GK1 rooms 710 and 720 (catacombs, inner and
+ // outer circle), for handling the tiles and talking to Wolfgang.
// HACK: Fix the coordinates by explicitly setting them here.
Common::Rect objNSRect = g_sci->_gfxCompare->getNSRect(itemEntry->object);
- if (objNSRect.top == nsRect.left && objNSRect.left == nsRect.top && nsRect.top != 0 && nsRect.left != 0) {
+ uint16 roomNumber = g_sci->getEngineState()->currentRoomNumber();
+ if (objNSRect.top == nsRect.left && objNSRect.left == nsRect.top && nsRect.top != 0 && nsRect.left != 0 ||
+ (g_sci->getGameId() == GID_GK1 && (roomNumber == 710 || roomNumber == 720))) {
g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
}
}
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index 693bbec744..27ebc58704 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -186,8 +186,7 @@ static bool parseList(ParseTreeNode* parentNode);
static bool parseListEntry(ParseTreeNode* parentNode);
static bool parseWord(ParseTreeNode* parentNode);
-static bool parseWord(ParseTreeNode* parentNode)
-{
+static bool parseWord(ParseTreeNode* parentNode) {
int token = said_tokens[said_token];
if (token & 0x8000)
return false;
@@ -201,8 +200,7 @@ static bool parseWord(ParseTreeNode* parentNode)
return true;
}
-static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty)
-{
+static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -259,8 +257,7 @@ static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty)
return false;
}
-static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty)
-{
+static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -318,8 +315,7 @@ static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty)
}
-static bool parseSlash(ParseTreeNode* parentNode)
-{
+static bool parseSlash(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -343,8 +339,7 @@ static bool parseSlash(ParseTreeNode* parentNode)
}
-static bool parseRef(ParseTreeNode* parentNode)
-{
+static bool parseRef(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -411,8 +406,7 @@ static bool parseRef(ParseTreeNode* parentNode)
return false;
}
-static bool parseComma(ParseTreeNode* parentNode)
-{
+static bool parseComma(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -435,8 +429,7 @@ static bool parseComma(ParseTreeNode* parentNode)
return false;
}
-static bool parseListEntry(ParseTreeNode* parentNode)
-{
+static bool parseListEntry(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -494,8 +487,7 @@ static bool parseListEntry(ParseTreeNode* parentNode)
return false;
}
-static bool parseList(ParseTreeNode* parentNode)
-{
+static bool parseList(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -524,8 +516,7 @@ static bool parseList(ParseTreeNode* parentNode)
return false;
}
-static bool parseExpr(ParseTreeNode* parentNode)
-{
+static bool parseExpr(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -546,7 +537,6 @@ static bool parseExpr(ParseTreeNode* parentNode)
said_attach_subtree(newParent, 0x141, 0x14F, newNode);
newParent = newParent->right;
-
}
found = parseRef(newParent);
@@ -561,8 +551,7 @@ static bool parseExpr(ParseTreeNode* parentNode)
return false;
}
-static bool parseSpec(ParseTreeNode* parentNode)
-{
+static bool parseSpec(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -748,9 +737,7 @@ static void node_print_desc(ParseTreeNode *) { }
-
-static int matchTrees(ParseTreeNode* parseT, ParseTreeNode* saidT)
-{
+static int matchTrees(ParseTreeNode* parseT, ParseTreeNode* saidT) {
outputDepth++;
scidprintf("%*smatchTrees on ", outputDepth, "");
node_print_desc(parseT);
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index b4a223dcff..3344b79e26 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -530,18 +530,19 @@ bool Vocabulary::tokenizeString(ResultWordListList &retval, const char *sentence
*error = NULL;
do {
-
c = sentence[pos_in_sentence++];
+
if (Common::isAlnum(c) || (c == '-' && wordLen) || (c >= 0x80)) {
currentWord[wordLen] = lowerCaseMap[c];
++wordLen;
- }
- // Continue on this word */
- // Words may contain a '-', but may not
- // start with one.
- else {
- if (wordLen) { // Finished a word?
+ } else if (c == '\'' && wordLen && (sentence[pos_in_sentence] == 's' || sentence[pos_in_sentence] == 'S')) {
+ // Skip apostrophe-s at the end of the word, if it exists
+ pos_in_sentence++; // skip the 's'
+ } else {
+ // Continue on this word. Words may contain a '-', but may not start with
+ // one.
+ if (wordLen) { // Finished a word?
ResultWordList lookup_result;
// Look it up
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 31c9d90de8..80a72b9a6f 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -398,8 +398,7 @@ void MidiPlayer_Midi::playSwitch(bool play) {
}
}
-bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size)
-{
+bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
if (size < 1155)
return false;
if (size > 16889)
@@ -957,7 +956,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
warning("The automatic mapping for General MIDI hasn't been worked on for "
"SCI1 games. Music might sound wrong or broken. Please choose another "
- "music driver for this game (e.g. Adlib or MT-32) if you are "
+ "music driver for this game (e.g. AdLib or MT-32) if you are "
"experiencing issues with music");
// Modify velocity map to make low velocity notes a little louder
diff --git a/engines/scumm/cdda.cpp b/engines/scumm/cdda.cpp
new file mode 100644
index 0000000000..adb414ecce
--- /dev/null
+++ b/engines/scumm/cdda.cpp
@@ -0,0 +1,120 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/cdda.h"
+#include "common/stream.h"
+#include "audio/audiostream.h"
+
+namespace Scumm {
+
+
+#pragma mark -
+#pragma mark --- CDDA stream ---
+#pragma mark -
+
+#define START_OF_CDDA_DATA 800
+#define BLOCK_SIZE 1177
+
+class CDDAStream : public Audio::SeekableAudioStream {
+private:
+ Common::SeekableReadStream *_stream;
+ DisposeAfterUse::Flag _disposeAfterUse;
+ byte _shiftLeft;
+ byte _shiftRight;
+ uint32 _pos;
+ Audio::Timestamp _length;
+
+public:
+ CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
+ virtual ~CDDAStream();
+
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return true; }
+ int getRate() const { return 44100; }
+ bool endOfData() const { return _stream->eos(); }
+ bool seek(const Audio::Timestamp &where);
+ Audio::Timestamp getLength() const { return _length; }
+};
+
+CDDAStream::CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) :
+ _stream(stream), _disposeAfterUse(disposeAfterUse), _pos(START_OF_CDDA_DATA) {
+ _stream->seek(START_OF_CDDA_DATA, SEEK_SET);
+ // The total size of CDDA.SOU is 289,808,802 bytes or (289808802 - 800) / 1177 = 246226 blocks
+ // We also deduct the shift values to return the correct length
+ uint32 blocks = (_stream->size() - START_OF_CDDA_DATA) / BLOCK_SIZE;
+ _length = Audio::Timestamp(0, (_stream->size() - START_OF_CDDA_DATA - blocks) / (isStereo() ? 2 : 1), getRate());
+}
+
+CDDAStream::~CDDAStream() {
+ if (_disposeAfterUse == DisposeAfterUse::YES)
+ delete _stream;
+}
+
+bool CDDAStream::seek(const Audio::Timestamp &where) {
+ const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames();
+ uint32 blocks = seekSample / 1176;
+
+ // Before seeking, read the shift values from the beginning of that block
+ _stream->seek(START_OF_CDDA_DATA + blocks * BLOCK_SIZE, SEEK_SET);
+ byte shiftVal = _stream->readByte();
+ _shiftLeft = shiftVal >> 4;
+ _shiftRight = shiftVal & 0x0F;
+
+ _pos = START_OF_CDDA_DATA + blocks + seekSample;
+ return _stream->seek(_pos, SEEK_SET);
+}
+
+int CDDAStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samples;
+
+ for (samples = 0 ; samples < numSamples && !_stream->eos() ; ) {
+ if (!((_pos - START_OF_CDDA_DATA) % BLOCK_SIZE)) {
+ byte shiftVal = _stream->readByte();
+ _shiftLeft = shiftVal >> 4;
+ _shiftRight = shiftVal & 0x0F;
+ _pos++;
+ }
+ buffer[samples++] = _stream->readSByte() << _shiftLeft;
+ buffer[samples++] = _stream->readSByte() << _shiftRight;
+ _pos += 2;
+ }
+ return samples;
+}
+
+#pragma mark -
+#pragma mark --- CDDA factory functions ---
+#pragma mark -
+
+Audio::SeekableAudioStream *makeCDDAStream(
+ Common::SeekableReadStream *stream,
+ DisposeAfterUse::Flag disposeAfterUse) {
+ Audio::SeekableAudioStream *s = new CDDAStream(stream, disposeAfterUse);
+ if (s && s->endOfData()) {
+ delete s;
+ return 0;
+ } else {
+ return s;
+ }
+ return 0;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/cdda.h b/engines/scumm/cdda.h
new file mode 100644
index 0000000000..c1e6e82c9e
--- /dev/null
+++ b/engines/scumm/cdda.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file
+ * CD audio decoder used in the Steam versions of Loom
+ */
+
+#ifndef SCUMM_CDDA_H
+#define SCUMM_CDDA_H
+
+#include "common/types.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Audio {
+class SeekableAudioStream;
+}
+
+namespace Scumm {
+
+/**
+ * Create a new SeekableAudioStream from the CDDA data in the given stream.
+ * Allows for seeking (which is why we require a SeekableReadStream).
+ *
+ * @param stream The SeekableReadStream from which to read the CDDA data
+ * @param disposeAfterUse Whether to delete the stream after use
+ * @return a new SeekableAudioStream, or NULL, if an error occurred
+ */
+Audio::SeekableAudioStream *makeCDDAStream(
+ Common::SeekableReadStream *stream,
+ DisposeAfterUse::Flag disposeAfterUse);
+
+} // End of namespace Audio
+
+#endif // #ifndef SCUMM_CDDA_H
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 185ebbce6e..e546c805b5 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -253,7 +253,7 @@ CharsetRenderer::~CharsetRenderer() {
CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm)
: CharsetRenderer(vm), _bytesPerPixel(0), _fontHeight(0), _numChars(0) {
- _shadowMode = false;
+ _enableShadow = false;
_shadowColor = 0;
}
@@ -392,6 +392,10 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
} else if (chr & 0x80) {
pos++;
width += _vm->_2byteWidth;
+ // Original keeps glyph width and character dimensions separately
+ if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) {
+ width++;
+ }
continue;
}
}
@@ -478,6 +482,12 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
} else if (chr & 0x80) {
pos++;
curw += _vm->_2byteWidth;
+ // Original keeps glyph width and character dimensions separately
+ if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) {
+ curw++;
+ }
+ } else {
+ curw += getCharWidth(chr);
}
} else {
curw += getCharWidth(chr);
@@ -507,12 +517,17 @@ int CharsetRendererV3::getCharWidth(uint16 chr) {
return spacing;
}
-void CharsetRendererV3::enableShadow(bool enable) {
+void CharsetRendererPC::enableShadow(bool enable) {
_shadowColor = 0;
- _shadowMode = enable;
+ _enableShadow = enable;
+
+ if (_vm->_game.version >= 7 && _vm->_language == Common::KO_KOR)
+ _shadowType = kHorizontalShadowType;
+ else
+ _shadowType = kNormalShadowType;
}
-void CharsetRendererV3::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) {
+void CharsetRendererPC::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) {
byte *dst = (byte *)dest.getBasePtr(x, y);
byte bits = 0;
@@ -525,8 +540,12 @@ void CharsetRendererV3::drawBits1(Graphics::Surface &dest, int x, int y, const b
if ((x % 8) == 0)
bits = *src++;
if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
- if (_shadowMode)
- dst[1] = dst2[0] = dst2[1] = _shadowColor;
+ if (_enableShadow) {
+ if (_shadowType == kNormalShadowType)
+ dst[1] = dst2[0] = dst2[1] = _shadowColor;
+ else if (_shadowType == kHorizontalShadowType)
+ dst[1] = _shadowColor;
+ }
dst[0] = col;
}
dst += dest.format.bytesPerPixel;
@@ -615,7 +634,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (_left + origWidth > _right + 1)
return;
- if (_shadowMode) {
+ if (_enableShadow) {
width++;
height++;
}
@@ -658,7 +677,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (_str.right < _left) {
_str.right = _left;
- if (_shadowMode)
+ if (_enableShadow)
_str.right++;
}
@@ -776,11 +795,15 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask);
+ // Original keeps glyph width and character dimensions separately
+ if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte)
+ _origWidth++;
+
_left += _origWidth;
if (_str.right < _left) {
_str.right = _left;
- if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode)
+ if (_vm->_game.platform != Common::kPlatformFMTowns && _enableShadow)
_str.right++;
}
@@ -844,7 +867,10 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
drawTop = _top - _vm->_screenTop;
}
- drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
+ if (is2byte && _vm->_game.platform != Common::kPlatformFMTowns)
+ drawBits1(dstSurface, _left, drawTop, charPtr, drawTop, origWidth, origHeight);
+ else
+ drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
if (_blitAlso && vs->hasTwoBuffers) {
// FIXME: Revisiting this code, I think the _blitAlso mode is likely broken
@@ -884,6 +910,24 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
}
bool CharsetRendererClassic::prepareDraw(uint16 chr) {
+ bool is2byte = (chr >= 256 && _vm->_useCJKMode);
+ if (is2byte) {
+ if (_vm->_language == Common::KO_KOR)
+ enableShadow(true);
+
+ _charPtr = _vm->get2byteCharPtr(chr);
+ _width = _origWidth = _vm->_2byteWidth;
+ _height = _origHeight = _vm->_2byteHeight;
+ _offsX = _offsY = 0;
+
+ if (_enableShadow) {
+ _width++;
+ _height++;
+ }
+
+ return true;
+ }
+
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
assert(charOffs < 0x14000);
if (!charOffs)
@@ -908,8 +952,14 @@ bool CharsetRendererClassic::prepareDraw(uint16 chr) {
void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) {
if (!prepareDraw(chr))
return;
+
byte *dst = (byte *)s.getBasePtr(x, y);
- drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height);
+
+ bool is2byte = (_vm->_useCJKMode && chr >= 256);
+ if (is2byte)
+ drawBits1(s, x, y, _charPtr, y, _width, _height);
+ else
+ drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height);
}
void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
@@ -982,7 +1032,7 @@ int CharsetRendererTownsV3::getFontHeight() {
void CharsetRendererTownsV3::enableShadow(bool enable) {
_shadowColor = 8;
- _shadowMode = enable;
+ _enableShadow = enable;
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
_shadowColor = 0x88;
@@ -1027,13 +1077,13 @@ void CharsetRendererTownsV3::drawBits1(Graphics::Surface &dest, int x, int y, co
bits = *src++;
if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
if (dest.format.bytesPerPixel == 2) {
- if (_shadowMode) {
+ if (_enableShadow) {
WRITE_UINT16(dst + 2, _vm->_16BitPalette[_shadowColor]);
WRITE_UINT16(dst + dest.pitch, _vm->_16BitPalette[_shadowColor]);
}
WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
} else {
- if (_shadowMode) {
+ if (_enableShadow) {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
if (scale2x) {
dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor;
@@ -1124,11 +1174,11 @@ void CharsetRendererPCE::drawBits1(Graphics::Surface &dest, int x, int y, const
bits = *src++;
if ((bits & revBitMask(bitCount % 8)) && y + drawTop >= 0) {
if (dest.format.bytesPerPixel == 2) {
- if (_shadowMode)
+ if (_enableShadow)
WRITE_UINT16(dst + dest.pitch + 2, _vm->_16BitPalette[_shadowColor]);
WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
} else {
- if (_shadowMode)
+ if (_enableShadow)
*(dst + dest.pitch + 1) = _shadowColor;
*dst = _color;
}
@@ -1227,7 +1277,8 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) {
int width = _current->getCharWidth(chr);
int height = _current->getCharHeight(chr);
- if (chr >= 256 && _vm->_useCJKMode)
+ bool is2byte = chr >= 256 && _vm->_useCJKMode;
+ if (is2byte)
width = _vm->_2byteWidth;
shadow.right = _left + width;
@@ -1259,8 +1310,8 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) {
_str.left = _left;
// Original keeps glyph width and character dimensions separately
- if (_vm->_language == Common::ZH_TWN && width == 16)
- width = 17;
+ if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte)
+ width++;
_left += width;
@@ -1327,7 +1378,7 @@ void CharsetRendererNES::printChar(int chr, bool ignoreCharsetMask) {
if (_str.right < _left) {
_str.right = _left;
- if (_shadowMode)
+ if (_enableShadow)
_str.right++;
}
@@ -1483,7 +1534,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) {
_origHeight = _height = _vm->_2byteHeight;
_charPtr = _vm->get2byteCharPtr(chr);
_offsX = _offsY = 0;
- if (_shadowMode) {
+ if (_enableShadow) {
_width++;
_height++;
}
@@ -1495,7 +1546,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) {
}
void CharsetRendererTownsClassic::setupShadowMode() {
- _shadowMode = true;
+ _enableShadow = true;
_shadowColor = _vm->_townsCharsetColorMap[0];
assert(_vm->_cjkFont);
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index 5a9977b7d6..b4b3d88ccd 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -100,7 +100,7 @@ protected:
int _numChars;
byte _shadowColor;
- bool _shadowMode;
+ bool _enableShadow;
public:
CharsetRendererCommon(ScummEngine *vm);
@@ -110,7 +110,24 @@ public:
virtual int getFontHeight();
};
-class CharsetRendererClassic : public CharsetRendererCommon {
+class CharsetRendererPC : public CharsetRendererCommon {
+ enum ShadowType {
+ kNoShadowType,
+ kNormalShadowType,
+ kHorizontalShadowType
+ };
+
+ ShadowType _shadowType;
+
+protected:
+ virtual void enableShadow(bool enable);
+ virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height);
+
+public:
+ CharsetRendererPC(ScummEngine *vm) : CharsetRendererCommon(vm), _shadowType(kNoShadowType) { }
+};
+
+class CharsetRendererClassic : public CharsetRendererPC {
protected:
virtual void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height);
void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask);
@@ -124,7 +141,7 @@ protected:
VirtScreenNumber _drawScreen;
public:
- CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {}
+ CharsetRendererClassic(ScummEngine *vm) : CharsetRendererPC(vm) {}
void printChar(int chr, bool ignoreCharsetMask);
void drawChar(int chr, Graphics::Surface &s, int x, int y);
@@ -170,10 +187,8 @@ public:
int getCharWidth(uint16 chr) { return 8; }
};
-class CharsetRendererV3 : public CharsetRendererCommon {
+class CharsetRendererV3 : public CharsetRendererPC {
protected:
- virtual void enableShadow(bool enable);
- virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height);
virtual int getDrawWidthIntern(uint16 chr);
virtual int getDrawHeightIntern(uint16 chr);
virtual void setDrawCharIntern(uint16 chr) {}
@@ -181,7 +196,7 @@ protected:
const byte *_widthTable;
public:
- CharsetRendererV3(ScummEngine *vm) : CharsetRendererCommon(vm) {}
+ CharsetRendererV3(ScummEngine *vm) : CharsetRendererPC(vm) {}
void printChar(int chr, bool ignoreCharsetMask);
void drawChar(int chr, Graphics::Surface &s, int x, int y);
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index b7a25808a5..7cd50e1f4c 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -79,10 +79,12 @@ Common::String ScummEngine::generateFilename(const int room) const {
} else {
switch (_filenamePattern.genMethod) {
case kGenDiskNum:
+ case kGenDiskNumSteam:
result = Common::String::format(_filenamePattern.pattern, diskNumber);
break;
case kGenRoomNum:
+ case kGenRoomNumSteam:
result = Common::String::format(_filenamePattern.pattern, room);
break;
@@ -209,7 +211,32 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const {
return result;
}
-static Common::String generateFilenameForDetection(const char *pattern, FilenameGenMethod genMethod) {
+// The following table includes all the index files, which are embedded in the
+// main game executables in Steam versions.
+static const SteamIndexFile steamIndexFiles[] = {
+ { GID_INDY3, Common::kPlatformWindows, "%02d.LFL", "00.LFL", "Indiana Jones and the Last Crusade.exe", 162056, 6295 },
+ { GID_INDY3, Common::kPlatformMacintosh, "%02d.LFL", "00.LFL", "The Last Crusade", 150368, 6295 },
+ { GID_INDY4, Common::kPlatformWindows, "atlantis.%03d", "ATLANTIS.000", "Indiana Jones and the Fate of Atlantis.exe", 224336, 12035 },
+ { GID_INDY4, Common::kPlatformMacintosh, "atlantis.%03d", "ATLANTIS.000", "The Fate of Atlantis", 260224, 12035 },
+ { GID_LOOM, Common::kPlatformWindows, "%03d.LFL", "000.LFL", "Loom.exe", 187248, 8307 },
+ { GID_LOOM, Common::kPlatformMacintosh, "%03d.LFL", "000.LFL", "Loom", 170464, 8307 },
+#ifdef ENABLE_SCUMM_7_8
+ { GID_DIG, Common::kPlatformWindows, "dig.la%d", "DIG.LA0", "The Dig.exe", 340632, 16304 },
+ { GID_DIG, Common::kPlatformMacintosh, "dig.la%d", "DIG.LA0", "The Dig", 339744, 16304 },
+#endif
+ { 0, Common::kPlatformUnknown, nullptr, nullptr, nullptr, 0, 0 }
+};
+
+const SteamIndexFile *lookUpSteamIndexFile(Common::String pattern, Common::Platform platform) {
+ for (const SteamIndexFile *indexFile = steamIndexFiles; indexFile->len; ++indexFile) {
+ if (platform == indexFile->platform && pattern.equalsIgnoreCase(indexFile->pattern))
+ return indexFile;
+ }
+
+ return nullptr;
+}
+
+static Common::String generateFilenameForDetection(const char *pattern, FilenameGenMethod genMethod, Common::Platform platform) {
Common::String result;
switch (genMethod) {
@@ -217,6 +244,16 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename
case kGenRoomNum:
result = Common::String::format(pattern, 0);
break;
+
+ case kGenDiskNumSteam:
+ case kGenRoomNumSteam: {
+ const SteamIndexFile *indexFile = lookUpSteamIndexFile(pattern, platform);
+ if (!indexFile) {
+ error("Unable to find Steam executable from detection pattern");
+ } else {
+ result = indexFile->executableName;
+ }
+ } break;
case kGenHEPC:
case kGenHEIOS:
@@ -528,7 +565,8 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
DetectorResult dr;
// Dive one level down since mac indy3/loom has its files split into directories. See Bug #1438631
- composeFileHashMap(fileMD5Map, fslist, 2, directoryGlobs);
+ // Dive two levels down for Mac Steam games
+ composeFileHashMap(fileMD5Map, fslist, 3, directoryGlobs);
// Iterate over all filename patterns.
for (const GameFilenamePattern *gfp = gameFilenamesTable; gfp->gameid; ++gfp) {
@@ -540,7 +578,7 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
// Generate the detectname corresponding to the gfp. If the file doesn't
// exist in the directory we are looking at, we can skip to the next
// one immediately.
- Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod));
+ Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod, gfp->platform));
if (!fileMD5Map.contains(file))
continue;
@@ -1025,7 +1063,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co
Common::FSNode dir(ConfMan.get("path"));
if (!dir.isDirectory())
return Common::kPathNotDirectory;
- if (!dir.getChildren(fslist, Common::FSNode::kListFilesOnly))
+ if (!dir.getChildren(fslist, Common::FSNode::kListAll))
return Common::kNoGameDataFoundError;
// Invoke the detector, but fixed to the specified gameid.
@@ -1081,7 +1119,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co
md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n",
res.game.gameid,
- generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(),
+ generateFilenameForDetection(res.fp.pattern, res.fp.genMethod, Common::kPlatformUnknown).c_str(),
res.md5.c_str());
g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str());
diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h
index f714812a9c..0587c3fab1 100644
--- a/engines/scumm/detection.h
+++ b/engines/scumm/detection.h
@@ -95,7 +95,9 @@ struct GameSettings {
enum FilenameGenMethod {
kGenDiskNum,
+ kGenDiskNumSteam,
kGenRoomNum,
+ kGenRoomNumSteam,
kGenHEMac,
kGenHEMacNoParens,
kGenHEPC,
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index c876af1256..ae334c201c 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -52,6 +52,8 @@ namespace Scumm {
*/
static const char *const directoryGlobs[] = {
"rooms *", // Mac version of indy3/loom
+ "Contents", // Mac Steam versions
+ "MacOS", // Mac Steam versions
0
};
@@ -221,6 +223,7 @@ static const GameSettings gameVariantsTable[] = {
{"indy3", "EGA", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
+ {"indy3", "Steam", "steam", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"indy3", "FM-TOWNS", 0, GID_INDY3, 3, 0, MDT_TOWNS, GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)},
{"loom", "EGA", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)},
@@ -230,6 +233,7 @@ static const GameSettings gameVariantsTable[] = {
#endif
{"loom", "FM-TOWNS", 0, GID_LOOM, 3, 0, MDT_TOWNS, GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)},
{"loom", "VGA", "vga", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
+ {"loom", "Steam", "steam", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
@@ -245,6 +249,7 @@ static const GameSettings gameVariantsTable[] = {
{"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)},
{"atlantis", "", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
+ {"atlantis", "Steam", "steam", GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
{"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)},
{"atlantis", "FM-TOWNS", 0, GID_INDY4, 5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO4(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)},
@@ -257,7 +262,8 @@ static const GameSettings gameVariantsTable[] = {
#ifdef ENABLE_SCUMM_7_8
{"ft", 0, 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
- {"dig", 0, 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+ {"dig", "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+ {"dig", "Steam", "steam", GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
{"comi", 0, 0, GID_CMI, 8, 0, MDT_NONE, 0, Common::kPlatformWindows, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)},
#endif
@@ -383,7 +389,7 @@ static const GameSettings gameVariantsTable[] = {
{"freddicove", "HE 100", 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
// Restructured the Scumm engine
- {"pjgames", 0, 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
+ {"pjgames", 0, 0, GID_PJGAMES, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
// Added the use of bink videos
{"Soccer2004", 0, 0, GID_SOCCER2004, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
@@ -422,10 +428,10 @@ static const GameSettings gameVariantsTable[] = {
using Common::UNK_LANG;
// The following describes how Fingolfin thinks this table might be used one day;
-// this is work in progress, so read this with a salt of grain...
+// this is work in progress, so read this with a grain of salt...
//
// The following table maps gameids to possible filename variants for that game.
-// This information is used by the detector to determin possible "detect files".
+// This information is used by the detector to determine possible "detect files".
// It is also later used by the engine creation code to verify the game to be
// launched is present. Finally, the correct GameFilenamePattern entry is passed on
// to the engine which uses it to locate the files for the game.
@@ -451,6 +457,8 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "zak", "zak1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, "V1" }, // ... and zak2.d64
{ "indy3", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },
+ { "indy3", "%02d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" },
+ { "indy3", "%02d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
{ "indyloom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },
{ "indyzak", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },
@@ -458,6 +466,8 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "loom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },
{ "loom", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, "VGA" }, // Loom CD
+ { "loom", "%03d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" },
+ { "loom", "%03d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
{ "pass", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },
@@ -471,6 +481,8 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "monkey2", "mi2demo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
{ "atlantis", "atlantis.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
+ { "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" },
+ { "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
{ "atlantis", "fate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
{ "atlantis", "playfate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
{ "atlantis", "indy4.%03d", kGenDiskNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" },
@@ -494,6 +506,8 @@ static const GameFilenamePattern gameFilenamesTable[] = {
#ifdef ENABLE_SCUMM_7_8
{ "dig", "dig.la%d", kGenDiskNum, UNK_LANG, UNK, 0 },
+ { "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" },
+ { "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
{ "dig", "thedig.la%d", kGenDiskNum, UNK_LANG, UNK, "Demo" }, // Used by an alternate version of the demo
{ "dig", "The Dig Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "dig", "The Dig Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, "Demo" },
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 8321daa583..52120949cc 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -428,7 +428,9 @@ const Common::String InfoDialog::queryResString(int stringno) {
if (stringno == 0)
return String();
- if (_vm->_game.version == 8)
+ if (_vm->_game.heversion >= 80)
+ return _(string_map_table_v6[stringno - 1].string);
+ else if (_vm->_game.version == 8)
result = (const byte *)string_map_table_v8[stringno - 1].string;
else if (_vm->_game.version == 7)
result = _vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 9c161ff1cc..475ffa3238 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -185,6 +185,30 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) {
}
#pragma mark -
+#pragma mark --- ScummSteamFile ---
+#pragma mark -
+
+bool ScummSteamFile::open(const Common::String &filename) {
+ if (filename.equalsIgnoreCase(_indexFile.indexFileName)) {
+ return openWithSubRange(_indexFile.executableName, _indexFile.start, _indexFile.len);
+ } else {
+ // Regular non-bundled file
+ return ScummFile::open(filename);
+ }
+}
+
+bool ScummSteamFile::openWithSubRange(const Common::String &filename, int32 subFileStart, int32 subFileLen) {
+ if (ScummFile::open(filename)) {
+ _subFileStart = subFileStart;
+ _subFileLen = subFileLen;
+ seek(0, SEEK_SET);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+#pragma mark -
#pragma mark --- ScummDiskImage ---
#pragma mark -
diff --git a/engines/scumm/file.h b/engines/scumm/file.h
index d6dbc06ddc..e7c1eb6d71 100644
--- a/engines/scumm/file.h
+++ b/engines/scumm/file.h
@@ -53,7 +53,7 @@ public:
};
class ScummFile : public BaseScummFile {
-private:
+protected:
int32 _subFileStart;
int32 _subFileLen;
bool _myEos; // Have we read past the end of the subfile?
@@ -64,7 +64,7 @@ private:
public:
ScummFile();
- bool open(const Common::String &filename);
+ virtual bool open(const Common::String &filename);
bool openSubFile(const Common::String &filename);
void clearErr() { _myEos = false; BaseScummFile::clearErr(); }
@@ -120,6 +120,29 @@ public:
uint32 read(void *dataPtr, uint32 dataSize);
};
+struct SteamIndexFile {
+ byte id;
+ Common::Platform platform;
+ const char *pattern;
+ const char *indexFileName;
+ const char *executableName;
+ int32 start;
+ int32 len;
+};
+
+const SteamIndexFile *lookUpSteamIndexFile(Common::String pattern, Common::Platform platform);
+
+class ScummSteamFile : public ScummFile {
+private:
+ const SteamIndexFile &_indexFile;
+
+ bool openWithSubRange(const Common::String &filename, int32 subFileStart, int32 subFileLen);
+public:
+ ScummSteamFile(const SteamIndexFile &indexFile) : ScummFile(), _indexFile(indexFile) {}
+
+ bool open(const Common::String &filename);
+};
+
} // End of namespace Scumm
#endif
diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp
index 218f2ec59c..245a986531 100644
--- a/engines/scumm/he/sprite_he.cpp
+++ b/engines/scumm/he/sprite_he.cpp
@@ -264,6 +264,13 @@ int Sprite::getSpriteFlagRemapPalette(int spriteId) {
int Sprite::getSpriteFlagAutoAnim(int spriteId) {
assertRange(1, spriteId, _varNumSprites, "sprite");
+ // WORKAROUND: Two scripts (room 2 script 2070/2071) compare against
+ // a return value of one, but the original game returned the flag value
+ // (0x200000) for true. These scripts bugs caused problems (infinite loop
+ // and beans not appearing) in the Jumping Beans mini games under ScummVM.
+ if (_vm->_game.id == GID_PJGAMES)
+ return 0;
+
return ((_spriteTable[spriteId].flags & kSFAutoAnim) != 0) ? 1 : 0;
}
@@ -793,6 +800,11 @@ void Sprite::resetSprite(int spriteId) {
_spriteTable[spriteId].field_84 = 0;
_spriteTable[spriteId].imgFlags = 0;
_spriteTable[spriteId].field_90 = 0;
+
+ if (_vm->_game.heversion >= 100) {
+ _spriteTable[spriteId].flags &= ~kSFMarkDirty;
+ _spriteTable[spriteId].flags |= kSFAutoAnim | kSFBlitDirectly;
+ }
}
void Sprite::setSpriteImage(int spriteId, int imageNum) {
@@ -820,6 +832,8 @@ void Sprite::setSpriteImage(int spriteId, int imageNum) {
} else {
if (_vm->VAR(139))
_spriteTable[spriteId].flags &= ~kSFActive;
+ else if (_vm->_game.heversion >= 100 && origResId == 0)
+ _spriteTable[spriteId].flags = 0;
else if (_spriteTable[spriteId].flags & kSFImageless)
_spriteTable[spriteId].flags = 0;
else
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 5e2566dc32..824dfec144 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -435,8 +435,9 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
break;
}
- if (VAR_VOICE_MODE != 0xFF)
- VAR(VAR_VOICE_MODE) = _voiceMode;
+ // We need to sync the current sound settings here to make sure that
+ // we actually update the mute state of speech properly.
+ syncSoundSettings();
return;
}
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index d43db1e5f1..416a8f7ef9 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -7,6 +7,7 @@ MODULE_OBJS := \
bomp.o \
boxes.o \
camera.o \
+ cdda.o \
charset.o \
charset-fontdata.o \
costume.o \
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index 1d5761ef48..d8672c473c 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -395,10 +395,6 @@ void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byt
}
void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color) {
- // FIXME: This gets passed a const destination Surface. Intuitively this
- // should never get written to. But sadly it does... For now we simply
- // cast the const qualifier away.
- byte *dst = (byte *)const_cast<void *>(s.getBasePtr(x, y));
const int width = _vm->_2byteWidth;
const int height = MIN(_vm->_2byteHeight, s.h - y);
const byte *src = _vm->get2byteCharPtr(c);
@@ -408,17 +404,50 @@ void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byt
return;
}
- for (int ty = 0; ty < height; ty++) {
- for (int tx = 0; tx < width; tx++) {
- if ((tx & 7) == 0)
- bits = *src++;
- if (x + tx < 0 || x + tx >= s.w || y + ty < 0)
- continue;
- if (bits & revBitMask(tx % 8)) {
- dst[tx] = color;
+ enum ShadowMode {
+ kNone,
+ kKoreanV8ShadowMode
+ };
+
+ ShadowMode shadowMode = kNone;
+
+ if (_vm->_language == Common::KO_KOR && _vm->_game.version == 8) {
+ shadowMode = kKoreanV8ShadowMode;
+ }
+
+ int shadowOffsetXTable[4] = {-1, 0, 1, 0};
+ int shadowOffsetYTable[4] = {0, 1, 0, 0};
+ int shadowOffsetColorTable[4] = {0, 0, 0, color};
+
+ int shadowIdx = 3;
+ if (shadowMode == kKoreanV8ShadowMode)
+ shadowIdx = 0;
+
+ const byte *origSrc = src;
+
+ for (; shadowIdx < 4; shadowIdx++) {
+ int offX = x + shadowOffsetXTable[shadowIdx];
+ int offY = y + shadowOffsetYTable[shadowIdx];
+ byte drawColor = shadowOffsetColorTable[shadowIdx];
+
+ // FIXME: This gets passed a const destination Surface. Intuitively this
+ // should never get written to. But sadly it does... For now we simply
+ // cast the const qualifier away.
+ byte *dst = (byte *)const_cast<void *>(s.getBasePtr(offX, offY));
+ src = origSrc;
+
+ for (int ty = 0; ty < height; ty++) {
+ for (int tx = 0; tx < width; tx++) {
+ if ((tx & 7) == 0)
+ bits = *src++;
+ if (offX + tx < 0 || offX + tx >= s.w || offY + ty < 0)
+ continue;
+ if (bits & revBitMask(tx % 8)) {
+ dst[tx] = drawColor;
+ }
}
+ dst += s.pitch;
}
- dst += s.pitch;
}
}
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index 5ed50ab65c..adcda68e10 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -137,6 +137,18 @@ void Player_AD::startSound(int sound) {
if (startSfx(sfx, res)) {
// Lock the new resource
_vm->_res->lock(rtSound, sound);
+ } else {
+ // When starting the sfx failed we need to reset the slot.
+ sfx->resource = -1;
+
+ for (int i = 0; i < ARRAYSIZE(sfx->channels); ++i) {
+ sfx->channels[i].state = kChannelStateOff;
+
+ if (sfx->channels[i].hardwareChannel != -1) {
+ freeHWChannel(sfx->channels[i].hardwareChannel);
+ sfx->channels[i].hardwareChannel = -1;
+ }
+ }
}
}
}
@@ -290,34 +302,43 @@ void Player_AD::setupVolume() {
}
int Player_AD::allocateHWChannel(int priority, SfxSlot *owner) {
- // First pass: Check whether there's any unallocated channel
+ // We always reaLlocate the channel with the lowest priority in case none
+ // is free.
+ int channel = -1;
+ int minPrio = priority;
+
for (int i = 0; i < _numHWChannels; ++i) {
if (!_hwChannels[i].allocated) {
- _hwChannels[i].allocated = true;
- _hwChannels[i].priority = priority;
- _hwChannels[i].sfxOwner = owner;
- return i;
+ channel = i;
+ break;
+ }
+
+ // We don't allow SFX to reallocate their own channels. Otherwise we
+ // would call stopSfx in the midst of startSfx and that can lead to
+ // horrible states...
+ // We also prevent the music from reallocating its own channels like
+ // in the original.
+ if (_hwChannels[i].priority <= minPrio && _hwChannels[i].sfxOwner != owner) {
+ minPrio = _hwChannels[i].priority;
+ channel = i;
}
}
- // Second pass: Reassign channels based on priority
- for (int i = 0; i < _numHWChannels; ++i) {
- if (_hwChannels[i].priority <= priority) {
- // In case the HW channel belongs to a SFX we will completely
- // stop playback of that SFX.
- // TODO: Maybe be more fine grained in the future and allow
- // detachment of individual channels of a SFX?
- if (_hwChannels[i].sfxOwner) {
- stopSfx(_hwChannels[i].sfxOwner);
- }
- _hwChannels[i].allocated = true;
- _hwChannels[i].priority = priority;
- _hwChannels[i].sfxOwner = owner;
- return i;
+ if (channel != -1) {
+ // In case the HW channel belongs to a SFX we will completely
+ // stop playback of that SFX.
+ // TODO: Maybe be more fine grained in the future and allow
+ // detachment of individual channels of a SFX?
+ if (_hwChannels[channel].allocated && _hwChannels[channel].sfxOwner) {
+ stopSfx(_hwChannels[channel].sfxOwner);
}
+
+ _hwChannels[channel].allocated = true;
+ _hwChannels[channel].priority = priority;
+ _hwChannels[channel].sfxOwner = owner;
}
- return -1;
+ return channel;
}
void Player_AD::freeHWChannel(int channel) {
@@ -747,23 +768,26 @@ const uint Player_AD::_rhythmChannelTable[6] = {
// SFX
Player_AD::SfxSlot *Player_AD::allocateSfxSlot(int priority) {
- // First pass: Check whether there's a unused slot
+ // We always reaLlocate the slot with the lowest priority in case none is
+ // free.
+ SfxSlot *sfx = nullptr;
+ int minPrio = priority;
+
for (int i = 0; i < ARRAYSIZE(_sfx); ++i) {
if (_sfx[i].resource == -1) {
return &_sfx[i];
+ } else if (_sfx[i].priority <= minPrio) {
+ minPrio = _sfx[i].priority;
+ sfx = &_sfx[i];
}
}
- // Second pass: Look for a slot with lower priority
- for (int i = 0; i < ARRAYSIZE(_sfx); ++i) {
- if (_sfx[i].priority <= priority) {
- // Stop the old sfx
- stopSfx(&_sfx[i]);
- return &_sfx[i];
- }
+ // In case we reallocate a slot stop the old one.
+ if (sfx) {
+ stopSfx(sfx);
}
- return nullptr;
+ return sfx;
}
bool Player_AD::startSfx(SfxSlot *sfx, const byte *resource) {
@@ -1163,7 +1187,7 @@ const uint Player_AD::_noteAdjustTable[16] = {
0, 4369, 8738, 13107,
17476, 21845, 26214, 30583,
34952, 39321, 43690, 48059,
- 52428, 46797, 61166, 65535
+ 52428, 56797, 61166, 65535
};
const bool Player_AD::_useOperatorTable[7] = {
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 0aaff4c094..7eadb042fb 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1453,7 +1453,7 @@ void ScummEngine::saveOrLoad(Serializer *s) {
// forever, then resume playing it. This helps a lot when the audio CD
// is used to provide ambient music (see bug #788195).
if (s->isLoading() && info.playing && info.numLoops < 0)
- _system->getAudioCDManager()->play(info.track, info.numLoops, info.start, info.duration);
+ _sound->playCDTrackInternal(info.track, info.numLoops, info.start, info.duration);
}
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 2c672ccc89..2fe5333bfc 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -972,6 +972,18 @@ void ScummEngine::runEntryScript() {
runScript(VAR(VAR_ENTRY_SCRIPT2), 0, 0, 0);
}
+void ScummEngine::runQuitScript() {
+ if (VAR_QUIT_SCRIPT != 0xFF && VAR(VAR_QUIT_SCRIPT)) {
+ int args[NUM_SCRIPT_LOCAL];
+
+ memset(args, 0, sizeof(args));
+ args[0] = 2;
+ args[1] = 1003;
+
+ runScript(VAR(VAR_QUIT_SCRIPT), 0, 0, args);
+ }
+}
+
void ScummEngine::killScriptsAndResources() {
ScriptSlot *ss;
int i;
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index 2cda9898af..91afa859a9 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -544,7 +544,7 @@ void ScummEngine_v5::o5_setClass() {
} else if (cls == 0) {
// Class '0' means: clean all class data
_classData[obj] = 0;
- if ((_game.features & GF_SMALL_HEADER) && obj <= _numActors) {
+ if ((_game.features & GF_SMALL_HEADER) && objIsActor(obj)) {
Actor *a = derefActor(obj, "o5_setClass");
a->_ignoreBoxes = false;
a->_forceClip = 0;
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index ae80f306af..0eeff57ff7 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
/*
- This file was generated by the md5table tool on Fri Sep 27 05:44:12 2013
+ This file was generated by the md5table tool on Wed Jun 25 10:34:07 2014
DO NOT EDIT MANUALLY!
*/
@@ -17,6 +17,7 @@ static const MD5Table md5table[] = {
{ "008e76ec3ae58d0add637ea7aa299a2c", "freddi3", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "02cae0e7ff8504f73618391873d5781a", "freddi3", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformWindows },
{ "0305e850382b812fec6e5998ef88a966", "pajama", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
+ { "0354ee0d14cde1264ec762261c04c14a", "loom", "Steam", "Steam", 585728, Common::EN_ANY, Common::kPlatformWindows },
{ "035deab53b47bc43abc763560d0f8d4b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformDOS },
{ "037385a953789190298494d92b89b3d0", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows },
@@ -194,6 +195,7 @@ static const MD5Table md5table[] = {
{ "45152f7cf2ba8f43cf8a8ea2e740ae09", "monkey", "VGA", "VGA", 8357, Common::ES_ESP, Common::kPlatformDOS },
{ "4521138d15d1fd7649c31fb981746231", "pajama2", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "4522564b3c31aaf218b6a96826a549fd", "maze", "HE 99", "", -1, Common::EN_USA, Common::kPlatformWindows },
+ { "45adb5065e77559196dc0477e0f91fb9", "freddi3", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows },
{ "46b53fd430adcfbed791b48a0d4b079f", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformDOS },
{ "470c45b636139bb40716daa1c7edaad0", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformDOS },
{ "477dbafbd66a53c98416dc01aef019ad", "monkey", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformDOS },
@@ -298,6 +300,7 @@ static const MD5Table md5table[] = {
{ "69ffe29185b8d71f09f6199f8b2a87cb", "lost", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "6a30a07f353a75cdc602db27d73e1b42", "puttputt", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "6a60d395b78b205c93a956100b1bf5ae", "pajama2", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
+ { "6a8133b63d46f6663fbcbb49d5a2edb1", "atlantis", "Steam", "Steam", 520548, Common::EN_ANY, Common::kPlatformMacintosh },
{ "6af2419fe3db5c2fdb091ae4e5833770", "puttrace", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "6b19d0e25cbf720d05822379b8b90ed9", "PuttTime", "HE 90", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "6b257bb2827dd894b8109a50a1a18b5a", "freddicove", "HE 100", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
@@ -356,6 +359,7 @@ static const MD5Table md5table[] = {
{ "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown },
{ "7f45ddd6dbfbf8f80c0c0efea4c295bc", "maniac", "V1", "V1", 1972, Common::EN_ANY, Common::kPlatformDOS },
{ "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown },
+ { "7fbcff27c323499beaedd605e1ebd47d", "indy3", "Steam", "Steam", 561152, Common::EN_ANY, Common::kPlatformWindows },
{ "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "810a9da887aefa597b0cf3c77d262897", "BluesABCTime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "822807c3cd3b43a925cab2767ca6b453", "BluesTreasureHunt", "", "Disc 1", -1, Common::EN_ANY, Common::kPlatformUnknown },
@@ -438,6 +442,7 @@ static const MD5Table md5table[] = {
{ "a095616d2d23ccf43b8e257711202cba", "football2002", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "a095e33061606d231ff37dca4c64c8ac", "pajama", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "a0a7dea72003933b8b3f8b99b9f7ddeb", "loom", "No AdLib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST },
+ { "a15d6e1e2c52bbd0ff7fa6b63ab7f796", "indy3", "Steam", "Steam", 680340, Common::EN_ANY, Common::kPlatformMacintosh },
{ "a194f15f51ee62badab74b9e7da97693", "baseball2001", "", "Demo", 20507, Common::EN_ANY, Common::kPlatformUnknown },
{ "a197a87ae77f3b3333f09a7a2c448fe2", "freddi", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "a22af0ad0e3126d19d22707b0267a37d", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows },
@@ -466,6 +471,7 @@ static const MD5Table md5table[] = {
{ "aa8a0cb65f3afbbe2c14c3f9f92775a3", "monkey", "CD", "CD", 8955, Common::FR_FRA, Common::kPlatformDOS },
{ "aaa587701cde7e74692c68c1024b85eb", "puttrace", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "aaa7f36a253f277dd29dd1c051b0e4b9", "indy3", "No AdLib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST },
+ { "aad201302286c1cfee92321cd406e427", "dig", "Steam", "Steam", 811008, Common::EN_ANY, Common::kPlatformWindows },
{ "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "ac1642b6edfb8521ca03760126f1c250", "tentacle", "", "Demo", -1, Common::DE_DEU, Common::kPlatformDOS },
{ "ac62d50e39492ee3738b4e83a5ac780f", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows },
@@ -479,6 +485,7 @@ static const MD5Table md5table[] = {
{ "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "V2", "V2", 1988, Common::EN_ANY, Common::kPlatformDOS },
{ "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformDOS },
{ "b47be81e39a9710f6f595f7b527b60f8", "puttrace", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows },
+ { "b4a677bf27c010a747975705108ff1e6", "loom", "Steam", "Steam", 393572, Common::EN_ANY, Common::kPlatformMacintosh },
{ "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", 5361, Common::EN_ANY, Common::kPlatformDOS },
{ "b628506f7def772e40de0aa5440fb8e1", "activity", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows },
@@ -568,6 +575,7 @@ static const MD5Table md5table[] = {
{ "d7b247c26bf1f01f8f7daf142be84de3", "balloon", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", 16304, Common::UNK_LANG, Common::kPlatformUnknown },
{ "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown },
+ { "d93cc8be628ed5d3b3a29188fc7105d3", "dig", "Steam", "Steam", 1061296, Common::EN_ANY, Common::kPlatformMacintosh },
{ "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformDOS },
{ "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "FM-TOWNS", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns },
{ "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", 8955, Common::IT_ITA, Common::kPlatformDOS },
@@ -628,6 +636,7 @@ static const MD5Table md5table[] = {
{ "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown },
{ "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformDOS },
{ "f2ec78e50bdc63b70044e9758be10914", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformMacintosh },
+ { "f3c5d9bf3f091bd1f18dc1013fba5396", "atlantis", "Steam", "Steam", 638976, Common::EN_ANY, Common::kPlatformWindows },
{ "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows },
{ "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 34c231e5d4..475b146a7b 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -467,6 +467,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
VAR_NUM_SCRIPT_CYCLES = 0xFF;
VAR_SCRIPT_CYCLE = 0xFF;
+ VAR_QUIT_SCRIPT = 0xFF;
+
VAR_NUM_GLOBAL_OBJS = 0xFF;
// Use g_scumm from error() ONLY
@@ -1026,6 +1028,35 @@ Common::Error ScummEngine::init() {
}
#endif
+ // Extra directories needed for the Steam versions
+ if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) {
+ if (_game.platform == Common::kPlatformWindows) {
+ switch (_game.id) {
+ case GID_INDY3 :
+ SearchMan.addSubDirectoryMatching(gameDataDir, "indy3");
+ break;
+ case GID_INDY4 :
+ SearchMan.addSubDirectoryMatching(gameDataDir, "atlantis");
+ break;
+ case GID_LOOM :
+ SearchMan.addSubDirectoryMatching(gameDataDir, "loom");
+ break;
+#ifdef ENABLE_SCUMM_7_8
+ case GID_DIG :
+ SearchMan.addSubDirectoryMatching(gameDataDir, "dig");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "dig/video");
+ break;
+#endif
+ default:
+ break;
+ }
+ } else {
+ SearchMan.addSubDirectoryMatching(gameDataDir, "Contents");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/MacOS");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/Resources");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/Resources/video");
+ }
+ }
// The kGenUnchanged method is only used for 'container files', i.e. files
// that contain the real game files bundled together in an archive format.
@@ -1126,15 +1157,30 @@ Common::Error ScummEngine::init() {
error("Couldn't find known subfile inside container file '%s'", _containerFile.c_str());
_fileHandle->close();
-
} else {
error("kGenUnchanged used with unsupported platform");
}
} else {
- // Regular access, no container file involved
- _fileHandle = new ScummFile();
+ if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) {
+ // Steam game versions have the index file embedded in the main executable
+ const SteamIndexFile *indexFile = lookUpSteamIndexFile(_filenamePattern.pattern, _game.platform);
+ if (!indexFile || indexFile->id != _game.id) {
+ error("Couldn't find index file description for Steam version");
+ } else {
+ _fileHandle = new ScummSteamFile(*indexFile);
+ }
+ } else {
+ // Regular access, no container file involved
+ _fileHandle = new ScummFile();
+ }
}
+ // Steam Win and Mac versions share the same DOS data files. We show Windows or Mac
+ // for the platform the detector, but internally we force the platform to DOS, so that
+ // the code for handling the original DOS data files is used.
+ if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam)
+ _game.platform = Common::kPlatformDOS;
+
// Load CJK font, if present
// Load it earlier so _useCJKMode variable could be set
loadCJKFont();
@@ -1218,7 +1264,7 @@ Common::Error ScummEngine::init() {
void ScummEngine::setupScumm() {
// On some systems it's not safe to run CD audio games from the CD.
- if (_game.features & GF_AUDIOTRACKS) {
+ if (_game.features & GF_AUDIOTRACKS && !Common::File::exists("CDDA.SOU")) {
checkCD();
int cd_num = ConfMan.getInt("cdrom");
@@ -2029,6 +2075,7 @@ Common::Error ScummEngine::go() {
if (shouldQuit()) {
// TODO: Maybe perform an autosave on exit?
+ runQuitScript();
}
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index be5a83d8c9..af118a89a1 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -256,6 +256,7 @@ enum ScummGameId {
GID_BASEBALL2003,
GID_BASKETBALL,
GID_MOONBASE,
+ GID_PJGAMES,
GID_HECUP // CUP demos
};
@@ -670,6 +671,7 @@ protected:
virtual void checkAndRunSentenceScript();
void runExitScript();
void runEntryScript();
+ void runQuitScript();
void runAllScripts();
void freezeScripts(int scr);
void unfreezeScripts();
@@ -1360,6 +1362,8 @@ public:
byte VAR_SCRIPT_CYCLE; // Used in runScript()/runObjectScript()
byte VAR_NUM_SCRIPT_CYCLES; // Used in runAllScripts()
+
+ byte VAR_QUIT_SCRIPT; // Used in confirmExitDialog()
// Exists both in V7 and in V72HE:
byte VAR_NUM_GLOBAL_OBJS;
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index 4c04901b42..e2f75a6862 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -115,9 +115,7 @@ int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
int w = _vm->_2byteWidth;
int h = _vm->_2byteHeight;
-
- byte *src = _vm->get2byteCharPtr(idx);
- byte *dst = buffer + dst_width * (y + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + x;
+ const byte *src = _vm->get2byteCharPtr(idx);
byte bits = 0;
char color = (_color != -1) ? _color : 1;
@@ -128,18 +126,60 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
if (_vm->_game.id == GID_FT)
color = 1;
- for (int j = 0; j < h; j++) {
- for (int i = 0; i < w; i++) {
- if ((i % 8) == 0)
- bits = *src++;
- if (bits & revBitMask(i % 8)) {
- dst[i + 1] = 0;
- dst[dst_width + i] = 0;
- dst[dst_width + i + 1] = 0;
- dst[i] = color;
+ enum ShadowMode {
+ kNone,
+ kNormalShadowMode,
+ kKoreanV7ShadowMode,
+ kKoreanV8ShadowMode
+ };
+
+ ShadowMode shadowMode = kNone;
+
+ if (_vm->_language == Common::KO_KOR) {
+ if (_vm->_game.version == 8)
+ shadowMode = kKoreanV8ShadowMode;
+ else
+ shadowMode = kKoreanV7ShadowMode;
+ }
+
+ int shadowOffsetXTable[4] = {-1, 0, 1, 0};
+ int shadowOffsetYTable[4] = {0, 1, 0, 0};
+ int shadowOffsetColorTable[4] = {0, 0, 0, color};
+
+ int shadowIdx = 3;
+ if (shadowMode == kKoreanV8ShadowMode)
+ shadowIdx = 0;
+ else if (shadowMode == kKoreanV7ShadowMode)
+ shadowIdx = 2;
+
+ const byte *origSrc = src;
+
+ for (; shadowIdx < 4; shadowIdx++) {
+ int offX = x + shadowOffsetXTable[shadowIdx];
+ int offY = y + shadowOffsetYTable[shadowIdx];
+ byte drawColor = shadowOffsetColorTable[shadowIdx];
+
+ src = origSrc;
+
+ byte *dst = buffer + dst_width * (offY + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + offX;
+
+ for (int j = 0; j < h; j++) {
+ for (int i = 0; i < w; i++) {
+ if (offX + i < 0)
+ continue;
+ if ((i % 8) == 0)
+ bits = *src++;
+ if (bits & revBitMask(i % 8)) {
+ if (shadowMode == kNormalShadowMode) {
+ dst[i + 1] = 0;
+ dst[dst_width + i] = 0;
+ dst[dst_width + i + 1] = 0;
+ }
+ dst[i] = drawColor;
+ }
}
+ dst += dst_width;
}
- dst += dst_width;
}
return w + 1;
}
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 01bdefc7c0..cb428d1c15 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -27,6 +27,7 @@
#include "common/substream.h"
#include "scumm/actor.h"
+#include "scumm/cdda.h"
#include "scumm/file.h"
#include "scumm/imuse/imuse.h"
#include "scumm/imuse_digi/dimuse.h"
@@ -36,8 +37,6 @@
#include "scumm/sound.h"
#include "scumm/util.h"
-#include "backends/audiocd/audiocd.h"
-
#include "audio/decoders/adpcm.h"
#include "audio/decoders/flac.h"
#include "audio/mididrv.h"
@@ -89,11 +88,21 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer)
memset(_mouthSyncTimes, 0, sizeof(_mouthSyncTimes));
_musicType = MDT_NONE;
+
+ _loomSteamCD.playing = false;
+ _loomSteamCD.track = 0;
+ _loomSteamCD.start = 0;
+ _loomSteamCD.duration = 0;
+ _loomSteamCD.numLoops = 0;
+ _loomSteamCD.volume = Audio::Mixer::kMaxChannelVolume;
+ _loomSteamCD.balance = 0;
+
+ _isLoomSteam = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU");
}
Sound::~Sound() {
stopCDTimer();
- g_system->getAudioCDManager()->stop();
+ stopCD();
free(_offsetTable);
}
@@ -649,7 +658,11 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle
_vm->_imuseDigital->startVoice(kTalkSoundID, input);
#endif
} else {
- _mixer->playStream(Audio::Mixer::kSpeechSoundType, handle, input, id);
+ if (mode == 1) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, handle, input, id);
+ } else {
+ _mixer->playStream(Audio::Mixer::kSpeechSoundType, handle, input, id);
+ }
}
}
}
@@ -838,9 +851,6 @@ void Sound::soundKludge(int *list, int num) {
}
void Sound::talkSound(uint32 a, uint32 b, int mode, int channel) {
- if (_vm->_game.version >= 5 && ConfMan.getBool("speech_mute"))
- return;
-
if (mode == 1) {
_talk_sound_a1 = a;
_talk_sound_b1 = b;
@@ -1033,7 +1043,7 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
// Play it
if (!_soundsPaused)
- g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration);
+ playCDTrackInternal(track, numLoops, startFrame, duration);
// Start the timer after starting the track. Starting an MP3 track is
// almost instantaneous, but a CD player may take some time. Hopefully
@@ -1041,16 +1051,59 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
startCDTimer();
}
+void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int duration) {
+ _loomSteamCD.track = track;
+ _loomSteamCD.numLoops = numLoops;
+ _loomSteamCD.start = startFrame;
+ _loomSteamCD.duration = duration;
+
+ if (!_isLoomSteam) {
+ g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration);
+ } else {
+ // Stop any currently playing track
+ _mixer->stopHandle(_loomSteamCDAudioHandle);
+
+ Common::File *cddaFile = new Common::File();
+ if (cddaFile->open("CDDA.SOU")) {
+ Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
+ Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
+ Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES);
+
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_loomSteamCDAudioHandle,
+ Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
+ } else {
+ delete cddaFile;
+ }
+ }
+}
+
void Sound::stopCD() {
- g_system->getAudioCDManager()->stop();
+ if (!_isLoomSteam)
+ g_system->getAudioCDManager()->stop();
+ else
+ _mixer->stopHandle(_loomSteamCDAudioHandle);
}
int Sound::pollCD() const {
- return g_system->getAudioCDManager()->isPlaying();
+ if (!_isLoomSteam)
+ return g_system->getAudioCDManager()->isPlaying();
+ else
+ return _mixer->isSoundHandleActive(_loomSteamCDAudioHandle);
}
void Sound::updateCD() {
- g_system->getAudioCDManager()->updateCD();
+ if (!_isLoomSteam)
+ g_system->getAudioCDManager()->updateCD();
+}
+
+AudioCDManager::Status Sound::getCDStatus() {
+ if (!_isLoomSteam)
+ return g_system->getAudioCDManager()->getStatus();
+ else {
+ AudioCDManager::Status info = _loomSteamCD;
+ info.playing = _mixer->isSoundHandleActive(_loomSteamCDAudioHandle);
+ return info;
+ }
}
void Sound::saveLoadWithSerializer(Serializer *ser) {
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index a96d2b8ed5..a479ad5731 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -27,6 +27,7 @@
#include "audio/audiostream.h"
#include "audio/mididrv.h"
#include "audio/mixer.h"
+#include "backends/audiocd/audiocd.h"
#include "scumm/saveload.h"
namespace Audio {
@@ -86,6 +87,10 @@ protected:
int16 _currentCDSound;
int16 _currentMusic;
+ Audio::SoundHandle _loomSteamCDAudioHandle;
+ bool _isLoomSteam;
+ AudioCDManager::Status _loomSteamCD;
+
public:
Audio::SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on
@@ -119,9 +124,11 @@ public:
void stopCDTimer();
void playCDTrack(int track, int numLoops, int startFrame, int duration);
+ void playCDTrackInternal(int track, int numLoops, int startFrame, int duration);
void stopCD();
int pollCD() const;
void updateCD();
+ AudioCDManager::Status getCDStatus();
int getCurrentCDSound() const { return _currentCDSound; }
// Used by the save/load system:
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index 79d7ed03da..a903ac5804 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -320,6 +320,7 @@ void ScummEngine_v90he::setupScummVars() {
ScummEngine_v80he::setupScummVars();
VAR_TIMER = 97;
+ VAR_QUIT_SCRIPT = 102;
VAR_SCRIPT_CYCLE = 103;
VAR_NUM_SCRIPT_CYCLES = 104;
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 0257a805ff..ac358e774b 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -542,7 +542,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
Video::VideoDecoder *dxaDecoder = new Video::DXADecoder();
return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA);
#else
- GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK"));
+ GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib"), _("OK"));
dialog.runModal();
return 0;
#endif
@@ -558,7 +558,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
Video::VideoDecoder *aviDecoder = new Video::AVIDecoder(12);
return new MoviePlayer(vm, textMan, resMan, system, aviDecoder, kVideoDecoderMP2);
#else
- GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"), _("OK"));
+ GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"), _("OK"));
dialog.runModal();
return 0;
#endif
diff --git a/engines/sword1/console.cpp b/engines/sword1/console.cpp
index 3eb3b93a19..7fabc62192 100644
--- a/engines/sword1/console.cpp
+++ b/engines/sword1/console.cpp
@@ -22,14 +22,37 @@
#include "sword1/console.h"
#include "sword1/sword1.h"
+#include "sword1/sound.h"
+#include "common/config-manager.h"
+#include "common/str.h"
namespace Sword1 {
SwordConsole::SwordConsole(SwordEngine *vm) : GUI::Debugger(), _vm(vm) {
assert(_vm);
+ if (scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1mac") == 0 || scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1macdemo") == 0)
+ registerCmd("speechEndianness", WRAP_METHOD(SwordConsole, Cmd_SpeechEndianness));
}
SwordConsole::~SwordConsole() {
}
+
+bool SwordConsole::Cmd_SpeechEndianness(int argc, const char **argv) {
+ if (argc == 1) {
+ debugPrintf("Using %s speech\n", _vm->_sound->_bigEndianSpeech ? "be" : "le");
+ return true;
+ }
+ if (argc == 2) {
+ if (scumm_stricmp(argv[1], "le") == 0) {
+ _vm->_sound->_bigEndianSpeech = false;
+ return false;
+ } else if (scumm_stricmp(argv[1], "be") == 0) {
+ _vm->_sound->_bigEndianSpeech = true;
+ return false;
+ }
+ }
+ debugPrintf("Usage: %s [le | be]\n", argv[0]);
+ return true;
+}
} // End of namespace Sword
diff --git a/engines/sword1/console.h b/engines/sword1/console.h
index a2bb51f9a4..88ee756151 100644
--- a/engines/sword1/console.h
+++ b/engines/sword1/console.h
@@ -36,6 +36,7 @@ public:
private:
SwordEngine *_vm;
+ bool Cmd_SpeechEndianness(int argc, const char **argv);
};
} // End of namespace Sword1
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
index 0b4d3829d6..a6e6d3917e 100644
--- a/engines/sword1/sound.cpp
+++ b/engines/sword1/sound.cpp
@@ -116,7 +116,7 @@ void Sound::checkSpeechFileEndianness() {
return;
// I picked the sample to use randomly (I just made sure it is long enough so that there is
- // a fair change of the heuristic to have a stable result and work for every language).
+ // a fair chance of the heuristic to have a stable result and work for every language).
int roomNo = _currentCowFile == 1 ? 1 : 129;
int localNo = _currentCowFile == 1 ? 2 : 933;
// Get the speech data and apply the heuristic
@@ -125,31 +125,46 @@ void Sound::checkSpeechFileEndianness() {
uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
if (sampleSize) {
uint32 size;
- double be_diff_sum = 0., le_diff_sum = 0.;
+ // Compute average of difference between two consecutive samples for both BE and LE
+ // The way uncompressSpeech works we may get un incorrect number of identical consecutive samples
+ // when using the wrong endianess. To avoid biasing the result we this we skip all duplicate values.
_bigEndianSpeech = false;
int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
- // Compute average of difference between two consecutive samples for both BE and LE
if (data) {
- if (size > 4000)
- size = 2000;
- else
- size /= 2;
- int16 prev_be_value = (int16)SWAP_BYTES_16(*((uint16 *)(data)));
- for (uint32 i = 1; i < size; ++i) {
- le_diff_sum += fabs((double)(data[i] - data[i - 1]));
- int16 be_value = (int16)SWAP_BYTES_16(*((uint16 *)(data + i)));
- be_diff_sum += fabs((double)(be_value - prev_be_value));
- prev_be_value = be_value;
+ uint32 max_cpt = size > 2000 ? 2000 : size;
+ double le_diff_sum = 0.;
+ uint32 le_cpt = 0;
+ for (uint32 i = 1; i < size && le_cpt < max_cpt; ++i) {
+ if (data[i] != data[i-1]) {
+ le_diff_sum += fabs((double)(data[i] - data[i - 1]));
+ ++le_cpt;
+ }
}
+ le_diff_sum /= le_cpt;
delete[] data;
+ _bigEndianSpeech = true;
+ data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
+ if (data) {
+ double be_diff_sum = 0.;
+ uint32 be_cpt = 0;
+ for (uint32 i = 1; i < size && be_cpt < le_cpt; ++i) {
+ if (data[i] != data[i-1]) {
+ be_diff_sum += fabs((double)(data[i] - data[i - 1]));
+ ++be_cpt;
+ }
+ }
+ be_diff_sum /= be_cpt;
+ delete [] data;
+ // Set the big endian flag
+ _bigEndianSpeech = (be_diff_sum < le_diff_sum);
+ if (_bigEndianSpeech)
+ debug(6, "Mac version: using big endian speech file");
+ else
+ debug(6, "Mac version: using little endian speech file");
+ debug(8, "Speech endianness heuristic: average = %f for BE (%d samples) and %f for LE (%d samples)", be_diff_sum, be_cpt, le_diff_sum, le_cpt);
+ } else
+ _bigEndianSpeech = false;
}
- // Set the big endian flag
- _bigEndianSpeech = (be_diff_sum < le_diff_sum);
- if (_bigEndianSpeech)
- debug(6, "Mac version: using big endian speech file");
- else
- debug(6, "Mac version: using little endian speech file");
- debug(8, "Speech endianness heuristic: average = %f for BE and %f for LE, computed on %d samples)", be_diff_sum / (size - 1), le_diff_sum / (size - 1), size);
}
}
diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h
index 666598dba0..54006bd8b4 100644
--- a/engines/sword1/sound.h
+++ b/engines/sword1/sound.h
@@ -79,6 +79,7 @@ enum CowMode {
};
class Sound {
+ friend class SwordConsole;
public:
Sound(Audio::Mixer *mixer, ResMan *pResMan);
~Sound();
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index c58e97e353..eb24ef70fa 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -79,6 +79,7 @@ struct SystemVars {
};
class SwordEngine : public Engine {
+ friend class SwordConsole;
public:
SwordEngine(OSystem *syst);
virtual ~SwordEngine();
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 92fa9d0e44..e93f27f76c 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -442,7 +442,7 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system
Video::DXADecoder *dxaDecoder = new Video::DXADecoder();
return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA);
#else
- GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK"));
+ GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib"), _("OK"));
dialog.runModal();
return NULL;
#endif
diff --git a/engines/sword25/gfx/animation.cpp b/engines/sword25/gfx/animation.cpp
index eeb78857ea..e2662fb2b3 100644
--- a/engines/sword25/gfx/animation.cpp
+++ b/engines/sword25/gfx/animation.cpp
@@ -189,14 +189,14 @@ bool Animation::doRender(RectangleList *updateRects) {
bool result;
if (isScalingAllowed() && (_width != pBitmapResource->getWidth() || _height != pBitmapResource->getHeight())) {
result = pBitmapResource->blit(_absoluteX, _absoluteY,
- (animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) |
- (animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0),
+ (animationDescriptionPtr->getFrame(_currentFrame).flipV ? Graphics::FLIP_V : 0) |
+ (animationDescriptionPtr->getFrame(_currentFrame).flipH ? Graphics::FLIP_H : 0),
0, _modulationColor, _width, _height,
updateRects);
} else {
result = pBitmapResource->blit(_absoluteX, _absoluteY,
- (animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) |
- (animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0),
+ (animationDescriptionPtr->getFrame(_currentFrame).flipV ? Graphics::FLIP_V : 0) |
+ (animationDescriptionPtr->getFrame(_currentFrame).flipH ? Graphics::FLIP_H : 0),
0, _modulationColor, -1, -1,
updateRects);
}
diff --git a/engines/sword25/gfx/bitmapresource.h b/engines/sword25/gfx/bitmapresource.h
index 7a4daedd84..2ae891f5cd 100644
--- a/engines/sword25/gfx/bitmapresource.h
+++ b/engines/sword25/gfx/bitmapresource.h
@@ -40,22 +40,6 @@ namespace Sword25 {
class BitmapResource : public Resource {
public:
- /**
- @brief Die möglichen Flippingparameter für die Blit-Methode.
- */
- enum FLIP_FLAGS {
- /// Das Bild wird nicht gespiegelt.
- FLIP_NONE = 0,
- /// Das Bild wird an der horizontalen Achse gespiegelt.
- FLIP_H = 1,
- /// Das Bild wird an der vertikalen Achse gespiegelt.
- FLIP_V = 2,
- /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt.
- FLIP_HV = FLIP_H | FLIP_V,
- /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt.
- FLIP_VH = FLIP_H | FLIP_V
- };
-
BitmapResource(const Common::String &filename, Image *pImage) :
_pImage(pImage), Resource(filename, Resource::TYPE_BITMAP) {}
virtual ~BitmapResource() { delete _pImage; }
@@ -120,7 +104,7 @@ public:
- IsColorModulationAllowed()
*/
bool blit(int posX = 0, int posY = 0,
- int flipping = FLIP_NONE,
+ int flipping = Graphics::FLIP_NONE,
Common::Rect *pSrcPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
diff --git a/engines/sword25/gfx/dynamicbitmap.cpp b/engines/sword25/gfx/dynamicbitmap.cpp
index ce9c056d08..a335f87fa5 100644
--- a/engines/sword25/gfx/dynamicbitmap.cpp
+++ b/engines/sword25/gfx/dynamicbitmap.cpp
@@ -86,8 +86,8 @@ bool DynamicBitmap::doRender(RectangleList *updateRects) {
// a bit slow when drawing videos, but it's not the main
// bottleneck.
result = _image->blit(_absoluteX, _absoluteY,
- (_flipV ? BitmapResource::FLIP_V : 0) |
- (_flipH ? BitmapResource::FLIP_H : 0),
+ (_flipV ? Graphics::FLIP_V : 0) |
+ (_flipH ? Graphics::FLIP_H : 0),
0, _modulationColor, -1, -1,
updateRects);
#else
@@ -105,8 +105,8 @@ bool DynamicBitmap::doRender(RectangleList *updateRects) {
return true;
} else {
result = _image->blit(_absoluteX, _absoluteY,
- (_flipV ? BitmapResource::FLIP_V : 0) |
- (_flipH ? BitmapResource::FLIP_H : 0),
+ (_flipV ? Graphics::FLIP_V : 0) |
+ (_flipH ? Graphics::FLIP_H : 0),
0, _modulationColor, _width, _height,
updateRects);
}
diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
index 2a870c021d..f887c3cd51 100644
--- a/engines/sword25/gfx/graphicengine.cpp
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -183,7 +183,7 @@ bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) {
if (rect.width() > 0 && rect.height() > 0) {
if (ca == 0xff) {
- _backSurface.fillRect(rect, color);
+ _backSurface.fillRect(rect, BS_ARGB(cr, cg, cb, ca));
} else {
byte *outo = (byte *)_backSurface.getBasePtr(rect.left, rect.top);
byte *out;
@@ -192,23 +192,23 @@ bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) {
out = outo;
for (int j = rect.left; j < rect.right; j++) {
#if defined(SCUMM_LITTLE_ENDIAN)
+ *out = 255;
+ out++;
*out += (byte)(((cb - *out) * ca) >> 8);
out++;
*out += (byte)(((cg - *out) * ca) >> 8);
out++;
*out += (byte)(((cr - *out) * ca) >> 8);
out++;
- *out = 255;
- out++;
#else
- *out = 255;
- out++;
*out += (byte)(((cr - *out) * ca) >> 8);
out++;
*out += (byte)(((cg - *out) * ca) >> 8);
out++;
*out += (byte)(((cb - *out) * ca) >> 8);
out++;
+ *out = 255;
+ out++;
#endif
}
diff --git a/engines/sword25/gfx/image/image.h b/engines/sword25/gfx/image/image.h
index 8fbf802501..f8cb0dfec0 100644
--- a/engines/sword25/gfx/image/image.h
+++ b/engines/sword25/gfx/image/image.h
@@ -43,6 +43,7 @@
#include "sword25/kernel/common.h"
#include "common/rect.h"
#include "sword25/gfx/graphicengine.h"
+#include "graphics/transparent_surface.h"
namespace Sword25 {
@@ -52,23 +53,6 @@ class Image {
public:
virtual ~Image() {}
- // Enums
- /**
- @brief The possible flipping parameters for the blit methode.
- */
- enum FLIP_FLAGS {
- /// The image will not be flipped.
- FLIP_NONE = 0,
- /// The image will be flipped at the horizontal axis.
- FLIP_H = 1,
- /// The image will be flipped at the vertical axis.
- FLIP_V = 2,
- /// The image will be flipped at the horizontal and vertical axis.
- FLIP_HV = FLIP_H | FLIP_V,
- /// The image will be flipped at the horizontal and vertical axis.
- FLIP_VH = FLIP_H | FLIP_V
- };
-
//@{
/** @name Accessor methods */
@@ -100,7 +84,7 @@ public:
@param PosY the position on the Y-axis in the target image in pixels where the image is supposed to be rendered.<br>
The default value is 0.
@param Flipping how the the image should be flipped.<br>
- The default value is BS_Image::FLIP_NONE (no flipping)
+ The default value is Graphics::FLIP_NONE (no flipping)
@param pSrcPartRect Pointer on Common::Rect which specifies the section to be rendered. If the whole image has to be rendered the Pointer is NULL.<br>
This referes to the unflipped and unscaled image.<br>
The default value is NULL.
@@ -128,7 +112,7 @@ public:
- IsSetContentAllowed()
*/
virtual bool blit(int posX = 0, int posY = 0,
- int flipping = FLIP_NONE,
+ int flipping = Graphics::FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
diff --git a/engines/sword25/gfx/image/imgloader.cpp b/engines/sword25/gfx/image/imgloader.cpp
index b4b3030de8..f299cee9d1 100644
--- a/engines/sword25/gfx/image/imgloader.cpp
+++ b/engines/sword25/gfx/image/imgloader.cpp
@@ -45,7 +45,7 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&un
error("Error while reading PNG image");
const Graphics::Surface *sourceSurface = png.getSurface();
- Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), png.getPalette());
+ Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette());
width = pngSurface->w;
height = pngSurface->h;
@@ -70,7 +70,7 @@ bool ImgLoader::decodeThumbnailImage(const byte *pFileData, uint fileSize, byte
uint32 totalSize = pitch * height;
pUncompressedData = new byte[totalSize];
uint32 *dst = (uint32 *)pUncompressedData; // treat as uint32, for pixelformat output
- const Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
+ const Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
byte r, g, b;
for (uint32 i = 0; i < totalSize / 4; i++) {
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index 107b4cd402..8c6369a790 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -100,9 +100,6 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz
}
RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
- _data(0),
- _width(0),
- _height(0),
_isTransparent(true) {
result = false;
@@ -130,10 +127,18 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
// Uncompress the image
int pitch;
+ byte *dst;
+ int w, h;
if (isPNG)
- result = ImgLoader::decodePNGImage(pFileData, fileSize, _data, _width, _height, pitch);
+ result = ImgLoader::decodePNGImage(pFileData, fileSize, dst, w, h, pitch);
else
- result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, _data, _width, _height, pitch);
+ result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, dst, w, h, pitch);
+
+ _surface.w = w;
+ _surface.h = h;
+ _surface.pitch = w * 4;
+ _surface.setPixels(dst);
+ _surface.format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
if (!result) {
error("Could not decode image.");
@@ -157,12 +162,9 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
// -----------------------------------------------------------------------------
RenderedImage::RenderedImage(uint width, uint height, bool &result) :
- _width(width),
- _height(height),
_isTransparent(true) {
- _data = new byte[width * height * 4];
- Common::fill(_data, &_data[width * height * 4], 0);
+ _surface.create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
@@ -172,9 +174,11 @@ RenderedImage::RenderedImage(uint width, uint height, bool &result) :
return;
}
-RenderedImage::RenderedImage() : _width(0), _height(0), _data(0), _isTransparent(true) {
+RenderedImage::RenderedImage() : _isTransparent(true) {
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
+ _surface.format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+
_doCleanup = false;
return;
@@ -183,8 +187,6 @@ RenderedImage::RenderedImage() : _width(0), _height(0), _data(0), _isTransparent
// -----------------------------------------------------------------------------
RenderedImage::~RenderedImage() {
- if (_doCleanup)
- delete[] _data;
}
// -----------------------------------------------------------------------------
@@ -198,17 +200,17 @@ bool RenderedImage::fill(const Common::Rect *pFillRect, uint color) {
bool RenderedImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
// Check if PixelData contains enough pixel to create an image with image size equals width * height
- if (size < static_cast<uint>(_width * _height * 4)) {
- error("PixelData vector is too small to define a 32 bit %dx%d image.", _width, _height);
+ if (size < static_cast<uint>(_surface.w * _surface.h * 4)) {
+ error("PixelData vector is too small to define a 32 bit %dx%d image.", _surface.w, _surface.h);
return false;
}
const byte *in = &pixeldata[offset];
- byte *out = _data;
+ byte *out = (byte *)_surface.getPixels();
- for (int i = 0; i < _height; i++) {
- memcpy(out, in, _width * 4);
- out += _width * 4;
+ for (int i = 0; i < _surface.h; i++) {
+ memcpy(out, in, _surface.w * 4);
+ out += _surface.w * 4;
in += stride;
}
@@ -216,9 +218,10 @@ bool RenderedImage::setContent(const byte *pixeldata, uint size, uint offset, ui
}
void RenderedImage::replaceContent(byte *pixeldata, int width, int height) {
- _width = width;
- _height = height;
- _data = pixeldata;
+ _surface.w = width;
+ _surface.h = height;
+ _surface.pitch = width * 4;
+ _surface.setPixels(pixeldata);
}
// -----------------------------------------------------------------------------
@@ -230,251 +233,26 @@ uint RenderedImage::getPixel(int x, int y) {
// -----------------------------------------------------------------------------
bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, RectangleList *updateRects) {
- int ca = (color >> 24) & 0xff;
-
- // Check if we need to draw anything at all
- if (ca == 0)
- return true;
-
- int cr = (color >> 16) & 0xff;
- int cg = (color >> 8) & 0xff;
- int cb = (color >> 0) & 0xff;
-
- // Create an encapsulating surface for the data
- Graphics::Surface srcImage;
- // TODO: Is the data really in the screen format?
- srcImage.init(_width, _height, _width * 4, _data, g_system->getScreenFormat());
-
- if (pPartRect) {
- srcImage.setPixels(&_data[pPartRect->top * srcImage.pitch + pPartRect->left * 4]);
- srcImage.w = pPartRect->right - pPartRect->left;
- srcImage.h = pPartRect->bottom - pPartRect->top;
-
- debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
- pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
- } else {
-
- debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
- srcImage.w, srcImage.h, color, width, height);
- }
-
- if (width == -1)
- width = srcImage.w;
- if (height == -1)
- height = srcImage.h;
-
-#ifdef SCALING_TESTING
- // Hardcode scaling to 66% to test scaling
- width = width * 2 / 3;
- height = height * 2 / 3;
-#endif
-
- Graphics::Surface *img;
- Graphics::Surface *imgScaled = NULL;
- byte *savedPixels = NULL;
- if ((width != srcImage.w) || (height != srcImage.h)) {
- // Scale the image
- img = imgScaled = scale(srcImage, width, height);
- savedPixels = (byte *)img->getPixels();
- } else {
- img = &srcImage;
- }
-
- for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) {
- const Common::Rect &clipRect = *it;
-
- int skipLeft = 0, skipTop = 0;
- int drawX = posX, drawY = posY;
- int drawWidth = img->w;
- int drawHeight = img->h;
-
- // Handle clipping
- if (drawX < clipRect.left) {
- skipLeft = clipRect.left - drawX;
- drawWidth -= skipLeft;
- drawX = clipRect.left;
- }
-
- if (drawY < clipRect.top) {
- skipTop = clipRect.top - drawY;
- drawHeight -= skipTop;
- drawY = clipRect.top;
- }
-
- if (drawX + drawWidth >= clipRect.right)
- drawWidth = clipRect.right - drawX;
-
- if (drawY + drawHeight >= clipRect.bottom)
- drawHeight = clipRect.bottom - drawY;
-
- if ((drawWidth > 0) && (drawHeight > 0)) {
- int xp = 0, yp = 0;
-
- int inStep = 4;
- int inoStep = img->pitch;
- if (flipping & Image::FLIP_V) {
- inStep = -inStep;
- xp = img->w - 1 - skipLeft;
- } else {
- xp = skipLeft;
- }
-
- if (flipping & Image::FLIP_H) {
- inoStep = -inoStep;
- yp = img->h - 1 - skipTop;
- } else {
- yp = skipTop;
- }
-
- byte *ino = (byte *)img->getBasePtr(xp, yp);
- byte *outo = (byte *)_backSurface->getBasePtr(drawX, drawY);
-
-#if defined(SCUMM_LITTLE_ENDIAN)
- // Simple memcpy if the source bitmap doesn't have transparent pixels and the drawing transparency is 255
- // NOTE Only possible with LE-machines at the moment, maybe it would be feasible to convert the bitmap pixels at loading time?
- if (!_isTransparent && ca == 255) {
- for (int i = 0; i < drawHeight; i++) {
- memcpy(outo, ino, drawWidth * 4);
- outo += _backSurface->pitch;
- ino += inoStep;
- }
- } else
-#endif
- {
- byte *in, *out;
- for (int i = 0; i < drawHeight; i++) {
- out = outo;
- in = ino;
- for (int j = 0; j < drawWidth; j++) {
- uint32 pix = *(uint32 *)in;
- int a = (pix >> 24) & 0xff;
- in += inStep;
-
- if (ca != 255) {
- a = a * ca >> 8;
- }
-
- if (a == 0) {
- // Full transparency
- out += 4;
- continue;
- }
-
- int b = (pix >> 0) & 0xff;
- int g = (pix >> 8) & 0xff;
- int r = (pix >> 16) & 0xff;
-
- if (a == 255) {
-#if defined(SCUMM_LITTLE_ENDIAN)
- if (cb != 255)
- b = (b * cb) >> 8;
- if (cg != 255)
- g = (g * cg) >> 8;
- if (cr != 255)
- r = (r * cr) >> 8;
- *(uint32 *)out = (255 << 24) | (r << 16) | (g << 8) | b;
- out += 4;
-#else
- *out++ = a;
- if (cr != 255)
- *out++ = (r * cr) >> 8;
- else
- *out++ = r;
- if (cg != 255)
- *out++ = (g * cg) >> 8;
- else
- *out++ = g;
- if (cb != 255)
- *out++ = (b * cb) >> 8;
- else
- *out++ = b;
-#endif
- } else {
-#if defined(SCUMM_LITTLE_ENDIAN)
- pix = *(uint32 *)out;
- int outb = ((pix >> 0) & 0xff) * (255 - a);
- int outg = ((pix >> 8) & 0xff) * (255 - a);
- int outr = ((pix >> 16) & 0xff) * (255 - a);
- if (cb == 0)
- outb = outb >> 8;
- else if (cb != 255)
- outb = ((outb << 8) + b * a * cb) >> 16;
- else
- outb = (outb + b * a) >> 8;
- if (cg == 0)
- outg = outg >> 8;
- else if (cg != 255)
- outg = ((outg << 8) + g * a * cg) >> 16;
- else
- outg = (outg + g * a) >> 8;
- if (cr == 0)
- outr = outr >> 8;
- else if (cr != 255)
- outr = ((outr << 8) + r * a * cr) >> 16;
- else
- outr = (outr + r * a) >> 8;
- *(uint32 *)out = (255 << 24) | (outr << 16) | (outg << 8) | outb;
- out += 4;
-#else
- *out = 255;
- out++;
- if (cr == 0)
- *out = (*out * (255-a)) >> 8;
- else if (cr != 255)
- *out = (((*out * (255-a)) << 8) + r * a * cr) >> 16;
- else
- *out = ((*out * (255-a)) + r * a) >> 8;
- out++;
- if (cg == 0)
- *out = (*out * (255-a)) >> 8;
- else if (cg != 255)
- *out = (((*out * (255-a)) << 8) + g * a * cg) >> 16;
- else
- *out = ((*out * (255-a)) + g * a) >> 8;
- out++;
- if (cb == 0)
- *out = (*out * (255-a)) >> 8;
- else if (cb != 255)
- *out = (((*out * (255-a)) << 8) + b * a * cb) >> 16;
- else
- *out = ((*out * (255-a)) + b * a) >> 8;
- out++;
-#endif
- }
- }
- outo += _backSurface->pitch;
- ino += inoStep;
- }
- }
-
- }
-
- }
-
- if (imgScaled) {
- imgScaled->setPixels(savedPixels);
- imgScaled->free();
- delete imgScaled;
- }
+ _surface.blit(*_backSurface, posX, posY, (((flipping & 1) ? Graphics::FLIP_V : 0) | ((flipping & 2) ? Graphics::FLIP_H : 0)), pPartRect, color, width, height);
return true;
}
void RenderedImage::copyDirectly(int posX, int posY) {
- byte *data = _data;
- int w = _width;
- int h = _height;
+ byte *data = (byte *)_surface.getPixels();
+ int w = _surface.w;
+ int h = _surface.h;
// Handle off-screen clipping
if (posY < 0) {
- h = MAX(0, (int)_height - -posY);
- data = (byte *)_data + _width * -posY;
+ h = MAX(0, (int)_surface.h - -posY);
+ data = (byte *)_surface.getPixels() + _surface.w * -posY;
posY = 0;
}
if (posX < 0) {
- w = MAX(0, (int)_width - -posX);
- data = (byte *)_data + (-posX * 4);
+ w = MAX(0, (int)_surface.h - -posX);
+ data = (byte *)_surface.getPixels() + (-posX * 4);
posX = 0;
}
@@ -487,9 +265,9 @@ void RenderedImage::copyDirectly(int posX, int posY) {
void RenderedImage::checkForTransparency() {
// Check if the source bitmap has any transparent pixels at all
_isTransparent = false;
- byte *data = _data;
- for (int i = 0; i < _height; i++) {
- for (int j = 0; j < _width; j++) {
+ byte *data = (byte *)_surface.getPixels();
+ for (int i = 0; i < _surface.h; i++) {
+ for (int j = 0; j < _surface.w; j++) {
_isTransparent = data[3] != 0xff;
if (_isTransparent)
return;
diff --git a/engines/sword25/gfx/image/renderedimage.h b/engines/sword25/gfx/image/renderedimage.h
index 3cc9725b12..5b65a27355 100644
--- a/engines/sword25/gfx/image/renderedimage.h
+++ b/engines/sword25/gfx/image/renderedimage.h
@@ -39,6 +39,7 @@
#include "sword25/kernel/common.h"
#include "sword25/gfx/image/image.h"
#include "sword25/gfx/graphicengine.h"
+#include "graphics/transparent_surface.h"
namespace Sword25 {
@@ -60,10 +61,10 @@ public:
virtual ~RenderedImage();
virtual int getWidth() const {
- return _width;
+ return _surface.w;
}
virtual int getHeight() const {
- return _height;
+ return _surface.h;
}
virtual GraphicEngine::COLOR_FORMATS getColorFormat() const {
return GraphicEngine::CF_ARGB32;
@@ -72,7 +73,7 @@ public:
void copyDirectly(int posX, int posY);
virtual bool blit(int posX = 0, int posY = 0,
- int flipping = Image::FLIP_NONE,
+ int flipping = Graphics::FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
@@ -108,9 +109,7 @@ public:
virtual bool isSolid() const { return !_isTransparent; }
private:
- byte *_data;
- int _width;
- int _height;
+ Graphics::TransparentSurface _surface;
bool _doCleanup;
bool _isTransparent;
diff --git a/engines/sword25/gfx/image/swimage.h b/engines/sword25/gfx/image/swimage.h
index b31c2318ec..60978eb6cc 100644
--- a/engines/sword25/gfx/image/swimage.h
+++ b/engines/sword25/gfx/image/swimage.h
@@ -55,7 +55,7 @@ public:
}
virtual bool blit(int posX = 0, int posY = 0,
- int flipping = Image::FLIP_NONE,
+ int flipping = Graphics::FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
diff --git a/engines/sword25/gfx/image/vectorimage.h b/engines/sword25/gfx/image/vectorimage.h
index a99d532e75..057064fc6a 100644
--- a/engines/sword25/gfx/image/vectorimage.h
+++ b/engines/sword25/gfx/image/vectorimage.h
@@ -209,7 +209,7 @@ public:
}
virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride);
virtual bool blit(int posX = 0, int posY = 0,
- int flipping = FLIP_NONE,
+ int flipping = Graphics::FLIP_NONE,
Common::Rect *pPartRect = NULL,
uint color = BS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
diff --git a/engines/sword25/gfx/image/vectorimagerenderer.cpp b/engines/sword25/gfx/image/vectorimagerenderer.cpp
index c7a79fd3c4..c69cb497c1 100644
--- a/engines/sword25/gfx/image/vectorimagerenderer.cpp
+++ b/engines/sword25/gfx/image/vectorimagerenderer.cpp
@@ -52,7 +52,7 @@ void art_rgb_fill_run1(byte *buf, byte r, byte g, byte b, int n) {
memset(buf, g, n + n + n + n);
} else {
uint32 *alt = (uint32 *)buf;
- uint32 color = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(0xff, r, g, b);
+ uint32 color = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(r, g, b, 0xff);
for (i = 0; i < n; i++)
*alt++ = color;
@@ -66,22 +66,22 @@ void art_rgb_run_alpha1(byte *buf, byte r, byte g, byte b, int alpha, int n) {
for (i = 0; i < n; i++) {
#if defined(SCUMM_LITTLE_ENDIAN)
v = *buf;
+ *buf++ = MIN(v + alpha, 0xff);
+ v = *buf;
*buf++ = v + (((b - v) * alpha + 0x80) >> 8);
v = *buf;
*buf++ = v + (((g - v) * alpha + 0x80) >> 8);
v = *buf;
*buf++ = v + (((r - v) * alpha + 0x80) >> 8);
- v = *buf;
- *buf++ = MIN(v + alpha, 0xff);
#else
v = *buf;
- *buf++ = MIN(v + alpha, 0xff);
- v = *buf;
*buf++ = v + (((r - v) * alpha + 0x80) >> 8);
v = *buf;
*buf++ = v + (((g - v) * alpha + 0x80) >> 8);
v = *buf;
*buf++ = v + (((b - v) * alpha + 0x80) >> 8);
+ v = *buf;
+ *buf++ = MIN(v + alpha, 0xff);
#endif
}
}
diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp
index 14e2012d80..1a6c812508 100644
--- a/engines/sword25/gfx/staticbitmap.cpp
+++ b/engines/sword25/gfx/staticbitmap.cpp
@@ -98,14 +98,14 @@ bool StaticBitmap::doRender(RectangleList *updateRects) {
bool result;
if (_scaleFactorX == 1.0f && _scaleFactorY == 1.0f) {
result = bitmapResourcePtr->blit(_absoluteX, _absoluteY,
- (_flipV ? BitmapResource::FLIP_V : 0) |
- (_flipH ? BitmapResource::FLIP_H : 0),
+ (_flipV ? Graphics::FLIP_V : 0) |
+ (_flipH ? Graphics::FLIP_H : 0),
0, _modulationColor, -1, -1,
updateRects);
} else {
result = bitmapResourcePtr->blit(_absoluteX, _absoluteY,
- (_flipV ? BitmapResource::FLIP_V : 0) |
- (_flipH ? BitmapResource::FLIP_H : 0),
+ (_flipV ? Graphics::FLIP_V : 0) |
+ (_flipH ? Graphics::FLIP_H : 0),
0, _modulationColor, _width, _height,
updateRects);
}
diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp
index b0a9e4ed3f..904435fcb0 100644
--- a/engines/sword25/gfx/text.cpp
+++ b/engines/sword25/gfx/text.cpp
@@ -99,7 +99,7 @@ void Text::setText(const Common::String &text) {
}
void Text::setColor(uint32 modulationColor) {
- uint32 newModulationColor = (modulationColor & 0x00ffffff) | (_modulationColor & 0xff000000);
+ uint32 newModulationColor = (modulationColor & 0xffffff00) | (_modulationColor & 0x000000ff);
if (newModulationColor != _modulationColor) {
_modulationColor = newModulationColor;
forceRefresh();
@@ -108,7 +108,7 @@ void Text::setColor(uint32 modulationColor) {
void Text::setAlpha(int alpha) {
assert(alpha >= 0 && alpha < 256);
- uint32 newModulationColor = (_modulationColor & 0x00ffffff) | alpha << 24;
+ uint32 newModulationColor = (_modulationColor & 0xffffff00) | alpha;
if (newModulationColor != _modulationColor) {
_modulationColor = newModulationColor;
forceRefresh();
@@ -173,7 +173,7 @@ bool Text::doRender(RectangleList *updateRects) {
Common::Rect renderRect(curX, curY, curX + curRect.width(), curY + curRect.height());
renderRect.translate(curRect.left - curX, curRect.top - curY);
- result = charMapPtr->blit(curX, curY, Image::FLIP_NONE, &renderRect, _modulationColor, -1, -1, updateRects);
+ result = charMapPtr->blit(curX, curY, Graphics::FLIP_NONE, &renderRect, _modulationColor, -1, -1, updateRects);
if (!result)
break;
diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp
index 259deb2ea8..bb0aab3ad4 100644
--- a/engines/sword25/sword25.cpp
+++ b/engines/sword25/sword25.cpp
@@ -97,7 +97,7 @@ Common::Error Sword25Engine::run() {
Common::Error Sword25Engine::appStart() {
// Initialize the graphics mode to ARGB8888
- Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
+ Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
initGraphics(800, 600, true, &format);
if (format != g_system->getScreenFormat())
return Common::kUnsupportedColorMode;
diff --git a/engines/testbed/sound.cpp b/engines/testbed/sound.cpp
index aebd981826..998afbf7db 100644
--- a/engines/testbed/sound.cpp
+++ b/engines/testbed/sound.cpp
@@ -235,7 +235,7 @@ TestExitStatus SoundSubsystem::sampleRates() {
Common::Point pt(0, 100);
mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, s1);
- Testsuite::writeOnScreen(Common::String::format("Playing at smaple rate: %d", s1->getRate()), pt);
+ Testsuite::writeOnScreen(Common::String::format("Playing at sample rate: %d", s1->getRate()), pt);
g_system->delayMillis(1000);
mixer->stopHandle(handle);
g_system->delayMillis(1000);
diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp
index b6c7ad3d2b..e8f08bcc61 100644
--- a/engines/toltecs/detection.cpp
+++ b/engines/toltecs/detection.cpp
@@ -86,6 +86,20 @@ static const ToltecsGameDescription gameDescriptions[] = {
},
{
+ // 3 Skulls of the Toltecs PIRATE CD-RIP version (no audio)
+ // == DO NOT RE-ADD ==
+ {
+ "toltecs",
+ 0,
+ AD_ENTRY1s("WESTERN", "56d0da91ec3db8ac869594357584e851", 104804435),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_PIRATED,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ {
// 3 Skulls of the Toltecs Russian version
{
"toltecs",
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 14e7d104d2..2f5051c157 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -2037,23 +2037,19 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
}
}
- int32 myId = 0;
char *myLine;
- if (dialogid < 1000) {
+ if (dialogid < 1000)
myLine = _roomTexts->getText(dialogid);
- myId = dialogid;
- } else {
+ else
myLine = _genericTexts->getText(dialogid - 1000);
- myId = dialogid - 1000;
- }
if (!myLine)
return 0;
bool oldMouseHidden = _gameState->_mouseHidden;
- if (blocking) {
+ if (blocking)
_gameState->_mouseHidden = true;
- }
+
// get what is before the string
int a = READ_LE_UINT16(myLine - 2);
@@ -2090,10 +2086,8 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit)
doFrame();
}
- } else {
- if (_audioManager->voiceStillPlaying())
- _audioManager->stopCurrentVoice();
- }
+ } else if (_audioManager->voiceStillPlaying())
+ _audioManager->stopCurrentVoice();
for (int32 i = 0; i < numParticipants - 1; i++) {
// listener
@@ -2133,10 +2127,10 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY);
if (dialogid < 1000) {
- myId = _roomTexts->getId(dialogid);
+ int myId = _roomTexts->getId(dialogid);
_audioManager->playVoice(myId, false);
} else {
- myId = _genericTexts->getId(dialogid - 1000);
+ int myId = _genericTexts->getId(dialogid - 1000);
_audioManager->playVoice(myId, true);
}
diff --git a/engines/tsage/ringworld/ringworld_scenes10.cpp b/engines/tsage/ringworld/ringworld_scenes10.cpp
index c4874c0f59..99c953217c 100644
--- a/engines/tsage/ringworld/ringworld_scenes10.cpp
+++ b/engines/tsage/ringworld/ringworld_scenes10.cpp
@@ -1004,7 +1004,7 @@ void Scene9450::postInit(SceneObjectList *OwnerList) {
_hotspot8.setDetails(110, 0, 199, 117, 9450, 7, 8);
_hotspot9.setDetails(101, 104, 130, 174, 9450, 9, 10);
_hotspot10.setDetails(110, 246, 149, 319, 9450, 11, 12);
- _hotspot11.setDetails(16, 34, 74, 62, 6450, 13, 14);
+ _hotspot11.setDetails(16, 34, 74, 62, 9450, 13, 14);
_hotspot12.setDetails(19, 108, 72, 134, 9450, 15, 16);
_hotspot13.setDetails(18, 215, 71, 237, 9450, 17, 18);
_hotspot14.setDetails(15, 288, 76, 314, 9450, 19, 20);
diff --git a/engines/tsage/ringworld2/ringworld2_logic.h b/engines/tsage/ringworld2/ringworld2_logic.h
index 31d801fa55..d95f279e27 100644
--- a/engines/tsage/ringworld2/ringworld2_logic.h
+++ b/engines/tsage/ringworld2/ringworld2_logic.h
@@ -320,7 +320,7 @@ public:
int pixelToCellXY(Common::Point &pt);
virtual Common::String getClassName() { return "MazeUI"; }
- void synchronize(Serializer &s);
+ virtual void synchronize(Serializer &s);
virtual void reposition();
virtual void draw();
};
diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
index 29646d1612..e2c22bd0b4 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
@@ -1919,7 +1919,7 @@ void Scene1200::process(Event &event) {
return;
}
} else if (event.eventType == EVENT_KEYPRESS) {
- if (_field414 == 0) {
+ if (_field414) {
event.handled = false;
return;
}
diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp
index 3f32503fdf..9eaead630b 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp
@@ -2843,8 +2843,8 @@ void Scene3400::signal() {
R2_INVENTORY.setObjectScene(R2_SAPPHIRE_BLUE, 0);
_stripManager.start(3307, this);
if (R2_GLOBALS._player._characterIndex == R2_SEEKER) {
- _sceneMode = 3400;
- R2_GLOBALS._player.setAction(&_sequenceManager, this, 3400, &R2_GLOBALS._player, &_teal, &_sapphire, NULL);
+ _sceneMode = 3404;
+ R2_GLOBALS._player.setAction(&_sequenceManager, this, 3404, &R2_GLOBALS._player, &_teal, &_sapphire, NULL);
} else {
_sceneMode = 3408;
_companion1.setAction(&_sequenceManager, this, 3408, &_companion1, &_teal, &_sapphire, NULL);
@@ -3668,11 +3668,12 @@ void Scene3500::postInit(SceneObjectList *OwnerList) {
_horizontalSpeedDisplay.setPosition(Common::Point(126, 108));
_horizontalSpeedDisplay.fixPriority(200);
+ _action1._turningFl = false;
+
+ _mazeUI.postInit();
_mazeUI.setDisplayBounds(Rect(160, 89, 299, 182));
_mazeUI.load(2);
_mazeUI.setMazePosition(_mazePosition);
-
- _action1._turningFl = false;
_mazeUI.draw();
_directionChangesEnabled = true;
@@ -3876,6 +3877,11 @@ void Scene3500::dispatch() {
Rect tmpRect;
Scene::dispatch();
+ // WORKAROUND: The _mazeUI wasn't originally added to the scene in postInit.
+ // This is only needed to fix old savegames
+ if (!R2_GLOBALS._sceneObjects->contains(&_mazeUI))
+ _mazeUI.draw();
+
if (((_shuttle._frame % 2) == 0) && (!_action1._turningFl)) {
_shuttle.setFrame(_shuttle.changeFrame());
_mazeDirection = _shuttle._frame;
@@ -4215,7 +4221,6 @@ void Scene3500::dispatch() {
_rotation->_idxChange = 0;
}
- _mazeUI.draw();
if (_exitCounter != 0)
++_exitCounter;
}
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp
index c5c38505a7..b95b614f09 100644
--- a/engines/tsage/sound.cpp
+++ b/engines/tsage/sound.cpp
@@ -164,7 +164,7 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) {
sd._status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED;
sd._field2 = 0;
sd._field6 = 15000;
- sd._shortDescription = "Adlib or SoundBlaster";
+ sd._shortDescription = "AdLib or SoundBlaster";
sd._longDescription = "3812fm";
_availableDrivers.push_back(sd);
@@ -379,7 +379,6 @@ void SoundManager::updateSoundLoop(Sound *sound) {
}
void SoundManager::rethinkVoiceTypes() {
- Common::StackLock slock(sfManager()._serverSuspendedMutex);
sfRethinkVoiceTypes();
}
@@ -1442,8 +1441,6 @@ bool SoundManager::sfDoRemoveFromPlayList(Sound *sound) {
}
void SoundManager::sfDoUpdateVolume(Sound *sound) {
- Common::StackLock slock(sfManager()._serverSuspendedMutex);
-
for (int voiceIndex = 0; voiceIndex < SOUND_ARR_SIZE; ++voiceIndex) {
VoiceTypeStruct *vs = sfManager()._voiceTypeStructPtrs[voiceIndex];
if (!vs)
@@ -1707,8 +1704,6 @@ void Sound::pause(bool flag) {
}
void Sound::mute(bool flag) {
- Common::StackLock slock(g_globals->_soundManager._serverSuspendedMutex);
-
if (flag)
++_mutedCount;
else if (_mutedCount > 0)
diff --git a/engines/voyeur/configure.engine b/engines/voyeur/configure.engine
index 23891fccb7..c53530a9ed 100644
--- a/engines/voyeur/configure.engine
+++ b/engines/voyeur/configure.engine
@@ -1,4 +1,4 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine voyeur "Voyeur" no
+add_engine voyeur "Voyeur" yes
diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp
index b1960a23ac..0615c67ba0 100644
--- a/engines/voyeur/files_threads.cpp
+++ b/engines/voyeur/files_threads.cpp
@@ -1007,8 +1007,11 @@ int ThreadResource::doApt() {
if (_vm->_loadGameSlot != -1) {
// Load a savegame
- _vm->loadGame(_vm->_loadGameSlot);
+ int slot = _vm->_loadGameSlot;
_vm->_loadGameSlot = -1;
+ _vm->loadGame(slot);
+
+ _vm->_eventsManager->showCursor();
}
_vm->_eventsManager->getMouseInfo();
@@ -1596,7 +1599,9 @@ void ThreadResource::loadTheApt() {
_vm->_voy->_aptLoadMode = -1;
if (_vm->_voy->_aptLoadMode != -1) {
- doAptAnim(1);
+ if (_vm->_loadGameSlot != -1)
+ doAptAnim(1);
+
_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId);
_vm->_voy->_aptLoadMode = -1;
_vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(
diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp
index 681f431635..dad634c9bb 100644
--- a/engines/voyeur/voyeur.cpp
+++ b/engines/voyeur/voyeur.cpp
@@ -556,6 +556,7 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
PictureResource *pic = NULL;
if (videoId == 42) {
+ _bVoy->getBoltGroup(0xE00);
_eventsManager->_videoDead = 0;
pic = _bVoy->boltEntry(0xE00 + _eventsManager->_videoDead)._picResource;
}
@@ -602,6 +603,9 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
pic->_imgData = imgData;
_voy->_eventFlags &= ~EVTFLAG_8;
}
+
+ if (videoId == 42)
+ _bVoy->freeBoltGroup(0xE00);
}
void VoyeurEngine::playAudio(int audioId) {
diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp
index 1f78303f52..58684b66a0 100644
--- a/engines/wintermute/base/base_file_manager.cpp
+++ b/engines/wintermute/base/base_file_manager.cpp
@@ -209,10 +209,15 @@ bool BaseFileManager::registerPackages() {
// than the equivalent of using equalsIgnoreCase.
Common::String fileName = fileIt->getName();
fileName.toLowercase();
+ bool searchSignature = false;
- if (!fileName.hasSuffix(".dcp")) {
+ if (!fileName.hasSuffix(".dcp") && !fileName.hasSuffix(".exe")) {
continue;
}
+ if (fileName.hasSuffix(".exe")) {
+ searchSignature = true;
+ }
+
// HACK: for Reversion1, avoid loading xlanguage_pt.dcp from the main folder:
if (_language != Common::PT_BRA && targetName.hasPrefix("reversion1")) {
if (fileName == "xlanguage_pt.dcp") {
@@ -263,7 +268,7 @@ bool BaseFileManager::registerPackages() {
}
}
debugC(kWintermuteDebugFileAccess, "Registering %s %s", fileIt->getPath().c_str(), fileIt->getName().c_str());
- registerPackage((*fileIt));
+ registerPackage((*fileIt), "", searchSignature);
}
}
diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h
index 653721c8f5..d953e44704 100644
--- a/engines/wintermute/base/base_file_manager.h
+++ b/engines/wintermute/base/base_file_manager.h
@@ -63,7 +63,6 @@ private:
Common::SeekableReadStream *openFileRaw(const Common::String &filename);
Common::SeekableReadStream *openPkgFile(const Common::String &filename);
Common::FSList _packagePaths;
- bool findPackageSignature(Common::SeekableReadStream *f, uint32 *offset);
bool registerPackage(Common::FSNode package, const Common::String &filename = "", bool searchSignature = false);
bool _detectionMode;
Common::SearchSet _packages;
diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp
index f2c24b8f6a..471185f2d2 100644
--- a/engines/wintermute/base/base_frame.cpp
+++ b/engines/wintermute/base/base_frame.cpp
@@ -76,7 +76,7 @@ BaseFrame::~BaseFrame() {
//////////////////////////////////////////////////////////////////////
-bool BaseFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, bool allFrames, float rotate, TSpriteBlendMode blendMode) {
+bool BaseFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, bool allFrames, float rotate, Graphics::TSpriteBlendMode blendMode) {
bool res;
for (uint32 i = 0; i < _subframes.size(); i++) {
diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h
index 49a56592bb..ff9e67a166 100644
--- a/engines/wintermute/base/base_frame.h
+++ b/engines/wintermute/base/base_frame.h
@@ -31,6 +31,7 @@
#include "engines/wintermute/base/base_scriptable.h"
#include "engines/wintermute/coll_templ.h"
+#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSound;
@@ -51,7 +52,7 @@ public:
int32 _moveX;
uint32 _delay;
BaseArray<BaseSubFrame *> _subframes;
- bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, bool allFrames = false, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL);
+ bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, bool allFrames = false, float rotate = 0.0f, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL);
bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded);
BaseFrame(BaseGame *inGame);
diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp
index d37a22e2a6..8df39c825a 100644
--- a/engines/wintermute/base/base_game.cpp
+++ b/engines/wintermute/base/base_game.cpp
@@ -3110,6 +3110,10 @@ bool BaseGame::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferUint32(TMEMBER(_autoSaveSlot));
persistMgr->transferBool(TMEMBER(_cursorHidden));
+ if (persistMgr->checkVersion(1, 3, 1)) {
+ _settings->persist(persistMgr);
+ }
+
if (!persistMgr->getIsSaving()) {
_quitting = false;
}
diff --git a/engines/wintermute/base/base_game_settings.cpp b/engines/wintermute/base/base_game_settings.cpp
index 3b54384cc7..61c5894be3 100644
--- a/engines/wintermute/base/base_game_settings.cpp
+++ b/engines/wintermute/base/base_game_settings.cpp
@@ -219,4 +219,8 @@ char *BaseGameSettings::getKeyFromStringTable(const char *str) const {
return _stringTable->getKey(str);
}
+bool BaseGameSettings::persist(BasePersistenceManager *persistMgr) {
+ return _stringTable->persist(persistMgr);
+}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_game_settings.h b/engines/wintermute/base/base_game_settings.h
index fe0e9907e6..2059cb075e 100644
--- a/engines/wintermute/base/base_game_settings.h
+++ b/engines/wintermute/base/base_game_settings.h
@@ -34,6 +34,7 @@
namespace Wintermute {
class BaseStringTable;
class BaseGame;
+class BasePersistenceManager;
class BaseGameSettings {
public:
const char *getGameFile() const { return (_gameFile ? _gameFile : "default.game"); }
@@ -46,6 +47,8 @@ public:
bool loadStringTable(const char *filename, bool clearOld);
void expandStringByStringTable(char **str) const;
char *getKeyFromStringTable(const char *str) const;
+
+ bool persist(BasePersistenceManager *persistMgr);
private:
char *_gameFile;
int _resWidth;
diff --git a/engines/wintermute/base/base_object.cpp b/engines/wintermute/base/base_object.cpp
index 708df8def1..cce3561f67 100644
--- a/engines/wintermute/base/base_object.cpp
+++ b/engines/wintermute/base/base_object.cpp
@@ -95,7 +95,7 @@ BaseObject::BaseObject(BaseGame *inGame) : BaseScriptHolder(inGame) {
_sFXType = SFX_NONE;
_sFXParam1 = _sFXParam2 = _sFXParam3 = _sFXParam4 = 0;
- _blendMode = BLEND_NORMAL;
+ _blendMode = Graphics::BLEND_NORMAL;
}
@@ -807,10 +807,10 @@ bool BaseObject::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "BlendMode") == 0) {
int i = value->getInt();
- if (i < BLEND_NORMAL || i >= NUM_BLEND_MODES) {
- i = BLEND_NORMAL;
+ if (i < Graphics::BLEND_NORMAL || i >= Graphics::NUM_BLEND_MODES) {
+ i = Graphics::BLEND_NORMAL;
}
- _blendMode = (TSpriteBlendMode)i;
+ _blendMode = (Graphics::TSpriteBlendMode)i;
return STATUS_OK;
}
diff --git a/engines/wintermute/base/base_object.h b/engines/wintermute/base/base_object.h
index f5036f4ec4..8ca8ffc246 100644
--- a/engines/wintermute/base/base_object.h
+++ b/engines/wintermute/base/base_object.h
@@ -33,6 +33,7 @@
#include "engines/wintermute/base/base_script_holder.h"
#include "engines/wintermute/persistent.h"
#include "common/events.h"
+#include "graphics/transform_struct.h"
namespace Wintermute {
@@ -75,7 +76,7 @@ protected:
int32 _iD;
char *_soundEvent;
public:
- TSpriteBlendMode _blendMode;
+ Graphics::TSpriteBlendMode _blendMode;
virtual bool afterMove();
float _scale;
uint32 _alphaColor;
diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp
index bea55fb857..bb5e0c4091 100644
--- a/engines/wintermute/base/base_persistence_manager.cpp
+++ b/engines/wintermute/base/base_persistence_manager.cpp
@@ -36,7 +36,7 @@
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/save_thumb_helper.h"
#include "engines/wintermute/base/sound/base_sound.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
+#include "graphics/transparent_surface.h"
#include "engines/wintermute/wintermute.h"
#include "graphics/scaler.h"
#include "image/bmp.h"
@@ -173,7 +173,7 @@ void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &des
Image::BitmapDecoder bmpDecoder;
if (bmpDecoder.loadStream(thumbStream)) {
const Graphics::Surface *bmpSurface = bmpDecoder.getSurface();
- TransparentSurface *scaleableSurface = new TransparentSurface(*bmpSurface, false);
+ Graphics::TransparentSurface *scaleableSurface = new Graphics::TransparentSurface(*bmpSurface, false);
Graphics::Surface *scaled = scaleableSurface->scale(kThumbnailWidth, kThumbnailHeight2);
Graphics::Surface *thumb = scaled->convertTo(g_system->getOverlayFormat());
desc.setThumbnail(thumb);
diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp
index 2e00998037..04060bff32 100644
--- a/engines/wintermute/base/base_sprite.cpp
+++ b/engines/wintermute/base/base_sprite.cpp
@@ -418,7 +418,7 @@ bool BaseSprite::getCurrentFrame(float zoomX, float zoomY) {
//////////////////////////////////////////////////////////////////////
-bool BaseSprite::display(int x, int y, BaseObject *registerVal, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode) {
+bool BaseSprite::display(int x, int y, BaseObject *registerVal, float zoomX, float zoomY, uint32 alpha, float rotate, Graphics::TSpriteBlendMode blendMode) {
if (_currentFrame < 0 || _currentFrame >= (int32)_frames.size()) {
return STATUS_OK;
}
diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h
index 92287995d9..ec71512ec9 100644
--- a/engines/wintermute/base/base_sprite.h
+++ b/engines/wintermute/base/base_sprite.h
@@ -32,7 +32,7 @@
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base_script_holder.h"
-#include "engines/wintermute/graphics/transform_tools.h"
+#include "graphics/transform_tools.h"
namespace Wintermute {
class BaseFrame;
@@ -45,17 +45,17 @@ public:
void setDefaults();
DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder)
- bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = kDefaultZoomX, float scaleY = kDefaultZoomY);
+ bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = Graphics::kDefaultZoomX, float scaleY = Graphics::kDefaultZoomY);
int32 _moveY;
int32 _moveX;
- bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod, float rotate = kDefaultAngle, TSpriteBlendMode blendMode = BLEND_NORMAL);
- bool getCurrentFrame(float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY);
+ bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY, uint32 alpha = Graphics::kDefaultRgbaMod, float rotate = Graphics::kDefaultAngle, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL);
+ bool getCurrentFrame(float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY);
void reset();
bool isChanged();
bool isFinished();
bool loadBuffer(char *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
- bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod);
+ bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY, uint32 alpha = Graphics::kDefaultRgbaMod);
bool _looping;
int32 _currentFrame;
bool addFrame(const char *filename, uint32 delay = 0, int hotspotX = 0, int hotspotY = 0, Rect32 *rect = nullptr);
diff --git a/engines/wintermute/base/base_string_table.cpp b/engines/wintermute/base/base_string_table.cpp
index 9adbbdf7be..89407a7b0e 100644
--- a/engines/wintermute/base/base_string_table.cpp
+++ b/engines/wintermute/base/base_string_table.cpp
@@ -189,8 +189,10 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) {
BaseEngine::LOG(0, "Loading string table...");
if (clearOld) {
+ _filenames.clear();
_strings.clear();
}
+ _filenames.push_back(Common::String(filename));
uint32 size;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &size);
@@ -253,4 +255,27 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) {
return STATUS_OK;
}
+bool BaseStringTable::persist(BasePersistenceManager *persistMgr) {
+ // Do nothing if the save game is too old.
+ if (!persistMgr->checkVersion(1, 3, 1)) {
+ return true;
+ }
+ uint32 numFiles = _filenames.size();
+ persistMgr->transferUint32("NumFiles", &numFiles);
+ if (persistMgr->getIsSaving()) {
+ for (uint i = 0; i < numFiles; i++) {
+ persistMgr->transferString("Filename", &_filenames[i]);
+ }
+ } else {
+ _strings.clear();
+ _filenames.clear();
+ for (uint i = 0; i < numFiles; i++) {
+ Common::String filename = "";
+ persistMgr->transferString("Filename", &filename);
+ loadFile(filename.c_str(), false);
+ }
+ }
+ return true;
+}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_string_table.h b/engines/wintermute/base/base_string_table.h
index 9e915a1ad9..cdcf11917d 100644
--- a/engines/wintermute/base/base_string_table.h
+++ b/engines/wintermute/base/base_string_table.h
@@ -35,6 +35,8 @@
namespace Wintermute {
+class BasePersistenceManager;
+
class BaseStringTable : public BaseClass {
public:
bool loadFile(const char *filename, bool deleteAll = true);
@@ -44,8 +46,10 @@ public:
BaseStringTable(BaseGame *inGame);
virtual ~BaseStringTable();
char *getKey(const char *str) const;
+ bool persist(BasePersistenceManager *persistMgr);
private:
Common::HashMap<Common::String, Common::String> _strings;
+ Common::Array<Common::String> _filenames;
typedef Common::HashMap<Common::String, Common::String>::const_iterator StringsIter;
};
diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp
index 3a6e28b1f2..4388942064 100644
--- a/engines/wintermute/base/base_sub_frame.cpp
+++ b/engines/wintermute/base/base_sub_frame.cpp
@@ -37,8 +37,8 @@
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
-#include "engines/wintermute/graphics/transform_tools.h"
-#include "engines/wintermute/graphics/transform_struct.h"
+#include "graphics/transform_tools.h"
+#include "graphics/transform_struct.h"
namespace Wintermute {
@@ -47,9 +47,9 @@ IMPLEMENT_PERSISTENT(BaseSubFrame, false)
//////////////////////////////////////////////////////////////////////////
BaseSubFrame::BaseSubFrame(BaseGame *inGame) : BaseScriptable(inGame, true) {
_surface = nullptr;
- _hotspotX = kDefaultHotspotX;
- _hotspotY = kDefaultHotspotY;
- _alpha = kDefaultRgbaMod;
+ _hotspotX = Graphics::kDefaultHotspotX;
+ _hotspotY = Graphics::kDefaultHotspotY;
+ _alpha = Graphics::kDefaultRgbaMod;
_transparent = 0xFFFF00FF;
_wantsDefaultRect = false;
@@ -234,7 +234,7 @@ const char* BaseSubFrame::getSurfaceFilename() {
}
//////////////////////////////////////////////////////////////////////
-bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, TSpriteBlendMode blendMode) {
+bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, Graphics::TSpriteBlendMode blendMode) {
rotate = fmod(rotate, 360.0f);
if (rotate < 0) {
@@ -246,7 +246,7 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl
}
if (registerOwner != nullptr && !_decoration) {
- if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) {
+ if (zoomX == Graphics::kDefaultZoomX && zoomY == Graphics::kDefaultZoomY) {
BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, x - _hotspotX + getRect().left, y - _hotspotY + getRect().top, getRect().right - getRect().left, getRect().bottom - getRect().top, zoomX, zoomY, precise));
} else {
BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, (int)(x - (_hotspotX + getRect().left) * (zoomX / 100)), (int)(y - (_hotspotY + getRect().top) * (zoomY / 100)), (int)((getRect().right - getRect().left) * (zoomX / 100)), (int)((getRect().bottom - getRect().top) * (zoomY / 100)), zoomX, zoomY, precise));
@@ -259,24 +259,26 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl
bool res;
//if (Alpha==0xFFFFFFFF) Alpha = _alpha; // TODO: better (combine owner's and self alpha)
- if (_alpha != kDefaultRgbaMod) {
+ if (_alpha != Graphics::kDefaultRgbaMod) {
alpha = _alpha;
}
- if (rotate != kDefaultAngle) {
- Point32 boxOffset, rotatedHotspot, hotspotOffset, newOrigin;
- Point32 origin(x, y);
- Rect32 oldRect = getRect();
- Point32 newHotspot;
- TransformStruct transform = TransformStruct(zoomX, zoomY, (uint32)rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0);
- Rect32 newRect = TransformTools::newRect (oldRect, transform, &newHotspot);
+ if (rotate != Graphics::kDefaultAngle) {
+ Point32 boxOffset, rotatedHotspot, hotspotOffset;
+ Common::Point origin(x, y);
+ Common::Point newOrigin;
+ Rect32 oldRect1 = getRect();
+ Common::Rect oldRect(oldRect1.top, oldRect1.left, oldRect1.bottom, oldRect1.right);
+ Common::Point newHotspot;
+ Graphics::TransformStruct transform = Graphics::TransformStruct(zoomX, zoomY, (uint32)rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0);
+ Rect32 newRect = Graphics::TransformTools::newRect(oldRect, transform, &newHotspot);
newOrigin = origin - newHotspot;
res = _surface->displayTransform(newOrigin.x, newOrigin.y, oldRect, newRect, transform);
} else {
- if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) {
+ if (zoomX == Graphics::kDefaultZoomX && zoomY == Graphics::kDefaultZoomY) {
res = _surface->displayTrans(x - _hotspotX, y - _hotspotY, getRect(), alpha, blendMode, _mirrorX, _mirrorY);
} else {
- res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);
+ res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / Graphics::kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / Graphics::kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);
}
}
diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h
index b2859fa3f3..f156c332d6 100644
--- a/engines/wintermute/base/base_sub_frame.h
+++ b/engines/wintermute/base/base_sub_frame.h
@@ -32,6 +32,7 @@
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_scriptable.h"
+#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseObject;
@@ -52,7 +53,7 @@ public:
BaseSubFrame(BaseGame *inGame);
virtual ~BaseSubFrame();
bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded);
- bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL);
+ bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL);
bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
const char* getSurfaceFilename();
diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp
index df9a8648db..f27b565a7f 100644
--- a/engines/wintermute/base/font/base_font_truetype.cpp
+++ b/engines/wintermute/base/font/base_font_truetype.cpp
@@ -234,7 +234,7 @@ void BaseFontTT::drawText(const byte *text, int x, int y, int width, TTextAlign
color = BYTETORGBA(RGBCOLGetR(color), RGBCOLGetG(color), RGBCOLGetB(color), RGBCOLGetA(renderer->_forceAlphaColor));
renderer->_forceAlphaColor = 0;
}
- surface->displayTransOffset(x, y - textOffset, rc, color, BLEND_NORMAL, false, false, _layers[i]->_offsetX, _layers[i]->_offsetY);
+ surface->displayTransOffset(x, y - textOffset, rc, color, Graphics::BLEND_NORMAL, false, false, _layers[i]->_offsetX, _layers[i]->_offsetY);
renderer->_forceAlphaColor = origForceAlpha;
}
diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp
index e676fafdbf..a1548b83ea 100644
--- a/engines/wintermute/base/gfx/base_image.cpp
+++ b/engines/wintermute/base/gfx/base_image.cpp
@@ -28,7 +28,7 @@
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/base_file_manager.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
+#include "graphics/transparent_surface.h"
#include "graphics/surface.h"
#include "image/png.h"
#include "image/jpeg.h"
@@ -112,7 +112,7 @@ bool BaseImage::saveBMPFile(const Common::String &filename) const {
//////////////////////////////////////////////////////////////////////////
bool BaseImage::resize(int newWidth, int newHeight) {
// WME Lite used FILTER_BILINEAR with FreeImage_Rescale here.
- TransparentSurface temp(*_surface, true);
+ Graphics::TransparentSurface temp(*_surface, true);
if (_deletableSurface) {
_deletableSurface->free();
delete _deletableSurface;
@@ -216,7 +216,7 @@ bool BaseImage::writeBMPToStream(Common::WriteStream *stream) const {
bool BaseImage::copyFrom(BaseImage *origImage, int newWidth, int newHeight) {
// WME Lite used FILTER_BILINEAR with FreeImage_Rescale here.
- TransparentSurface temp(*origImage->_surface, false);
+ Graphics::TransparentSurface temp(*origImage->_surface, false);
if (_deletableSurface) {
_deletableSurface->free();
delete _deletableSurface;
diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h
index 42ff2cb9e1..6b1a4f97f4 100644
--- a/engines/wintermute/base/gfx/base_renderer.h
+++ b/engines/wintermute/base/gfx/base_renderer.h
@@ -72,7 +72,6 @@ public:
* Fade the screen to black
*
* @param alpha amount to fade by (alpha value of black)
- * @return
*/
virtual void fade(uint16 alpha) = 0;
/**
diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp
index ec42a63c77..f8b96b5baf 100644
--- a/engines/wintermute/base/gfx/base_surface.cpp
+++ b/engines/wintermute/base/gfx/base_surface.cpp
@@ -75,7 +75,7 @@ bool BaseSurface::displayHalfTrans(int x, int y, Rect32 rect) {
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) {
+bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) {
return displayTransform(x, y, rect, newRect, transform);
}
diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h
index 7bd9bcbaea..ea743bdaf2 100644
--- a/engines/wintermute/base/gfx/base_surface.h
+++ b/engines/wintermute/base/gfx/base_surface.h
@@ -32,7 +32,7 @@
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/math/rect32.h"
#include "graphics/surface.h"
-#include "engines/wintermute/graphics/transform_struct.h"
+#include "graphics/transform_struct.h"
namespace Wintermute {
@@ -50,12 +50,12 @@ public:
virtual bool displayHalfTrans(int x, int y, Rect32 rect);
virtual bool isTransparentAt(int x, int y);
- virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
- virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
- virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0;
- virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
- virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) = 0;
- virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
+ virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
+ virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
+ virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0;
+ virtual bool display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
+ virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) = 0;
+ virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) = 0;
virtual bool restore();
virtual bool create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0;
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index 601fcc0ffa..0f6a184cb3 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -35,7 +35,7 @@
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sprite.h"
#include "common/system.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
+#include "graphics/transparent_surface.h"
#include "common/queue.h"
#include "common/config-manager.h"
@@ -254,7 +254,7 @@ void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a) {
Common::Rect sizeRect(fillRect);
sizeRect.translate(-fillRect.top, -fillRect.left);
surf.fillRect(fillRect, col);
- TransformStruct temp = TransformStruct();
+ Graphics::TransformStruct temp = Graphics::TransformStruct();
temp._alphaDisable = false;
drawSurface(nullptr, &surf, &sizeRect, &fillRect, temp);
surf.free();
@@ -268,7 +268,7 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const {
return _renderSurface->format;
}
-void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) {
+void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct &transform) {
if (_disableDirtyRects) {
RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
index c9b8a52282..bc267fd656 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
@@ -33,7 +33,7 @@
#include "common/rect.h"
#include "graphics/surface.h"
#include "common/list.h"
-#include "engines/wintermute/graphics/transform_struct.h"
+#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSurfaceOSystem;
@@ -110,7 +110,7 @@ public:
virtual bool startSpriteBatch() override;
virtual bool endSpriteBatch() override;
void endSaveLoad();
- void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform);
+ void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct &transform);
BaseSurface *createSurface() override;
private:
/**
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
index 983f9c1296..a2a0032e26 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
@@ -32,8 +32,8 @@
#include "engines/wintermute/base/gfx/osystem/base_render_osystem.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/platform_osystem.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
-#include "engines/wintermute/graphics/transform_tools.h"
+#include "graphics/transparent_surface.h"
+#include "graphics/transform_tools.h"
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
#include "common/stream.h"
@@ -45,7 +45,7 @@ namespace Wintermute {
BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) {
_surface = new Graphics::Surface();
_alphaMask = nullptr;
- _alphaType = TransparentSurface::ALPHA_FULL;
+ _alphaType = Graphics::ALPHA_FULL;
_lockPixels = nullptr;
_lockPitch = 0;
_loaded = false;
@@ -68,10 +68,10 @@ BaseSurfaceOSystem::~BaseSurfaceOSystem() {
renderer->invalidateTicketsFromSurface(this);
}
-TransparentSurface::AlphaType hasTransparencyType(const Graphics::Surface *surf) {
+Graphics::AlphaType hasTransparencyType(const Graphics::Surface *surf) {
if (surf->format.bytesPerPixel != 4) {
warning("hasTransparencyType:: non 32 bpp surface passed as argument");
- return TransparentSurface::ALPHA_OPAQUE;
+ return Graphics::ALPHA_OPAQUE;
}
uint8 r, g, b, a;
bool seenAlpha = false;
@@ -93,11 +93,11 @@ TransparentSurface::AlphaType hasTransparencyType(const Graphics::Surface *surf)
}
}
if (seenFullAlpha) {
- return TransparentSurface::ALPHA_FULL;
+ return Graphics::ALPHA_FULL;
} else if (seenAlpha) {
- return TransparentSurface::ALPHA_BINARY;
+ return Graphics::ALPHA_BINARY;
} else {
- return TransparentSurface::ALPHA_OPAQUE;
+ return Graphics::ALPHA_OPAQUE;
}
}
@@ -175,7 +175,7 @@ bool BaseSurfaceOSystem::finishLoad() {
}
if (needsColorKey) {
- TransparentSurface trans(*_surface);
+ Graphics::TransparentSurface trans(*_surface);
trans.applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha);
}
@@ -328,46 +328,46 @@ bool BaseSurfaceOSystem::endPixelOp() {
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
+bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
_rotation = 0;
- return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, mirrorX, mirrorY));
+ return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
+bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
_rotation = 0;
- return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY));
+ return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
+bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
_rotation = 0;
- return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY));
+ return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, Graphics::kDefaultAngle, Graphics::kDefaultHotspotX, Graphics::kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY));
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
+bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
_rotation = 0;
- return drawSprite(x, y, &rect, nullptr, TransformStruct((int32)zoomX, (int32)zoomY, blendMode, alpha, mirrorX, mirrorY));
+ return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct((int32)zoomX, (int32)zoomY, blendMode, alpha, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
+bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
_rotation = 0;
- TransformStruct transform;
+ Graphics::TransformStruct transform;
if (transparent) {
- transform = TransformStruct((int32)zoomX, (int32)zoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY);
+ transform = Graphics::TransformStruct((int32)zoomX, (int32)zoomY, Graphics::kDefaultAngle, Graphics::kDefaultHotspotX, Graphics::kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY);
} else {
- transform = TransformStruct((int32)zoomX, (int32)zoomY, mirrorX, mirrorY);
+ transform = Graphics::TransformStruct((int32)zoomX, (int32)zoomY, mirrorX, mirrorY);
}
return drawSprite(x, y, &rect, nullptr, transform);
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) {
+bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) {
_rotation = (uint32)transform._angle;
if (transform._angle < 0.0f) {
warning("Negative rotation: %d %d", transform._angle, _rotation);
@@ -380,13 +380,13 @@ bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newR
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) {
assert(numTimesX > 0 && numTimesY > 0);
- TransformStruct transform(numTimesX, numTimesY);
+ Graphics::TransformStruct transform(numTimesX, numTimesY);
return drawSprite(x, y, &rect, nullptr, transform);
}
//////////////////////////////////////////////////////////////////////////
-bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) {
+bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, Graphics::TransformStruct transform) {
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);
if (!_loaded) {
@@ -414,13 +414,13 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect,
position.setHeight(newRect->height());
} else {
- Rect32 r;
+ Common::Rect r;
r.top = 0;
r.left = 0;
r.setWidth(rect->width());
r.setHeight(rect->height());
- r = TransformTools::newRect(r, transform, 0);
+ r = Graphics::TransformTools::newRect(r, transform, 0);
position.top = r.top + y + transform._offset.y;
position.left = r.left + x + transform._offset.x;
@@ -433,7 +433,7 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect,
// But no checking is in place for that yet.
// Optimize by not doing alpha-blits if we lack alpha
- if (_alphaType == TransparentSurface::ALPHA_OPAQUE && !transform._alphaDisable) {
+ if (_alphaType == Graphics::ALPHA_OPAQUE && !transform._alphaDisable) {
transform._alphaDisable = true;
}
@@ -452,9 +452,9 @@ bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAl
_surface->copyFrom(surface);
}
if (hasAlpha) {
- _alphaType = TransparentSurface::ALPHA_FULL;
+ _alphaType = Graphics::ALPHA_FULL;
} else {
- _alphaType = TransparentSurface::ALPHA_OPAQUE;
+ _alphaType = Graphics::ALPHA_OPAQUE;
}
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);
renderer->invalidateTicketsFromSurface(this);
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
index 4a05b2c66c..9fbbe1d498 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
@@ -30,7 +30,7 @@
#define WINTERMUTE_BASE_SURFACESDL_H
#include "graphics/surface.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
+#include "graphics/transparent_surface.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "common/list.h"
@@ -52,12 +52,12 @@ public:
bool endPixelOp() override;
- bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
- bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = kDefaultRgbaMod, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
- bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) override;
+ bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
+ bool display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = Graphics::kDefaultRgbaMod, bool transparent = false, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
+ bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) override;
virtual bool displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY);
virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override;
/* static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle);
@@ -82,17 +82,17 @@ public:
return _height;
}
- TransparentSurface::AlphaType getAlphaType() const { return _alphaType; }
+ Graphics::AlphaType getAlphaType() const { return _alphaType; }
private:
Graphics::Surface *_surface;
bool _loaded;
bool finishLoad();
- bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transformStruct);
+ bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, Graphics::TransformStruct transformStruct);
void genAlphaMask(Graphics::Surface *surface);
uint32 getPixelAt(Graphics::Surface *surface, int x, int y);
uint32 _rotation;
- TransparentSurface::AlphaType _alphaType;
+ Graphics::AlphaType _alphaType;
void *_lockPixels;
int _lockPitch;
byte *_alphaMask;
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
index f8579dfd41..afe884300a 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp
@@ -29,12 +29,12 @@
#include "engines/wintermute/base/gfx/osystem/render_ticket.h"
#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h"
-#include "engines/wintermute/graphics/transform_tools.h"
+#include "graphics/transform_tools.h"
#include "common/textconsole.h"
namespace Wintermute {
-RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct transform) :
+RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct transform) :
_owner(owner),
_srcRect(*srcRect),
_dstRect(*dstRect),
@@ -57,8 +57,8 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s
// NB: Mirroring and rotation are probably done in the wrong order.
// (Mirroring should most likely be done before rotation. See also
// TransformTools.)
- if (_transform._angle != kDefaultAngle) {
- TransparentSurface src(*_surface, false);
+ if (_transform._angle != Graphics::kDefaultAngle) {
+ Graphics::TransparentSurface src(*_surface, false);
Graphics::Surface *temp = src.rotoscale(transform);
_surface->free();
delete _surface;
@@ -66,7 +66,7 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s
} else if ((dstRect->width() != srcRect->width() ||
dstRect->height() != srcRect->height()) &&
_transform._numTimesX * _transform._numTimesY == 1) {
- TransparentSurface src(*_surface, false);
+ Graphics::TransparentSurface src(*_surface, false);
Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height());
_surface->free();
delete _surface;
@@ -97,7 +97,7 @@ bool RenderTicket::operator==(const RenderTicket &t) const {
// Replacement for SDL2's SDL_RenderCopy
void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {
- TransparentSurface src(*getSurface(), false);
+ Graphics::TransparentSurface src(*getSurface(), false);
Common::Rect clipRect;
clipRect.setWidth(getSurface()->w);
@@ -105,7 +105,7 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {
if (_owner) {
if (_transform._alphaDisable) {
- src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE);
+ src.setAlphaMode(Graphics::ALPHA_OPAQUE);
} else {
src.setAlphaMode(_owner->getAlphaType());
}
@@ -126,7 +126,7 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const {
}
void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const {
- TransparentSurface src(*getSurface(), false);
+ Graphics::TransparentSurface src(*getSurface(), false);
bool doDelete = false;
if (!clipRect) {
doDelete = true;
@@ -137,7 +137,7 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect
if (_owner) {
if (_transform._alphaDisable) {
- src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE);
+ src.setAlphaMode(Graphics::ALPHA_OPAQUE);
} else {
src.setAlphaMode(_owner->getAlphaType());
}
diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h
index de95273021..3d3bd2e844 100644
--- a/engines/wintermute/base/gfx/osystem/render_ticket.h
+++ b/engines/wintermute/base/gfx/osystem/render_ticket.h
@@ -29,7 +29,7 @@
#ifndef WINTERMUTE_RENDER_TICKET_H
#define WINTERMUTE_RENDER_TICKET_H
-#include "engines/wintermute/graphics/transparent_surface.h"
+#include "graphics/transparent_surface.h"
#include "graphics/surface.h"
#include "common/rect.h"
@@ -51,8 +51,8 @@ class BaseSurfaceOSystem;
*/
class RenderTicket {
public:
- RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform);
- RenderTicket() : _isValid(true), _wantsDraw(false), _transform(TransformStruct()) {}
+ RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, Graphics::TransformStruct transform);
+ RenderTicket() : _isValid(true), _wantsDraw(false), _transform(Graphics::TransformStruct()) {}
~RenderTicket();
const Graphics::Surface *getSurface() const { return _surface; }
// Non-dirty-rects:
@@ -65,7 +65,7 @@ public:
bool _isValid;
bool _wantsDraw;
- TransformStruct _transform;
+ Graphics::TransformStruct _transform;
BaseSurfaceOSystem *_owner;
bool operator==(const RenderTicket &a) const;
diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp
index 539dc0dd1d..41cfe5ea62 100644
--- a/engines/wintermute/base/sound/base_sound_manager.cpp
+++ b/engines/wintermute/base/sound/base_sound_manager.cpp
@@ -87,6 +87,7 @@ bool BaseSoundMgr::initialize() {
setMasterVolumePercent(volumeMasterPercent);
_soundAvailable = true;
+ g_engine->syncSoundSettings();
return STATUS_OK;
}
diff --git a/engines/wintermute/dcgf.h b/engines/wintermute/dcgf.h
index 78503b8c3b..c919180e45 100644
--- a/engines/wintermute/dcgf.h
+++ b/engines/wintermute/dcgf.h
@@ -32,8 +32,8 @@
//////////////////////////////////////////////////////////////////////////
#define DCGF_VER_MAJOR 1
-#define DCGF_VER_MINOR 2
-#define DCGF_VER_BUILD 2
+#define DCGF_VER_MINOR 3
+#define DCGF_VER_BUILD 1
#define DCGF_VER_SUFFIX "ScummVM"
#define DCGF_VER_BETA true
diff --git a/engines/wintermute/dctypes.h b/engines/wintermute/dctypes.h
index 33e1cc4018..90340f437d 100644
--- a/engines/wintermute/dctypes.h
+++ b/engines/wintermute/dctypes.h
@@ -200,14 +200,6 @@ enum TTextEncoding {
NUM_TEXT_ENCODINGS
};
-enum TSpriteBlendMode {
- BLEND_UNKNOWN = -1,
- BLEND_NORMAL = 0,
- BLEND_ADDITIVE = 1,
- BLEND_SUBTRACTIVE = 2,
- NUM_BLEND_MODES
-};
-
enum TTTSType {
TTS_CAPTION = 0,
TTS_TALK,
diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h
index 6087e60ece..8206ca9643 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -39,41 +39,50 @@ static const PlainGameDescriptor wintermuteGames[] = {
{"carolreed8", "Carol Reed 8 - Amber's Blood"},
{"carolreed9", "Carol Reed 9 - Cold Case Summer"},
{"chivalry", "Chivalry is Not Dead"},
- {"corrosion", "Corrosion: Cold Winter Waiting"},
+ {"conspiracao", "Conspiracao Dumont"},
+ {"corrosion", "Corrosion: Cold Winter Waiting"},
{"deadcity", "Dead City"},
{"dreaming", "Des Reves Elastiques Avec Mille Insectes Nommes Georges"},
{"dirtysplit", "Dirty Split"},
{"dreamscape", "Dreamscape"},
{"escapemansion", "Escape from the Mansion"},
+ {"four", "Four"},
{"framed", "Framed"},
{"ghostsheet", "Ghost in the Sheet"},
{"hamlet", "Hamlet or the last game without MMORPS features, shaders and product placement"},
{"helga", "Helga Deep In Trouble"},
{"jamesperis", "James Peris: No License Nor Control"},
{"kulivocko", "Kulivocko"},
+ {"lifein3minutes", "Life In 3 Minutes"},
{"lonelyrobot", "Project Lonely Robot"},
{"looky", "Looky"},
{"julia", "J.U.L.I.A."},
{"mirage", "Mirage"},
+ {"nighttrain", "Night Train"},
{"oknytt", "Oknytt"},
{"paintaria", "Paintaria"},
{"pigeons", "Pigeons in the Park"},
{"projectdoom", "Project: Doom"},
+ {"projectjoe", "Project Joe"},
{"reversion1", "Reversion: The Escape"},
{"reversion2", "Reversion: The Meeting"},
- {"rhiannon", "Rhiannon: Curse of the four Branches"},
- {"ritter", "1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde"},
+ {"rhiannon", "Rhiannon: Curse of the four Branches"},
+ {"ritter", "1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde"},
{"rosemary", "Rosemary"},
+ {"satanandson", "Satan and Son"},
{"securanote", "Securanote"},
{"shaban", "Shaban"},
{"shinestar", "The Shine of a Star"},
{"spaceinvaders", "Space Invaders"},
{"spacemadness", "Space Madness"},
+ {"sofiasdebt", "Sofia's Debt"},
+ {"theancientmark1", "The Ancient Mark - Episode 1"},
{"thebox", "The Box"},
- {"thekite", "The Kite"},
+ {"thekite", "The Kite"},
{"tib", "Fairy Tales About Toshechka and Boshechka"},
{"tradestory", "The Trader of Stories"},
{"twc", "the white chamber"},
+ {"war", "War"},
{"vsevolod", "Vsevolod"},
{"wintermute", "Wintermute engine game"},
{"wtetris", "Wilma Tetris"},
@@ -275,6 +284,17 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_TESTING,
GUIO0()
},
+ // Conspiracao Dumont
+ {
+ "conspiracao",
+ "",
+ AD_ENTRY1s("ConspiracaoDumont.exe", "106f3f2c8f18bb5ffffeed634ace256c", 32908032),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE |
+ ADGF_DEMO,
+ GUIO0()
+ },
// Corrosion: Cold Winter Waiting
{
"corrosion",
@@ -466,6 +486,16 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO0()
},
+ // Four
+ {
+ "four",
+ "",
+ AD_ENTRY1s("data.dcp", "ec05cd5e37c9a524053b8859635a4234", 62599855),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
// Framed
{
"framed",
@@ -645,6 +675,16 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_DEMO,
GUIO0()
},
+ // Life In 3 Minutes
+ {
+ "lifein3minutes",
+ "",
+ AD_ENTRY1s("data.dcp", "c6368950e37a95bf098b02b4eaa5b929", 141787214),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
// Looky Demo (English)
{
"looky",
@@ -709,6 +749,17 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO0()
},
+ // Night Train Demo
+ {
+ "nighttrain",
+ "",
+ AD_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE |
+ ADGF_DEMO,
+ GUIO0()
+ },
// Paintaria
{
"paintaria",
@@ -739,6 +790,17 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO0()
},
+ // Project Joe
+ {
+ "projectjoe",
+ "",
+ AD_ENTRY1s("data.dcp", "ada3c08542901295076b5349e655e73f", 160780037),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE |
+ ADGF_DEMO,
+ GUIO0()
+ },
// Project Lonely Robot
{
"lonelyrobot",
@@ -1138,6 +1200,17 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO0()
},
+ // Satan and Son
+ {
+ "satanandson",
+ "",
+ AD_ENTRY1s("data.dcp", "16a6ba8174b697bbba9299619d1e20c4", 67539054),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE |
+ ADGF_DEMO,
+ GUIO0()
+ },
// Rosemary
{
"rosemary",
@@ -1178,6 +1251,16 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO0()
},
+ // Sofia's Debt
+ {
+ "sofiasdebt",
+ "",
+ AD_ENTRY1s("SD.exe", "e9515f9ba1a2925bb6733476a826a650", 9915047),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
// Space Invaders (Demo)
{
"spaceinvaders",
@@ -1199,6 +1282,16 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_UNSTABLE,
GUIO0()
},
+ // The Ancient Mark - Episode 1
+ {
+ "theancientmark1",
+ "",
+ AD_ENTRY1s("data.dcp", "ca04c26f03b2bd307368b306b297ddd7", 364664692),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
// The Box
{
"thebox",
@@ -1301,6 +1394,16 @@ static const ADGameDescription gameDescriptions[] = {
ADGF_DEMO,
GUIO0()
},
+ // War
+ {
+ "war",
+ "",
+ AD_ENTRY1s("data.dcp", "003e317cda6d0137bbd5e5d7f089ee4d", 32591890),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO0()
+ },
// Wilma Tetris
{
"wtetris",
diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp
deleted file mode 100644
index 9483975d94..0000000000
--- a/engines/wintermute/graphics/transform_struct.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "engines/wintermute/graphics/transform_struct.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
-
-namespace Wintermute {
-void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, Point32 offset) {
- _zoom = zoom;
- _angle = angle;
- _hotspot = hotspot;
- _blendMode = blendMode;
- _rgbaMod = rgbaMod;
- _alphaDisable = alphaDisable;
- _flip = 0;
- _flip += TransparentSurface::FLIP_H * mirrorX;
- _flip += TransparentSurface::FLIP_V * mirrorY;
- _offset = offset;
- _numTimesX = 1;
- _numTimesY = 1;
-}
-
-TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) {
- init(Point32(zoomX, zoomY),
- angle,
- Point32(hotspotX, hotspotY),
- false,
- blendMode,
- rgbaMod,
- mirrorX, mirrorY,
- Point32(offsetX, offsetY));
-}
-
-TransformStruct::TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) {
- init(Point32((int32)(zoomX / 100.0 * kDefaultZoomX),
- (int32)(zoomY / 100.0 * kDefaultZoomY)),
- angle,
- Point32(hotspotX, hotspotY),
- false,
- blendMode,
- rgbaMod,
- mirrorX, mirrorY,
- Point32(offsetX, offsetY));
-}
-
-TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) {
- init(Point32(zoomX, zoomY),
- kDefaultAngle,
- Point32(kDefaultHotspotX, kDefaultHotspotY),
- false,
- blendMode,
- rgbaMod,
- mirrorX,
- mirrorY,
- Point32(kDefaultOffsetX, kDefaultOffsetY));
-}
-
-TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) {
- init(Point32(zoomX, zoomY),
- angle,
- Point32(hotspotX, hotspotY),
- true,
- BLEND_NORMAL,
- kDefaultRgbaMod,
- false, false,
- Point32(kDefaultOffsetX, kDefaultOffsetY));
-}
-
-TransformStruct::TransformStruct(int32 numTimesX, int32 numTimesY) {
- init(Point32(kDefaultZoomX, kDefaultZoomY),
- kDefaultAngle,
- Point32(kDefaultHotspotX, kDefaultHotspotY),
- false,
- BLEND_NORMAL,
- kDefaultRgbaMod,
- false, false,
- Point32(kDefaultOffsetX, kDefaultOffsetY));
- _numTimesX = numTimesX;
- _numTimesY = numTimesY;
-}
-
-TransformStruct::TransformStruct() {
- init(Point32(kDefaultZoomX, kDefaultZoomY),
- kDefaultAngle,
- Point32(kDefaultHotspotX, kDefaultHotspotY),
- true,
- BLEND_NORMAL,
- kDefaultRgbaMod,
- false, false,
- Point32(kDefaultOffsetX, kDefaultOffsetY));
-}
-
-bool TransformStruct::getMirrorX() const {
- return (bool)(_flip & TransparentSurface::FLIP_H);
-}
-
-bool TransformStruct::getMirrorY() const {
- return (bool)(_flip & TransparentSurface::FLIP_V);
-}
-} // End of namespace Wintermute
diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h
deleted file mode 100644
index f80b0967cb..0000000000
--- a/engines/wintermute/graphics/transform_struct.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef WINTERMUTE_TRANSFORM_STRUCT_H
-#define WINTERMUTE_TRANSFORM_STRUCT_H
-
-#include "engines/wintermute/math/rect32.h"
-#include "engines/wintermute/dctypes.h"
-
-namespace Wintermute {
-/**
- * Contains all the required information that define a transform.
- * Same source sprite + same TransformStruct = Same resulting sprite.
- * Has a number of overloaded constructors to accomodate various argument lists.
- */
-
-const int32 kDefaultZoomX = 100;
-const int32 kDefaultZoomY = 100;
-const uint32 kDefaultRgbaMod = 0xFFFFFFFF;
-const int32 kDefaultHotspotX = 0;
-const int32 kDefaultHotspotY = 0;
-const int32 kDefaultOffsetX = 0;
-const int32 kDefaultOffsetY = 0;
-const int32 kDefaultAngle = 0;
-
-struct TransformStruct {
-private:
- void init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX, bool mirrorY, Point32 offset);
-
-public:
- TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0);
- TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0);
- TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false);
- TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0);
- TransformStruct(int32 numTimesX, int32 numTimesY);
- TransformStruct();
-
- Point32 _zoom; ///< Zoom; 100 = no zoom
- Point32 _hotspot; ///< Position of the hotspot
- int32 _angle; ///< Rotation angle, in degrees
- byte _flip; ///< Bitflag: see TransparentSurface::FLIP_XXX
- bool _alphaDisable;
- TSpriteBlendMode _blendMode;
- uint32 _rgbaMod; ///< RGBa
- Point32 _offset;
- int32 _numTimesX;
- int32 _numTimesY;
-
- bool getMirrorX() const;
- bool getMirrorY() const;
-
- bool operator==(const TransformStruct &compare) const {
- return (compare._angle == _angle &&
- compare._flip == _flip &&
- compare._zoom == _zoom &&
- compare._offset == _offset &&
- compare._alphaDisable == _alphaDisable &&
- compare._rgbaMod == _rgbaMod &&
- compare._blendMode == _blendMode &&
- compare._numTimesX == _numTimesX &&
- compare._numTimesY == _numTimesY
- );
- }
-
- bool operator!=(const TransformStruct &compare) const {
- return !(compare == *this);
- }
-};
-} // End of namespace Wintermute
-#endif
diff --git a/engines/wintermute/graphics/transform_tools.cpp b/engines/wintermute/graphics/transform_tools.cpp
deleted file mode 100644
index 7a009c26fa..0000000000
--- a/engines/wintermute/graphics/transform_tools.cpp
+++ /dev/null
@@ -1,87 +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 "engines/wintermute/graphics/transform_tools.h"
-#include <math.h>
-
-namespace Wintermute {
-
-FloatPoint TransformTools::transformPoint(FloatPoint point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) {
- float rotateRad = rotate * M_PI / 180.0f;
- float x = point.x;
- float y = point.y;
- x = (x * zoom.x) / kDefaultZoomX;
- y = (y * zoom.y) / kDefaultZoomY;
-#if 0
- // TODO: Mirroring should be done before rotation, but the blitting
- // code does the inverse, so we match that for now.
- if (mirrorX)
- x *= -1;
- if (mirrorY)
- y *= -1;
-#endif
- FloatPoint newPoint;
- newPoint.x = x * cos(rotateRad) - y * sin(rotateRad);
- newPoint.y = x * sin(rotateRad) + y * cos(rotateRad);
- if (mirrorX) {
- newPoint.x *= -1;
- }
- if (mirrorY) {
- newPoint.y *= -1;
- }
- return newPoint;
-}
-
-Rect32 TransformTools::newRect(const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot) {
- Point32 nw(oldRect.left, oldRect.top);
- Point32 ne(oldRect.right, oldRect.top);
- Point32 sw(oldRect.left, oldRect.bottom);
- Point32 se(oldRect.right, oldRect.bottom);
-
- FloatPoint nw1, ne1, sw1, se1;
-
- nw1 = transformPoint(nw - transform._hotspot, transform._angle, transform._zoom);
- ne1 = transformPoint(ne - transform._hotspot, transform._angle, transform._zoom);
- sw1 = transformPoint(sw - transform._hotspot, transform._angle, transform._zoom);
- se1 = transformPoint(se - transform._hotspot, transform._angle, transform._zoom);
-
- float top = MIN(nw1.y, MIN(ne1.y, MIN(sw1.y, se1.y)));
- float bottom = MAX(nw1.y, MAX(ne1.y, MAX(sw1.y, se1.y)));
- float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x)));
- float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x)));
-
- if (newHotspot) {
- newHotspot->y = (uint32)(-floor(top));
- newHotspot->x = (uint32)(-floor(left));
- }
-
- Rect32 res;
- res.top = (int32)(floor(top)) + transform._hotspot.y;
- res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y;
- res.left = (int32)(floor(left)) + transform._hotspot.x;
- res.right = (int32)(ceil(right)) + transform._hotspot.x;
-
- return res;
-}
-
-} // End of namespace Wintermute
diff --git a/engines/wintermute/graphics/transform_tools.h b/engines/wintermute/graphics/transform_tools.h
deleted file mode 100644
index e259db04e5..0000000000
--- a/engines/wintermute/graphics/transform_tools.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef WINTERMUTE_TRANSFORM_TOOLS_H
-#define WINTERMUTE_TRANSFORM_TOOLS_H
-
-#include "engines/wintermute/math/rect32.h"
-#include "engines/wintermute/math/floatpoint.h"
-#include "engines/wintermute/graphics/transform_struct.h"
-
-namespace Wintermute {
-
-class TransformTools {
-public:
- /**
- * Basic transform (scale + rotate) for a single point
- */
- static FloatPoint transformPoint(FloatPoint point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false);
-
- /**
- * @param &point the point on which the transform is to be applied
- * @param rotate the angle in degrees
- * @param &zoom zoom x,y in percent
- * @param mirrorX flip along the vertical axis?
- * @param mirrorY flip along the horizontal axis?
- * @return the smallest rect that can contain the transformed sprite
- * and, as a side-effect, "newHotspot" will tell you where the hotspot will
- * have ended up in the new rect, for centering.
- */
- static Rect32 newRect(const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot);
-};
-
-} // End of namespace Wintermute
-#endif
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp
deleted file mode 100644
index 5fe0d13766..0000000000
--- a/engines/wintermute/graphics/transparent_surface.cpp
+++ /dev/null
@@ -1,950 +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.
- *
- *
- * The bottom part of this is file is adapted from SDL_rotozoom.c. The
- * relevant copyright notice for those specific functions can be found at the
- * top of that section.
- *
- */
-
-
-
-#include "common/algorithm.h"
-#include "common/endian.h"
-#include "common/util.h"
-#include "common/rect.h"
-#include "common/math.h"
-#include "common/textconsole.h"
-#include "graphics/primitives.h"
-#include "engines/wintermute/graphics/transparent_surface.h"
-#include "engines/wintermute/graphics/transform_tools.h"
-
-//#define ENABLE_BILINEAR
-
-namespace Wintermute {
-
-void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
-void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
-
-// These gather together various blendPixel functions for use with templates.
-
-class BlenderAdditive {
-public:
- inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb);
- inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb);
- inline void blendPixel(byte *in, byte *out);
- inline void blendPixel(byte *in, byte *out, int colorMod);
-};
-
-class BlenderSubtractive {
-public:
- inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb);
- inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb);
- inline void blendPixel(byte *in, byte *out);
- inline void blendPixel(byte *in, byte *out, int colorMod);
-};
-
-class BlenderNormal {
-public:
- inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb);
- inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb);
- inline void blendPixel(byte *in, byte *out);
- inline void blendPixel(byte *in, byte *out, int colorMod);
-};
-
-/**
- * Perform additive blending of a pixel, applying beforehand a given colormod.
- * @param ina, inr, ing, inb: the input pixel, split into its components.
- * @param *outa, *outr, *outg, *outb pointer to the output pixel.
- * @param *outa, *outr, *outg, *outb pointer to the colormod components.
- */
-void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) {
- if (*ca != 255) {
- ina = (ina) * (*ca) >> 8;
- }
-
- if (ina == 0) {
- return;
- } else {
- if (*cb != 255) {
- *outb = MIN(*outb + ((inb * (*cb) * ina) >> 16), 255);
- } else {
- *outb = MIN(*outb + (inb * ina >> 8), 255);
- }
-
- if (*cg != 255) {
- *outg = MIN(*outg + ((ing * (*cg) * ina) >> 16), 255);
- } else {
- *outg = MIN(*outg + (ing * ina >> 8), 255);
- }
-
- if (*cr != 255) {
- *outr = MIN(*outr + ((inr * (*cr) * ina) >> 16), 255);
- } else {
- *outr = MIN(*outr + (inr * ina >> 8), 255);
- }
- }
-}
-
-/**
- * Perform subtractive blending of a pixel, applying beforehand a given colormod.
- * @param ina, inr, ing, inb: the input pixel, split into its components.
- * @param *outa, *outr, *outg, *outb pointer to the output pixel.
- * @param *outa, *outr, *outg, *outb pointer to the colormod components.
- */
-void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) {
- //if (*ca != 255) {
- // ina = ina * (*ca) >> 8;
- // }
-
- // As weird as it is, evidence suggests that alphamod is ignored when doing
- // subtractive...
-
- // TODO if ina == 255 fast version
-
- if (ina == 0) {
- return;
- } else {
- if (*cb != 255) {
- *outb = MAX(*outb - ((inb * (*cb) * (*outb) * ina) >> 24), 0);
- } else {
- *outb = MAX(*outb - (inb * (*outb) * ina >> 16), 0);
- }
-
- if (*cg != 255) {
- *outg = MAX(*outg - ((ing * (*cg) * (*outg) * ina) >> 24), 0);
- } else {
- *outg = MAX(*outg - (ing * (*outg) * ina >> 16), 0);
- }
-
- if (*cr != 255) {
- *outr = MAX(*outr - ((inr * (*cr) * (*outr) * ina) >> 24), 0);
- } else {
- *outr = MAX(*outr - (inr * (*outr) * ina >> 16), 0);
- }
- }
-}
-
-/**
- * Perform "regular" alphablending of a pixel, applying beforehand a given colormod.
- * @param ina, inr, ing, inb: the input pixel, split into its components.
- * @param *outa, *outr, *outg, *outb pointer to the output pixel.
- * @param *outa, *outr, *outg, *outb pointer to the colormod components.
- */
-
-void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) {
- if (*ca != 255) {
- ina = ina * (*ca) >> 8;
- }
-
- if (ina == 0) {
- return;
- } else if (ina == 255) {
- if (*cb != 255) {
- *outb = (inb * (*cb)) >> 8;
- } else {
- *outb = inb;
- }
-
- if (*cr != 255) {
- *outr = (inr * (*cr)) >> 8;
- } else {
- *outr = inr;
- }
-
- if (*cg != 255) {
- *outg = (ing * (*cg)) >> 8;
- } else {
- *outg = ing;
- }
-
- *outa = ina;
-
- return;
-
- } else {
-
- *outa = 255;
- *outb = (*outb * (255 - ina) >> 8);
- *outr = (*outr * (255 - ina) >> 8);
- *outg = (*outg * (255 - ina) >> 8);
-
- if (*cb == 0) {
- *outb = *outb;
- } else if (*cb != 255) {
- *outb = *outb + (inb * ina * (*cb) >> 16);
- } else {
- *outb = *outb + (inb * ina >> 8);
- }
-
- if (*cr == 0) {
- *outr = *outr;
- } else if (*cr != 255) {
- *outr = *outr + (inr * ina * (*cr) >> 16);
- } else {
- *outr = *outr + (inr * ina >> 8);
- }
-
- if (*cg == 0) {
- *outg = *outg;
- } else if (*cg != 255) {
- *outg = *outg + (ing * ina * (*cg) >> 16);
- } else {
- *outg = *outg + (ing * ina >> 8);
- }
-
- return;
- }
-}
-
-/**
- * Perform "regular" alphablending of a pixel.
- * @param ina, inr, ing, inb: the input pixel, split into its components.
- * @param *outa, *outr, *outg, *outb pointer to the output pixel.
- */
-
-void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) {
-
- if (ina == 0) {
- return;
- } else if (ina == 255) {
- *outb = inb;
- *outg = ing;
- *outr = inr;
- *outa = ina;
- return;
- } else {
- *outa = 255;
- *outb = ((inb * ina) + *outb * (255 - ina)) >> 8;
- *outg = ((ing * ina) + *outg * (255 - ina)) >> 8;
- *outr = ((inr * ina) + *outr * (255 - ina)) >> 8;
- }
-}
-
-/**
- * Perform subtractive blending of a pixel.
- * @param ina, inr, ing, inb: the input pixel, split into its components.
- * @param *outa, *outr, *outg, *outb pointer to the output pixel.
- */
-void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) {
-
- if (ina == 0) {
- return;
- } else if (ina == 255) {
- *outa = *outa;
- *outr = *outr - (inr * (*outr) >> 8);
- *outg = *outg - (ing * (*outg) >> 8);
- *outb = *outb - (inb * (*outb) >> 8);
- return;
- } else {
- *outa = *outa;
- *outb = MAX(*outb - ((inb * (*outb)) * ina >> 16), 0);
- *outg = MAX(*outg - ((ing * (*outg)) * ina >> 16), 0);
- *outr = MAX(*outr - ((inr * (*outr)) * ina >> 16), 0);
- return;
- }
-}
-
-/**
- * Perform additive blending of a pixel.
- * @param ina, inr, ing, inb: the input pixel, split into its components.
- * @param *outa, *outr, *outg, *outb pointer to the output pixel.
- */
-void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) {
-
- if (ina == 0) {
- return;
- } else if (ina == 255) {
- *outa = *outa;
- *outr = MIN(*outr + inr, 255);
- *outg = MIN(*outg + ing, 255);
- *outb = MIN(*outb + inb, 255);
- return;
- } else {
- *outa = *outa;
- *outb = MIN((inb * ina >> 8) + *outb, 255);
- *outg = MIN((ing * ina >> 8) + *outg, 255);
- *outr = MIN((inr * ina >> 8) + *outr, 255);
- return;
- }
-}
-
-
-TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {}
-
-TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _alphaMode(ALPHA_FULL) {
- if (copyData) {
- copyFrom(surf);
- } else {
- w = surf.w;
- h = surf.h;
- pitch = surf.pitch;
- format = surf.format;
- // We need to cast the const qualifier away here because 'pixels'
- // always needs to be writable. 'surf' however is a constant Surface,
- // thus getPixels will always return const pixel data.
- pixels = const_cast<void *>(surf.getPixels());
- }
-}
-
-/**
- * Optimized version of doBlit to be used w/opaque blitting (no alpha).
- */
-void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
-
- byte *in;
- byte *out;
-
- for (uint32 i = 0; i < height; i++) {
- out = outo;
- in = ino;
- memcpy(out, in, width * 4);
- for (uint32 j = 0; j < width; j++) {
- out[TransparentSurface::kAIndex] = 0xFF;
- out += 4;
- }
- outo += pitch;
- ino += inoStep;
- }
-}
-
-/**
- * Optimized version of doBlit to be used w/binary blitting (blit or no-blit, no blending).
- */
-void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
-
- byte *in;
- byte *out;
-
- for (uint32 i = 0; i < height; i++) {
- out = outo;
- in = ino;
- for (uint32 j = 0; j < width; j++) {
- uint32 pix = *(uint32 *)in;
- int a = (pix >> TransparentSurface::kAShift) & 0xff;
-
- if (a == 0) { // Full transparency
- } else { // Full opacity (Any value not exactly 0 is Opaque here)
- *(uint32 *)out = pix;
- out[TransparentSurface::kAIndex] = 0xFF;
- }
- out += 4;
- in += inStep;
- }
- outo += pitch;
- ino += inoStep;
- }
-}
-
-/**
- * What we have here is a template method that calls blendPixel() from a different
- * class - the one we call it with - thus performing a different type of blending.
- *
- * @param ino a pointer to the input surface
- * @param outo a pointer to the output surface
- * @param width width of the input surface
- * @param height height of the input surface
- * @param pitch pitch of the output surface - that is, width in bytes of every row, usually bpp * width of the TARGET surface (the area we are blitting to might be smaller, do the math)
- * @inStep size in bytes to skip to address each pixel, usually bpp of the source surface
- * @inoStep width in bytes of every row on the *input* surface / kind of like pitch
- * @color colormod in 0xAARRGGBB format - 0xFFFFFFFF for no colormod
- */
-
-template<class Blender>
-void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
- Blender b;
- byte *in;
- byte *out;
-
- if (color == 0xffffffff) {
-
- for (uint32 i = 0; i < height; i++) {
- out = outo;
- in = ino;
- for (uint32 j = 0; j < width; j++) {
-
- byte *outa = &out[TransparentSurface::kAIndex];
- byte *outr = &out[TransparentSurface::kRIndex];
- byte *outg = &out[TransparentSurface::kGIndex];
- byte *outb = &out[TransparentSurface::kBIndex];
-
- b.blendPixel(in[TransparentSurface::kAIndex],
- in[TransparentSurface::kRIndex],
- in[TransparentSurface::kGIndex],
- in[TransparentSurface::kBIndex],
- outa, outr, outg, outb);
-
- in += inStep;
- out += 4;
- }
- outo += pitch;
- ino += inoStep;
- }
- } else {
-
- byte ca = (color >> TransparentSurface::kAModShift) & 0xFF;
- byte cr = (color >> TransparentSurface::kRModShift) & 0xFF;
- byte cg = (color >> TransparentSurface::kGModShift) & 0xFF;
- byte cb = (color >> TransparentSurface::kBModShift) & 0xFF;
-
- for (uint32 i = 0; i < height; i++) {
- out = outo;
- in = ino;
- for (uint32 j = 0; j < width; j++) {
-
- byte *outa = &out[TransparentSurface::kAIndex];
- byte *outr = &out[TransparentSurface::kRIndex];
- byte *outg = &out[TransparentSurface::kGIndex];
- byte *outb = &out[TransparentSurface::kBIndex];
-
- b.blendPixel(in[TransparentSurface::kAIndex],
- in[TransparentSurface::kRIndex],
- in[TransparentSurface::kGIndex],
- in[TransparentSurface::kBIndex],
- outa, outr, outg, outb, &ca, &cr, &cg, &cb);
- in += inStep;
- out += 4;
- }
- outo += pitch;
- ino += inoStep;
- }
- }
-}
-
-Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {
-
- Common::Rect retSize;
- retSize.top = 0;
- retSize.left = 0;
- retSize.setWidth(0);
- retSize.setHeight(0);
- // Check if we need to draw anything at all
- int ca = (color >> 24) & 0xff;
-
- if (ca == 0) {
- return retSize;
- }
-
- // Create an encapsulating surface for the data
- TransparentSurface srcImage(*this, false);
- // TODO: Is the data really in the screen format?
- if (format.bytesPerPixel != 4) {
- warning("TransparentSurface can only blit 32 bpp images");
- return retSize;
- }
-
- if (pPartRect) {
-
- int xOffset = pPartRect->left;
- int yOffset = pPartRect->top;
-
- if (flipping & FLIP_V) {
- yOffset = srcImage.h - pPartRect->bottom;
- }
-
- if (flipping & FLIP_H) {
- xOffset = srcImage.w - pPartRect->right;
- }
-
- srcImage.pixels = getBasePtr(xOffset, yOffset);
- srcImage.w = pPartRect->width();
- srcImage.h = pPartRect->height();
-
- debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
- pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
- } else {
-
- debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
- srcImage.w, srcImage.h, color, width, height);
- }
-
- if (width == -1) {
- width = srcImage.w;
- }
- if (height == -1) {
- height = srcImage.h;
- }
-
-#ifdef SCALING_TESTING
- // Hardcode scaling to 66% to test scaling
- width = width * 2 / 3;
- height = height * 2 / 3;
-#endif
-
- Graphics::Surface *img = nullptr;
- Graphics::Surface *imgScaled = nullptr;
- byte *savedPixels = nullptr;
- if ((width != srcImage.w) || (height != srcImage.h)) {
- // Scale the image
- img = imgScaled = srcImage.scale(width, height);
- savedPixels = (byte *)img->getPixels();
- } else {
- img = &srcImage;
- }
-
- // Handle off-screen clipping
- if (posY < 0) {
- img->h = MAX(0, (int)img->h - -posY);
- img->setPixels((byte *)img->getBasePtr(0, -posY));
- posY = 0;
- }
-
- if (posX < 0) {
- img->w = MAX(0, (int)img->w - -posX);
- img->setPixels((byte *)img->getBasePtr(-posX, 0));
- posX = 0;
- }
-
- img->w = CLIP((int)img->w, 0, (int)MAX((int)target.w - posX, 0));
- img->h = CLIP((int)img->h, 0, (int)MAX((int)target.h - posY, 0));
-
- if ((img->w > 0) && (img->h > 0)) {
- int xp = 0, yp = 0;
-
- int inStep = 4;
- int inoStep = img->pitch;
- if (flipping & TransparentSurface::FLIP_H) {
- inStep = -inStep;
- xp = img->w - 1;
- }
-
- if (flipping & TransparentSurface::FLIP_V) {
- inoStep = -inoStep;
- yp = img->h - 1;
- }
-
- byte *ino = (byte *)img->getBasePtr(xp, yp);
- byte *outo = (byte *)target.getBasePtr(posX, posY);
-
- if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) {
- doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
- } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) {
- doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
- } else {
- if (blendMode == BLEND_ADDITIVE) {
- doBlit<BlenderAdditive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
- } else if (blendMode == BLEND_SUBTRACTIVE) {
- doBlit<BlenderSubtractive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
- } else {
- assert(blendMode == BLEND_NORMAL);
- doBlit<BlenderNormal>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
- }
- }
-
- }
-
- retSize.setWidth(img->w);
- retSize.setHeight(img->h);
-
- if (imgScaled) {
- imgScaled->setPixels(savedPixels);
- imgScaled->free();
- delete imgScaled;
- }
-
- return retSize;
-}
-
-/**
- * Writes a color key to the alpha channel of the surface
- * @param rKey the red component of the color key
- * @param gKey the green component of the color key
- * @param bKey the blue component of the color key
- * @param overwriteAlpha if true, all other alpha will be set fully opaque
- */
-void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) {
- assert(format.bytesPerPixel == 4);
- for (int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- uint32 pix = ((uint32 *)pixels)[i * w + j];
- uint8 r, g, b, a;
- format.colorToARGB(pix, a, r, g, b);
- if (r == rKey && g == gKey && b == bKey) {
- a = 0;
- ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
- } else if (overwriteAlpha) {
- a = 255;
- ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
- }
- }
- }
-}
-
-TransparentSurface::AlphaType TransparentSurface::getAlphaMode() const {
- return _alphaMode;
-}
-
-void TransparentSurface::setAlphaMode(TransparentSurface::AlphaType mode) {
- _alphaMode = mode;
-}
-
-
-
-
-
-
-/*
-
-The below two functions are adapted from SDL_rotozoom.c,
-taken from SDL_gfx-2.0.18.
-
-Its copyright notice:
-
-=============================================================================
-SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
-
-Copyright (C) 2001-2012 Andreas Schiffler
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must not
-claim that you wrote the original software. If you use this software
-in a product, an acknowledgment in the product documentation would be
-appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and must not be
-misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-
-Andreas Schiffler -- aschiffler at ferzkopp dot net
-=============================================================================
-
-
-The functions have been adapted for different structures and coordinate
-systems.
-
-*/
-
-
-
-
-
-TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
-
- assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway.
-
- Point32 newHotspot;
- Common::Rect srcRect(0, 0, (int16)w, (int16)h);
- Rect32 rect = TransformTools::newRect(Rect32(srcRect), transform, &newHotspot);
- Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top));
-
- TransparentSurface *target = new TransparentSurface();
- assert(format.bytesPerPixel == 4);
-
- int srcW = w;
- int srcH = h;
- int dstW = dstRect.width();
- int dstH = dstRect.height();
-
- target->create((uint16)dstW, (uint16)dstH, this->format);
-
- if (transform._zoom.x == 0 || transform._zoom.y == 0) {
- return target;
- }
-
- uint32 invAngle = 360 - (transform._angle % 360);
- float invCos = cos(invAngle * M_PI / 180.0);
- float invSin = sin(invAngle * M_PI / 180.0);
-
- struct tColorRGBA { byte r; byte g; byte b; byte a; };
- int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x));
- int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x));
- int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y));
- int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y));
-
-
- bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
-
- int xd = (srcRect.left + transform._hotspot.x) << 16;
- int yd = (srcRect.top + transform._hotspot.y) << 16;
- int cx = newHotspot.x;
- int cy = newHotspot.y;
-
- int ax = -icosx * cx;
- int ay = -isiny * cx;
- int sw = srcW - 1;
- int sh = srcH - 1;
-
- tColorRGBA *pc = (tColorRGBA*)target->getBasePtr(0, 0);
-
- for (int y = 0; y < dstH; y++) {
- int t = cy - y;
- int sdx = ax + (isinx * t) + xd;
- int sdy = ay - (icosy * t) + yd;
- for (int x = 0; x < dstW; x++) {
- int dx = (sdx >> 16);
- int dy = (sdy >> 16);
- if (flipx) {
- dx = sw - dx;
- }
- if (flipy) {
- dy = sh - dy;
- }
-
-#ifdef ENABLE_BILINEAR
- if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) {
- const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
- tColorRGBA c00, c01, c10, c11, cswap;
- c00 = *sp;
- sp += 1;
- c01 = *sp;
- sp += (this->pitch / 4);
- c11 = *sp;
- sp -= 1;
- c10 = *sp;
- if (flipx) {
- cswap = c00; c00=c01; c01=cswap;
- cswap = c10; c10=c11; c11=cswap;
- }
- if (flipy) {
- cswap = c00; c00=c10; c10=cswap;
- cswap = c01; c01=c11; c11=cswap;
- }
- /*
- * Interpolate colors
- */
- int ex = (sdx & 0xffff);
- int ey = (sdy & 0xffff);
- int t1, t2;
- t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
- t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
- pc->r = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
- t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
- pc->g = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
- t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
- pc->b = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
- t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
- pc->a = (((t2 - t1) * ey) >> 16) + t1;
- }
-#else
- if ((dx >= 0) && (dy >= 0) && (dx < srcW) && (dy < srcH)) {
- const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
- *pc = *sp;
- }
-#endif
- sdx += icosx;
- sdy += isiny;
- pc++;
- }
- }
- return target;
-}
-
-TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const {
-
- Common::Rect srcRect(0, 0, (int16)w, (int16)h);
- Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight);
-
- TransparentSurface *target = new TransparentSurface();
-
- assert(format.bytesPerPixel == 4);
-
- int srcW = srcRect.width();
- int srcH = srcRect.height();
- int dstW = dstRect.width();
- int dstH = dstRect.height();
-
- target->create((uint16)dstW, (uint16)dstH, this->format);
-
-#ifdef ENABLE_BILINEAR
-
- // NB: The actual order of these bytes may not be correct, but
- // since all values are treated equal, that does not matter.
- struct tColorRGBA { byte r; byte g; byte b; byte a; };
-
- bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
-
-
- int *sax = new int[dstW + 1];
- int *say = new int[dstH + 1];
- assert(sax && say);
-
- /*
- * Precalculate row increments
- */
- int spixelw = (srcW - 1);
- int spixelh = (srcH - 1);
- int sx = (int) (65536.0f * (float) spixelw / (float) (dstW - 1));
- int sy = (int) (65536.0f * (float) spixelh / (float) (dstH - 1));
-
- /* Maximum scaled source size */
- int ssx = (srcW << 16) - 1;
- int ssy = (srcH << 16) - 1;
-
- /* Precalculate horizontal row increments */
- int csx = 0;
- int *csax = sax;
- for (int x = 0; x <= dstW; x++) {
- *csax = csx;
- csax++;
- csx += sx;
-
- /* Guard from overflows */
- if (csx > ssx) {
- csx = ssx;
- }
- }
-
- /* Precalculate vertical row increments */
- int csy = 0;
- int *csay = say;
- for (int y = 0; y <= dstH; y++) {
- *csay = csy;
- csay++;
- csy += sy;
-
- /* Guard from overflows */
- if (csy > ssy) {
- csy = ssy;
- }
- }
-
- const tColorRGBA *sp = (const tColorRGBA *) getBasePtr(0, 0);
- tColorRGBA *dp = (tColorRGBA *) target->getBasePtr(0, 0);
- int spixelgap = srcW;
-
- if (flipx) {
- sp += spixelw;
- }
- if (flipy) {
- sp += spixelgap * spixelh;
- }
-
- csay = say;
- for (int y = 0; y < dstH; y++) {
- const tColorRGBA *csp = sp;
- csax = sax;
- for (int x = 0; x < dstW; x++) {
- /*
- * Setup color source pointers
- */
- int ex = (*csax & 0xffff);
- int ey = (*csay & 0xffff);
- int cx = (*csax >> 16);
- int cy = (*csay >> 16);
-
- const tColorRGBA *c00, *c01, *c10, *c11;
- c00 = sp;
- c01 = sp;
- c10 = sp;
- if (cy < spixelh) {
- if (flipy) {
- c10 -= spixelgap;
- } else {
- c10 += spixelgap;
- }
- }
- c11 = c10;
- if (cx < spixelw) {
- if (flipx) {
- c01--;
- c11--;
- } else {
- c01++;
- c11++;
- }
- }
-
- /*
- * Draw and interpolate colors
- */
- int t1, t2;
- t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
- t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
- dp->r = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
- t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
- dp->g = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
- t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
- dp->b = (((t2 - t1) * ey) >> 16) + t1;
- t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
- t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
- dp->a = (((t2 - t1) * ey) >> 16) + t1;
-
- /*
- * Advance source pointer x
- */
- int *salastx = csax;
- csax++;
- int sstepx = (*csax >> 16) - (*salastx >> 16);
- if (flipx) {
- sp -= sstepx;
- } else {
- sp += sstepx;
- }
-
- /*
- * Advance destination pointer x
- */
- dp++;
- }
- /*
- * Advance source pointer y
- */
- int *salasty = csay;
- csay++;
- int sstepy = (*csay >> 16) - (*salasty >> 16);
- sstepy *= spixelgap;
- if (flipy) {
- sp = csp - sstepy;
- } else {
- sp = csp + sstepy;
- }
- }
-
- delete[] sax;
- delete[] say;
-
-#else
-
- int *scaleCacheX = new int[dstW];
- for (int x = 0; x < dstW; x++) {
- scaleCacheX[x] = (x * srcW) / dstW;
- }
-
- for (int y = 0; y < dstH; y++) {
- uint32 *destP = (uint32 *)target->getBasePtr(0, y);
- const uint32 *srcP = (const uint32 *)getBasePtr(0, (y * srcH) / dstH);
- for (int x = 0; x < dstW; x++) {
- *destP++ = srcP[scaleCacheX[x]];
- }
- }
- delete[] scaleCacheX;
-
-#endif
-
- return target;
-
-}
-
-} // End of namespace Wintermute
diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h
deleted file mode 100644
index 4ad9bf07eb..0000000000
--- a/engines/wintermute/graphics/transparent_surface.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef GRAPHICS_TRANSPARENTSURFACE_H
-#define GRAPHICS_TRANSPARENTSURFACE_H
-
-#include "graphics/surface.h"
-#include "engines/wintermute/graphics/transform_struct.h"
-
-/*
- * This code is based on Broken Sword 2.5 engine
- *
- * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
- *
- * Licensed under GNU GPL v2
- *
- */
-
-// TODO: Find a better solution for this.
-#define BS_RGB(R,G,B) (0xFF000000 | ((R) << 16) | ((G) << 8) | (B))
-#define BS_ARGB(A,R,G,B) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B))
-
-namespace Wintermute {
-
-/**
- * A transparent graphics surface, which implements alpha blitting.
- */
-struct TransparentSurface : public Graphics::Surface {
- TransparentSurface();
- TransparentSurface(const Graphics::Surface &surf, bool copyData = false);
-
- void setColorKey(char r, char g, char b);
- void disableColorKey();
-
- // Enums
- /**
- @brief The possible flipping parameters for the blit methode.
- */
- enum FLIP_FLAGS {
- /// The image will not be flipped.
- FLIP_NONE = 0,
- /// The image will be flipped at the horizontal axis.
- FLIP_H = 1,
- /// The image will be flipped at the vertical axis.
- FLIP_V = 2,
- /// The image will be flipped at the horizontal and vertical axis.
- FLIP_HV = FLIP_H | FLIP_V,
- /// The image will be flipped at the horizontal and vertical axis.
- FLIP_VH = FLIP_H | FLIP_V
- };
-
- enum AlphaType {
- ALPHA_OPAQUE = 0,
- ALPHA_BINARY = 1,
- ALPHA_FULL = 2
- };
-
-#ifdef SCUMM_LITTLE_ENDIAN
- static const int kAIndex = 0;
- static const int kBIndex = 1;
- static const int kGIndex = 2;
- static const int kRIndex = 3;
-#else
- static const int kAIndex = 3;
- static const int kBIndex = 2;
- static const int kGIndex = 1;
- static const int kRIndex = 0;
-#endif
-
- static const int kBShift = 8;//img->format.bShift;
- static const int kGShift = 16;//img->format.gShift;
- static const int kRShift = 24;//img->format.rShift;
- static const int kAShift = 0;//img->format.aShift;
-
-
- static const int kBModShift = 0;//img->format.bShift;
- static const int kGModShift = 8;//img->format.gShift;
- static const int kRModShift = 16;//img->format.rShift;
- static const int kAModShift = 24;//img->format.aShift;
-
-
- /**
- @brief renders the surface to another surface
- @param target a pointer to the target surface. In most cases this is the framebuffer.
- @param posX the position on the X-axis in the target image in pixels where the image is supposed to be rendered.<br>
- The default value is 0.
- @param posY the position on the Y-axis in the target image in pixels where the image is supposed to be rendered.<br>
- The default value is 0.
- @param flipping how the the image should be flipped.<br>
- The default value is BS_Image::FLIP_NONE (no flipping)
- @param pPartRect Pointer on Common::Rect which specifies the section to be rendered. If the whole image has to be rendered the Pointer is NULL.<br>
- This referes to the unflipped and unscaled image.<br>
- The default value is NULL.
- @param color an ARGB color value, which determines the parameters for the color modulation und alpha blending.<br>
- The alpha component of the color determines the alpha blending parameter (0 = no covering, 255 = full covering).<br>
- The color components determines the color for color modulation.<br>
- The default value is BS_ARGB(255, 255, 255, 255) (full covering, no color modulation).
- The macros BS_RGB and BS_ARGB can be used for the creation of the color value.
- @param width the output width of the screen section.
- The images will be scaled if the output width of the screen section differs from the image section.<br>
- The value -1 determines that the image should not be scaled.<br>
- The default value is -1.
- @param height the output height of the screen section.
- The images will be scaled if the output width of the screen section differs from the image section.<br>
- The value -1 determines that the image should not be scaled.<br>
- The default value is -1.
- @return returns false if the rendering failed.
- */
- Common::Rect blit(Graphics::Surface &target, int posX = 0, int posY = 0,
- int flipping = FLIP_NONE,
- Common::Rect *pPartRect = nullptr,
- uint color = BS_ARGB(255, 255, 255, 255),
- int width = -1, int height = -1,
- TSpriteBlendMode blend = BLEND_NORMAL);
- void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false);
-
- /**
- * @brief Scale function; this returns a transformed version of this surface after rotation and
- * scaling. Please do not use this if angle != 0, use rotoscale.
- *
- * @param newWidth the resulting width.
- * @param newHeight the resulting height.
- * @see TransformStruct
- */
- TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const;
-
- /**
- * @brief Rotoscale function; this returns a transformed version of this surface after rotation and
- * scaling. Please do not use this if angle == 0, use plain old scaling function.
- *
- * @param transform a TransformStruct wrapping the required info. @see TransformStruct
- *
- */
- TransparentSurface *rotoscale(const TransformStruct &transform) const;
- AlphaType getAlphaMode() const;
- void setAlphaMode(AlphaType);
-private:
- AlphaType _alphaMode;
-
-};
-
-/**
- * A deleter for Surface objects which can be used with SharedPtr.
- *
- * This deleter assures Surface::free is called on deletion.
- */
-/*struct SharedPtrTransparentSurfaceDeleter {
- void operator()(TransparentSurface *ptr) {
- ptr->free();
- delete ptr;
- }
-};*/
-
-} // End of namespace Wintermute
-
-
-#endif
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 19fb3d6717..1b6c52e0b7 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -89,9 +89,6 @@ MODULE_OBJS := \
base/save_thumb_helper.o \
base/timer.o \
detection.o \
- graphics/transform_struct.o \
- graphics/transform_tools.o \
- graphics/transparent_surface.o \
math/math_util.o \
math/matrix4.o \
math/vector2.o \
diff --git a/engines/wintermute/utils/utils.cpp b/engines/wintermute/utils/utils.cpp
index d592019418..dc6476d4ea 100644
--- a/engines/wintermute/utils/utils.cpp
+++ b/engines/wintermute/utils/utils.cpp
@@ -32,11 +32,6 @@
namespace Wintermute {
-//////////////////////////////////////////////////////////////////////
-static inline unsigned Sqr(int x) {
- return (x * x);
-}
-
//////////////////////////////////////////////////////////////////////////////////
// Swap - swaps two integers
//////////////////////////////////////////////////////////////////////////////////
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp
index e854378ae4..517278e155 100644
--- a/engines/zvision/scripting/actions.cpp
+++ b/engines/zvision/scripting/actions.cpp
@@ -155,7 +155,7 @@ bool ActionEnableControl::execute(ZVision *engine) {
ActionMusic::ActionMusic(const Common::String &line) : _volume(255) {
uint type;
- char fileNameBuffer[25];
+ char fileNameBuffer[26];
uint loop;
uint volume = 255;
@@ -211,7 +211,7 @@ bool ActionMusic::execute(ZVision *engine) {
//////////////////////////////////////////////////////////////////////////////
ActionPreloadAnimation::ActionPreloadAnimation(const Common::String &line) {
- char fileName[25];
+ char fileName[26];
// The two %*u are always 0 and dont seem to have a use
sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%25s %*u %*u %u %u)", &_key, fileName, &_mask, &_framerate);
@@ -238,7 +238,7 @@ bool ActionPreloadAnimation::execute(ZVision *engine) {
//////////////////////////////////////////////////////////////////////////////
ActionPlayAnimation::ActionPlayAnimation(const Common::String &line) {
- char fileName[25];
+ char fileName[26];
// The two %*u are always 0 and dont seem to have a use
sscanf(line.c_str(),
@@ -312,7 +312,7 @@ bool ActionRandom::execute(ZVision *engine) {
//////////////////////////////////////////////////////////////////////////////
ActionSetPartialScreen::ActionSetPartialScreen(const Common::String &line) {
- char fileName[25];
+ char fileName[26];
uint color;
sscanf(line.c_str(), "%*[^(](%u %u %25s %*u %u)", &_x, &_y, fileName, &color);
@@ -342,7 +342,7 @@ bool ActionSetPartialScreen::execute(ZVision *engine) {
//////////////////////////////////////////////////////////////////////////////
ActionSetScreen::ActionSetScreen(const Common::String &line) {
- char fileName[25];
+ char fileName[26];
sscanf(line.c_str(), "%*[^(](%25[^)])", fileName);
_fileName = Common::String(fileName);
@@ -360,7 +360,7 @@ bool ActionSetScreen::execute(ZVision *engine) {
//////////////////////////////////////////////////////////////////////////////
ActionStreamVideo::ActionStreamVideo(const Common::String &line) {
- char fileName[25];
+ char fileName[26];
uint skippable;
sscanf(line.c_str(), "%*[^(](%25s %u %u %u %u %u %u)", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skippable);
diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp
index 5cf5086691..a35548d02e 100644
--- a/engines/zvision/scripting/controls/input_control.cpp
+++ b/engines/zvision/scripting/controls/input_control.cpp
@@ -75,7 +75,7 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
} else if (line.matchString("*next_tabstop*", true)) {
sscanf(line.c_str(), "%*[^(](%u)", &_nextTabstop);
} else if (line.matchString("*cursor_animation*", true)) {
- char fileName[25];
+ char fileName[26];
sscanf(line.c_str(), "%*[^(](%25s %*u)", fileName);