1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "engines/util.h"
24 #include "gui/saveload.h"
25 #include "common/translation.h"
26 #include "sherlock/scalpel/scalpel.h"
27 #include "sherlock/scalpel/scalpel_fixed_text.h"
28 #include "sherlock/scalpel/scalpel_map.h"
29 #include "sherlock/scalpel/scalpel_people.h"
30 #include "sherlock/scalpel/scalpel_scene.h"
31 #include "sherlock/scalpel/scalpel_screen.h"
32 #include "sherlock/scalpel/3do/scalpel_3do_screen.h"
33 #include "sherlock/scalpel/tsage/logo.h"
34 #include "sherlock/sherlock.h"
35 #include "sherlock/music.h"
36 #include "sherlock/animation.h"
37 #include "video/3do_decoder.h"
38 
39 namespace Sherlock {
40 
41 namespace Scalpel {
42 
43 #define PROLOGUE_NAMES_COUNT 6
44 
45 // The following are a list of filenames played in the prologue that have
46 // special effects associated with them at specific frames
47 static const char *const PROLOGUE_NAMES[PROLOGUE_NAMES_COUNT] = {
48 	"subway1", "subway2", "finale2", "suicid", "coff3", "coff4"
49 };
50 
51 static const int PROLOGUE_FRAMES[6][9] = {
52 	{ 4, 26, 54, 72, 92, 134, FRAMES_END },
53 	{ 2, 80, 95, 117, 166, FRAMES_END },
54 	{ 1, FRAMES_END },
55 	{ 42, FRAMES_END },
56 	{ FRAMES_END },
57 	{ FRAMES_END }
58 };
59 
60 #define TITLE_NAMES_COUNT 7
61 
62 // Title animations file list
63 static const char *const TITLE_NAMES[TITLE_NAMES_COUNT] = {
64 	"27pro1", "14note", "coff1", "coff2", "coff3", "coff4", "14kick"
65 };
66 
67 static const int TITLE_FRAMES[7][9] = {
68 	{ 29, 131, FRAMES_END },
69 	{ 55, 80, 95, 117, 166, FRAMES_END },
70 	{ 15, FRAMES_END },
71 	{ 4, 37, 92, FRAMES_END },
72 	{ 2, 43, FRAMES_END },
73 	{ 2, FRAMES_END },
74 	{ 10, 50, FRAMES_END }
75 };
76 
77 #define NUM_PLACES 100
78 
79 static const int MAP_X[NUM_PLACES] = {
80 	0, 368, 0, 219, 0, 282, 0, 43, 0, 0, 396, 408, 0, 0, 0, 568, 37, 325,
81 	28, 0, 263, 36, 148, 469, 342, 143, 443, 229, 298, 0, 157, 260, 432,
82 	174, 0, 351, 0, 528, 0, 136, 0, 0, 0, 555, 165, 0, 506, 0, 0, 344, 0, 0
83 };
84 static const int MAP_Y[NUM_PLACES] = {
85 	0, 147, 0, 166, 0, 109, 0, 61, 0, 0, 264, 70, 0, 0, 0, 266, 341, 30, 275,
86 	0, 294, 146, 311, 230, 184, 268, 133, 94, 207, 0, 142, 142, 330, 255, 0,
87 	37, 0, 70, 0, 116, 0, 0, 0, 50, 21, 0, 303, 0, 0, 229, 0, 0
88 };
89 
90 static const int MAP_TRANSLATE[NUM_PLACES] = {
91 	0, 0, 0, 1, 0, 2, 0, 3, 4, 0, 4, 6, 0, 0, 0, 8, 9, 10, 11, 0, 12, 13, 14, 7,
92 	15, 16, 17, 18, 19, 0, 20, 21, 22, 23, 0, 24, 0, 25, 0, 26, 0, 0, 0, 27,
93 	28, 0, 29, 0, 0, 30, 0
94 };
95 
96 static const byte MAP_SEQUENCES[3][MAX_FRAME] = {
97 	{ 1, 1, 2, 3, 4, 0 },		// Overview Still
98 	{ 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0 },
99 	{ 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0 }
100 };
101 
102 #define MAX_PEOPLE 66
103 
104 struct PeopleData {
105 	const char *portrait;
106 	int fixedTextId;
107 	byte stillSequences[MAX_TALK_SEQUENCES];
108 	byte talkSequences[MAX_TALK_SEQUENCES];
109 };
110 
111 const PeopleData PEOPLE_DATA[MAX_PEOPLE] = {
112 	{ "HOLM", kFixedText_People_SherlockHolmes, { 1, 0, 0 }, { 1, 0, 0 } },
113 	{ "WATS", kFixedText_People_DrWatson, { 6, 0, 0 }, { 5, 5, 6, 7, 8, 7, 8, 6, 0, 0 } },
114 	{ "LEST", kFixedText_People_InspectorLestrade, { 4, 0, 0 }, { 2, 0, 0 } },
115 	{ "CON1", kFixedText_People_ConstableOBrien, { 2, 0, 0 }, { 1, 0, 0 } },
116 	{ "CON2", kFixedText_People_ConstableLewis, { 2, 0, 0 }, { 1, 0, 0 } },
117 	{ "SHEI", kFixedText_People_SheilaParker, { 2, 0, 0 }, { 2, 3, 0, 0 } },
118 	{ "HENR", kFixedText_People_HenryCarruthers, { 3, 0, 0 }, { 3, 0, 0 } },
119 	{ "LESL", kFixedText_People_Lesley, { 9, 0, 0 }, { 1, 2, 3, 2, 1, 2, 3, 0, 0 } },
120 	{ "USH1", kFixedText_People_AnUsher, { 13, 0, 0 }, { 13, 14, 0, 0 } },
121 	{ "USH2", kFixedText_People_AnUsher, { 2, 0, 0 }, { 2, 0, 0 } },
122 	{ "FRED", kFixedText_People_FredrickEpstein, { 4, 0, 0 }, { 1, 2, 3, 4, 3, 4, 3, 2, 0, 0 } },
123 	{ "WORT", kFixedText_People_MrsWorthington, { 9, 0, 0 }, { 8, 0, 0 } },
124 	{ "COAC", kFixedText_People_TheCoach, { 2, 0, 0 }, { 1, 2, 3, 4, 5, 4, 3, 2, 0, 0 } },
125 	{ "PLAY", kFixedText_People_APlayer, { 8, 0, 0 }, { 7, 8, 0, 0 } },
126 	{ "WBOY", kFixedText_People_Tim, { 13, 0, 0 }, { 12, 13, 0, 0 } },
127 	{ "JAME", kFixedText_People_JamesSanders, { 6, 0, 0 }, { 3, 4, 0, 0 } },
128 	{ "BELL", kFixedText_People_Belle, { 1, 0, 0 }, { 4, 5, 0, 0 } },
129 	{ "GIRL", kFixedText_People_CleaningGirl, { 20, 0, 0 }, { 14, 15, 16, 17, 18, 19, 20, 20, 20, 0, 0 } },
130 	{ "EPST", kFixedText_People_FredrickEpstein, { 17, 0, 0 }, { 16, 17, 18, 18, 18, 17, 17, 0, 0 } },
131 	{ "WIGG", kFixedText_People_Wiggins, { 3, 0, 0 }, { 2, 3, 0, 0 } },
132 	{ "PAUL", kFixedText_People_Paul, { 2, 0, 0 }, { 1, 2, 0, 0 } },
133 	{ "BART", kFixedText_People_TheBartender, { 1, 0, 0 }, { 1, 0, 0 } },
134 	{ "DIRT", kFixedText_People_ADirtyDrunk, { 1, 0, 0 }, { 1, 0, 0 } },
135 	{ "SHOU", kFixedText_People_AShoutingDrunk, { 1, 0, 0 }, { 1, 0, 0 } },
136 	{ "STAG", kFixedText_People_AStaggeringDrunk, { 1, 0, 0 }, { 1, 0, 0 } },
137 	{ "BOUN", kFixedText_People_TheBouncer, { 1, 0, 0 }, { 1, 0, 0 } },
138 	{ "SAND", kFixedText_People_JamesSanders, { 6, 0, 0 }, { 5, 6, 0, 0 } },
139 	{ "CORO", kFixedText_People_TheCoroner, { 6, 0, 0 }, { 4, 5, 0, 0 } },
140 	{ "EQUE", kFixedText_People_ReginaldSnipes, { 1, 0, 0 }, { 1, 0, 0 } },
141 	{ "GEOR", kFixedText_People_GeorgeBlackwood, { 1, 0, 0 }, { 1, 0, 0 } },
142 	{ "LARS", kFixedText_People_Lars, { 7, 0, 0 }, { 5, 6, 0, 0 } },
143 	{ "PARK", kFixedText_People_SheilaParker, { 1, 0, 0 }, { 1, 0, 0 } },
144 	{ "CHEM", kFixedText_People_TheChemist, { 8, 0, 0 }, { 8, 9, 0, 0 } },
145 	{ "GREG", kFixedText_People_InspectorGregson, { 6, 0, 0 }, { 5, 6, 0, 0 } },
146 	{ "LAWY", kFixedText_People_JacobFarthington, { 1, 0, 0 }, { 1, 0, 0 } },
147 	{ "MYCR", kFixedText_People_Mycroft, { 1, 0, 0 }, { 1, 0, 0 } },
148 	{ "SHER", kFixedText_People_OldSherman, { 7, 0, 0 }, { 7, 8, 0, 0 } },
149 	{ "CHMB", kFixedText_People_Richard, { 1, 0, 0 }, { 1, 0, 0 } },
150 	{ "BARM", kFixedText_People_TheBarman, { 1, 0, 0 }, { 1, 0, 0 } },
151 	{ "DAND", kFixedText_People_ADandyPlayer, { 1, 0, 0 }, { 1, 0, 0 } },
152 	{ "ROUG", kFixedText_People_ARoughlookingPlayer, { 1, 0, 0 }, { 1, 0, 0 } },
153 	{ "SPEC", kFixedText_People_ASpectator, { 1, 0, 0 }, { 1, 0, 0 } },
154 	{ "HUNT", kFixedText_People_RobertHunt, { 1, 0, 0 }, { 1, 0, 0 } },
155 	{ "VIOL", kFixedText_People_Violet, { 3, 0, 0 }, { 3, 4, 0, 0 } },
156 	{ "PETT", kFixedText_People_Pettigrew, { 1, 0, 0 }, { 1, 0, 0 } },
157 	{ "APPL", kFixedText_People_Augie, { 8, 0, 0 }, { 14, 15, 0, 0 } },
158 	{ "ANNA", kFixedText_People_AnnaCarroway, { 16, 0, 0 }, { 3, 4, 5, 6, 0, 0 } },
159 	{ "GUAR", kFixedText_People_AGuard, { 1, 0, 0 }, { 4, 5, 6, 0, 0 } },
160 	{ "ANTO", kFixedText_People_AntonioCaruso, { 8, 0, 0 }, { 7, 8, 0, 0 } },
161 	{ "TOBY", kFixedText_People_TobyTheDog, { 1, 0, 0 }, { 1, 0, 0 } },
162 	{ "KING", kFixedText_People_SimonKingsley, { 13, 0, 0 }, { 13, 14, 0, 0 } },
163 	{ "ALFR", kFixedText_People_Alfred, { 2, 0, 0 }, { 2, 3, 0, 0 } },
164 	{ "LADY", kFixedText_People_LadyBrumwell, { 1, 0, 0 }, { 3, 4, 0, 0 } },
165 	{ "ROSA", kFixedText_People_MadameRosa, { 1, 0, 0 }, { 1, 30, 0, 0 } },
166 	{ "LADB", kFixedText_People_LadyBrumwell, { 1, 0, 0 }, { 3, 4, 0, 0 } },
167 	{ "MOOR", kFixedText_People_JosephMoorehead, { 1, 0, 0 }, { 1, 0, 0 } },
168 	{ "BEAL", kFixedText_People_MrsBeale, { 5, 0, 0 }, { 14, 15, 16, 17, 18, 19, 20, 0, 0 } },
169 	{ "LION", kFixedText_People_Felix, { 1, 0, 0 }, { 1, 0, 0 } },
170 	{ "HOLL", kFixedText_People_Hollingston, { 1, 0, 0 }, { 1, 0, 0 } },
171 	{ "CALL", kFixedText_People_ConstableCallaghan, { 1, 0, 0 }, { 1, 0, 0 } },
172 	{ "JERE", kFixedText_People_SergeantDuncan, { 2, 0, 0 }, { 1, 1, 2, 2, 0, 0 } },
173 	{ "LORD", kFixedText_People_LordBrumwell, { 1, 0, 0 }, { 9, 10, 0, 0 } },
174 	{ "NIGE", kFixedText_People_NigelJaimeson, { 1, 0, 0 }, { 1, 2, 0, 138, 3, 4, 0, 138, 0, 0 } },
175 	{ "JONA", kFixedText_People_Jonas, { 1, 0, 0 }, { 1, 8, 0, 0 } },
176 	{ "DUGA", kFixedText_People_ConstableDugan, { 1, 0, 0 }, { 1, 0, 0 } },
177 	{ "INSP", kFixedText_People_InspectorLestrade, { 4, 0, 0 }, { 2, 0, 0 } }
178 };
179 
180 uint INFO_BLACK;
181 uint BORDER_COLOR;
182 uint COMMAND_BACKGROUND;
183 uint BUTTON_BACKGROUND;
184 uint TALK_FOREGROUND;
185 uint TALK_NULL;
186 uint BUTTON_TOP;
187 uint BUTTON_MIDDLE;
188 uint BUTTON_BOTTOM;
189 uint COMMAND_FOREGROUND;
190 uint COMMAND_HIGHLIGHTED;
191 uint COMMAND_NULL;
192 uint INFO_FOREGROUND;
193 uint INFO_BACKGROUND;
194 uint INV_FOREGROUND;
195 uint INV_BACKGROUND;
196 uint PEN_COLOR;
197 
198 /*----------------------------------------------------------------*/
199 
200 #define FROM_RGB(r, g, b) pixelFormatRGB565.RGBToColor(r, g, b)
201 
ScalpelEngine(OSystem * syst,const SherlockGameDescription * gameDesc)202 ScalpelEngine::ScalpelEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
203 		SherlockEngine(syst, gameDesc) {
204 	_darts = nullptr;
205 	_mapResult = 0;
206 
207 	if (getPlatform() == Common::kPlatform3DO) {
208 		const Graphics::PixelFormat pixelFormatRGB565 = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
209 		INFO_BLACK = FROM_RGB(0, 0, 0);
210 		BORDER_COLOR = FROM_RGB(0x6d, 0x38, 0x10);
211 		COMMAND_BACKGROUND = FROM_RGB(0x38, 0x38, 0xce);
212 		BUTTON_BACKGROUND = FROM_RGB(0x95, 0x5d, 0x24);
213 		TALK_FOREGROUND = FROM_RGB(0xff, 0x55, 0x55);
214 		TALK_NULL = FROM_RGB(0xce, 0xc6, 0xc2);
215 		BUTTON_TOP = FROM_RGB(0xbe, 0x85, 0x3c);
216 		BUTTON_MIDDLE = FROM_RGB(0x9d, 0x40, 0);
217 		BUTTON_BOTTOM = FROM_RGB(0x69, 0x24, 0);
218 		COMMAND_FOREGROUND = FROM_RGB(0xFF, 0xFF, 0xFF);
219 		COMMAND_HIGHLIGHTED = FROM_RGB(0x55, 0xff, 0x55);
220 		COMMAND_NULL = FROM_RGB(0x69, 0x24, 0);
221 		INFO_FOREGROUND = FROM_RGB(0x55, 0xff, 0xff);
222 		INFO_BACKGROUND = FROM_RGB(0, 0, 0x48);
223 		INV_FOREGROUND = FROM_RGB(0xff, 0xff, 0x55);
224 		INV_BACKGROUND = FROM_RGB(0, 0, 0x48);
225 		PEN_COLOR = FROM_RGB(0x50, 0x18, 0);
226 	} else {
227 		INFO_BLACK = 1;
228 		BORDER_COLOR = 237;
229 		COMMAND_BACKGROUND = 4;
230 		BUTTON_BACKGROUND = 235;
231 		TALK_FOREGROUND = 12;
232 		TALK_NULL = 16;
233 		BUTTON_TOP = 233;
234 		BUTTON_MIDDLE = 244;
235 		BUTTON_BOTTOM = 248;
236 		COMMAND_FOREGROUND = 15;
237 		COMMAND_HIGHLIGHTED = 10;
238 		COMMAND_NULL = 248;
239 		INFO_FOREGROUND = 11;
240 		INFO_BACKGROUND = 1;
241 		INV_FOREGROUND = 14;
242 		INV_BACKGROUND = 1;
243 		PEN_COLOR = 250;
244 	}
245 }
246 
~ScalpelEngine()247 ScalpelEngine::~ScalpelEngine() {
248 	delete _darts;
249 }
250 
setupGraphics()251 void ScalpelEngine::setupGraphics() {
252 	if (getPlatform() != Common::kPlatform3DO) {
253 		// 320x200 palettized
254 		initGraphics(320, 200);
255 	} else {
256 		// 3DO actually uses RGB555, but some platforms of ours only support RGB565, so we use that
257 		const Graphics::PixelFormat pixelFormatRGB565 = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
258 
259 		// First try for a 640x400 mode
260 		g_system->beginGFXTransaction();
261 			initCommonGFX();
262 			g_system->initSize(640, 400, &pixelFormatRGB565);
263 		OSystem::TransactionError gfxError = g_system->endGFXTransaction();
264 
265 		if (gfxError == OSystem::kTransactionSuccess) {
266 			_isScreenDoubled = true;
267 		} else {
268 			// System doesn't support it, so fall back on 320x200 mode
269 			initGraphics(320, 200, &pixelFormatRGB565);
270 		}
271 	}
272 }
273 
initialize()274 void ScalpelEngine::initialize() {
275 	// Setup graphics mode
276 	setupGraphics();
277 
278 	// Let the base engine intialize
279 	SherlockEngine::initialize();
280 
281 	_darts = new Darts(this);
282 
283 	_flags.resize(100 * 8);
284 	_flags[3] = true;		// Turn on Alley
285 	_flags[39] = true;		// Turn on Baker Street
286 
287 	if (!isDemo()) {
288 		// Load the map co-ordinates for each scene and sequence data
289 		ScalpelMap &map = *(ScalpelMap *)_map;
290 		map.loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
291 		map.loadSequences(3, &MAP_SEQUENCES[0][0]);
292 		map._oldCharPoint = BAKER_ST_EXTERIOR;
293 	}
294 
295 	// Load the inventory
296 	loadInventory();
297 
298 	// Set up list of people
299 	ScalpelFixedText &fixedText = *(ScalpelFixedText *)_fixedText;
300 	const char *peopleNamePtr = nullptr;
301 
302 	for (int idx = 0; idx < MAX_PEOPLE; ++idx) {
303 		peopleNamePtr = fixedText.getText(PEOPLE_DATA[idx].fixedTextId);
304 		_people->_characters.push_back(PersonData(peopleNamePtr, PEOPLE_DATA[idx].portrait,
305 			PEOPLE_DATA[idx].stillSequences, PEOPLE_DATA[idx].talkSequences));
306 	}
307 
308 	_animation->setPrologueNames(&PROLOGUE_NAMES[0], PROLOGUE_NAMES_COUNT);
309 	_animation->setPrologueFrames(&PROLOGUE_FRAMES[0][0], 6, 9);
310 
311 	_animation->setTitleNames(&TITLE_NAMES[0], TITLE_NAMES_COUNT);
312 	_animation->setTitleFrames(&TITLE_FRAMES[0][0], 7, 9);
313 
314 	// Starting scene
315 	if (isDemo() && _interactiveFl)
316 		_scene->_goToScene = 3;
317 	else
318 		_scene->_goToScene = 4;
319 }
320 
showOpening()321 void ScalpelEngine::showOpening() {
322 	bool finished = true;
323 
324 	if (isDemo() && _interactiveFl)
325 		return;
326 
327 	_events->setFrameRate(60);
328 
329 	if (getPlatform() == Common::kPlatform3DO) {
330 		show3DOSplash();
331 
332 		finished = showCityCutscene3DO();
333 		if (finished)
334 			finished = showAlleyCutscene3DO();
335 		if (finished)
336 			finished = showStreetCutscene3DO();
337 		if (finished)
338 			showOfficeCutscene3DO();
339 
340 		_events->clearEvents();
341 		_music->stopMusic();
342 	} else {
343 		TsAGE::Logo::show(this);
344 
345 		finished = showCityCutscene();
346 		if (finished)
347 			finished = showAlleyCutscene();
348 		if (finished)
349 			finished = showStreetCutscene();
350 		if (finished)
351 			showOfficeCutscene();
352 
353 		_events->clearEvents();
354 		_music->stopMusic();
355 	}
356 
357 	_events->setFrameRate(GAME_FRAME_RATE);
358 }
359 
showCityCutscene()360 bool ScalpelEngine::showCityCutscene() {
361 	byte greyPalette[PALETTE_SIZE];
362 	byte palette[PALETTE_SIZE];
363 
364 	// Demo fades from black into grey and then fades from grey into the scene
365 	Common::fill(&greyPalette[0], &greyPalette[PALETTE_SIZE], 142);
366 	_screen->fadeIn((const byte *)greyPalette, 3);
367 
368 	_music->loadSong("prolog1");
369 	_animation->_gfxLibraryFilename = "title.lib";
370 	_animation->_soundLibraryFilename = "title.snd";
371 	bool finished = _animation->play("26open1", true, 1, 255, true, 2);
372 
373 	if (finished) {
374 		ImageFile titleImages_LondonNovember("title2.vgs", true);
375 		_screen->_backBuffer1.SHblitFrom(*_screen);
376 		_screen->_backBuffer2.SHblitFrom(*_screen);
377 
378 		Common::Point londonPosition;
379 
380 		if ((titleImages_LondonNovember[0]._width == 302) && (titleImages_LondonNovember[0]._height == 39)) {
381 			// Spanish
382 			londonPosition = Common::Point(9, 8);
383 		} else {
384 			// English (German uses the same English graphics), width 272, height 37
385 			// In the German version this is placed differently, check against German floppy version TODO
386 			londonPosition = Common::Point(30, 50);
387 		}
388 
389 		// London, England
390 		_screen->_backBuffer1.SHtransBlitFrom(titleImages_LondonNovember[0], londonPosition);
391 		_screen->randomTransition();
392 		finished = _events->delay(1000, true);
393 
394 		// November, 1888
395 		if (finished) {
396 			_screen->_backBuffer1.SHtransBlitFrom(titleImages_LondonNovember[1], Common::Point(100, 100));
397 			_screen->randomTransition();
398 			finished = _events->delay(5000, true);
399 		}
400 
401 		// Transition out the title
402 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2);
403 		_screen->randomTransition();
404 	}
405 
406 	if (finished)
407 		finished = _animation->play("26open2", true, 1, 0, false, 2);
408 
409 	if (finished) {
410 		ImageFile titleImages_SherlockHolmesTitle("title.vgs", true);
411 		_screen->_backBuffer1.SHblitFrom(*_screen);
412 		_screen->_backBuffer2.SHblitFrom(*_screen);
413 
414 		Common::Point lostFilesPosition;
415 		Common::Point sherlockHolmesPosition;
416 		Common::Point copyrightPosition;
417 
418 		if ((titleImages_SherlockHolmesTitle[0]._width == 306) && (titleImages_SherlockHolmesTitle[0]._height == 39)) {
419 			// Spanish
420 			lostFilesPosition = Common::Point(5, 5);
421 			sherlockHolmesPosition = Common::Point(24, 40);
422 			copyrightPosition = Common::Point(3, 190);
423 		} else {
424 			// English (German uses the same English graphics), width 208, height 39
425 			lostFilesPosition = Common::Point(75, 6);
426 			sherlockHolmesPosition = Common::Point(34, 21);
427 			copyrightPosition = Common::Point(4, 190);
428 		}
429 
430 		// The Lost Files of
431 		_screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[0], lostFilesPosition);
432 		// Sherlock Holmes
433 		_screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[1], sherlockHolmesPosition);
434 		// copyright
435 		_screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[2], copyrightPosition);
436 
437 		_screen->verticalTransition();
438 		finished = _events->delay(4000, true);
439 
440 		if (finished) {
441 			_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2);
442 			_screen->randomTransition();
443 			finished = _events->delay(2000);
444 		}
445 
446 		if (finished) {
447 			_screen->getPalette(palette);
448 			_screen->fadeToBlack(2);
449 		}
450 
451 		if (finished) {
452 			// In the alley...
453 			Common::Point alleyPosition;
454 
455 			if ((titleImages_SherlockHolmesTitle[3]._width == 105) && (titleImages_SherlockHolmesTitle[3]._height == 16)) {
456 				// German
457 				alleyPosition = Common::Point(72, 50);
458 			} else if ((titleImages_SherlockHolmesTitle[3]._width == 166) && (titleImages_SherlockHolmesTitle[3]._height == 36)) {
459 				// Spanish
460 				alleyPosition = Common::Point(71, 50);
461 			} else {
462 				// English, width 175, height 38
463 				alleyPosition = Common::Point(72, 51);
464 			}
465 			_screen->SHtransBlitFrom(titleImages_SherlockHolmesTitle[3], alleyPosition);
466 			_screen->fadeIn(palette, 3);
467 
468 			// Wait until the track got looped and the first few notes were played
469 			finished = _music->waitUntilMSec(4300, 21300, 0, 2500); // ticks 0x104 / ticks 0x500
470 		}
471 	}
472 
473 	_animation->_gfxLibraryFilename = "";
474 	_animation->_soundLibraryFilename = "";
475 	return finished;
476 }
477 
showAlleyCutscene()478 bool ScalpelEngine::showAlleyCutscene() {
479 	byte palette[PALETTE_SIZE];
480 	_music->loadSong("prolog2");
481 
482 	_animation->_gfxLibraryFilename = "TITLE.LIB";
483 	_animation->_soundLibraryFilename = "TITLE.SND";
484 
485 	// Fade "In The Alley..." text to black
486 	_screen->fadeToBlack(2);
487 
488 	bool finished = _animation->play("27PRO1", true, 1, 3, true, 2);
489 	if (finished) {
490 		_screen->getPalette(palette);
491 		_screen->fadeToBlack(2);
492 
493 		// wait until second lower main note
494 		finished = _music->waitUntilMSec(26800, 0xFFFFFFFF, 0, 1000); // ticks 0x64A
495 	}
496 
497 	if (finished) {
498 		_screen->setPalette(palette);
499 		finished = _animation->play("27PRO2", true, 1, 0, false, 2);
500 	}
501 
502 	if (finished) {
503 		showLBV("scream.lbv");
504 
505 		// wait until first "scream" in music happened
506 		finished = _music->waitUntilMSec(45800, 0xFFFFFFFF, 0, 6000); // ticks 0xABE
507 	}
508 
509 	if (finished) {
510 		// quick fade out
511 		_screen->fadeToBlack(1);
512 
513 		// wait until after third "scream" in music happened
514 		finished = _music->waitUntilMSec(49000, 0xFFFFFFFF, 0, 2000); // ticks 0xB80
515 	}
516 
517 	if (finished)
518 		finished = _animation->play("27PRO3", true, 1, 0, true, 2);
519 
520 	if (finished) {
521 		_screen->getPalette(palette);
522 		_screen->fadeToBlack(2);
523 	}
524 
525 	if (finished) {
526 		ImageFile titleImages_EarlyTheFollowingMorning("title3.vgs", true);
527 		// "Early the following morning on Baker Street..."
528 		Common::Point earlyTheFollowingMorningPosition;
529 
530 		if ((titleImages_EarlyTheFollowingMorning[0]._width == 164) && (titleImages_EarlyTheFollowingMorning[0]._height == 19)) {
531 			// German
532 			earlyTheFollowingMorningPosition = Common::Point(35, 50);
533 		} else if ((titleImages_EarlyTheFollowingMorning[0]._width == 171) && (titleImages_EarlyTheFollowingMorning[0]._height == 32)) {
534 			// Spanish
535 			earlyTheFollowingMorningPosition = Common::Point(35, 50);
536 		} else {
537 			// English, width 218, height 31
538 			earlyTheFollowingMorningPosition = Common::Point(35, 52);
539 		}
540 
541 		_screen->SHtransBlitFrom(titleImages_EarlyTheFollowingMorning[0], earlyTheFollowingMorningPosition);
542 
543 		// fast fade-in
544 		_screen->fadeIn(palette, 1);
545 
546 		// wait for music to end and wait an additional 2.5 seconds
547 		finished = _music->waitUntilMSec(0xFFFFFFFF, 0xFFFFFFFF, 2500, 3000);
548 	}
549 
550 	_animation->_gfxLibraryFilename = "";
551 	_animation->_soundLibraryFilename = "";
552 	return finished;
553 }
554 
showStreetCutscene()555 bool ScalpelEngine::showStreetCutscene() {
556 	_animation->_gfxLibraryFilename = "TITLE.LIB";
557 	_animation->_soundLibraryFilename = "TITLE.SND";
558 
559 	_music->loadSong("prolog3");
560 
561 	// wait a bit
562 	bool finished = _events->delay(500);
563 
564 	if (finished) {
565 		// fade out "Early the following morning..."
566 		_screen->fadeToBlack(2);
567 
568 		// wait for music a bit
569 		finished = _music->waitUntilMSec(3800, 0xFFFFFFFF, 0, 1000); // ticks 0xE4
570 	}
571 
572 	if (finished)
573 		finished = _animation->play("14KICK", true, 1, 3, true, 2);
574 
575 	// Constable animation plays slower than speed 2
576 	// If we play it with speed 2, music gets obviously out of sync
577 	if (finished)
578 		finished = _animation->play("14NOTE", true, 1, 0, false, 3);
579 
580 	// Fade to black
581 	if (finished)
582 		_screen->fadeToBlack(1);
583 
584 	_animation->_gfxLibraryFilename = "";
585 	_animation->_soundLibraryFilename = "";
586 	return finished;
587 }
588 
showOfficeCutscene()589 bool ScalpelEngine::showOfficeCutscene() {
590 	_music->loadSong("prolog4");
591 	_animation->_gfxLibraryFilename = "TITLE2.LIB";
592 	_animation->_soundLibraryFilename = "TITLE.SND";
593 
594 	bool finished = _animation->play("COFF1", true, 1, 3, true, 3);
595 	if (finished)
596 		finished = _animation->play("COFF2", true, 1, 0, false, 3);
597 	if (finished) {
598 		showLBV("note.lbv");
599 
600 		if (_sound->_voices) {
601 			finished = _sound->playSound("NOTE1", WAIT_KBD_OR_FINISH);
602 			if (finished)
603 				finished = _sound->playSound("NOTE2", WAIT_KBD_OR_FINISH);
604 			if (finished)
605 				finished = _sound->playSound("NOTE3", WAIT_KBD_OR_FINISH);
606 			if (finished)
607 				finished = _sound->playSound("NOTE4", WAIT_KBD_OR_FINISH);
608 		} else
609 			finished = _events->delay(19000);
610 
611 		if (finished) {
612 			_events->clearEvents();
613 			finished = _events->delay(500);
614 		}
615 	}
616 
617 	if (finished)
618 		finished = _animation->play("COFF3", true, 1, 0, true, 3);
619 
620 	if (finished)
621 		finished = _animation->play("COFF4", true, 1, 0, false, 3);
622 
623 	if (finished)
624 		finished = scrollCredits();
625 
626 	if (finished)
627 		_screen->fadeToBlack(3);
628 
629 	_animation->_gfxLibraryFilename = "";
630 	_animation->_soundLibraryFilename = "";
631 	return finished;
632 }
633 
scrollCredits()634 bool ScalpelEngine::scrollCredits() {
635 	// Load the images for displaying credit text
636 	Common::SeekableReadStream *stream = _res->load("credits.vgs", "title.lib");
637 	ImageFile creditsImages(*stream);
638 
639 	// Demo fades slowly from the scene into credits palette
640 	_screen->fadeIn(creditsImages._palette, 3);
641 
642 	delete stream;
643 
644 	// Save a copy of the screen background for use in drawing each credit frame
645 	_screen->_backBuffer1.SHblitFrom(*_screen);
646 
647 	// Loop for showing the credits
648 	for(int idx = 0; idx < 600 && !_events->kbHit() && !shouldQuit(); ++idx) {
649 		// Copy the entire screen background before writing text
650 		_screen->SHblitFrom(_screen->_backBuffer1);
651 
652 		// Write the text appropriate for the next frame
653 		if (idx < 400)
654 			_screen->SHtransBlitFrom(creditsImages[0], Common::Point(10, 200 - idx), false, 0);
655 		if (idx > 200)
656 			_screen->SHtransBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
657 
658 		// Don't show credit text on the top and bottom ten rows of the screen
659 		_screen->SHblitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->width(), 10));
660 		_screen->SHblitFrom(_screen->_backBuffer1, Common::Point(0, _screen->height() - 10),
661 			Common::Rect(0, _screen->height() - 10, _screen->width(), _screen->height()));
662 
663 		_events->delay(100);
664 	}
665 
666 	return true;
667 }
668 
669 // 3DO variant
show3DOSplash()670 bool ScalpelEngine::show3DOSplash() {
671 	// 3DO EA Splash screen
672 	ImageFile3DO titleImage_3DOSplash("3DOSplash.cel", kImageFile3DOType_Cel);
673 
674 	_screen->SHtransBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20));
675 	bool finished = _events->delay(3000, true);
676 
677 	if (finished) {
678 		_screen->clear();
679 		finished = _events->delay(500, true);
680 	}
681 
682 	if (finished) {
683 		// EA logo movie
684 		play3doMovie("EAlogo.stream", Common::Point(20, 0));
685 	}
686 
687 	// Always clear screen
688 	_screen->clear();
689 	return finished;
690 }
691 
showCityCutscene3DO()692 bool ScalpelEngine::showCityCutscene3DO() {
693 	Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
694 	_animation->_soundLibraryFilename = "TITLE.SND";
695 
696 	screen.clear();
697 	bool finished = _events->delay(2500, true);
698 
699 	if (finished) {
700 		finished = _events->delay(2500, true);
701 
702 		// Play intro music
703 		_music->loadSong("prolog");
704 
705 		// Loop rain.aiff until the Sherlock logo fades away.
706 		// TODO: The volume is just a guess.
707 		_sound->playAiff("prologue/sounds/rain.aiff", 15, true);
708 
709 		// Fade screen to grey
710 		screen._backBuffer1.clear(0xCE59); // RGB565: 25, 50, 25 (grey)
711 		screen.fadeIntoScreen3DO(2);
712 	}
713 
714 	if (finished) {
715 		finished = _music->waitUntilMSec(3400, 0, 0, 3400);
716 	}
717 
718 	if (finished) {
719 		screen._backBuffer1.clear(0); // fill backbuffer with black to avoid issues during fade from white
720 		finished = _animation->play3DO("26open1", true, 1, true, 2);
721 	}
722 
723 	if (finished) {
724 		screen._backBuffer2.SHblitFrom(screen._backBuffer1);
725 
726 		// "London, England"
727 		ImageFile3DO titleImage_London("title2a.cel", kImageFile3DOType_Cel);
728 		screen._backBuffer1.SHtransBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50));
729 
730 		screen.fadeIntoScreen3DO(1);
731 		finished = _events->delay(1500, true);
732 
733 		if (finished) {
734 			// "November, 1888"
735 			ImageFile3DO titleImage_November("title2b.cel", kImageFile3DOType_Cel);
736 			screen._backBuffer1.SHtransBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100));
737 
738 			screen.fadeIntoScreen3DO(1);
739 			finished = _music->waitUntilMSec(14700, 0, 0, 5000);
740 		}
741 
742 		if (finished) {
743 			// Restore screen
744 			_screen->_backBuffer1.SHblitFrom(screen._backBuffer2);
745 			_screen->SHblitFrom(screen._backBuffer1);
746 		}
747 	}
748 
749 	if (finished)
750 		finished = _animation->play3DO("26open2", true, 1, false, 2);
751 
752 	if (finished) {
753 		// "Sherlock Holmes" (title)
754 		ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel", kImageFile3DOType_Cel);
755 		screen._backBuffer1.SHtransBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5));
756 
757 		// Blend in
758 		screen.fadeIntoScreen3DO(2);
759 		finished = _events->delay(500, true);
760 
761 		// Title should fade in, Copyright should be displayed a bit after that
762 		if (finished) {
763 			ImageFile3DO titleImage_Copyright("title1c.cel", kImageFile3DOType_Cel);
764 
765 			screen.SHtransBlitFrom(titleImage_Copyright[0]._frame, Common::Point(40, 380));
766 			finished = _events->delay(3500, true);
767 		}
768 	}
769 
770 	if (finished)
771 		finished = _music->waitUntilMSec(33600, 0, 0, 2000);
772 
773 	_sound->stopAiff();
774 
775 	if (finished) {
776 		// Fade to black
777 		screen._backBuffer1.clear();
778 		screen.fadeIntoScreen3DO(3);
779 	}
780 
781 	if (finished) {
782 		// "In the alley behind the Regency Theatre..."
783 		ImageFile3DO titleImage_InTheAlley("title1d.cel", kImageFile3DOType_Cel);
784 		screen._backBuffer1.SHtransBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51));
785 
786 		// Fade in
787 		screen.fadeIntoScreen3DO(4);
788 		finished = _music->waitUntilMSec(39900, 0, 0, 2500);
789 
790 		// Fade out
791 		screen._backBuffer1.clear();
792 		screen.fadeIntoScreen3DO(4);
793 	}
794 	return finished;
795 }
796 
showAlleyCutscene3DO()797 bool ScalpelEngine::showAlleyCutscene3DO() {
798 	Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
799 	bool finished = _music->waitUntilMSec(43500, 0, 0, 1000);
800 
801 	if (finished)
802 		finished = _animation->play3DO("27PRO1", true, 1, false, 2);
803 
804 	if (finished) {
805 		// Fade out...
806 		screen._backBuffer1.clear();
807 		screen.fadeIntoScreen3DO(3);
808 
809 		finished = _music->waitUntilMSec(67100, 0, 0, 1000); // 66700
810 	}
811 
812 	if (finished)
813 		finished = _animation->play3DO("27PRO2", true, 1, false, 2);
814 
815 	if (finished)
816 		finished = _music->waitUntilMSec(76000, 0, 0, 1000);
817 
818 	if (finished) {
819 		// Show screaming victim
820 		ImageFile3DO titleImage_ScreamingVictim("scream.cel", kImageFile3DOType_Cel);
821 
822 		screen.clear();
823 		screen.SHtransBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0));
824 
825 		// Play "scream.aiff"
826 		if (_sound->_voices)
827 			_sound->playSound("prologue/sounds/scream.aiff", WAIT_RETURN_IMMEDIATELY, 100);
828 
829 		finished = _music->waitUntilMSec(81600, 0, 0, 6000);
830 	}
831 
832 	if (finished) {
833 		// Fade out
834 		screen._backBuffer1.clear();
835 		screen.fadeIntoScreen3DO(5);
836 
837 		finished = _music->waitUntilMSec(84400, 0, 0, 2000);
838 	}
839 
840 	if (finished)
841 		finished = _animation->play3DO("27PRO3", true, 1, false, 2);
842 
843 	if (finished) {
844 		// Fade out
845 		screen._backBuffer1.clear();
846 		screen.fadeIntoScreen3DO(5);
847 	}
848 
849 	if (finished) {
850 		// "Early the following morning on Baker Street..."
851 		ImageFile3DO titleImage_EarlyTheFollowingMorning("title3.cel", kImageFile3DOType_Cel);
852 		screen._backBuffer1.SHtransBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51));
853 
854 		// Fade in
855 		screen.fadeIntoScreen3DO(4);
856 		finished = _music->waitUntilMSec(96700, 0, 0, 3000);
857 	}
858 
859 	return finished;
860 }
861 
showStreetCutscene3DO()862 bool ScalpelEngine::showStreetCutscene3DO() {
863 	Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
864 	bool finished = true;
865 
866 	if (finished) {
867 		// fade out "Early the following morning..."
868 		screen._backBuffer1.clear();
869 		screen.fadeIntoScreen3DO(4);
870 
871 		// wait for music a bit
872 		finished = _music->waitUntilMSec(100300, 0, 0, 1000);
873 	}
874 
875 	if (finished)
876 		finished = _animation->play3DO("14KICK", true, 1, false, 2);
877 
878 	// note: part of the constable is sticking to the door during the following
879 	//       animation, when he walks away. This is a bug of course, but it actually happened on 3DO!
880 	//       I'm not sure if it happens because the door is pure black (0, 0, 0) and it's because
881 	//       of transparency - or if the animation itself is bad. We will definitely have to adjust
882 	//       the animation data to fix it.
883 	if (finished)
884 		finished = _animation->play3DO("14NOTE", true, 1, false, 3);
885 
886 	if (finished) {
887 		// Fade out
888 		screen._backBuffer1.clear();
889 		screen.fadeIntoScreen3DO(4);
890 	}
891 
892 	return finished;
893 }
894 
showOfficeCutscene3DO()895 bool ScalpelEngine::showOfficeCutscene3DO() {
896 	bool finished = _music->waitUntilMSec(151000, 0, 0, 1000);
897 
898 	if (finished)
899 		finished = _animation->play3DO("COFF1", true, 1, false, 3);
900 
901 	if (finished)
902 		finished = _animation->play3DO("COFF2", true, 1, false, 3);
903 
904 	if (finished)
905 		finished = _music->waitUntilMSec(182400, 0, 0, 1000);
906 
907 	if (finished) {
908 		// Show the note
909 		ImageFile3DO titleImage_CoffeeNote("note.cel", kImageFile3DOType_Cel);
910 
911 		_screen->clear();
912 		_screen->SHtransBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0));
913 
914 		if (_sound->_voices) {
915 			finished = _sound->playSound("prologue/sounds/note.aiff", WAIT_KBD_OR_FINISH);
916 		} else
917 			finished = _events->delay(19000);
918 
919 		if (finished)
920 			finished = _music->waitUntilMSec(218800, 0, 0, 1000);
921 
922 		// Fade out
923 		_screen->clear();
924 	}
925 
926 	if (finished)
927 		finished = _music->waitUntilMSec(222200, 0, 0, 1000);
928 
929 	if (finished)
930 		finished = _animation->play3DO("COFF3", true, 1, false, 3);
931 
932 	if (finished)
933 		finished = _animation->play3DO("COFF4", true, 1, false, 3);
934 
935 	if (finished) {
936 		finished = _music->waitUntilMSec(244500, 0, 0, 2000);
937 
938 		// TODO: Brighten the image, possibly by doing a partial fade
939 		// to white.
940 
941 		_screen->_backBuffer2.SHblitFrom(_screen->_backBuffer1);
942 
943 		for (int nr = 1; finished && nr <= 4; nr++) {
944 			char filename[15];
945 			sprintf(filename, "credits%d.cel", nr);
946 			ImageFile3DO *creditsImage = new ImageFile3DO(filename, kImageFile3DOType_Cel);
947 			ImageFrame *creditsFrame = &(*creditsImage)[0];
948 			for (int i = 0; finished && i < 200 + creditsFrame->_height; i++) {
949 				_screen->SHblitFrom(_screen->_backBuffer2);
950 				_screen->SHtransBlitFrom(creditsFrame->_frame, Common::Point((320 - creditsFrame->_width) / 2, 200 - i));
951 				if (!_events->delay(70, true))
952 					finished = false;
953 			}
954 			delete creditsImage;
955 		}
956 	}
957 
958 	return finished;
959 }
960 
loadInventory()961 void ScalpelEngine::loadInventory() {
962 	ScalpelFixedText &fixedText = *(ScalpelFixedText *)_fixedText;
963 	Inventory &inv = *_inventory;
964 
965 	Common::String fixedText_Message    = fixedText.getText(kFixedText_InitInventory_Message);
966 	Common::String fixedText_HolmesCard = fixedText.getText(kFixedText_InitInventory_HolmesCard);
967 	Common::String fixedText_Tickets    = fixedText.getText(kFixedText_InitInventory_Tickets);
968 	Common::String fixedText_CuffLink   = fixedText.getText(kFixedText_InitInventory_CuffLink);
969 	Common::String fixedText_WireHook   = fixedText.getText(kFixedText_InitInventory_WireHook);
970 	Common::String fixedText_Note       = fixedText.getText(kFixedText_InitInventory_Note);
971 	Common::String fixedText_OpenWatch  = fixedText.getText(kFixedText_InitInventory_OpenWatch);
972 	Common::String fixedText_Paper      = fixedText.getText(kFixedText_InitInventory_Paper);
973 	Common::String fixedText_Letter     = fixedText.getText(kFixedText_InitInventory_Letter);
974 	Common::String fixedText_Tarot      = fixedText.getText(kFixedText_InitInventory_Tarot);
975 	Common::String fixedText_OrnateKey  = fixedText.getText(kFixedText_InitInventory_OrnateKey);
976 	Common::String fixedText_PawnTicket = fixedText.getText(kFixedText_InitInventory_PawnTicket);
977 
978 	// Initial inventory
979 	inv._holdings = 2;
980 	inv.push_back(InventoryItem(0,     "Message", fixedText_Message,    "_ITEM03A"));
981 	inv.push_back(InventoryItem(0, "Holmes Card", fixedText_HolmesCard, "_ITEM07A"));
982 
983 	// Hidden items
984 	inv.push_back(InventoryItem(95,  "Tickets",     fixedText_Tickets,    "_ITEM10A"));
985 	inv.push_back(InventoryItem(138, "Cuff Link",   fixedText_CuffLink,   "_ITEM04A"));
986 	inv.push_back(InventoryItem(138, "Wire Hook",   fixedText_WireHook,   "_ITEM06A"));
987 	inv.push_back(InventoryItem(150, "Note",        fixedText_Note,       "_ITEM13A"));
988 	inv.push_back(InventoryItem(481, "Open Watch",  fixedText_OpenWatch,  "_ITEM62A"));
989 	inv.push_back(InventoryItem(481, "Paper",       fixedText_Paper,      "_ITEM44A"));
990 	inv.push_back(InventoryItem(532, "Letter",      fixedText_Letter,     "_ITEM68A"));
991 	inv.push_back(InventoryItem(544, "Tarot",       fixedText_Tarot,      "_ITEM71A"));
992 	inv.push_back(InventoryItem(544, "Ornate Key",  fixedText_OrnateKey,  "_ITEM70A"));
993 	inv.push_back(InventoryItem(586, "Pawn ticket", fixedText_PawnTicket, "_ITEM16A"));
994 }
995 
showLBV(const Common::String & filename)996 void ScalpelEngine::showLBV(const Common::String &filename) {
997 	Common::SeekableReadStream *stream = _res->load(filename, "title.lib");
998 	ImageFile images(*stream);
999 	delete stream;
1000 
1001 	_screen->setPalette(images._palette);
1002 	_screen->_backBuffer1.SHblitFrom(images[0]);
1003 	_screen->verticalTransition();
1004 }
1005 
startScene()1006 void ScalpelEngine::startScene() {
1007 	if (_scene->_goToScene == OVERHEAD_MAP || _scene->_goToScene == OVERHEAD_MAP2) {
1008 		// Show the map
1009 		if (_music->_musicOn && _music->loadSong(100))
1010 			_music->startSong();
1011 
1012 		_scene->_goToScene = _map->show();
1013 
1014 		_music->freeSong();
1015 		_people->_savedPos = Common::Point(-1, -1);
1016 		_people->_savedPos._facing = -1;
1017 	}
1018 
1019 	// Some rooms are prologue cutscenes, rather than normal game scenes. These are:
1020 	//  2: Blackwood's capture
1021 	// 52: Rescuing Anna
1022 	// 53: Moorehead's death / subway train
1023 	// 55: Fade out and exit
1024 	// 70: Brumwell suicide
1025 	switch (_scene->_goToScene) {
1026 	case BLACKWOOD_CAPTURE:
1027 	case RESCUE_ANNA:
1028 	case MOOREHEAD_DEATH:
1029 	case BRUMWELL_SUICIDE:
1030 		if (_music->_musicOn && _music->loadSong(_scene->_goToScene))
1031 			_music->startSong();
1032 
1033 		switch (_scene->_goToScene) {
1034 		case BLACKWOOD_CAPTURE:
1035 			// Blackwood's capture
1036 			_res->addToCache("final2.vda", "epilogue.lib");
1037 			_res->addToCache("final2.vdx", "epilogue.lib");
1038 			_animation->play("final1", false, 1, 3, true, 2);
1039 			_animation->play("final2", false, 1, 0, false, 2);
1040 			break;
1041 
1042 		case RESCUE_ANNA:
1043 			// Rescuing Anna
1044 			_res->addToCache("finalr2.vda", "epilogue.lib");
1045 			_res->addToCache("finalr2.vdx", "epilogue.lib");
1046 			_res->addToCache("finale1.vda", "epilogue.lib");
1047 			_res->addToCache("finale1.vdx", "epilogue.lib");
1048 			_res->addToCache("finale2.vda", "epilogue.lib");
1049 			_res->addToCache("finale2.vdx", "epilogue.lib");
1050 			_res->addToCache("finale3.vda", "epilogue.lib");
1051 			_res->addToCache("finale3.vdx", "epilogue.lib");
1052 			_res->addToCache("finale4.vda", "EPILOG2.lib");
1053 			_res->addToCache("finale4.vdx", "EPILOG2.lib");
1054 
1055 			_animation->play("finalr1", false, 1, 3, true, 2);
1056 			_animation->play("finalr2", false, 1, 0, false, 2);
1057 
1058 			if (!_res->isInCache("finale2.vda")) {
1059 				// Finale file isn't cached
1060 				_res->addToCache("finale2.vda", "epilogue.lib");
1061 				_res->addToCache("finale2.vdx", "epilogue.lib");
1062 				_res->addToCache("finale3.vda", "epilogue.lib");
1063 				_res->addToCache("finale3.vdx", "epilogue.lib");
1064 				_res->addToCache("finale4.vda", "EPILOG2.lib");
1065 				_res->addToCache("finale4.vdx", "EPILOG2.lib");
1066 			}
1067 
1068 			_animation->play("finale1", false, 1, 0, false, 2);
1069 			_animation->play("finale2", false, 1, 0, false, 2);
1070 			_animation->play("finale3", false, 1, 0, false, 2);
1071 
1072 			_useEpilogue2 = true;
1073 			_animation->play("finale4", false, 1, 0, false, 2);
1074 			_useEpilogue2 = false;
1075 			break;
1076 
1077 		case MOOREHEAD_DEATH:
1078 			// Moorehead's death / subway train
1079 			_res->addToCache("SUBWAY2.vda", "epilogue.lib");
1080 			_res->addToCache("SUBWAY2.vdx", "epilogue.lib");
1081 			_res->addToCache("SUBWAY3.vda", "epilogue.lib");
1082 			_res->addToCache("SUBWAY3.vdx", "epilogue.lib");
1083 
1084 			_animation->play("SUBWAY1", false, 1, 3, true, 2);
1085 			_animation->play("SUBWAY2", false, 1, 0, false, 2);
1086 			_animation->play("SUBWAY3", false, 1, 0, false, 2);
1087 
1088 			// Set fading to direct fade temporary so the transition goes quickly.
1089 			_scene->_tempFadeStyle = _screen->_fadeStyle ? 257 : 256;
1090 			_screen->_fadeStyle = false;
1091 			break;
1092 
1093 		case BRUMWELL_SUICIDE:
1094 			// Brumwell suicide
1095 			_animation->play("suicid", false, 1, 3, true, 2);
1096 			break;
1097 		default:
1098 			break;
1099 		}
1100 
1101 		// Except for the Moorehead Murder scene, fade to black first
1102 		if (_scene->_goToScene != MOOREHEAD_DEATH) {
1103 			_events->wait(40);
1104 			_screen->fadeToBlack(3);
1105 		}
1106 
1107 		switch (_scene->_goToScene) {
1108 		case 52:
1109 			_scene->_goToScene = LAWYER_OFFICE;		// Go to the Lawyer's Office
1110 			_map->_bigPos = Common::Point(0, 0);	// Overland scroll position
1111 			_map->_overPos = Common::Point(22900 - 600, 9400 + 900);	// Overland position
1112 			_map->_oldCharPoint = LAWYER_OFFICE;
1113 			break;
1114 
1115 		case 53:
1116 			_scene->_goToScene = STATION;			// Go to St. Pancras Station
1117 			_map->_bigPos = Common::Point(0, 0);	// Overland scroll position
1118 			_map->_overPos = Common::Point(32500 - 600, 3000 + 900);	// Overland position
1119 			_map->_oldCharPoint = STATION;
1120 			break;
1121 
1122 		default:
1123 			_scene->_goToScene = BAKER_STREET;		// Back to Baker st.
1124 			_map->_bigPos = Common::Point(0, 0);	// Overland scroll position
1125 			_map->_overPos = Common::Point(14500 - 600, 8400 + 900);	// Overland position
1126 			_map->_oldCharPoint = BAKER_STREET;
1127 			break;
1128 		}
1129 
1130 		// Free any song from the previous scene
1131 		_music->freeSong();
1132 		break;
1133 
1134 	case EXIT_GAME:
1135 		// Exit game
1136 		_screen->fadeToBlack(3);
1137 		quitGame();
1138 		return;
1139 
1140 	default:
1141 		break;
1142 	}
1143 
1144 	_events->setCursor(ARROW);
1145 
1146 	if (_scene->_goToScene == 99) {
1147 		// Darts Board minigame
1148 		_darts->playDarts();
1149 		_mapResult = _scene->_goToScene = PUB_INTERIOR;
1150 	}
1151 
1152 	_mapResult = _scene->_goToScene;
1153 }
1154 
eraseBrumwellMirror()1155 void ScalpelEngine::eraseBrumwellMirror() {
1156 	Common::Point pt((*_people)[HOLMES]._position.x / FIXED_INT_MULTIPLIER, (*_people)[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
1157 
1158 	// If player is in range of the mirror, then restore background from the secondary back buffer
1159 	if (Common::Rect(70, 100, 200, 200).contains(pt)) {
1160 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(137, 18),
1161 			Common::Rect(137, 18, 184, 74));
1162 	}
1163 }
1164 
doBrumwellMirror()1165 void ScalpelEngine::doBrumwellMirror() {
1166 	People &people = *_people;
1167 	Person &player = people[HOLMES];
1168 
1169 	Common::Point pt((*_people)[HOLMES]._position.x / FIXED_INT_MULTIPLIER, (*_people)[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
1170 	int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
1171 		player._walkSequences[player._sequenceNumber][0] - 2;
1172 
1173 	switch ((*_people)[HOLMES]._sequenceNumber) {
1174 	case WALK_DOWN:
1175 		frameNum -= 7;
1176 		break;
1177 	case WALK_UP:
1178 		frameNum += 7;
1179 		break;
1180 	case WALK_DOWNRIGHT:
1181 		frameNum += 7;
1182 		break;
1183 	case WALK_UPRIGHT:
1184 		frameNum -= 7;
1185 		break;
1186 	case WALK_DOWNLEFT:
1187 		frameNum += 7;
1188 		break;
1189 	case WALK_UPLEFT:
1190 		frameNum -= 7;
1191 		break;
1192 	case STOP_DOWN:
1193 		frameNum -= 10;
1194 		break;
1195 	case STOP_UP:
1196 		frameNum += 11;
1197 		break;
1198 	case STOP_DOWNRIGHT:
1199 		frameNum -= 15;
1200 		break;
1201 	case STOP_DOWNLEFT:
1202 		frameNum -= 15;
1203 		break;
1204 	case STOP_UPRIGHT:
1205 	case STOP_UPLEFT:
1206 		frameNum += 15;
1207 		if (frameNum == 55)
1208 			frameNum = 54;
1209 		break;
1210 	default:
1211 		break;
1212 	}
1213 
1214 	if (Common::Rect(80, 100, 145, 138).contains(pt)) {
1215 		// Get the frame of Sherlock to draw
1216 		ImageFrame &imageFrame = (*people[HOLMES]._images)[frameNum];
1217 
1218 		// Draw the mirror image of Holmes
1219 		bool flipped = people[HOLMES]._sequenceNumber == WALK_LEFT || people[HOLMES]._sequenceNumber == STOP_LEFT
1220 			|| people[HOLMES]._sequenceNumber == WALK_UPRIGHT || people[HOLMES]._sequenceNumber == STOP_UPRIGHT
1221 			|| people[HOLMES]._sequenceNumber == WALK_DOWNLEFT || people[HOLMES]._sequenceNumber == STOP_DOWNLEFT;
1222 		_screen->_backBuffer1.SHtransBlitFrom(imageFrame, pt + Common::Point(38, -imageFrame._frame.h - 25), flipped);
1223 
1224 		// Redraw the mirror borders to prevent the drawn image of Holmes from appearing outside of the mirror
1225 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(114, 18),
1226 			Common::Rect(114, 18, 137, 114));
1227 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(137, 70),
1228 			Common::Rect(137, 70, 142, 114));
1229 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(142, 71),
1230 			Common::Rect(142, 71, 159, 114));
1231 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(159, 72),
1232 			Common::Rect(159, 72, 170, 116));
1233 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(170, 73),
1234 			Common::Rect(170, 73, 184, 114));
1235 		_screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(184, 18),
1236 			Common::Rect(184, 18, 212, 114));
1237 	}
1238 }
1239 
flushBrumwellMirror()1240 void ScalpelEngine::flushBrumwellMirror() {
1241 	Common::Point pt((*_people)[HOLMES]._position.x / FIXED_INT_MULTIPLIER, (*_people)[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
1242 
1243 	// If player is in range of the mirror, then draw the entire mirror area to the screen
1244 	if (Common::Rect(70, 100, 200, 200).contains(pt))
1245 		_screen->slamArea(137, 18, 47, 56);
1246 }
1247 
1248 
showScummVMSaveDialog()1249 void ScalpelEngine::showScummVMSaveDialog() {
1250 	GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
1251 
1252 	int slot = dialog->runModalWithCurrentTarget();
1253 	if (slot >= 0) {
1254 		Common::String desc = dialog->getResultString();
1255 
1256 		saveGameState(slot, desc);
1257 	}
1258 
1259 	delete dialog;
1260 }
1261 
showScummVMRestoreDialog()1262 void ScalpelEngine::showScummVMRestoreDialog() {
1263 	GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
1264 
1265 	int slot = dialog->runModalWithCurrentTarget();
1266 	if (slot >= 0) {
1267 		loadGameState(slot);
1268 	}
1269 
1270 	delete dialog;
1271 }
1272 
play3doMovie(const Common::String & filename,const Common::Point & pos,bool isPortrait)1273 bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::Point &pos, bool isPortrait) {
1274 	Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
1275 	Video::ThreeDOMovieDecoder *videoDecoder = new Video::ThreeDOMovieDecoder();
1276 	Graphics::ManagedSurface tempSurface;
1277 
1278 	Common::Point framePos(pos.x, pos.y);
1279 	ImageFile3DO *frameImageFile = nullptr;
1280 	ImageFrame *frameImage = nullptr;
1281 	bool frameShown = false;
1282 
1283 	if (!videoDecoder->loadFile(filename)) {
1284 		warning("Scalpel3DOMoviePlay: could not open '%s'", filename.c_str());
1285 		return false;
1286 	}
1287 
1288 	bool halfSize = isPortrait && !_isScreenDoubled;
1289 	if (isPortrait) {
1290 		// only for portrait videos, not for EA intro logo and such
1291 		if ((framePos.x >= 8) && (framePos.y >= 8)) { // safety check
1292 			framePos.x -= 8;
1293 			framePos.y -= 8; // frame is 8 pixels on left + top, and 7 pixels on right + bottom
1294 		}
1295 
1296 		frameImageFile = new ImageFile3DO("vidframe.cel", kImageFile3DOType_Cel);
1297 		frameImage = &(*frameImageFile)[0];
1298 	}
1299 
1300 	bool skipVideo = false;
1301 	//byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel;
1302 	uint16 width = videoDecoder->getWidth();
1303 	uint16 height = videoDecoder->getHeight();
1304 	//uint16 pitch = videoDecoder->getWidth() * bytesPerPixel;
1305 
1306 	_events->clearEvents();
1307 	videoDecoder->start();
1308 
1309 	// If we're to show the movie at half-size, we'll need a temporary intermediate surface
1310 	if (halfSize)
1311 		tempSurface.create(width / 2, height / 2);
1312 
1313 	while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
1314 		if (videoDecoder->needsUpdate()) {
1315 			const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
1316 
1317 			if (frame) {
1318 				if (halfSize) {
1319 					// movies are 152 x 200
1320 
1321 					// Downscale, but calculate average color out of 4 pixels and put that average into the target pixel
1322 					// TODO: 3DO actually did pixel weighting, exact details about this are unknown
1323 					// It's also unknown what 3DO exactly did for interpolation
1324 					// and it's also unknown atm if the CinePak videos contained pixel weighting information
1325 
1326 					if ((height & 1) || (width & 1)) {
1327 						error("Scalpel3DOMoviePlay: critical error, half-size requested on video with uneven height/width");
1328 					}
1329 
1330 					for (int downscaleY = 0; downscaleY < height / 2; downscaleY++) {
1331 						const uint16 *downscaleSource1Ptr = (const uint16 *)frame->getBasePtr(0, downscaleY * 2);
1332 						const uint16 *downscaleSource2Ptr = (const uint16 *)frame->getBasePtr(0, (downscaleY * 2) + 1);
1333 						uint16 *downscaleTargetPtr = (uint16 *)tempSurface.getBasePtr(0, downscaleY);
1334 
1335 						for (int downscaleX = 0; downscaleX < width / 2; downscaleX++) {
1336 							// get 4 pixel colors
1337 							uint16 downscaleColor = *downscaleSource1Ptr;
1338 							uint32 downscaleRed = downscaleColor >> 11; // 5 bits
1339 							uint32 downscaleGreen = (downscaleColor >> 5) & 0x3f; // 6 bits
1340 							uint32 downscaleBlue = downscaleColor & 0x1f;
1341 
1342 							downscaleSource1Ptr++;
1343 							downscaleColor = *downscaleSource1Ptr;
1344 							downscaleRed += downscaleColor >> 11;
1345 							downscaleGreen += (downscaleColor >> 5) & 0x3f;
1346 							downscaleBlue += downscaleColor & 0x1f;
1347 
1348 							downscaleColor = *downscaleSource2Ptr;
1349 							downscaleRed += downscaleColor >> 11;
1350 							downscaleGreen += (downscaleColor >> 5) & 0x3f;
1351 							downscaleBlue += downscaleColor & 0x1f;
1352 
1353 							downscaleSource2Ptr++;
1354 							downscaleColor = *downscaleSource2Ptr;
1355 							downscaleRed += downscaleColor >> 11;
1356 							downscaleGreen += (downscaleColor >> 5) & 0x3f;
1357 							downscaleBlue += downscaleColor & 0x1f;
1358 
1359 							// Divide colors by 4, so that we get the average
1360 							downscaleRed = downscaleRed >> 2;
1361 							downscaleGreen = downscaleGreen >> 2;
1362 							downscaleBlue = downscaleBlue >> 2;
1363 
1364 							// write new color to target pixel
1365 							downscaleColor = (downscaleRed << 11) | (downscaleGreen << 5) | downscaleBlue;
1366 							*downscaleTargetPtr = downscaleColor;
1367 
1368 							downscaleSource1Ptr++;
1369 							downscaleSource2Ptr++;
1370 							downscaleTargetPtr++;
1371 						}
1372 					}
1373 
1374 					// Point the drawing frame to the temporary surface
1375 					frame = &tempSurface.rawSurface();
1376 				}
1377 
1378 				if (isPortrait && !frameShown) {
1379 					// Draw the frame (not the frame of the video, but a frame around the video) itself
1380 					_screen->SHtransBlitFrom(frameImage->_frame, framePos);
1381 					frameShown = true;
1382 				}
1383 
1384 				if (isPortrait && !halfSize) {
1385 					screen.rawBlitFrom(*frame, Common::Point(pos.x * 2, pos.y * 2));
1386 				} else {
1387 					_screen->SHblitFrom(*frame, pos);
1388 				}
1389 
1390 				_screen->update();
1391 			}
1392 		}
1393 
1394 		_events->pollEventsAndWait();
1395 		_events->setButtonState();
1396 
1397 		if (_events->kbHit()) {
1398 			Common::KeyState keyState = _events->getKey();
1399 			if (keyState.keycode == Common::KEYCODE_ESCAPE)
1400 				skipVideo = true;
1401 		} else if (_events->_pressed) {
1402 			skipVideo = true;
1403 		}
1404 	}
1405 
1406 	if (halfSize)
1407 		tempSurface.free();
1408 
1409 	videoDecoder->close();
1410 	delete videoDecoder;
1411 
1412 	if (isPortrait) {
1413 		delete frameImageFile;
1414 	}
1415 
1416 	// Restore scene
1417 	screen._backBuffer1.SHblitFrom(screen._backBuffer2);
1418 	_scene->updateBackground();
1419 	screen.slamArea(0, 0, screen.width(), CONTROLS_Y);
1420 
1421 	return !skipVideo;
1422 }
1423 
1424 } // End of namespace Scalpel
1425 
1426 } // End of namespace Sherlock
1427