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  * Additional copyright for this file:
8  * Copyright (C) 1995 Presto Studios, Inc.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  */
25 
26 #include "buried/biochip_right.h"
27 #include "buried/buried.h"
28 #include "buried/gameui.h"
29 #include "buried/graphics.h"
30 #include "buried/invdata.h"
31 #include "buried/inventory_window.h"
32 #include "buried/navarrow.h"
33 #include "buried/resources.h"
34 #include "buried/scene_view.h"
35 #include "buried/sound.h"
36 #include "buried/environ/scene_base.h"
37 #include "buried/environ/scene_common.h"
38 
39 #include "common/system.h"
40 #include "graphics/font.h"
41 
42 namespace Buried {
43 
44 enum {
45 	GC_AIHW_STARTING_VALUE = 100,
46 	GC_AI_OT_WALK_DECREMENT = 2,
47 	GC_AI_OT_TURN_DECREMENT = 1,
48 	GC_AI_OT_WAIT_DECREMENT = 1,
49 	GC_AI_OT_WAIT_TIME_PERIOD = 10000
50 };
51 
52 class BaseOxygenTimer : public SceneBase {
53 public:
54 	BaseOxygenTimer(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
55 	virtual int postEnterRoom(Window *viewWindow, const Location &priorLocation);
56 	virtual int preExitRoom(Window *viewWindow, const Location &priorLocation);
57 	virtual int timerCallback(Window *viewWindow);
58 
59 protected:
60 	uint32 _entryStartTime;
61 	int _deathID;
62 	bool _jumped;
63 };
64 
BaseOxygenTimer(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)65 BaseOxygenTimer::BaseOxygenTimer(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
66 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
67 	_deathID = 41;
68 	_jumped = false;
69 	_entryStartTime = g_system->getMillis();
70 }
71 
postEnterRoom(Window * viewWindow,const Location & priorLocation)72 int BaseOxygenTimer::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
73 	_entryStartTime = g_system->getMillis();
74 	return SC_TRUE;
75 }
76 
preExitRoom(Window * viewWindow,const Location & newLocation)77 int BaseOxygenTimer::preExitRoom(Window *viewWindow, const Location &newLocation) {
78 	// NOTE: v1.01 used 25% as the low threshold instead of ~14.2%
79 
80 	if (newLocation.timeZone == -2) {
81 		_jumped = true;
82 		return SC_TRUE;
83 	}
84 
85 	int currentValue = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer;
86 
87 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 0) {
88 		if (_staticData.location.node != newLocation.node) {
89 			if (currentValue <= GC_AI_OT_WALK_DECREMENT) {
90 				if (newLocation.timeZone != -2)
91 					((SceneViewWindow *)viewWindow)->showDeathScene(_deathID);
92 				return SC_DEATH;
93 			} else {
94 				currentValue -= GC_AI_OT_WALK_DECREMENT;
95 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = currentValue;
96 
97 				if (currentValue < GC_AIHW_STARTING_VALUE / 7 || (currentValue % (GC_AIHW_STARTING_VALUE / 10)) == 0) {
98 					if (currentValue < GC_AIHW_STARTING_VALUE / 7) {
99 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_LOW);
100 						assert(!oxygenMessage.empty());
101 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
102 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
103 					} else {
104 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_NORM);
105 						assert(!oxygenMessage.empty());
106 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
107 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
108 					}
109 				}
110 			}
111 		} else {
112 			if (currentValue <= GC_AI_OT_TURN_DECREMENT) {
113 				if (newLocation.timeZone != -2)
114 					((SceneViewWindow *)viewWindow)->showDeathScene(_deathID);
115 				return SC_DEATH;
116 			} else {
117 				currentValue -= GC_AI_OT_TURN_DECREMENT;
118 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = currentValue;
119 
120 				if (currentValue < GC_AIHW_STARTING_VALUE / 7 || (currentValue % (GC_AIHW_STARTING_VALUE / 10)) == 0) {
121 					if (currentValue < GC_AIHW_STARTING_VALUE / 7) {
122 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_LOW);
123 						assert(!oxygenMessage.empty());
124 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
125 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
126 					} else {
127 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_NORM);
128 						assert(!oxygenMessage.empty());
129 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
130 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
131 					}
132 				}
133 			}
134 		}
135 	}
136 
137 	return SC_TRUE;
138 }
139 
timerCallback(Window * viewWindow)140 int BaseOxygenTimer::timerCallback(Window *viewWindow) {
141 	// NOTE: Earlier versions (1.01) used 25% as the low threshold instead of
142 	// ~14.2%
143 
144 	if (_jumped)
145 		return SC_TRUE;
146 
147 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 0) {
148 		if ((g_system->getMillis() - _entryStartTime) >= GC_AI_OT_WAIT_TIME_PERIOD) {
149 			int currentValue = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer;
150 
151 			if (currentValue <= GC_AI_OT_WAIT_DECREMENT) {
152 				((SceneViewWindow *)viewWindow)->showDeathScene(_deathID);
153 				return SC_DEATH;
154 			} else {
155 				currentValue -= GC_AI_OT_WAIT_DECREMENT;
156 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = currentValue;
157 
158 				if (currentValue < GC_AIHW_STARTING_VALUE / 7 || (currentValue % (GC_AIHW_STARTING_VALUE / 10)) == 0) {
159 					if (currentValue < GC_AIHW_STARTING_VALUE / 7) {
160 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_LOW);
161 						assert(!oxygenMessage.empty());
162 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
163 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
164 					} else {
165 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_NORM);
166 						assert(!oxygenMessage.empty());
167 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
168 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
169 					}
170 				}
171 			}
172 
173 			_entryStartTime = g_system->getMillis();
174 		}
175 	}
176 
177 	return SC_TRUE;
178 }
179 
180 class SpaceDoorTimer : public BaseOxygenTimer {
181 public:
182 	SpaceDoorTimer(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
183 			int left = -1, int top = -1, int right = -1, int bottom = -1, int openFrame = -1, int closedFrame = -1, int depth = -1,
184 			int transitionType = -1, int transitionData = -1, int transitionStartFrame = -1, int transitionLength = -1,
185 			int doorFlag = -1, int doorFlagValue = 0);
186 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation);
187 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
188 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
189 
190 private:
191 	bool _clicked;
192 	Common::Rect _clickable;
193 	DestinationScene _destData;
194 	int _openFrame;
195 	int _closedFrame;
196 	int _doorFlag;
197 	int _doorFlagValue;
198 };
199 
SpaceDoorTimer(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int left,int top,int right,int bottom,int openFrame,int closedFrame,int depth,int transitionType,int transitionData,int transitionStartFrame,int transitionLength,int doorFlag,int doorFlagValue)200 SpaceDoorTimer::SpaceDoorTimer(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
201 		int left, int top, int right, int bottom, int openFrame, int closedFrame, int depth,
202 		int transitionType, int transitionData, int transitionStartFrame, int transitionLength,
203 		int doorFlag, int doorFlagValue) :
204 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
205 	_clicked = false;
206 	_openFrame = openFrame;
207 	_closedFrame = closedFrame;
208 	_doorFlag = doorFlag;
209 	_doorFlagValue = doorFlagValue;
210 	_clickable = Common::Rect(left, top, right, bottom);
211 	_destData.destinationScene = _staticData.location;
212 	_destData.destinationScene.depth = depth;
213 	_destData.transitionType = transitionType;
214 	_destData.transitionData = transitionData;
215 	_destData.transitionStartFrame = transitionStartFrame;
216 	_destData.transitionLength = transitionLength;
217 }
218 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)219 int SpaceDoorTimer::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
220 	if (_clickable.contains(pointLocation)) {
221 		_clicked = true;
222 		return SC_TRUE;
223 	}
224 
225 	return SC_FALSE;
226 }
227 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)228 int SpaceDoorTimer::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
229 	if (_clicked) {
230 		// If we are facing the habitat wing death door in walkthrough mode,
231 		// keep it locked.
232 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1 &&
233 				_staticData.location.timeZone == 6 && _staticData.location.environment == 1 &&
234 				_staticData.location.node == 3 && _staticData.location.facing == 1 &&
235 				_staticData.location.orientation == 2 && _staticData.location.depth == 0) {
236 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 12));
237 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13));
238 			_clicked = false;
239 			return SC_TRUE;
240 		}
241 
242 		// If we are facing the scanning room door and we have Arthur, automatically recall
243 		// to the future apartment
244 		if (_staticData.location.timeZone == 6 && _staticData.location.environment == 3 &&
245 				_staticData.location.node == 9 && _staticData.location.facing == 0 &&
246 				_staticData.location.orientation == 0 && _staticData.location.depth == 0 &&
247 				((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI)) {
248 			((SceneViewWindow *)viewWindow)->timeSuitJump(4);
249 			return SC_TRUE;
250 		}
251 
252 		if (_doorFlag < 0 || ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_doorFlag) == _doorFlagValue) {
253 			// Change the still frame to the new one
254 			if (_openFrame >= 0) {
255 				_staticData.navFrameIndex = _openFrame;
256 				viewWindow->invalidateWindow(false);
257 				_vm->_sound->playSynchronousSoundEffect("BITDATA/AILAB/AI_LOCK.BTA"); // Broken in 1.01
258 			}
259 
260 			((SceneViewWindow *)viewWindow)->moveToDestination(_destData);
261 		} else {
262 			// Display the closed frame
263 			if (_closedFrame >= 0) {
264 				int oldFrame = _staticData.navFrameIndex;
265 				_staticData.navFrameIndex = _closedFrame;
266 				viewWindow->invalidateWindow(false);
267 
268 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 12));
269 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13));
270 
271 				_staticData.navFrameIndex = oldFrame;
272 				viewWindow->invalidateWindow(false);
273 			}
274 		}
275 
276 		_clicked = false;
277 		return SC_TRUE;
278 	}
279 
280 	return SC_FALSE;
281 }
282 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)283 int SpaceDoorTimer::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
284 	// If we are in walkthrough mode and are at the death door in the habitat wing,
285 	// don't allow you to open the door.
286 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1 &&
287 			_staticData.location.timeZone == 6 && _staticData.location.environment == 1 &&
288 			_staticData.location.node == 3 && _staticData.location.facing == 1 &&
289 			_staticData.location.orientation == 2 && _staticData.location.depth == 0) {
290 		return kCursorArrow;
291 	}
292 
293 	if (_clickable.contains(pointLocation))
294 		return kCursorFinger;
295 
296 	return kCursorArrow;
297 }
298 
299 class UseCheeseGirlPropellant : public BaseOxygenTimer {
300 public:
301 	UseCheeseGirlPropellant(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
302 	int postEnterRoom(Window *viewWindow, const Location &priorLocation) override;
303 	int draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) override;
304 	int droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) override;
305 
306 private:
307 	Common::Rect _badPos;
308 };
309 
UseCheeseGirlPropellant(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)310 UseCheeseGirlPropellant::UseCheeseGirlPropellant(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
311 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
312 	_deathID = 40;
313 	_badPos = Common::Rect(144, 0, 288, 189);
314 }
315 
postEnterRoom(Window * viewWindow,const Location & priorLocation)316 int UseCheeseGirlPropellant::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
317 	// Display text message about zero-g and no propulsion and oxygen level
318 	((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_AI_IS_JUMP_IN_TEXT));
319 	return SC_TRUE;
320 }
321 
draggingItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)322 int UseCheeseGirlPropellant::draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
323 	if (itemID == kItemCheeseGirl && !_badPos.contains(pointLocation))
324 		return 1;
325 
326 	return 0;
327 }
328 
droppedItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)329 int UseCheeseGirlPropellant::droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
330 	if (itemID == kItemCheeseGirl) {
331 		if (_badPos.contains(pointLocation)) {
332 			DestinationScene destData;
333 			destData.destinationScene.timeZone = 6;
334 			destData.destinationScene.environment = 10;
335 			destData.destinationScene.node = 1;
336 			destData.destinationScene.facing = 0;
337 			destData.destinationScene.orientation = 0;
338 			destData.destinationScene.depth = 0;
339 			destData.transitionType = TRANSITION_VIDEO;
340 			destData.transitionData = 1;
341 			destData.transitionStartFrame = -1;
342 			destData.transitionLength = -1;
343 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
344 		} else {
345 			DestinationScene destData;
346 			destData.destinationScene.timeZone = 6;
347 			destData.destinationScene.environment = 1;
348 			destData.destinationScene.node = 1;
349 			destData.destinationScene.facing = 1;
350 			destData.destinationScene.orientation = 2;
351 			destData.destinationScene.depth = 0;
352 			destData.transitionType = TRANSITION_VIDEO;
353 			destData.transitionData = 0;
354 			destData.transitionStartFrame = -1;
355 			destData.transitionLength = -1;
356 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
357 		}
358 
359 		return SIC_ACCEPT;
360 	}
361 
362 	return SIC_REJECT;
363 }
364 
365 class PlayArthurOffsetTimed : public BaseOxygenTimer {
366 public:
367 	PlayArthurOffsetTimed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
368 			int stingerVolume = 127, int lastStingerFlagOffset = -1, int effectIDFlagOffset = -1, int firstStingerFileID = -1,
369 			int lastStingerFileID = -1, int stingerDelay = 1);
370 	int postEnterRoom(Window *viewWindow, const Location &priorLocation) override;
371 
372 private:
373 	int _stingerVolume;
374 	int _lastStingerFlagOffset;
375 	int _effectIDFlagOffset;
376 	int _firstStingerFileID;
377 	int _lastStingerFileID;
378 	int _stingerDelay;
379 	//int _timerFlagOffset;
380 };
381 
PlayArthurOffsetTimed(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int stingerVolume,int lastStingerFlagOffset,int effectIDFlagOffset,int firstStingerFileID,int lastStingerFileID,int stingerDelay)382 PlayArthurOffsetTimed::PlayArthurOffsetTimed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
383 		int stingerVolume, int lastStingerFlagOffset, int effectIDFlagOffset, int firstStingerFileID,
384 		int lastStingerFileID, int stingerDelay) :
385 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
386 	_stingerVolume = stingerVolume;
387 	_lastStingerFlagOffset = lastStingerFlagOffset;
388 	_effectIDFlagOffset = effectIDFlagOffset;
389 	_firstStingerFileID = firstStingerFileID;
390 	_lastStingerFileID = lastStingerFileID;
391 	_stingerDelay = stingerDelay;
392 }
393 
postEnterRoom(Window * viewWindow,const Location & priorLocation)394 int PlayArthurOffsetTimed::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
395 	if (_effectIDFlagOffset >= 0 && (priorLocation.node != _staticData.location.node || priorLocation.environment != _staticData.location.environment)) {
396 		byte effectID = ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_effectIDFlagOffset);
397 
398 		if (!_vm->_sound->isSoundEffectPlaying(effectID - 1)) {
399 			int lastStinger = ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_lastStingerFlagOffset) + 1;
400 
401 			if ((lastStinger % _stingerDelay) == 0) {
402 				if (lastStinger <= (_lastStingerFileID - _firstStingerFileID) * _stingerDelay) {
403 					int fileNameIndex = _vm->computeFileNameResourceID(_staticData.location.timeZone, _staticData.location.environment, _firstStingerFileID + lastStinger / _stingerDelay - 1);
404 					byte newStingerID = 0;
405 
406 					if (((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI)) {
407 						newStingerID = _vm->_sound->playSoundEffect(_vm->getFilePath(fileNameIndex), _stingerVolume / 2, false, true) + 1;
408 						byte &lastArthurComment = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiHWLastCommentPlayed;
409 
410 						if ((lastStinger / 2) != 0 && lastArthurComment < 4) {
411 							lastArthurComment++;
412 							_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 10, lastArthurComment + 5), 128, false, true);
413 						}
414 					} else {
415 						newStingerID = _vm->_sound->playSoundEffect(_vm->getFilePath(fileNameIndex), _stingerVolume, false, true) + 1;
416 					}
417 
418 					((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_effectIDFlagOffset, newStingerID);
419 					((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_lastStingerFlagOffset, lastStinger);
420 				}
421 			} else {
422 				((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_effectIDFlagOffset, 0xFF);
423 				((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_lastStingerFlagOffset, lastStinger);
424 			}
425 		}
426 	}
427 
428 	return SC_TRUE;
429 }
430 
431 class HabitatWingIceteroidDoor : public BaseOxygenTimer {
432 public:
433 	HabitatWingIceteroidDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
434 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
435 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
436 
437 private:
438 	Common::Rect _doorHandle;
439 };
440 
HabitatWingIceteroidDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)441 HabitatWingIceteroidDoor::HabitatWingIceteroidDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
442 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
443 	_doorHandle = Common::Rect(122, 48, 246, 172);
444 }
445 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)446 int HabitatWingIceteroidDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
447 	if (_doorHandle.contains(pointLocation)) {
448 		if (((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI)) {
449 			if (((SceneViewWindow * )viewWindow)->getGlobalFlags().aiHWIceDoorUnlocked == 0) {
450 				// Move to depth one (door open)
451 				DestinationScene destData;
452 				destData.destinationScene = _staticData.location;
453 				destData.destinationScene.depth = 1;
454 				destData.transitionType = TRANSITION_VIDEO;
455 				destData.transitionData = 6;
456 				destData.transitionStartFrame = -1;
457 				destData.transitionLength = -1;
458 				((SceneViewWindow *)viewWindow)->moveToDestination(destData);
459 
460 				// Add the explosive charge to your inventory
461 				((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->addItem(kItemExplosiveCharge);
462 
463 				// Set the door unlocked flag
464 				((SceneViewWindow * )viewWindow)->getGlobalFlags().aiHWIceDoorUnlocked = 1;
465 			} else {
466 				// Move to depth one (door open)
467 				DestinationScene destData;
468 				destData.destinationScene = _staticData.location;
469 				destData.destinationScene.depth = 1;
470 				destData.transitionType = TRANSITION_VIDEO;
471 				destData.transitionData = 3;
472 				destData.transitionStartFrame = -1;
473 				destData.transitionLength = -1;
474 				((SceneViewWindow *)viewWindow)->moveToDestination(destData);
475 			}
476 		} else {
477 			// Play the closed door video clip
478 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(7);
479 		}
480 
481 		return SC_TRUE;
482 	}
483 
484 	return SC_FALSE;
485 }
486 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)487 int HabitatWingIceteroidDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
488 	if (_doorHandle.contains(pointLocation))
489 		return kCursorFinger;
490 
491 	return kCursorArrow;
492 }
493 
494 class IceteroidPodTimed : public BaseOxygenTimer {
495 public:
496 	IceteroidPodTimed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
497 			int left = -1, int top = -1, int right = -1, int bottom = -1, int animID = -1, int timeZone = -1,
498 			int environment = -1, int node = -1, int facing = -1, int orientation = -1, int depth = -1);
499 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
500 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
501 
502 private:
503 	Common::Rect _engageButton;
504 	DestinationScene _clickDestination;
505 };
506 
IceteroidPodTimed(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int left,int top,int right,int bottom,int animID,int timeZone,int environment,int node,int facing,int orientation,int depth)507 IceteroidPodTimed::IceteroidPodTimed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
508 			int left, int top, int right, int bottom, int animID, int timeZone,
509 			int environment, int node, int facing, int orientation, int depth) :
510 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
511 	_engageButton = Common::Rect(left, top, right, bottom);
512 	_clickDestination.destinationScene = Location(timeZone, environment, node, facing, orientation, depth);
513 	_clickDestination.transitionType = TRANSITION_VIDEO;
514 	_clickDestination.transitionData = animID;
515 	_clickDestination.transitionStartFrame = -1;
516 	_clickDestination.transitionLength = -1;
517 }
518 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)519 int IceteroidPodTimed::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
520 	if (_engageButton.contains(pointLocation)) // Make it so!
521 		((SceneViewWindow *)viewWindow)->moveToDestination(_clickDestination);
522 
523 	return SC_FALSE;
524 }
525 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)526 int IceteroidPodTimed::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
527 	if (_engageButton.contains(pointLocation))
528 		return kCursorFinger;
529 
530 	return kCursorArrow;
531 }
532 
533 class IceteroidElevatorExtremeControls : public BaseOxygenTimer {
534 public:
535 	IceteroidElevatorExtremeControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
536 			int upTimeZone = -1, int upEnvironment = -1, int upNode = -1, int upFacing = -1, int upOrientation = -1, int upDepth = -1, int upAnimID = -1,
537 			int downTimeZone = -1, int downEnvironment = -1, int downNode = -1, int downFacing = -1, int downOrientation = -1, int downDepth = -1, int downAnimID = -1);
538 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
539 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
540 
541 private:
542 	Common::Rect _up, _down;
543 	DestinationScene _upDestination;
544 	DestinationScene _downDestination;
545 };
546 
IceteroidElevatorExtremeControls(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int upTimeZone,int upEnvironment,int upNode,int upFacing,int upOrientation,int upDepth,int upAnimID,int downTimeZone,int downEnvironment,int downNode,int downFacing,int downOrientation,int downDepth,int downAnimID)547 IceteroidElevatorExtremeControls::IceteroidElevatorExtremeControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
548 		int upTimeZone, int upEnvironment, int upNode, int upFacing, int upOrientation, int upDepth, int upAnimID,
549 		int downTimeZone, int downEnvironment, int downNode, int downFacing, int downOrientation, int downDepth, int downAnimID) :
550 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
551 	_up = Common::Rect(192, 123, 212, 143);
552 	_down = Common::Rect(192, 148, 212, 168);
553 
554 	_upDestination.destinationScene = Location(upTimeZone, upEnvironment, upNode, upFacing, upOrientation, upDepth);
555 	_upDestination.transitionType = TRANSITION_VIDEO;
556 	_upDestination.transitionData = upAnimID;
557 	_upDestination.transitionStartFrame = -1;
558 	_upDestination.transitionLength = -1;
559 
560 	_downDestination.destinationScene = Location(downTimeZone, downEnvironment, downNode, downFacing, downOrientation, downDepth);
561 	_downDestination.transitionType = TRANSITION_VIDEO;
562 	_downDestination.transitionData = downAnimID;
563 	_downDestination.transitionStartFrame = -1;
564 	_downDestination.transitionLength = -1;
565 }
566 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)567 int IceteroidElevatorExtremeControls::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
568 	if (_up.contains(pointLocation) && _upDestination.transitionData >= 0) {
569 		((SceneViewWindow *)viewWindow)->moveToDestination(_upDestination);
570 		return SC_TRUE;
571 	}
572 
573 	if (_down.contains(pointLocation) && _downDestination.transitionData >= 0) {
574 		((SceneViewWindow *)viewWindow)->moveToDestination(_downDestination);
575 		return SC_TRUE;
576 	}
577 
578 	return SC_FALSE;
579 }
580 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)581 int IceteroidElevatorExtremeControls::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
582 	if (_up.contains(pointLocation) && _upDestination.transitionData >= 0)
583 		return kCursorFinger;
584 
585 	if (_down.contains(pointLocation) && _downDestination.transitionData >= 0)
586 		return kCursorFinger;
587 
588 	return kCursorArrow;
589 }
590 
591 class IceteroidZoomInMineControls : public BaseOxygenTimer {
592 public:
593 	IceteroidZoomInMineControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
594 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
595 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
596 
597 private:
598 	Common::Rect _controls;
599 };
600 
IceteroidZoomInMineControls(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)601 IceteroidZoomInMineControls::IceteroidZoomInMineControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
602 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
603 	_controls = Common::Rect(152, 76, 180, 114);
604 }
605 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)606 int IceteroidZoomInMineControls::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
607 	if (_controls.contains(pointLocation)) {
608 		DestinationScene destinationData;
609 		destinationData.destinationScene = _staticData.location;
610 		destinationData.destinationScene.depth = 1;
611 		destinationData.transitionType = TRANSITION_VIDEO;
612 		destinationData.transitionData = 8;
613 		destinationData.transitionStartFrame = -1;
614 		destinationData.transitionLength = -1;
615 		((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
616 		return SC_TRUE;
617 	}
618 
619 	return SC_FALSE;
620 }
621 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)622 int IceteroidZoomInMineControls::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
623 	if (_controls.contains(pointLocation))
624 		return kCursorMagnifyingGlass;
625 
626 	return kCursorArrow;
627 }
628 
629 class IceteroidMineControls : public BaseOxygenTimer {
630 public:
631 	IceteroidMineControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
632 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
633 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
634 
635 private:
636 	Common::Rect _mineButton, _makeOxygenButton;
637 };
638 
IceteroidMineControls(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)639 IceteroidMineControls::IceteroidMineControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
640 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
641 	_mineButton = Common::Rect(190, 40, 204, 128);
642 	_makeOxygenButton = Common::Rect(205, 40, 220, 128);
643 }
644 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)645 int IceteroidMineControls::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
646 	if (_mineButton.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiIceMined < 255) {
647 		TempCursorChange cursorChange(kCursorWait);
648 
649 		// Update the amount of ice mined
650 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiIceMined++;
651 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICUsedMiningControls = 1;
652 
653 		// Transition to another scene, using the video clip
654 		DestinationScene destinationData;
655 		destinationData.destinationScene = _staticData.location;
656 		destinationData.destinationScene.facing = 2;
657 		destinationData.destinationScene.orientation = 2;
658 		destinationData.destinationScene.depth = 0;
659 		destinationData.transitionType = TRANSITION_VIDEO;
660 		destinationData.transitionData = 10;
661 		destinationData.transitionStartFrame = -1;
662 		destinationData.transitionLength = -1;
663 		((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
664 
665 		return SC_TRUE;
666 	}
667 
668 	if (_makeOxygenButton.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiIceMined > 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves < 255) {
669 		int currentStillFrame = _staticData.navFrameIndex;
670 		_staticData.navFrameIndex = 108;
671 		viewWindow->invalidateWindow(false);
672 
673 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICProcessedOxygen = 1;
674 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiIceMined--;
675 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves++;
676 
677 		// Play the conversion audio file
678 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128);
679 
680 		// Reset the frame
681 		_staticData.navFrameIndex = currentStillFrame;
682 		viewWindow->invalidateWindow(false);
683 		return SC_TRUE;
684 	}
685 
686 	// Move back to the far view
687 	DestinationScene destinationData;
688 	destinationData.destinationScene = _staticData.location;
689 	destinationData.destinationScene.depth = 0;
690 	destinationData.transitionType = TRANSITION_VIDEO;
691 	destinationData.transitionData = 9;
692 	destinationData.transitionStartFrame = -1;
693 	destinationData.transitionLength = -1;
694 	((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
695 	return SC_TRUE;
696 }
697 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)698 int IceteroidMineControls::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
699 	if (_mineButton.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiIceMined < 255)
700 		return kCursorFinger;
701 
702 	if (_makeOxygenButton.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiIceMined > 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves < 255)
703 		return kCursorFinger;
704 
705 	return kCursorPutDown;
706 }
707 
708 class IceteroidZoomInDispenser : public BaseOxygenTimer {
709 public:
710 	IceteroidZoomInDispenser(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
711 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
712 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
713 
714 private:
715 	Common::Rect _controls;
716 };
717 
IceteroidZoomInDispenser(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)718 IceteroidZoomInDispenser::IceteroidZoomInDispenser(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
719 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
720 	_controls = Common::Rect(90, 0, 350, 189);
721 }
722 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)723 int IceteroidZoomInDispenser::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
724 	if (_controls.contains(pointLocation)) {
725 		DestinationScene destinationData;
726 		destinationData.destinationScene = _staticData.location;
727 		destinationData.destinationScene.depth = 1;
728 		destinationData.transitionType = TRANSITION_VIDEO;
729 		destinationData.transitionData = 11;
730 		destinationData.transitionStartFrame = -1;
731 		destinationData.transitionLength = -1;
732 		((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
733 		return SC_TRUE;
734 	}
735 
736 	return SC_FALSE;
737 }
738 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)739 int IceteroidZoomInDispenser::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
740 	if (_controls.contains(pointLocation))
741 		return kCursorMagnifyingGlass;
742 
743 	return kCursorArrow;
744 }
745 
746 class IceteroidDispenserControls : public BaseOxygenTimer {
747 public:
748 	IceteroidDispenserControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
749 	int preExitRoom(Window *viewWindow, const Location &priorLocation) override;
750 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation) override;
751 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation) override;
752 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation) override;
753 	int draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) override;
754 	int droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) override;
755 
756 private:
757 	Common::Rect _oxygenHandle;
758 	Common::Rect _fillHandle;
759 	Common::Rect _dropZone;
760 };
761 
IceteroidDispenserControls(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)762 IceteroidDispenserControls::IceteroidDispenserControls(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
763 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
764 	_oxygenHandle = Common::Rect(290, 42, 410, 128);
765 	_fillHandle = Common::Rect(0, 36, 102, 132);
766 	_dropZone = Common::Rect(0, 136, 148, 189);
767 
768 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle > 0)
769 		_staticData.navFrameIndex = 110;
770 }
771 
preExitRoom(Window * viewWindow,const Location & priorLocation)772 int IceteroidDispenserControls::preExitRoom(Window *viewWindow, const Location &priorLocation) {
773 	// Add the canister back into the inventory
774 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle > 0) {
775 		_staticData.navFrameIndex = 109;
776 
777 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle == 1)
778 			((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->addItem(kItemWaterCanEmpty);
779 		else
780 			((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->addItem(kItemWaterCanFull);
781 
782 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle = 0;
783 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
784 	}
785 
786 	return BaseOxygenTimer::preExitRoom(viewWindow, priorLocation);
787 }
788 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)789 int IceteroidDispenserControls::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
790 	if (_dropZone.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle > 0) {
791 		int itemID = (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle == 1) ? kItemWaterCanEmpty : kItemWaterCanFull;
792 
793 		// Reset present flag and change the frame of the background
794 		_staticData.navFrameIndex = 109;
795 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle = 0;
796 
797 		// Start dragging
798 		Common::Point ptInventoryWindow = viewWindow->convertPointToGlobal(pointLocation);
799 		ptInventoryWindow = ((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->convertPointToLocal(ptInventoryWindow);
800 		((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->startDraggingNewItem(itemID, ptInventoryWindow);
801 
802 		// Update the biochips
803 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
804 		return SC_TRUE;
805 	}
806 
807 	return SC_FALSE;
808 }
809 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)810 int IceteroidDispenserControls::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
811 	if (_oxygenHandle.contains(pointLocation)) {
812 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves > 0 || ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICProcessedOxygen == 1) {
813 			TempCursorChange cursorChange(kCursorWait);
814 
815 			// Reset the flags
816 			if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICProcessedOxygen == 0)
817 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves--;
818 
819 			// Set the use flag
820 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICRefilledOxygen = 1;
821 
822 			// Play the refill animation
823 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(18);
824 
825 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = GC_AIHW_STARTING_VALUE;
826 
827 			// Place a message in the window
828 			Common::String text;
829 			if (_vm->getVersion() >= MAKEVERSION(1, 0, 4, 0))
830 				text = _vm->getString(IDS_AI_IC_OXYGEN_REFILLED);
831 			else
832 				text = "Emergency oxygen reserves refilled.";
833 			((SceneViewWindow *)viewWindow)->displayLiveText(text, false);
834 		} else {
835 			// Play voiceover informing the player the oxygen needs to be refilled
836 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 12));
837 		}
838 
839 		return SC_TRUE;
840 	}
841 
842 	if (_fillHandle.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle > 0) {
843 		TempCursorChange cursorChange(kCursorWait);
844 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle = 2;
845 		((SceneViewWindow *)viewWindow)->playSynchronousAnimation(17);
846 		return SC_TRUE;
847 	}
848 
849 	DestinationScene destinationData;
850 	destinationData.destinationScene = _staticData.location;
851 	destinationData.destinationScene.depth = 0;
852 	destinationData.transitionType = TRANSITION_VIDEO;
853 	destinationData.transitionData = 12;
854 	destinationData.transitionStartFrame = -1;
855 	destinationData.transitionLength = -1;
856 	((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
857 	return SC_TRUE;
858 }
859 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)860 int IceteroidDispenserControls::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
861 	// Water canister
862 	if (_dropZone.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle > 0)
863 		return kCursorOpenHand;
864 
865 	// Oxygen handle
866 	if (_oxygenHandle.contains(pointLocation))
867 		return kCursorFinger;
868 
869 	// Fill handle
870 	if (_fillHandle.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle > 0)
871 		return kCursorFinger;
872 
873 	return kCursorPutDown;
874 }
875 
draggingItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)876 int IceteroidDispenserControls::draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
877 	if ((itemID == kItemWaterCanFull || itemID == kItemWaterCanEmpty) && _dropZone.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle == 0)
878 		return 1;
879 
880 	return 0;
881 }
882 
droppedItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)883 int IceteroidDispenserControls::droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
884 	if ((itemID == kItemWaterCanFull || itemID == kItemWaterCanEmpty) && _dropZone.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle == 0) {
885 		_staticData.navFrameIndex = 110;
886 		viewWindow->invalidateWindow(false);
887 
888 		if (itemID == kItemWaterCanEmpty)
889 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle = 1;
890 		else
891 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICWaterInFillHandle = 2;
892 
893 		return SIC_ACCEPT;
894 	}
895 
896 	return SIC_REJECT;
897 }
898 
899 class PlaySoundExitingForward : public BaseOxygenTimer {
900 public:
901 	PlaySoundExitingForward(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation, int soundFileNameID);
902 	int postExitRoom(Window *viewWindow, const Location &newLocation);
903 
904 private:
905 	int _soundFileNameID;
906 };
907 
PlaySoundExitingForward(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int soundFileNameID)908 PlaySoundExitingForward::PlaySoundExitingForward(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation, int soundFileNameID) :
909 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
910 	_soundFileNameID = soundFileNameID;
911 }
912 
postExitRoom(Window * viewWindow,const Location & newLocation)913 int PlaySoundExitingForward::postExitRoom(Window *viewWindow, const Location &newLocation) {
914 	if (_soundFileNameID >= 0 && _staticData.location.timeZone == newLocation.timeZone && _staticData.location.node != newLocation.node)
915 		_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, _soundFileNameID), 128, false, true);
916 
917 	return SC_TRUE;
918 }
919 
920 class TakeWaterCanister : public BaseOxygenTimer {
921 public:
922 	TakeWaterCanister(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
923 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation);
924 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
925 
926 private:
927 	Common::Rect _canister;
928 };
929 
TakeWaterCanister(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)930 TakeWaterCanister::TakeWaterCanister(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
931 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
932 	_canister = Common::Rect(232, 76, 376, 134);
933 
934 	// If the canister has not been taken, change the still
935 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICTakenWaterCanister == 0)
936 		_staticData.navFrameIndex = 111;
937 }
938 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)939 int TakeWaterCanister::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
940 	if (_canister.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICTakenWaterCanister == 0) {
941 		// Set the frame
942 		_staticData.navFrameIndex = 51;
943 
944 		// Walkthrough mode skips the filling the canister puzzle and gets it filled already
945 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICTakenWaterCanister = 1;
946 		int itemID = (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1) ? kItemWaterCanFull : kItemWaterCanEmpty;
947 
948 		// Start dragging
949 		Common::Point ptInventoryWindow = viewWindow->convertPointToGlobal(pointLocation);
950 		ptInventoryWindow = ((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->convertPointToLocal(ptInventoryWindow);
951 		((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->startDraggingNewItem(itemID, ptInventoryWindow);
952 
953 		// Update the biochips
954 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
955 		return SC_TRUE;
956 	}
957 
958 	return SC_FALSE;
959 }
960 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)961 int TakeWaterCanister::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
962 	if (_canister.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICTakenWaterCanister == 0)
963 		return kCursorOpenHand;
964 
965 	return kCursorArrow;
966 }
967 
968 class ScienceWingZoomIntoPanel : public BaseOxygenTimer {
969 public:
970 	ScienceWingZoomIntoPanel(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
971 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
972 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
973 
974 private:
975 	int _cursorID;
976 	Common::Rect _clickRegion;
977 	DestinationScene _clickDestination;
978 };
979 
ScienceWingZoomIntoPanel(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)980 ScienceWingZoomIntoPanel::ScienceWingZoomIntoPanel(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
981 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
982 	_clickRegion = Common::Rect(282, 6, 390, 189);
983 	_cursorID = kCursorMagnifyingGlass;
984 	_clickDestination.destinationScene = _staticData.location;
985 	_clickDestination.destinationScene.depth = 1;
986 	_clickDestination.transitionType = TRANSITION_VIDEO;
987 	_clickDestination.transitionData = 1;
988 	_clickDestination.transitionStartFrame = -1;
989 	_clickDestination.transitionLength = -1;
990 }
991 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)992 int ScienceWingZoomIntoPanel::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
993 	if (_clickRegion.contains(pointLocation))
994 		((SceneViewWindow *)viewWindow)->moveToDestination(_clickDestination);
995 
996 	return SC_FALSE;
997 }
998 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)999 int ScienceWingZoomIntoPanel::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1000 	if (_clickRegion.contains(pointLocation))
1001 		return _cursorID;
1002 
1003 	return kCursorArrow;
1004 }
1005 
1006 class ScienceWingPanelInterface : public BaseOxygenTimer {
1007 public:
1008 	ScienceWingPanelInterface(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1009 	~ScienceWingPanelInterface();
1010 	void preDestructor();
1011 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
1012 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
1013 	int gdiPaint(Window *viewWindow);
1014 
1015 private:
1016 	Common::Rect _stationRegions[15];
1017 	int _currentSelection;
1018 	int _currentTextIndex;
1019 	int _lineHeight;
1020 	Graphics::Font *_textFont;
1021 	Common::Rect _leftTextRegion;
1022 	Common::Rect _rightTextRegion;
1023 };
1024 
ScienceWingPanelInterface(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1025 ScienceWingPanelInterface::ScienceWingPanelInterface(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1026 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
1027 	_currentSelection = -1;
1028 	_currentTextIndex = -1;
1029 	_stationRegions[0] = Common::Rect(265, 110, 286, 135);
1030 	_stationRegions[1] = Common::Rect(102, 45, 180, 134);
1031 	_stationRegions[2] = Common::Rect(195, 106, 216, 133);
1032 	_stationRegions[3] = Common::Rect(268, 72, 283, 87);
1033 	_stationRegions[4] = Common::Rect(221, 46, 236, 74);
1034 	_stationRegions[5] = Common::Rect(290, 72, 317, 108);
1035 	_stationRegions[6] = Common::Rect(264, 55, 288, 67);
1036 	_stationRegions[7] = Common::Rect(194, 74, 266, 84);
1037 	_stationRegions[8] = Common::Rect(198, 62, 214, 74);
1038 	_stationRegions[9] = Common::Rect(221, 106, 236, 134);
1039 	_stationRegions[10] = Common::Rect(245, 46, 260, 74);
1040 	_stationRegions[11] = Common::Rect(245, 106, 260, 134);
1041 	_stationRegions[12] = Common::Rect(266, 92, 290, 109);
1042 	_stationRegions[13] = Common::Rect(194, 96, 264, 106);
1043 	_stationRegions[14] = Common::Rect(180, 85, 194, 94);
1044 	_leftTextRegion = Common::Rect(83, 144, 211, 170);
1045 	_rightTextRegion = Common::Rect(228, 144, 356, 170);
1046 	_lineHeight = _vm->getLanguage() == Common::JA_JPN ? 10 : 13;
1047 	_textFont = _vm->_gfx->createFont(_lineHeight);
1048 }
1049 
~ScienceWingPanelInterface()1050 ScienceWingPanelInterface::~ScienceWingPanelInterface() {
1051 	preDestructor();
1052 }
1053 
preDestructor()1054 void ScienceWingPanelInterface::preDestructor() {
1055 	delete _textFont;
1056 	_textFont = nullptr;
1057 }
1058 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)1059 int ScienceWingPanelInterface::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
1060 	byte &oxygenReserves = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves;
1061 
1062 	if (_currentSelection == 2) {
1063 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized == 0 && (_stationRegions[_currentSelection].contains(pointLocation) || _rightTextRegion.contains(pointLocation))) {
1064 			if (oxygenReserves > 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiICProcessedOxygen != 0) {
1065 				// Decrement reserves flag
1066 				oxygenReserves--;
1067 
1068 				// Set the machine room to pressurized
1069 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized = 1;
1070 
1071 				// Display pressurizing message
1072 				viewWindow->invalidateWindow(false);
1073 				_currentTextIndex = IDS_AI_PRES_PANEL_PRES_ENV_TEXT;
1074 
1075 				// Play sound file
1076 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128);
1077 
1078 				// Display pressurized text
1079 				viewWindow->invalidateWindow(false);
1080 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
1081 				return SC_TRUE;
1082 			} else {
1083 				// Not enough oxygen reserves
1084 				viewWindow->invalidateWindow(false);
1085 				_currentTextIndex = IDS_AI_PRES_PANEL_INSUF_OXYGEN;
1086 
1087 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSWAttemptedPresMR = 1;
1088 
1089 				return SC_TRUE;
1090 			}
1091 		}
1092 	}
1093 
1094 	// Check against the hotspots
1095 	for (int i = 0; i < 15; i++) {
1096 		if (_stationRegions[i].contains(pointLocation) && _currentSelection != i) {
1097 			switch (i) {
1098 			case 0:
1099 				_staticData.navFrameIndex = 60;
1100 				viewWindow->invalidateWindow(false);
1101 				_currentSelection = i;
1102 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
1103 				return SC_TRUE;
1104 			case 1:
1105 				_staticData.navFrameIndex = 61;
1106 				viewWindow->invalidateWindow(false);
1107 				_currentSelection = i;
1108 				_currentTextIndex = IDS_AI_PRES_PANEL_ZERO_PRES_ENV;
1109 				return SC_TRUE;
1110 			case 2:
1111 				_staticData.navFrameIndex = 62;
1112 				viewWindow->invalidateWindow(false);
1113 				_currentSelection = i;
1114 
1115 				if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized == 1)
1116 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
1117 				else
1118 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES;
1119 				return SC_TRUE;
1120 			case 3:
1121 				_staticData.navFrameIndex = 63;
1122 				viewWindow->invalidateWindow(false);
1123 				_currentSelection = i;
1124 
1125 				if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 1)
1126 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
1127 				else
1128 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_OBST;
1129 				return SC_TRUE;
1130 			case 4:
1131 				_staticData.navFrameIndex = 64;
1132 				viewWindow->invalidateWindow(false);
1133 				_currentSelection = i;
1134 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1135 				return SC_TRUE;
1136 			case 5:
1137 				_staticData.navFrameIndex = 65;
1138 				viewWindow->invalidateWindow(false);
1139 				_currentSelection = i;
1140 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
1141 				return SC_TRUE;
1142 			case 6:
1143 				_staticData.navFrameIndex = 66;
1144 				viewWindow->invalidateWindow(false);
1145 				_currentSelection = i;
1146 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1147 				return SC_TRUE;
1148 			case 7:
1149 				_staticData.navFrameIndex = 67;
1150 				viewWindow->invalidateWindow(false);
1151 				_currentSelection = i;
1152 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1153 				return SC_TRUE;
1154 			case 8:
1155 				_staticData.navFrameIndex = 68;
1156 				viewWindow->invalidateWindow(false);
1157 				_currentSelection = i;
1158 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1159 				return SC_TRUE;
1160 			case 9:
1161 				_staticData.navFrameIndex = 69;
1162 				viewWindow->invalidateWindow(false);
1163 				_currentSelection = i;
1164 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1165 				return SC_TRUE;
1166 			case 10:
1167 				_staticData.navFrameIndex = 70;
1168 				viewWindow->invalidateWindow(false);
1169 				_currentSelection = i;
1170 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1171 				return SC_TRUE;
1172 			case 11:
1173 				_staticData.navFrameIndex = 71;
1174 				viewWindow->invalidateWindow(false);
1175 				_currentSelection = i;
1176 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1177 				return SC_TRUE;
1178 			case 12:
1179 				_staticData.navFrameIndex = 72;
1180 				viewWindow->invalidateWindow(false);
1181 				_currentSelection = i;
1182 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
1183 				return SC_TRUE;
1184 			case 13:
1185 			case 14:
1186 				_staticData.navFrameIndex = 73;
1187 				viewWindow->invalidateWindow(false);
1188 				_currentSelection = i;
1189 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
1190 				return SC_TRUE;
1191 			}
1192 		}
1193 	}
1194 
1195 	// By default, return to depth zero (zoomed out)
1196 	DestinationScene destData;
1197 	destData.destinationScene = _staticData.location;
1198 	destData.destinationScene.depth = 0;
1199 	destData.transitionType = TRANSITION_NONE;
1200 	destData.transitionData = -1;
1201 	destData.transitionStartFrame = -1;
1202 	destData.transitionLength = -1;
1203 	((SceneViewWindow *)viewWindow)->moveToDestination(destData);
1204 	return SC_TRUE;
1205 }
1206 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1207 int ScienceWingPanelInterface::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1208 	for (int i = 0; i < 15; i++)
1209 		if (_stationRegions[i].contains(pointLocation))
1210 			return kCursorFinger;
1211 
1212 	return kCursorPutDown;
1213 }
1214 
gdiPaint(Window * viewWindow)1215 int ScienceWingPanelInterface::gdiPaint(Window *viewWindow) {
1216 	if (_currentSelection >= 0) {
1217 		uint32 color = _vm->_gfx->getColor(208, 144, 24);
1218 
1219 		Common::String location = _vm->getString(IDS_AI_PRES_PANEL_DESC_BASE + _currentSelection);
1220 		if (_currentSelection == 2)
1221 			location += _vm->getString(IDS_AI_PRES_PANEL_DESC_BASE + 19);
1222 
1223 		Common::Rect absoluteRect = viewWindow->getAbsoluteRect();
1224 		Common::Rect rect(_leftTextRegion);
1225 		rect.translate(absoluteRect.left, absoluteRect.top);
1226 		_vm->_gfx->renderText(_vm->_gfx->getScreen(), _textFont, location, rect.left, rect.top, rect.width(), rect.height(), color, _lineHeight, kTextAlignCenter, true);
1227 
1228 		if (_currentTextIndex >= 0) {
1229 			rect = _rightTextRegion;
1230 			rect.translate(absoluteRect.left, absoluteRect.top);
1231 			_vm->_gfx->renderText(_vm->_gfx->getScreen(), _textFont, _vm->getString(_currentTextIndex), rect.left, rect.top, rect.width(), rect.height(), color, _lineHeight, kTextAlignCenter, true);
1232 		}
1233 	}
1234 
1235 	return SC_FALSE;
1236 }
1237 
1238 class ScienceWingMachineRoomDoor : public BaseOxygenTimer {
1239 public:
1240 	ScienceWingMachineRoomDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1241 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
1242 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
1243 
1244 private:
1245 	int _cursorID;
1246 	Common::Rect _clickRegion;
1247 	DestinationScene _clickDestination;
1248 };
1249 
ScienceWingMachineRoomDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1250 ScienceWingMachineRoomDoor::ScienceWingMachineRoomDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1251 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
1252 	_clickRegion = Common::Rect(162, 54, 250, 142);
1253 	_cursorID = kCursorFinger;
1254 	_clickDestination.destinationScene = Location(6, 8, 0, 0, 1, 0);
1255 	_clickDestination.transitionType = TRANSITION_VIDEO;
1256 	_clickDestination.transitionData = (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized == 0) ? 2 : 3;
1257 	_clickDestination.transitionStartFrame = -1;
1258 	_clickDestination.transitionLength = -1;
1259 }
1260 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)1261 int ScienceWingMachineRoomDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
1262 	if (_clickRegion.contains(pointLocation))
1263 		((SceneViewWindow *)viewWindow)->moveToDestination(_clickDestination);
1264 
1265 	return SC_FALSE;
1266 }
1267 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1268 int ScienceWingMachineRoomDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1269 	if (_clickRegion.contains(pointLocation))
1270 		return _cursorID;
1271 
1272 	return 0;
1273 }
1274 
1275 class ScienceWingStingersTimed : public BaseOxygenTimer {
1276 public:
1277 	ScienceWingStingersTimed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1278 	int postEnterRoom(Window *viewWindow, const Location &priorLocation) override;
1279 };
1280 
ScienceWingStingersTimed(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1281 ScienceWingStingersTimed::ScienceWingStingersTimed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1282 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
1283 }
1284 
postEnterRoom(Window * viewWindow,const Location & priorLocation)1285 int ScienceWingStingersTimed::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
1286 	BaseOxygenTimer::postEnterRoom(viewWindow, priorLocation);
1287 
1288 	byte effectID = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSWStingerChannelID;
1289 
1290 	if (!_vm->_sound->isSoundEffectPlaying(effectID - 1)) {
1291 		byte &lastStinger = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSWStingerID;
1292 
1293 		byte newStingerID = _vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, lastStinger + 7)) + 1;
1294 
1295 		lastStinger++;
1296 		if (lastStinger > 3)
1297 			lastStinger = 0;
1298 
1299 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSWStingerChannelID = newStingerID;
1300 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSWStingerID = lastStinger;
1301 	}
1302 
1303 	return SC_TRUE;
1304 }
1305 
1306 class NexusDoor : public BaseOxygenTimer {
1307 public:
1308 	NexusDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1309 	int postEnterRoom(Window *viewWindow, const Location &priorLocation) override;
1310 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation) override;
1311 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation) override;
1312 
1313 private:
1314 	//uint32 _entryStartTime;
1315 	Common::Rect _door;
1316 	//bool _jumped;
1317 };
1318 
NexusDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1319 NexusDoor::NexusDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1320 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
1321 	_door = Common::Rect(148, 30, 328, 192);
1322 }
1323 
postEnterRoom(Window * viewWindow,const Location & priorLocation)1324 int NexusDoor::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
1325 	BaseOxygenTimer::postEnterRoom(viewWindow, priorLocation);
1326 
1327 	if (priorLocation.environment != _staticData.location.environment || priorLocation.timeZone != _staticData.location.timeZone) {
1328 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = GC_AIHW_STARTING_VALUE;
1329 		((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_AI_ENTERING_PRES_ENV_TEXT));
1330 	}
1331 
1332 	return SC_TRUE;
1333 }
1334 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)1335 int NexusDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
1336 	if (_door.contains(pointLocation)) {
1337 		DestinationScene destData;
1338 		destData.destinationScene = Location(6, 5, 1, 0, 1, 0);
1339 		destData.transitionType = TRANSITION_VIDEO;
1340 		destData.transitionData = 0;
1341 		destData.transitionStartFrame = -1;
1342 		destData.transitionLength = -1;
1343 		((SceneViewWindow *)viewWindow)->moveToDestination(destData);
1344 		return SC_TRUE;
1345 	}
1346 
1347 	return SC_FALSE;
1348 }
1349 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1350 int NexusDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1351 	if (_door.contains(pointLocation))
1352 		return kCursorFinger;
1353 
1354 	return kCursorArrow;
1355 }
1356 
1357 class NexusPuzzle : public SceneBase {
1358 public:
1359 	NexusPuzzle(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1360 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
1361 	int gdiPaint(Window *viewWindow);
1362 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation);
1363 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
1364 
1365 private:
1366 	Common::Rect _lights[7];
1367 	int _data[7];
1368 	bool _resetMessage;
1369 };
1370 
NexusPuzzle(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1371 NexusPuzzle::NexusPuzzle(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1372 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
1373 	_data[0] = 2;
1374 	_data[1] = 2;
1375 	_data[2] = 2;
1376 	_data[3] = 0;
1377 	_data[4] = 1;
1378 	_data[5] = 1;
1379 	_data[6] = 1;
1380 
1381 	_lights[0] = Common::Rect(209, 39, 225, 47);
1382 	_lights[1] = Common::Rect(209, 52, 225, 63);
1383 	_lights[2] = Common::Rect(209, 71, 225, 84);
1384 	_lights[3] = Common::Rect(209, 90, 225, 106);
1385 	_lights[4] = Common::Rect(209, 110, 225, 123);
1386 	_lights[5] = Common::Rect(209, 126, 225, 137);
1387 	_lights[6] = Common::Rect(209, 140, 225, 148);
1388 
1389 	_resetMessage = false;
1390 }
1391 
postEnterRoom(Window * viewWindow,const Location & priorLocation)1392 int NexusPuzzle::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
1393 	// If we came from outside (node zero), display the atmosphere message
1394 	if (priorLocation.node == 0) {
1395 		((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_AI_ENTERING_PRES_ENV_TEXT));
1396 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = GC_AIHW_STARTING_VALUE;
1397 	}
1398 
1399 	// Check to see if we heard the brain comment before
1400 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiNXPlayedBrainComment == 0) {
1401 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiNXPlayedBrainComment = 1;
1402 
1403 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 0) {
1404 			// Play a synchronous comment here to introduce the player to the puzzle
1405 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 9));
1406 		} else {
1407 			// Play a synchronous comment to introduce what is about to happen
1408 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 8));
1409 
1410 			// Play the Farnstein voiceover
1411 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 14));
1412 
1413 			// Move to the next node, playing the Arthur retrieval movie
1414 			DestinationScene destData;
1415 			destData.destinationScene = _staticData.location;
1416 			destData.destinationScene.node = 2;
1417 			destData.transitionType = TRANSITION_VIDEO;
1418 			destData.transitionData = 1;
1419 			destData.transitionStartFrame = -1;
1420 			destData.transitionLength = -1;
1421 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
1422 		}
1423 	}
1424 
1425 	return SC_TRUE;
1426 }
1427 
gdiPaint(Window * viewWindow)1428 int NexusPuzzle::gdiPaint(Window *viewWindow) {
1429 	// Puzzle is only in adventure mode
1430 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1)
1431 		return SC_REPAINT;
1432 
1433 	uint32 green = _vm->_gfx->getColor(0, 255, 0);
1434 	uint32 red = _vm->_gfx->getColor(255, 0, 0);
1435 	Common::Rect absoluteRect = viewWindow->getAbsoluteRect();
1436 
1437 	for (int i = 0; i < 7; i++) {
1438 		if (_data[i] != 0) {
1439 			uint32 color = (_data[i] == 1) ? green : red;
1440 
1441 			Common::Rect rect(_lights[i]);
1442 			rect.translate(absoluteRect.left, absoluteRect.top);
1443 			rect.left++;
1444 			rect.top++;
1445 
1446 			_vm->_gfx->drawEllipse(rect, color);
1447 		}
1448 	}
1449 
1450 	return SC_REPAINT;
1451 }
1452 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)1453 int NexusPuzzle::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
1454 	// Puzzle is only in adventure mode
1455 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1)
1456 		return SC_FALSE;
1457 
1458 	// Reset the live text, if the puzzle was reset
1459 	if (_resetMessage) {
1460 		((SceneViewWindow *)viewWindow)->displayLiveText("");
1461 		_resetMessage = false;
1462 	}
1463 
1464 	// Check to see if we clicked on any of the colored circles, and if a jump is allowed
1465 	for (int i = 0; i < 7; i++) {
1466 		if (_lights[i].contains(pointLocation) && _data[i] != 0) {
1467 			if (_data[i] == 1) {
1468 				// Can we move up one?
1469 				if (i > 0) {
1470 					if (_data[i - 1] == 0) {
1471 						_data[i - 1] = _data[i];
1472 						_data[i] = 0;
1473 						viewWindow->invalidateWindow(false);
1474 					} else if (i > 1 && _data[i - 2] == 0) {
1475 						_data[i - 2] = _data[i];
1476 						_data[i] = 0;
1477 						viewWindow->invalidateWindow(false);
1478 					}
1479 				}
1480 			} else {
1481 				if (i < 6) {
1482 					if (_data[i + 1] == 0) {
1483 						_data[i + 1] = _data[i];
1484 						_data[i] = 0;
1485 						viewWindow->invalidateWindow(false);
1486 					} else if (i < 5 && _data[i + 2] == 0) {
1487 						_data[i + 2] = _data[i];
1488 						_data[i] = 0;
1489 						viewWindow->invalidateWindow(false);
1490 					}
1491 				}
1492 			}
1493 
1494 			// Check to see if we completed the puzzle
1495 			if (_data[0] == 1 && _data[1] == 1 && _data[2] == 1 && _data[3] == 0 && _data[4] == 2 && _data[5] == 2 && _data[6] == 2) {
1496 				// Play the Farnstein voiceover
1497 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 14));
1498 
1499 				// Move to the next node, playing the Arthur retrieval movie
1500 				DestinationScene destData;
1501 				destData.destinationScene = _staticData.location;
1502 				destData.destinationScene.node = 2;
1503 				destData.transitionType = TRANSITION_VIDEO;
1504 				destData.transitionData = 1;
1505 				destData.transitionStartFrame = -1;
1506 				destData.transitionLength = -1;
1507 				((SceneViewWindow *)viewWindow)->moveToDestination(destData);
1508 				return SC_TRUE;
1509 			}
1510 
1511 			// Check to see that we can still make valid moves
1512 			bool validMove = false;
1513 			for (int j = 0; j < 7; j++) {
1514 				if (_data[j] == 1) {
1515 					if (j > 1 && _data[j - 2] == 0) {
1516 						validMove = true;
1517 						break;
1518 					}
1519 
1520 					if (j > 0 && _data[j - 1] == 0) {
1521 						validMove = true;
1522 						break;
1523 					}
1524 				} else if (_data[j] == 2) {
1525 					if (j < 5 && _data[j + 2] == 0) {
1526 						validMove = true;
1527 						break;
1528 					}
1529 
1530 					if (j < 6 && _data[j + 1] == 0) {
1531 						validMove = true;
1532 						break;
1533 					}
1534 				}
1535 			}
1536 
1537 			if (!validMove) {
1538 				// Reset the puzzle
1539 				_data[0] = 2;
1540 				_data[1] = 2;
1541 				_data[2] = 2;
1542 				_data[3] = 0;
1543 				_data[4] = 1;
1544 				_data[5] = 1;
1545 				_data[6] = 1;
1546 				viewWindow->invalidateWindow(false);
1547 
1548 				Common::String text;
1549 				if (_vm->getVersion() >= MAKEVERSION(1, 0, 4, 0))
1550 					text = _vm->getString(IDS_AI_NX_CODE_RESET_MESSAGE);
1551 				else
1552 					text = "Unable to complete in current state. Resetting code lock.";
1553 
1554 				((SceneViewWindow *)viewWindow)->displayLiveText(text);
1555 				_resetMessage = true;
1556 			}
1557 
1558 			return SC_TRUE;
1559 		}
1560 	}
1561 
1562 	return SC_FALSE;
1563 }
1564 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1565 int NexusPuzzle::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1566 	// Puzzle is only in adventure mode
1567 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1)
1568 		return kCursorArrow;
1569 
1570 	for (int i = 0; i < 7; i++)
1571 		if (_lights[i].contains(pointLocation) && _data[i] != 0) // In the liiiiiight
1572 			return kCursorFinger;
1573 
1574 	return kCursorArrow;
1575 }
1576 
1577 class NexusEnd : public SceneBase {
1578 public:
1579 	NexusEnd(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1580 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
1581 };
1582 
NexusEnd(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1583 NexusEnd::NexusEnd(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1584 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
1585 }
1586 
postEnterRoom(Window * viewWindow,const Location & priorLocation)1587 int NexusEnd::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
1588 	if (!((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI)) {
1589 		// Congrats, you have Arthur!
1590 
1591 		// Swap and activate the chips
1592 		((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->removeItem(kItemBioChipBlank);
1593 		((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->addItem(kItemBioChipAI);
1594 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->changeCurrentBioChip(kItemBioChipAI);
1595 
1596 		// Play Arthur's comments
1597 
1598 		TempCursorChange cursorChange(kCursorWait);
1599 
1600 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->_forceComment = true;
1601 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->invalidateWindow(false);
1602 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 10));
1603 
1604 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->_forceComment = false;
1605 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->_forceHelp = true;
1606 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->invalidateWindow(false);
1607 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 11));
1608 
1609 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->_forceHelp = false;
1610 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->invalidateWindow(false);
1611 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 12));
1612 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13));
1613 	}
1614 
1615 	return SC_TRUE;
1616 }
1617 
1618 class HabitatWingLockedDoor : public BaseOxygenTimer {
1619 public:
1620 	HabitatWingLockedDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
1621 			int newFrameID = -1, int beepSoundID = -1, int voSoundID = -1, int left = 0, int top = 0, int right = 0, int bottom = 0);
1622 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
1623 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
1624 
1625 private:
1626 	int _newFrameID;
1627 	Common::Rect _clickRegion;
1628 	int _beepSoundID;
1629 	int _voSoundID;
1630 };
1631 
HabitatWingLockedDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int newFrameID,int beepSoundID,int voSoundID,int left,int top,int right,int bottom)1632 HabitatWingLockedDoor::HabitatWingLockedDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
1633 		int newFrameID, int beepSoundID, int voSoundID, int left, int top, int right, int bottom) :
1634 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
1635 	_clickRegion = Common::Rect(left, top, right, bottom);
1636 	_newFrameID = newFrameID;
1637 	_beepSoundID = beepSoundID;
1638 	_voSoundID = voSoundID;
1639 }
1640 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)1641 int HabitatWingLockedDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
1642 	if (_clickRegion.contains(pointLocation)) {
1643 		int oldFrame = _staticData.navFrameIndex;
1644 		_staticData.navFrameIndex = _newFrameID;
1645 		viewWindow->invalidateWindow(false);
1646 
1647 		if (_beepSoundID != -1)
1648 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, _beepSoundID));
1649 
1650 		if (_voSoundID != -1)
1651 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, _voSoundID));
1652 
1653 		_staticData.navFrameIndex = oldFrame;
1654 		viewWindow->invalidateWindow(false);
1655 
1656 		return SC_TRUE;
1657 	}
1658 
1659 	return SC_FALSE;
1660 }
1661 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1662 int HabitatWingLockedDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1663 	if (_clickRegion.contains(pointLocation))
1664 		return kCursorFinger;
1665 
1666 	return kCursorArrow;
1667 }
1668 
1669 class BaseOxygenTimerInSpace : public BaseOxygenTimer {
1670 public:
1671 	BaseOxygenTimerInSpace(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1672 };
1673 
BaseOxygenTimerInSpace(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1674 BaseOxygenTimerInSpace::BaseOxygenTimerInSpace(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1675 		BaseOxygenTimer(vm, viewWindow, sceneStaticData, priorLocation) {
1676 	_deathID = 40;
1677 }
1678 
1679 class BaseOxygenTimerCapacitance : public SceneBase {
1680 public:
1681 	BaseOxygenTimerCapacitance(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1682 	virtual int postEnterRoom(Window *viewWindow, const Location &priorLocation);
1683 	virtual int preExitRoom(Window *viewWindow, const Location &priorLocation);
1684 	virtual int timerCallback(Window *viewWindow);
1685 
1686 protected:
1687 	uint32 _entryStartTime;
1688 	bool _jumped;
1689 };
1690 
BaseOxygenTimerCapacitance(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1691 BaseOxygenTimerCapacitance::BaseOxygenTimerCapacitance(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1692 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
1693 	_jumped = false;
1694 	_entryStartTime = g_system->getMillis();
1695 }
1696 
postEnterRoom(Window * viewWindow,const Location & priorLocation)1697 int BaseOxygenTimerCapacitance::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
1698 	_entryStartTime = g_system->getMillis();
1699 	return SC_TRUE;
1700 }
1701 
preExitRoom(Window * viewWindow,const Location & newLocation)1702 int BaseOxygenTimerCapacitance::preExitRoom(Window *viewWindow, const Location &newLocation) {
1703 	// This does the 25% warning, unlike BaseOxygenTimer
1704 
1705 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 0) {
1706 		if (newLocation.timeZone == -2) {
1707 			_jumped = true;
1708 			return SC_TRUE;
1709 		}
1710 
1711 		int currentValue = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer;
1712 
1713 		if (_staticData.location.node != newLocation.node) {
1714 			if (currentValue <= GC_AI_OT_WALK_DECREMENT) {
1715 				if (newLocation.timeZone != -2)
1716 					((SceneViewWindow *)viewWindow)->showDeathScene(41);
1717 				return SC_DEATH;
1718 			} else {
1719 				currentValue -= GC_AI_OT_WALK_DECREMENT;
1720 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = currentValue;
1721 
1722 				if (currentValue < GC_AIHW_STARTING_VALUE / 4 || (currentValue % (GC_AIHW_STARTING_VALUE / 10)) == 0) {
1723 					if (currentValue < GC_AIHW_STARTING_VALUE / 4) {
1724 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_LOW);
1725 						assert(!oxygenMessage.empty());
1726 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
1727 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
1728 					} else {
1729 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_NORM);
1730 						assert(!oxygenMessage.empty());
1731 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
1732 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
1733 					}
1734 				}
1735 			}
1736 		} else {
1737 			if (currentValue <= GC_AI_OT_TURN_DECREMENT) {
1738 				if (newLocation.timeZone != -2)
1739 					((SceneViewWindow *)viewWindow)->showDeathScene(41);
1740 				return SC_DEATH;
1741 			} else {
1742 				currentValue -= GC_AI_OT_TURN_DECREMENT;
1743 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = currentValue;
1744 
1745 				if (currentValue < GC_AIHW_STARTING_VALUE / 4 || (currentValue % (GC_AIHW_STARTING_VALUE / 10)) == 0) {
1746 					if (currentValue < GC_AIHW_STARTING_VALUE / 4) {
1747 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_LOW);
1748 						assert(!oxygenMessage.empty());
1749 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
1750 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
1751 					} else {
1752 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_NORM);
1753 						assert(!oxygenMessage.empty());
1754 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
1755 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
1756 					}
1757 				}
1758 			}
1759 		}
1760 	}
1761 
1762 	return SC_TRUE;
1763 }
1764 
timerCallback(Window * viewWindow)1765 int BaseOxygenTimerCapacitance::timerCallback(Window *viewWindow) {
1766 	// This does the 25% warning, unlike BaseOxygenTimer
1767 
1768 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 0) {
1769 		if (_jumped)
1770 			return SC_TRUE;
1771 
1772 		if ((g_system->getMillis() - _entryStartTime) >= GC_AI_OT_WAIT_TIME_PERIOD) {
1773 			int currentValue = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer;
1774 
1775 			if (currentValue <= GC_AI_OT_WAIT_DECREMENT) {
1776 				((SceneViewWindow *)viewWindow)->showDeathScene(41);
1777 				return SC_DEATH;
1778 			} else {
1779 				currentValue -= GC_AI_OT_WAIT_DECREMENT;
1780 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = currentValue;
1781 
1782 				if (currentValue < GC_AIHW_STARTING_VALUE / 4 || (currentValue % (GC_AIHW_STARTING_VALUE / 10)) == 0) {
1783 					if (currentValue < GC_AIHW_STARTING_VALUE / 4) {
1784 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_LOW);
1785 						assert(!oxygenMessage.empty());
1786 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
1787 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
1788 					} else {
1789 						Common::String oxygenMessage = _vm->getString(IDS_AI_OXY_LEVEL_TEXT_TEMPLATE_NORM);
1790 						assert(!oxygenMessage.empty());
1791 						oxygenMessage = Common::String::format(oxygenMessage.c_str(), currentValue * 100 / GC_AIHW_STARTING_VALUE);
1792 						((SceneViewWindow *)viewWindow)->displayLiveText(oxygenMessage);
1793 					}
1794 				}
1795 			}
1796 
1797 			_entryStartTime = g_system->getMillis();
1798 		}
1799 	}
1800 
1801 	return SC_TRUE;
1802 }
1803 
1804 class CapacitanceToHabitatDoorClosed : public BaseOxygenTimerCapacitance {
1805 public:
1806 	CapacitanceToHabitatDoorClosed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1807 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation);
1808 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
1809 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
1810 	int draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags);
1811 	int droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags);
1812 
1813 private:
1814 	Common::Rect _metalBar;
1815 	Common::Rect _door;
1816 };
1817 
CapacitanceToHabitatDoorClosed(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1818 CapacitanceToHabitatDoorClosed::CapacitanceToHabitatDoorClosed(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1819 		BaseOxygenTimerCapacitance(vm, viewWindow, sceneStaticData, priorLocation) {
1820 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 1)
1821 		_staticData.navFrameIndex = 7;
1822 	else
1823 		_staticData.navFrameIndex = 55;
1824 
1825 	_metalBar = Common::Rect(184, 146, 264, 184);
1826 	_door = Common::Rect(132, 14, 312, 180);
1827 }
1828 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)1829 int CapacitanceToHabitatDoorClosed::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
1830 	if (_metalBar.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 0) {
1831 		_staticData.navFrameIndex = 7;
1832 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar = 1;
1833 
1834 		Common::Point ptInventoryWindow = viewWindow->convertPointToWindow(pointLocation, ((GameUIWindow *)viewWindow->getParent())->_inventoryWindow);
1835 		((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->startDraggingNewItem(kItemMetalBar, ptInventoryWindow);
1836 
1837 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
1838 		return SC_TRUE;
1839 	}
1840 
1841 	return SC_FALSE;
1842 }
1843 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)1844 int CapacitanceToHabitatDoorClosed::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
1845 	if (_door.contains(pointLocation)) {
1846 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 0) {
1847 			_staticData.navFrameIndex = 96;
1848 			viewWindow->invalidateWindow(false);
1849 
1850 			// Wait for a second (why?)
1851 			uint32 startTime = g_system->getMillis();
1852 
1853 			while (!_vm->shouldQuit() && g_system->getMillis() < startTime + 1000) {
1854 				_vm->yield();
1855 				_vm->_sound->timerCallback();
1856 			}
1857 
1858 			DestinationScene destData;
1859 			destData.destinationScene = _staticData.location;
1860 			destData.destinationScene.depth = 1;
1861 			destData.transitionType = TRANSITION_VIDEO;
1862 			destData.transitionData = 1;
1863 			destData.transitionStartFrame = -1;
1864 			destData.transitionLength = -1;
1865 
1866 			// Move to the final destination
1867 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
1868 			return SC_TRUE;
1869 		} else {
1870 			if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 0) {
1871 				_staticData.navFrameIndex = 97;
1872 				viewWindow->invalidateWindow(false);
1873 
1874 				// Wait for a second (why?)
1875 				uint32 startTime = g_system->getMillis();
1876 
1877 				while (!_vm->shouldQuit() && g_system->getMillis() < startTime + 1000) {
1878 					_vm->yield();
1879 					_vm->_sound->timerCallback();
1880 				}
1881 
1882 				DestinationScene destData;
1883 				destData.destinationScene = _staticData.location;
1884 				destData.destinationScene.depth = 1;
1885 				destData.transitionType = TRANSITION_VIDEO;
1886 				destData.transitionData = 2;
1887 				destData.transitionStartFrame = -1;
1888 				destData.transitionLength = -1;
1889 
1890 				// Move to the final destination
1891 				((SceneViewWindow *)viewWindow)->moveToDestination(destData);
1892 				return SC_TRUE;
1893 			} else {
1894 				int oldFrame = _staticData.navFrameIndex;
1895 				_staticData.navFrameIndex = 121;
1896 				viewWindow->invalidateWindow(false);
1897 
1898 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment - 1, 12));
1899 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment - 1, 13));
1900 
1901 				_staticData.navFrameIndex = oldFrame;
1902 				viewWindow->invalidateWindow(false);
1903 				return SC_TRUE;
1904 			}
1905 		}
1906 	}
1907 
1908 	return SC_FALSE;
1909 }
1910 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1911 int CapacitanceToHabitatDoorClosed::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1912 	if (_metalBar.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 0)
1913 		return kCursorOpenHand;
1914 
1915 	if (_door.contains(pointLocation))
1916 		return kCursorFinger;
1917 
1918 	return kCursorArrow;
1919 }
1920 
draggingItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)1921 int CapacitanceToHabitatDoorClosed::draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
1922 	if (itemID == kItemMetalBar && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 1)
1923 		return 1;
1924 
1925 	return 0;
1926 }
1927 
droppedItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)1928 int CapacitanceToHabitatDoorClosed::droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
1929 	if (pointLocation.x == -1 && pointLocation.y == -1)
1930 		return SIC_REJECT;
1931 
1932 	return SIC_REJECT;
1933 }
1934 
1935 class CapacitanceToHabitatDoorOpen : public BaseOxygenTimerCapacitance {
1936 public:
1937 	CapacitanceToHabitatDoorOpen(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
1938 	int postExitRoom(Window *viewWindow, const Location &newLocation);
1939 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation);
1940 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
1941 	int draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags);
1942 	int droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags);
1943 
1944 private:
1945 	Common::Rect _metalBar;
1946 };
1947 
CapacitanceToHabitatDoorOpen(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)1948 CapacitanceToHabitatDoorOpen::CapacitanceToHabitatDoorOpen(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
1949 		BaseOxygenTimerCapacitance(vm, viewWindow, sceneStaticData, priorLocation) {
1950 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 1) {
1951 		_staticData.navFrameIndex = 101;
1952 		_staticData.destForward.transitionStartFrame = 0;
1953 		_staticData.destForward.transitionLength = 28;
1954 	} else {
1955 		_staticData.navFrameIndex = 100;
1956 		_staticData.destForward.transitionStartFrame = 53;
1957 		_staticData.destForward.transitionLength = 28;
1958 	}
1959 
1960 	_metalBar = Common::Rect(184, 146, 264, 184);
1961 }
1962 
postExitRoom(Window * viewWindow,const Location & newLocation)1963 int CapacitanceToHabitatDoorOpen::postExitRoom(Window *viewWindow, const Location &newLocation) {
1964 	// Play the door closing sound
1965 	if (_staticData.location.timeZone == newLocation.timeZone)
1966 		_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 14), 128, false, true);
1967 
1968 	return SC_TRUE;
1969 }
1970 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)1971 int CapacitanceToHabitatDoorOpen::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
1972 	if (_metalBar.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 0) {
1973 		_staticData.navFrameIndex = 101;
1974 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar = 1;
1975 		_staticData.destForward.transitionStartFrame = 0;
1976 		_staticData.destForward.transitionLength = 28;
1977 
1978 		Common::Point ptInventoryWindow = viewWindow->convertPointToWindow(pointLocation, ((GameUIWindow *)viewWindow->getParent())->_inventoryWindow);
1979 		((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->startDraggingNewItem(kItemMetalBar, ptInventoryWindow);
1980 
1981 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
1982 		return SC_TRUE;
1983 	}
1984 
1985 	return SC_FALSE;
1986 }
1987 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)1988 int CapacitanceToHabitatDoorOpen::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
1989 	if (_metalBar.contains(pointLocation) && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 0)
1990 		return kCursorOpenHand;
1991 
1992 	return kCursorArrow;
1993 }
1994 
draggingItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)1995 int CapacitanceToHabitatDoorOpen::draggingItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
1996 	if (itemID == kItemMetalBar && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 1)
1997 		return 1;
1998 
1999 	return 0;
2000 }
2001 
droppedItem(Window * viewWindow,int itemID,const Common::Point & pointLocation,int itemFlags)2002 int CapacitanceToHabitatDoorOpen::droppedItem(Window *viewWindow, int itemID, const Common::Point &pointLocation, int itemFlags) {
2003 	if (pointLocation.x == -1 && pointLocation.y == -1)
2004 		return SIC_REJECT;
2005 
2006 	if (itemID == kItemMetalBar && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 1) {
2007 		_staticData.navFrameIndex = 100;
2008 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar = 0;
2009 		viewWindow->invalidateWindow(false);
2010 		_staticData.destForward.transitionStartFrame = 53;
2011 		_staticData.destForward.transitionLength = 28;
2012 
2013 		((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
2014 		return SIC_ACCEPT;
2015 	}
2016 
2017 	return SIC_REJECT;
2018 }
2019 
2020 class CapacitancePanelInterface : public BaseOxygenTimerCapacitance {
2021 public:
2022 	CapacitancePanelInterface(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2023 	~CapacitancePanelInterface();
2024 	void preDestructor();
2025 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2026 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2027 	int gdiPaint(Window *viewWindow);
2028 
2029 private:
2030 	Common::Rect _stationRegions[15];
2031 	int _currentSelection;
2032 	int _currentTextIndex;
2033 	int _lineHeight;
2034 	Graphics::Font *_textFont;
2035 	Common::Rect _leftTextRegion;
2036 	Common::Rect _rightTextRegion;
2037 };
2038 
CapacitancePanelInterface(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2039 CapacitancePanelInterface::CapacitancePanelInterface(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2040 		BaseOxygenTimerCapacitance(vm, viewWindow, sceneStaticData, priorLocation) {
2041 	_currentSelection = -1;
2042 	_currentTextIndex = -1;
2043 	_stationRegions[0] = Common::Rect(265, 110, 286, 135);
2044 	_stationRegions[1] = Common::Rect(102, 45, 180, 134);
2045 	_stationRegions[2] = Common::Rect(195, 106, 216, 133);
2046 	_stationRegions[3] = Common::Rect(268, 72, 283, 87);
2047 	_stationRegions[4] = Common::Rect(221, 46, 236, 74);
2048 	_stationRegions[5] = Common::Rect(290, 72, 317, 108);
2049 	_stationRegions[6] = Common::Rect(264, 55, 288, 67);
2050 	_stationRegions[7] = Common::Rect(194, 74, 266, 84);
2051 	_stationRegions[8] = Common::Rect(198, 62, 214, 74);
2052 	_stationRegions[9] = Common::Rect(221, 106, 236, 134);
2053 	_stationRegions[10] = Common::Rect(245, 46, 260, 74);
2054 	_stationRegions[11] = Common::Rect(245, 106, 260, 134);
2055 	_stationRegions[12] = Common::Rect(266, 92, 290, 109);
2056 	_stationRegions[13] = Common::Rect(194, 96, 264, 106);
2057 	_stationRegions[14] = Common::Rect(180, 85, 194, 94);
2058 	_leftTextRegion = Common::Rect(83, 144, 211, 170);
2059 	_rightTextRegion = Common::Rect(228, 144, 356, 170);
2060 	_lineHeight = _vm->getLanguage() == Common::JA_JPN ? 10 : 13;
2061 	_textFont = _vm->_gfx->createFont(_lineHeight);
2062 }
2063 
~CapacitancePanelInterface()2064 CapacitancePanelInterface::~CapacitancePanelInterface() {
2065 	preDestructor();
2066 }
2067 
preDestructor()2068 void CapacitancePanelInterface::preDestructor() {
2069 	delete _textFont;
2070 	_textFont = nullptr;
2071 }
2072 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2073 int CapacitancePanelInterface::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2074 	byte &oxygenReserves = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenReserves;
2075 
2076 	if (_currentSelection == 2) {
2077 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized == 0 && (_stationRegions[_currentSelection].contains(pointLocation) || _rightTextRegion.contains(pointLocation))) {
2078 			if (oxygenReserves > 0) {
2079 				// Decrement reserves flag
2080 				oxygenReserves--;
2081 
2082 				// Set the machine room to pressurized
2083 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized = 1;
2084 
2085 				// Display pressurizing message
2086 				viewWindow->invalidateWindow(false);
2087 				_currentTextIndex = IDS_AI_PRES_PANEL_PRES_ENV_TEXT;
2088 
2089 				// Play sound file
2090 				_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128);
2091 
2092 				// Display pressurized text
2093 				viewWindow->invalidateWindow(false);
2094 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2095 				return SC_TRUE;
2096 			} else {
2097 				// Not enough oxygen reserves
2098 				viewWindow->invalidateWindow(false);
2099 				_currentTextIndex = IDS_AI_PRES_PANEL_INSUF_OXYGEN;
2100 				return SC_TRUE;
2101 			}
2102 		}
2103 	} else if (_currentSelection == 3) {
2104 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 0 && (_stationRegions[_currentSelection].contains(pointLocation) || _rightTextRegion.contains(pointLocation))) {
2105 			if (oxygenReserves > 0) {
2106 				if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRGrabbedMetalBar == 0) {
2107 					if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurizedAttempted == 0) {
2108 						// Display pressurizing message
2109 						viewWindow->invalidateWindow(false);
2110 						_currentTextIndex = IDS_AI_PRES_PANEL_PRES_ENV_TEXT;
2111 
2112 						// Play sound file
2113 						_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128);
2114 
2115 						// Display bulkhead message
2116 						viewWindow->invalidateWindow(false);
2117 						_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2118 
2119 						// Play Mom audio
2120 						// (Is this an Alien reference?)
2121 						_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 11));
2122 
2123 						// Update attempt flag
2124 						((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurizedAttempted = 1;
2125 					}
2126 				} else {
2127 					// Decrement reserves flag
2128 					oxygenReserves--;
2129 
2130 					// Set the capacitance array to pressurized
2131 					((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized = 1;
2132 
2133 					// Display pressurizing message
2134 					viewWindow->invalidateWindow(false);
2135 					_currentTextIndex = IDS_AI_PRES_PANEL_PRES_ENV_TEXT;
2136 
2137 					// Play sound file
2138 					_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128);
2139 
2140 					// Display pressurized text
2141 					viewWindow->invalidateWindow(false);
2142 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2143 
2144 					// Display oxygen text in the message window
2145 					((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_AI_ENTERING_PRES_ENV_TEXT));
2146 					((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = GC_AIHW_STARTING_VALUE;
2147 				}
2148 
2149 				return SC_TRUE;
2150 			} else {
2151 				// Not enough oxygen reserves
2152 				viewWindow->invalidateWindow(false);
2153 				_currentTextIndex = IDS_AI_PRES_PANEL_INSUF_OXYGEN;
2154 				return SC_TRUE;
2155 			}
2156 		}
2157 	}
2158 
2159 	// Check against the hotspots
2160 	for (int i = 0; i < 15; i++) {
2161 		if (_stationRegions[i].contains(pointLocation) && _currentSelection != i) {
2162 			switch (i) {
2163 			case 0:
2164 				_staticData.navFrameIndex = 107;
2165 				viewWindow->invalidateWindow(false);
2166 				_currentSelection = i;
2167 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2168 				return SC_TRUE;
2169 			case 1:
2170 				_staticData.navFrameIndex = 108;
2171 				viewWindow->invalidateWindow(false);
2172 				_currentSelection = i;
2173 				_currentTextIndex = IDS_AI_PRES_PANEL_ZERO_PRES_ENV;
2174 				return SC_TRUE;
2175 			case 2:
2176 				_staticData.navFrameIndex = 109;
2177 				viewWindow->invalidateWindow(false);
2178 				_currentSelection = i;
2179 
2180 				if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized == 1)
2181 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2182 				else
2183 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES;
2184 				return SC_TRUE;
2185 			case 3:
2186 				_staticData.navFrameIndex = 110;
2187 				viewWindow->invalidateWindow(false);
2188 				_currentSelection = i;
2189 
2190 				if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 1)
2191 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2192 				else
2193 					_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES;
2194 				return SC_TRUE;
2195 			case 4:
2196 				_staticData.navFrameIndex = 111;
2197 				viewWindow->invalidateWindow(false);
2198 				_currentSelection = i;
2199 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2200 				return SC_TRUE;
2201 			case 5:
2202 				_staticData.navFrameIndex = 112;
2203 				viewWindow->invalidateWindow(false);
2204 				_currentSelection = i;
2205 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2206 				return SC_TRUE;
2207 			case 6:
2208 				_staticData.navFrameIndex = 113;
2209 				viewWindow->invalidateWindow(false);
2210 				_currentSelection = i;
2211 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2212 				return SC_TRUE;
2213 			case 7:
2214 				_staticData.navFrameIndex = 114;
2215 				viewWindow->invalidateWindow(false);
2216 				_currentSelection = i;
2217 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2218 				return SC_TRUE;
2219 			case 8:
2220 				_staticData.navFrameIndex = 115;
2221 				viewWindow->invalidateWindow(false);
2222 				_currentSelection = i;
2223 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2224 				return SC_TRUE;
2225 			case 9:
2226 				_staticData.navFrameIndex = 116;
2227 				viewWindow->invalidateWindow(false);
2228 				_currentSelection = i;
2229 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2230 				return SC_TRUE;
2231 			case 10:
2232 				_staticData.navFrameIndex = 117;
2233 				viewWindow->invalidateWindow(false);
2234 				_currentSelection = i;
2235 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2236 				return SC_TRUE;
2237 			case 11:
2238 				_staticData.navFrameIndex = 118;
2239 				viewWindow->invalidateWindow(false);
2240 				_currentSelection = i;
2241 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2242 				return SC_TRUE;
2243 			case 12:
2244 				_staticData.navFrameIndex = 119;
2245 				viewWindow->invalidateWindow(false);
2246 				_currentSelection = i;
2247 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_PRES_TEXT;
2248 				return SC_TRUE;
2249 			case 13:
2250 			case 14:
2251 				_staticData.navFrameIndex = 120;
2252 				viewWindow->invalidateWindow(false);
2253 				_currentSelection = i;
2254 				_currentTextIndex = IDS_AI_PRES_PANEL_ENV_DEPRES_BREACH;
2255 				return SC_TRUE;
2256 			}
2257 		}
2258 	}
2259 
2260 	// By default, return to depth zero (zoomed out)
2261 	DestinationScene destData;
2262 	destData.destinationScene = _staticData.location;
2263 	destData.destinationScene.depth = 0;
2264 	destData.transitionType = TRANSITION_NONE;
2265 	destData.transitionData = -1;
2266 	destData.transitionStartFrame = -1;
2267 	destData.transitionLength = -1;
2268 	((SceneViewWindow *)viewWindow)->moveToDestination(destData);
2269 	return SC_TRUE;
2270 }
2271 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2272 int CapacitancePanelInterface::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2273 	for (int i = 0; i < 15; i++)
2274 		if (_stationRegions[i].contains(pointLocation))
2275 			return kCursorFinger;
2276 
2277 	return kCursorPutDown;
2278 }
2279 
gdiPaint(Window * viewWindow)2280 int CapacitancePanelInterface::gdiPaint(Window *viewWindow) {
2281 	if (_currentSelection >= 0) {
2282 		uint32 color = _vm->_gfx->getColor(208, 144, 24);
2283 
2284 		Common::String location = _vm->getString(IDS_AI_PRES_PANEL_DESC_BASE + _currentSelection);
2285 		if (_currentSelection == 3)
2286 			location += _vm->getString(IDS_AI_PRES_PANEL_DESC_BASE + 19);
2287 
2288 		Common::Rect absoluteRect = viewWindow->getAbsoluteRect();
2289 		Common::Rect rect(_leftTextRegion);
2290 		rect.translate(absoluteRect.left, absoluteRect.top);
2291 		_vm->_gfx->renderText(_vm->_gfx->getScreen(), _textFont, location, rect.left, rect.top, rect.width(), rect.height(), color, _lineHeight, kTextAlignCenter, true);
2292 
2293 		if (_currentTextIndex >= 0) {
2294 			rect = _rightTextRegion;
2295 			rect.translate(absoluteRect.left, absoluteRect.top);
2296 			_vm->_gfx->renderText(_vm->_gfx->getScreen(), _textFont, _vm->getString(_currentTextIndex), rect.left, rect.top, rect.width(), rect.height(), color, _lineHeight, kTextAlignCenter, true);
2297 		}
2298 	}
2299 
2300 	return SC_FALSE;
2301 }
2302 
2303 class PlayArthurOffsetCapacitance : public BaseOxygenTimerCapacitance {
2304 public:
2305 	PlayArthurOffsetCapacitance(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
2306 			int stingerVolume = 127, int lastStingerFlagOffset = -1, int effectIDFlagOffset = -1, int firstStingerFileID = -1,
2307 			int lastStingerFileID = -1, int stingerDelay = 1, int flagOffset = -1, int newStill = -1, int newNavStart = -1, int newNavLength = -1);
2308 	int postEnterRoom(Window *viewWindow, const Location &priorLocation) override;
2309 
2310 private:
2311 	int _stingerVolume;
2312 	int _lastStingerFlagOffset;
2313 	int _effectIDFlagOffset;
2314 	int _firstStingerFileID;
2315 	int _lastStingerFileID;
2316 	int _stingerDelay;
2317 };
2318 
PlayArthurOffsetCapacitance(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int stingerVolume,int lastStingerFlagOffset,int effectIDFlagOffset,int firstStingerFileID,int lastStingerFileID,int stingerDelay,int flagOffset,int newStill,int newNavStart,int newNavLength)2319 PlayArthurOffsetCapacitance::PlayArthurOffsetCapacitance(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
2320 		int stingerVolume, int lastStingerFlagOffset, int effectIDFlagOffset, int firstStingerFileID,
2321 		int lastStingerFileID, int stingerDelay, int flagOffset, int newStill, int newNavStart, int newNavLength) :
2322 		BaseOxygenTimerCapacitance(vm, viewWindow, sceneStaticData, priorLocation) {
2323 	_stingerVolume = stingerVolume;
2324 	_lastStingerFlagOffset = lastStingerFlagOffset;
2325 	_effectIDFlagOffset = effectIDFlagOffset;
2326 	_firstStingerFileID = firstStingerFileID;
2327 	_lastStingerFileID = lastStingerFileID;
2328 	_stingerDelay = stingerDelay;
2329 
2330 	if (flagOffset >= 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(flagOffset) == 0) {
2331 		// This is completely wrong.
2332 		//if (newStill >= 0)
2333 		//	_staticData.navFrameIndex;
2334 		if (newNavStart >= 0)
2335 			_staticData.destForward.transitionStartFrame = newNavStart;
2336 		if (newNavLength >= 0)
2337 			_staticData.destForward.transitionLength = newNavLength;
2338 	}
2339 }
2340 
postEnterRoom(Window * viewWindow,const Location & priorLocation)2341 int PlayArthurOffsetCapacitance::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
2342 	BaseOxygenTimerCapacitance::postEnterRoom(viewWindow, priorLocation);
2343 
2344 	if (_effectIDFlagOffset >= 0) {
2345 		byte effectID = ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_effectIDFlagOffset);
2346 
2347 		if (!_vm->_sound->isSoundEffectPlaying(effectID - 1)) {
2348 			byte lastStinger = ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_lastStingerFlagOffset) + 1;
2349 
2350 			if ((lastStinger % _stingerDelay) == 0) {
2351 				if (lastStinger < (_lastStingerFileID - _firstStingerFileID) * _stingerDelay) {
2352 					int fileNameIndex = _vm->computeFileNameResourceID(_staticData.location.timeZone, _staticData.location.environment, _firstStingerFileID + (lastStinger / _stingerDelay) - 1);
2353 
2354 					if (((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI) && (lastStinger / _stingerDelay) < 3) {
2355 						_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(fileNameIndex));
2356 
2357 						// Play an Arthur comment if we have the chip
2358 						switch (lastStinger / _stingerDelay) {
2359 						case 0:
2360 							_vm->_sound->playSynchronousSoundEffect("BITDATA/AILAB/AICR_C01.BTA", 127);
2361 							break;
2362 						case 1:
2363 							_vm->_sound->playSynchronousSoundEffect("BITDATA/AILAB/AICR_C02.BTA", 127);
2364 							break;
2365 						case 2:
2366 							_vm->_sound->playSynchronousSoundEffect("BITDATA/AILAB/AICR_C03.BTA", 127);
2367 							break;
2368 						}
2369 
2370 						// Update the global flags
2371 						((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_lastStingerFlagOffset, lastStinger);
2372 					} else {
2373 						byte newStingerID = _vm->_sound->playSoundEffect(_vm->getFilePath(fileNameIndex), _stingerVolume, false, true) + 1;
2374 
2375 						// Update the global flags
2376 						((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_effectIDFlagOffset, newStingerID);
2377 						((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_lastStingerFlagOffset, lastStinger);
2378 					}
2379 				}
2380 			} else {
2381 				((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_effectIDFlagOffset, 0xFF);
2382 				((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_lastStingerFlagOffset, lastStinger);
2383 			}
2384 		}
2385 	}
2386 
2387 	return SC_TRUE;
2388 }
2389 
2390 class ClickChangeSceneCapacitance : public BaseOxygenTimerCapacitance {
2391 public:
2392 	ClickChangeSceneCapacitance(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
2393 			int left = -1, int top = -1, int right = -1, int bottom = -1, int cursorID = 0,
2394 			int timeZone = -1, int environment = -1, int node = -1, int facing = -1, int orientation = -1, int depth = -1,
2395 			int transitionType = -1, int transitionData = -1, int transitionStartFrame = -1, int transitionLength = -1);
2396 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2397 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2398 
2399 private:
2400 	int _cursorID;
2401 	Common::Rect _clickRegion;
2402 	DestinationScene _clickDestination;
2403 };
2404 
ClickChangeSceneCapacitance(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int left,int top,int right,int bottom,int cursorID,int timeZone,int environment,int node,int facing,int orientation,int depth,int transitionType,int transitionData,int transitionStartFrame,int transitionLength)2405 ClickChangeSceneCapacitance::ClickChangeSceneCapacitance(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
2406 		int left, int top, int right, int bottom, int cursorID,
2407 		int timeZone, int environment, int node, int facing, int orientation, int depth,
2408 		int transitionType, int transitionData, int transitionStartFrame, int transitionLength) :
2409 		BaseOxygenTimerCapacitance(vm, viewWindow, sceneStaticData, priorLocation) {
2410 	_clickRegion = Common::Rect(left, top, right, bottom);
2411 	_cursorID = cursorID;
2412 	_clickDestination.destinationScene = Location(timeZone, environment, node, facing, orientation, depth);
2413 	_clickDestination.transitionType = transitionType;
2414 	_clickDestination.transitionData = transitionData;
2415 	_clickDestination.transitionStartFrame = transitionStartFrame;
2416 	_clickDestination.transitionLength = transitionLength;
2417 }
2418 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2419 int ClickChangeSceneCapacitance::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2420 	if (_clickRegion.contains(pointLocation))
2421 		((SceneViewWindow *)viewWindow)->moveToDestination(_clickDestination);
2422 
2423 	return SC_FALSE;
2424 }
2425 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2426 int ClickChangeSceneCapacitance::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2427 	if (_clickRegion.contains(pointLocation))
2428 		return _cursorID;
2429 
2430 	return kCursorArrow;
2431 }
2432 
2433 class CapacitanceDockingBayDoor : public BaseOxygenTimerCapacitance {
2434 public:
2435 	CapacitanceDockingBayDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2436 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2437 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2438 
2439 private:
2440 	Common::Rect _door;
2441 };
2442 
CapacitanceDockingBayDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2443 CapacitanceDockingBayDoor::CapacitanceDockingBayDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2444 		BaseOxygenTimerCapacitance(vm, viewWindow, sceneStaticData, priorLocation) {
2445 	_door = Common::Rect(160, 54, 276, 168);
2446 }
2447 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2448 int CapacitanceDockingBayDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2449 	if (_door.contains(pointLocation)) {
2450 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiCRPressurized == 1) {
2451 			_staticData.navFrameIndex = 98;
2452 			viewWindow->invalidateWindow(false);
2453 
2454 			_vm->_sound->playSynchronousSoundEffect("BITDATA/AILAB/AI_LOCK.BTA");
2455 
2456 			// Wait a second?
2457 			uint32 startTime = g_system->getMillis();
2458 			while (!_vm->shouldQuit() && g_system->getMillis() < startTime + 1000) {
2459 				_vm->yield();
2460 				_vm->_sound->timerCallback();
2461 			}
2462 
2463 			DestinationScene destData;
2464 			destData.destinationScene = _staticData.location;
2465 			destData.destinationScene.depth = 1;
2466 			destData.transitionType = TRANSITION_VIDEO;
2467 			destData.transitionData = 0;
2468 			destData.transitionStartFrame = -1;
2469 			destData.transitionLength = -1;
2470 
2471 			// Move to the final destination
2472 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
2473 			return SC_TRUE;
2474 		} else {
2475 			int oldFrame = _staticData.navFrameIndex;
2476 			_staticData.navFrameIndex = 99;
2477 			viewWindow->invalidateWindow(false);
2478 
2479 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment - 1, 12));
2480 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment - 1, 13));
2481 
2482 			_staticData.navFrameIndex = oldFrame;
2483 			viewWindow->invalidateWindow(false);
2484 			return SC_TRUE;
2485 		}
2486 	}
2487 
2488 	return SC_FALSE;
2489 }
2490 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2491 int CapacitanceDockingBayDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2492 	if (_door.contains(pointLocation))
2493 		return kCursorFinger;
2494 
2495 	return kCursorArrow;
2496 }
2497 
2498 class ScanningRoomEntryScan : public SceneBase {
2499 public:
2500 	ScanningRoomEntryScan(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2501 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
2502 	int postExitRoom(Window *viewWindow, const Location &newLocation);
2503 	int timerCallback(Window *viewWindow);
2504 
2505 private:
2506 	DestinationScene _savedForwardData;
2507 };
2508 
ScanningRoomEntryScan(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2509 ScanningRoomEntryScan::ScanningRoomEntryScan(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2510 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2511 	_savedForwardData = _staticData.destForward;
2512 
2513 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardInitialSpeech == 0)
2514 		_staticData.destForward.destinationScene = Location(-1, -1, -1, -1, -1, -1);
2515 
2516 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel > 0) {
2517 		if (_vm->_sound->isSoundEffectPlaying(((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel - 1))
2518 			_staticData.destForward.destinationScene = Location(-1, -1, -1, -1, -1, -1);
2519 		else
2520 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = 0;
2521 	}
2522 
2523 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus == 3)
2524 		_staticData.destForward.destinationScene = Location(-1, -1, -1, -1, -1, -1);
2525 }
2526 
postEnterRoom(Window * viewWindow,const Location & priorLocation)2527 int ScanningRoomEntryScan::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
2528 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardInitialSpeech == 0) {
2529 		// Play the scanning movie
2530 		((SceneViewWindow *)viewWindow)->playSynchronousAnimation(7);
2531 
2532 		// Set the flag
2533 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardInitialSpeech = 1;
2534 
2535 		// Start the initial monologue
2536 		byte channel = _vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 12), 127, false, true) + 1;
2537 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = channel;
2538 	}
2539 
2540 	return SC_TRUE;
2541 }
2542 
postExitRoom(Window * viewWindow,const Location & newLocation)2543 int ScanningRoomEntryScan::postExitRoom(Window *viewWindow, const Location &newLocation) {
2544 	if (newLocation.timeZone == 6 && newLocation.environment == 4 && newLocation.node != 3 && newLocation.node != 0 &&
2545 			_staticData.location.timeZone == newLocation.timeZone) {
2546 		_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128, false, true);
2547 	}
2548 
2549 	return SC_TRUE;
2550 }
2551 
timerCallback(Window * viewWindow)2552 int ScanningRoomEntryScan::timerCallback(Window *viewWindow) {
2553 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel > 0 && !_vm->_sound->isSoundEffectPlaying(((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel - 1)) {
2554 		_staticData.destForward = _savedForwardData;
2555 		((GameUIWindow *)viewWindow->getParent())->_navArrowWindow->updateAllArrows(_staticData);
2556 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = 0;
2557 	}
2558 
2559 	return SC_TRUE;
2560 }
2561 
2562 class ScanningRoomWalkWarning : public SceneBase {
2563 public:
2564 	ScanningRoomWalkWarning(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2565 	int postExitRoom(Window *viewWindow, const Location &newLocation);
2566 	int timerCallback(Window *viewWindow);
2567 
2568 private:
2569 	DestinationScene _savedForwardData;
2570 };
2571 
ScanningRoomWalkWarning(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2572 ScanningRoomWalkWarning::ScanningRoomWalkWarning(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2573 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2574 	_savedForwardData = _staticData.destForward;
2575 
2576 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel > 0) {
2577 		if (_vm->_sound->isSoundEffectPlaying(((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel - 1))
2578 			_staticData.destForward.destinationScene = Location(-1, -1, -1, -1, -1, -1);
2579 		else
2580 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = 0;
2581 	}
2582 }
2583 
postExitRoom(Window * viewWindow,const Location & newLocation)2584 int ScanningRoomWalkWarning::postExitRoom(Window *viewWindow, const Location &newLocation) {
2585 	if (newLocation.timeZone == 6 && newLocation.environment == 4 && newLocation.node != 3 && newLocation.node != 0 &&
2586 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCMoveCenterWarning == 0) {
2587 		if (_staticData.location.timeZone == newLocation.timeZone)
2588 			_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 13), 128, false, true);
2589 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCMoveCenterWarning = 1;
2590 	}
2591 
2592 	return SC_TRUE;
2593 }
2594 
timerCallback(Window * viewWindow)2595 int ScanningRoomWalkWarning::timerCallback(Window *viewWindow) {
2596 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel > 0 && !_vm->_sound->isSoundEffectPlaying(((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel - 1)) {
2597 		_staticData.destForward = _savedForwardData;
2598 		((GameUIWindow *)viewWindow->getParent())->_navArrowWindow->updateAllArrows(_staticData);
2599 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = 0;
2600 	}
2601 
2602 	return SC_TRUE;
2603 }
2604 
2605 class ScanningRoomDockingBayDoor : public SceneBase {
2606 public:
2607 	ScanningRoomDockingBayDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2608 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2609 	int timerCallback(Window *viewWindow);
2610 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2611 
2612 private:
2613 	bool _audioEnded;
2614 	Common::Rect _doorRegion;
2615 };
2616 
ScanningRoomDockingBayDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2617 ScanningRoomDockingBayDoor::ScanningRoomDockingBayDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2618 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2619 	_audioEnded = true;
2620 	_doorRegion = Common::Rect(152, 34, 266, 148);
2621 
2622 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel > 0) {
2623 		if (!_vm->_sound->isSoundEffectPlaying(((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel - 1)) {
2624 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = 0;
2625 			_audioEnded = true;
2626 		} else {
2627 			_audioEnded = false;
2628 		}
2629 	}
2630 }
2631 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2632 int ScanningRoomDockingBayDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2633 	if (_audioEnded && _doorRegion.contains(pointLocation)) {
2634 		// Change the still frame
2635 		int oldFrame = _staticData.navFrameIndex;
2636 		_staticData.navFrameIndex = 46;
2637 		viewWindow->invalidateWindow(false);
2638 
2639 		// Play the beep and voiceovers
2640 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 1, 12));
2641 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 1, 13));
2642 
2643 		// Reset the frame
2644 		_staticData.navFrameIndex = oldFrame;
2645 		viewWindow->invalidateWindow(false);
2646 
2647 		// Play Arthur's voiceover
2648 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCDBDoorWarning == 0) {
2649 			_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 11), 127);
2650 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCDBDoorWarning = 1;
2651 		}
2652 	}
2653 
2654 	return SC_FALSE;
2655 }
2656 
timerCallback(Window * viewWindow)2657 int ScanningRoomDockingBayDoor::timerCallback(Window *viewWindow) {
2658 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel > 0 && !_vm->_sound->isSoundEffectPlaying(((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel - 1)) {
2659 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCInitialAudioChannel = 0;
2660 		_audioEnded = true;
2661 	}
2662 
2663 	return SC_TRUE;
2664 }
2665 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2666 int ScanningRoomDockingBayDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2667 	if (_audioEnded && _doorRegion.contains(pointLocation))
2668 		return kCursorFinger;
2669 
2670 	return kCursorArrow;
2671 }
2672 
2673 class ScanningRoomScienceWingDoor : public SceneBase {
2674 public:
2675 	ScanningRoomScienceWingDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2676 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2677 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2678 
2679 private:
2680 	Common::Rect _doorRegion;
2681 };
2682 
ScanningRoomScienceWingDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2683 ScanningRoomScienceWingDoor::ScanningRoomScienceWingDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2684 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2685 	_doorRegion = Common::Rect(152, 34, 266, 148);
2686 }
2687 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2688 int ScanningRoomScienceWingDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2689 	if (_doorRegion.contains(pointLocation)) {
2690 		// Change the still frame
2691 		int oldFrame = _staticData.navFrameIndex;
2692 		_staticData.navFrameIndex = 44;
2693 		viewWindow->invalidateWindow(false);
2694 
2695 		// Play the beep and voiceovers
2696 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 1, 12));
2697 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 1, 13));
2698 
2699 		// Reset the frame
2700 		_staticData.navFrameIndex = oldFrame;
2701 		viewWindow->invalidateWindow(false);
2702 	}
2703 
2704 	return SC_FALSE;
2705 }
2706 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2707 int ScanningRoomScienceWingDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2708 	if (_doorRegion.contains(pointLocation))
2709 		return kCursorFinger;
2710 
2711 	return kCursorArrow;
2712 }
2713 
2714 class ArthurScanningRoomConversation : public SceneBase {
2715 public:
2716 	ArthurScanningRoomConversation(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2717 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
2718 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2719 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2720 
2721 private:
2722 	Common::Rect _yes;
2723 	Common::Rect _no;
2724 };
2725 
ArthurScanningRoomConversation(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2726 ArthurScanningRoomConversation::ArthurScanningRoomConversation(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2727 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2728 	_yes = Common::Rect(152, 54, 284, 124);
2729 	_no = Common::Rect(194, 128, 244, 152);
2730 }
2731 
postEnterRoom(Window * viewWindow,const Location & priorLocation)2732 int ArthurScanningRoomConversation::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
2733 	// If this is the initial entry, play Arthur's comment
2734 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus == 0) {
2735 		((SceneViewWindow *)viewWindow)->playSynchronousAnimation(9);
2736 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus = 1;
2737 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCPlayedNoStinger = 0;
2738 	}
2739 
2740 	_staticData.cycleStartFrame = 0;
2741 	_staticData.cycleFrameCount = 20;
2742 	_staticData.navFrameIndex = 37;
2743 	viewWindow->invalidateWindow(false);
2744 	return SC_TRUE;
2745 }
2746 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2747 int ArthurScanningRoomConversation::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2748 	if (_yes.contains(pointLocation)) {
2749 		switch (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus) {
2750 		case 1: // Proceed with scan, then ask about downloading into biochips
2751 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(8);
2752 			_staticData.navFrameIndex = 36;
2753 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(10);
2754 			_staticData.navFrameIndex = 37;
2755 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus = 2;
2756 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCPlayedNoStinger = 0;
2757 			viewWindow->invalidateWindow(false); // Original doesn't do this, but I can't see how it works otherwise
2758 			return SC_TRUE;
2759 		case 2: { // Proceed with downloading
2760 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(11);
2761 			_staticData.navFrameIndex = 36;
2762 			((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus = 3;
2763 
2764 			// Move the player back and play the instructions for the door
2765 			DestinationScene destData;
2766 			destData.destinationScene = Location(6, 4, 1, 2, 1, 0);
2767 			destData.transitionType = TRANSITION_VIDEO;
2768 			destData.transitionData = 0;
2769 			destData.transitionStartFrame = -1;
2770 			destData.transitionLength = -1;
2771 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
2772 			return SC_TRUE;
2773 		}
2774 		}
2775 	} else if (_no.contains(pointLocation)) {
2776 		switch (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus) {
2777 		case 1: { // No-go on the scan, so drop the player back and play the rejection sound file
2778 			if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCPlayedNoStinger == 0) {
2779 				_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 9), 128, false, true);
2780 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCPlayedNoStinger = 1;
2781 			}
2782 
2783 			DestinationScene destData;
2784 			destData.destinationScene = Location(6, 4, 1, 2, 1, 0);
2785 			destData.transitionType = TRANSITION_VIDEO;
2786 			destData.transitionData = 0;
2787 			destData.transitionStartFrame = -1;
2788 			destData.transitionLength = -1;
2789 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
2790 			return SC_TRUE;
2791 		}
2792 		case 2: { // No-go on the download, so drop the player back and play the rejection sound file
2793 			if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCPlayedNoStinger == 0) {
2794 				_vm->_sound->playSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 10), 128, false, true);
2795 				((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCPlayedNoStinger = 1;
2796 			}
2797 
2798 			DestinationScene destData;
2799 			destData.destinationScene = Location(6, 4, 1, 2, 1, 0);
2800 			destData.transitionType = TRANSITION_VIDEO;
2801 			destData.transitionData = 0;
2802 			destData.transitionStartFrame = -1;
2803 			destData.transitionLength = -1;
2804 			((SceneViewWindow *)viewWindow)->moveToDestination(destData);
2805 			return SC_TRUE;
2806 		}
2807 		}
2808 	}
2809 
2810 	return SC_FALSE;
2811 }
2812 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2813 int ArthurScanningRoomConversation::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2814 	if (_yes.contains(pointLocation) || _no.contains(pointLocation))
2815 		return kCursorFinger;
2816 
2817 	return kCursorArrow;
2818 }
2819 
2820 class ScanningRoomNexusDoorNormalFacing : public SceneBase {
2821 public:
2822 	ScanningRoomNexusDoorNormalFacing(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2823 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
2824 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2825 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2826 
2827 private:
2828 	Common::Rect _clickable;
2829 };
2830 
ScanningRoomNexusDoorNormalFacing(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2831 ScanningRoomNexusDoorNormalFacing::ScanningRoomNexusDoorNormalFacing(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2832 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2833 	_clickable = Common::Rect(162, 67, 284, 189);
2834 }
2835 
postEnterRoom(Window * viewWindow,const Location & priorLocation)2836 int ScanningRoomNexusDoorNormalFacing::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
2837 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardNexusDoorComment == 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus == 3) {
2838 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 8));
2839 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardNexusDoorComment = 1;
2840 	}
2841 
2842 	return SC_TRUE;
2843 }
2844 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2845 int ScanningRoomNexusDoorNormalFacing::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2846 	if (_clickable.contains(pointLocation)) {
2847 		// Change the still frame
2848 		int oldFrame = _staticData.navFrameIndex;
2849 		_staticData.navFrameIndex = 43;
2850 		viewWindow->invalidateWindow(false);
2851 
2852 		// Play the beep and voiceovers
2853 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 1, 12));
2854 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, 1, 13));
2855 
2856 		// Reset the frame
2857 		_staticData.navFrameIndex = oldFrame;
2858 		viewWindow->invalidateWindow(false);
2859 		return SC_TRUE;
2860 	}
2861 
2862 	return SC_FALSE;
2863 }
2864 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2865 int ScanningRoomNexusDoorNormalFacing::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2866 	if (_clickable.contains(pointLocation))
2867 		return kCursorFinger;
2868 
2869 	return kCursorArrow;
2870 }
2871 
2872 class ScanningRoomNexusDoorZoomInCodePad : public SceneBase {
2873 public:
2874 	ScanningRoomNexusDoorZoomInCodePad(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2875 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2876 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2877 
2878 private:
2879 	Common::Rect _controls;
2880 };
2881 
ScanningRoomNexusDoorZoomInCodePad(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2882 ScanningRoomNexusDoorZoomInCodePad::ScanningRoomNexusDoorZoomInCodePad(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2883 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2884 	_controls = Common::Rect(160, 50, 282, 140);
2885 }
2886 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2887 int ScanningRoomNexusDoorZoomInCodePad::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2888 	if (_controls.contains(pointLocation)) {
2889 		DestinationScene destinationData;
2890 		destinationData.destinationScene = _staticData.location;
2891 		destinationData.destinationScene.depth = 1;
2892 		destinationData.transitionType = TRANSITION_VIDEO;
2893 		destinationData.transitionData = 1;
2894 		destinationData.transitionStartFrame = -1;
2895 		destinationData.transitionLength = -1;
2896 		((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
2897 		return SC_TRUE;
2898 	}
2899 
2900 	return SC_FALSE;
2901 }
2902 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)2903 int ScanningRoomNexusDoorZoomInCodePad::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
2904 	if (_controls.contains(pointLocation))
2905 		return kCursorMagnifyingGlass;
2906 
2907 	return kCursorArrow;
2908 }
2909 
2910 class ScanningRoomNexusDoorCodePad : public SceneBase {
2911 public:
2912 	ScanningRoomNexusDoorCodePad(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
2913 	~ScanningRoomNexusDoorCodePad();
2914 	void preDestructor();
2915 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
2916 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
2917 	int onCharacter(Window *viewWindow, const Common::KeyState &character);
2918 	int gdiPaint(Window *viewWindow);
2919 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
2920 
2921 private:
2922 	Common::Rect _numbers[10];
2923 	Common::String _entries;
2924 	Graphics::Font *_textFont;
2925 	int _lineHeight;
2926 	Common::Rect _display;
2927 };
2928 
ScanningRoomNexusDoorCodePad(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)2929 ScanningRoomNexusDoorCodePad::ScanningRoomNexusDoorCodePad(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
2930 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
2931 	_numbers[0] = Common::Rect(200, 129, 229, 146);
2932 	_numbers[1] = Common::Rect(165, 63, 194, 80);
2933 	_numbers[2] = Common::Rect(200, 63, 229, 80);
2934 	_numbers[3] = Common::Rect(235, 63, 264, 80);
2935 	_numbers[4] = Common::Rect(165, 85, 194, 102);
2936 	_numbers[5] = Common::Rect(200, 85, 229, 102);
2937 	_numbers[6] = Common::Rect(235, 85, 264, 102);
2938 	_numbers[7] = Common::Rect(165, 107, 194, 124);
2939 	_numbers[8] = Common::Rect(200, 107, 229, 124);
2940 	_numbers[9] = Common::Rect(235, 107, 264, 124);
2941 	_display = Common::Rect(166, 40, 262, 58);
2942 	_lineHeight = _vm->getLanguage() == Common::JA_JPN ? 12 : 14;
2943 	_textFont = _vm->_gfx->createFont(_lineHeight);
2944 }
2945 
~ScanningRoomNexusDoorCodePad()2946 ScanningRoomNexusDoorCodePad::~ScanningRoomNexusDoorCodePad() {
2947 	preDestructor();
2948 }
2949 
preDestructor()2950 void ScanningRoomNexusDoorCodePad::preDestructor() {
2951 	delete _textFont;
2952 	_textFont = nullptr;
2953 }
2954 
postEnterRoom(Window * viewWindow,const Location & priorLocation)2955 int ScanningRoomNexusDoorCodePad::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
2956 	// Play Arthur's comment, if applicable
2957 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardNexusDoorCode == 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus == 3) {
2958 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 7));
2959 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardNexusDoorCode = 1;
2960 	}
2961 
2962 	return SC_TRUE;
2963 }
2964 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)2965 int ScanningRoomNexusDoorCodePad::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
2966 	for (int i = 0; i < 10; i++) {
2967 		if (_numbers[i].contains(pointLocation)) {
2968 			if (_entries.size() < 5) {
2969 				// Append
2970 				_entries += (char)('0' + i);
2971 				viewWindow->invalidateWindow(false);
2972 
2973 				if (_entries == "32770") {
2974 					// If the answer is correct, move to the depth with the open hatch movie
2975 					DestinationScene destinationData;
2976 					destinationData.destinationScene = _staticData.location;
2977 					destinationData.destinationScene.depth = 2;
2978 					destinationData.transitionType = TRANSITION_VIDEO;
2979 					destinationData.transitionData = 3;
2980 					destinationData.transitionStartFrame = -1;
2981 					destinationData.transitionLength = -1;
2982 					((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
2983 				}
2984 
2985 				return SC_TRUE;
2986 			} else {
2987 				// Reset
2988 				_entries = (char)('0' + i);
2989 				viewWindow->invalidateWindow(false);
2990 				return SC_TRUE;
2991 			}
2992 		}
2993 	}
2994 
2995 	DestinationScene destinationData;
2996 	destinationData.destinationScene = _staticData.location;
2997 	destinationData.destinationScene.depth = 0;
2998 	destinationData.transitionType = TRANSITION_VIDEO;
2999 	destinationData.transitionData = 2;
3000 	destinationData.transitionStartFrame = -1;
3001 	destinationData.transitionLength = -1;
3002 	((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
3003 	return SC_TRUE;
3004 }
3005 
onCharacter(Window * viewWindow,const Common::KeyState & character)3006 int ScanningRoomNexusDoorCodePad::onCharacter(Window *viewWindow, const Common::KeyState &character) {
3007 	if (character.keycode >= Common::KEYCODE_0 && character.keycode <= Common::KEYCODE_9) {
3008 		char c = (char)('0' + character.keycode - Common::KEYCODE_0);
3009 
3010 		if (_entries.size() < 5) {
3011 			// Append
3012 			_entries += c;
3013 			viewWindow->invalidateWindow(false);
3014 
3015 			if (_entries == "32770") {
3016 				// If the answer is correct, move to the depth with the open hatch movie
3017 				DestinationScene destinationData;
3018 				destinationData.destinationScene = _staticData.location;
3019 				destinationData.destinationScene.depth = 2;
3020 				destinationData.transitionType = TRANSITION_VIDEO;
3021 				destinationData.transitionData = 3;
3022 				destinationData.transitionStartFrame = -1;
3023 				destinationData.transitionLength = -1;
3024 				((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
3025 			}
3026 
3027 			return SC_TRUE;
3028 		} else {
3029 			// Reset
3030 			_entries = c;
3031 			viewWindow->invalidateWindow(false);
3032 			return SC_TRUE;
3033 		}
3034 	}
3035 
3036 	if ((character.keycode == Common::KEYCODE_BACKSPACE || character.keycode == Common::KEYCODE_DELETE) && !_entries.empty()) {
3037 		// Delete last character
3038 		_entries.deleteLastChar();
3039 		viewWindow->invalidateWindow(false);
3040 		return SC_TRUE;
3041 	}
3042 
3043 	return SC_FALSE;
3044 }
3045 
gdiPaint(Window * viewWindow)3046 int ScanningRoomNexusDoorCodePad::gdiPaint(Window *viewWindow) {
3047 	if (!_entries.empty()) {
3048 		uint32 textColor = _vm->_gfx->getColor(208, 144, 24);
3049 		Common::Rect absoluteRect = viewWindow->getAbsoluteRect();
3050 		Common::Rect rect(_display);
3051 		rect.translate(absoluteRect.left, absoluteRect.top);
3052 		_vm->_gfx->renderText(_vm->_gfx->getScreen(), _textFont, _entries, rect.left, rect.top, rect.width(), rect.height(), textColor, _lineHeight, kTextAlignLeft, true);
3053 	}
3054 
3055 	return SC_REPAINT;
3056 }
3057 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3058 int ScanningRoomNexusDoorCodePad::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3059 	for (int i = 0; i < 10; i++)
3060 		if (_numbers[i].contains(pointLocation))
3061 			return kCursorFinger;
3062 
3063 	return kCursorPutDown;
3064 }
3065 
3066 class ScanningRoomNexusDoorPullHandle : public SceneBase {
3067 public:
3068 	ScanningRoomNexusDoorPullHandle(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
3069 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
3070 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3071 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3072 
3073 private:
3074 	Common::Rect _handle;
3075 };
3076 
ScanningRoomNexusDoorPullHandle(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3077 ScanningRoomNexusDoorPullHandle::ScanningRoomNexusDoorPullHandle(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
3078 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3079 	_handle = Common::Rect(186, 44, 276, 154);
3080 }
3081 
postEnterRoom(Window * viewWindow,const Location & priorLocation)3082 int ScanningRoomNexusDoorPullHandle::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
3083 	// Play Arthur's comment, if applicable
3084 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardNexusDoorCode == 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus == 3) {
3085 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, 7));
3086 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCHeardNexusDoorCode = 1;
3087 	}
3088 
3089 	return SC_TRUE;
3090 }
3091 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3092 int ScanningRoomNexusDoorPullHandle::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3093 	if (_handle.contains(pointLocation)) {
3094 		DestinationScene destinationData;
3095 		destinationData.destinationScene = Location(6, 5, 0, 0, 1, 0);
3096 		destinationData.transitionType = TRANSITION_VIDEO;
3097 		destinationData.transitionData = 4;
3098 		destinationData.transitionStartFrame = -1;
3099 		destinationData.transitionLength = -1;
3100 		((SceneViewWindow *)viewWindow)->moveToDestination(destinationData);
3101 		return SC_TRUE;
3102 	}
3103 
3104 	return SC_FALSE;
3105 }
3106 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3107 int ScanningRoomNexusDoorPullHandle::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3108 	if (_handle.contains(pointLocation))
3109 		return kCursorFinger;
3110 
3111 	return kCursorArrow;
3112 }
3113 
3114 class MachineRoomExitDoor : public SceneBase {
3115 public:
3116 	MachineRoomExitDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
3117 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3118 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3119 
3120 private:
3121 	Common::Rect _clickable;
3122 	DestinationScene _destData;
3123 };
3124 
MachineRoomExitDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3125 MachineRoomExitDoor::MachineRoomExitDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
3126 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3127 	_clickable = Common::Rect(138, 0, 338, 189);
3128 	_destData.destinationScene = Location(6, 7, 1, 3, 1, 0);
3129 	_destData.transitionType = TRANSITION_VIDEO;
3130 	_destData.transitionData = 4;
3131 	_destData.transitionStartFrame = -1;
3132 	_destData.transitionLength = -1;
3133 }
3134 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3135 int MachineRoomExitDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3136 	if (_clickable.contains(pointLocation)) {
3137 		((SceneViewWindow *)viewWindow)->moveToDestination(_destData);
3138 		return SC_TRUE;
3139 	}
3140 
3141 	return SC_FALSE;
3142 }
3143 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3144 int MachineRoomExitDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3145 	if (_clickable.contains(pointLocation))
3146 		return kCursorFinger;
3147 
3148 	return kCursorArrow;
3149 }
3150 
3151 class MachineRoomTamperedSculpture : public SceneBase {
3152 public:
3153 	MachineRoomTamperedSculpture(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
3154 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3155 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
3156 	int locateAttempted(Window *viewWindow, const Common::Point &pointLocation);
3157 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3158 
3159 private:
3160 	Common::Rect _clickable;
3161 };
3162 
MachineRoomTamperedSculpture(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3163 MachineRoomTamperedSculpture::MachineRoomTamperedSculpture(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
3164 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3165 	_clickable = Common::Rect(184, 54, 274, 142);
3166 }
3167 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3168 int MachineRoomTamperedSculpture::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3169 	if (_clickable.contains(pointLocation)) {
3170 		if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRCorrectFreqSet == 2) {
3171 			// Play the morph movie
3172 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(1);
3173 
3174 			// Attempt to add it to the biochip
3175 			if (((SceneViewWindow *)viewWindow)->addNumberToGlobalFlagTable(offsetof(GlobalFlags, evcapBaseID), offsetof(GlobalFlags, evcapNumCaptured), 12, AI_EVIDENCE_SCULPTURE))
3176 				((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_MBT_EVIDENCE_RIPPLE_DOCUMENTED));
3177 			else
3178 				((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_MBT_EVIDENCE_ALREADY_ACQUIRED));
3179 
3180 			// Turn off evidence capture
3181 			((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->disableEvidenceCapture();
3182 
3183 			// Set the scoring flag
3184 			((SceneViewWindow *)viewWindow)->getGlobalFlags().scoreFoundSculptureDiagram = 1;
3185 
3186 			// Update the AI chip and check for spontaneous comments
3187 			if (((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI))
3188 				((SceneViewWindow *)viewWindow)->playAIComment(_staticData.location, AI_COMMENT_TYPE_SPONTANEOUS);
3189 
3190 			((GameUIWindow *)viewWindow->getParent())->_bioChipRightWindow->sceneChanged();
3191 		} else {
3192 			// Play the normal morphing animation
3193 			((SceneViewWindow *)viewWindow)->playSynchronousAnimation(0);
3194 		}
3195 
3196 		return SC_TRUE;
3197 	}
3198 
3199 	return SC_FALSE;
3200 }
3201 
postEnterRoom(Window * viewWindow,const Location & priorLocation)3202 int MachineRoomTamperedSculpture::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
3203 	// If we have not yet captured it, set the anachronism message
3204 	if (!((SceneViewWindow *)viewWindow)->isNumberInGlobalFlagTable(offsetof(GlobalFlags, evcapBaseID), offsetof(GlobalFlags, evcapNumCaptured), AI_EVIDENCE_SCULPTURE))
3205 		((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_MBT_EVIDENCE_PRESENT));
3206 
3207 	return SC_TRUE;
3208 }
3209 
locateAttempted(Window * viewWindow,const Common::Point & pointLocation)3210 int MachineRoomTamperedSculpture::locateAttempted(Window *viewWindow, const Common::Point &pointLocation) {
3211 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().bcLocateEnabled == 1 && _clickable.contains(pointLocation) &&
3212 			!((SceneViewWindow *)viewWindow)->isNumberInGlobalFlagTable(offsetof(GlobalFlags, evcapBaseID), offsetof(GlobalFlags, evcapNumCaptured), AI_EVIDENCE_SCULPTURE)) {
3213 		((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_MBT_EVIDENCE_MUST_BE_REVEALED)); // All will be reveaaaaaled
3214 		return SC_TRUE;
3215 	}
3216 
3217 	return SC_FALSE;
3218 }
3219 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3220 int MachineRoomTamperedSculpture::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3221 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().bcLocateEnabled == 1) {
3222 		if (_clickable.contains(pointLocation))
3223 			return -2;
3224 		return -1;
3225 	}
3226 
3227 	if (_clickable.contains(pointLocation))
3228 		return kCursorFinger;
3229 
3230 	return kCursorArrow;
3231 }
3232 
3233 class MachineRoomHarmonicsInterface : public SceneBase {
3234 public:
3235 	MachineRoomHarmonicsInterface(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
3236 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3237 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3238 
3239 private:
3240 	Common::Rect _testButton;
3241 	Common::Rect _turnRight;
3242 	Common::Rect _turnLeft;
3243 	int _currentSelection;
3244 	bool _tested;
3245 };
3246 
MachineRoomHarmonicsInterface(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3247 MachineRoomHarmonicsInterface::MachineRoomHarmonicsInterface(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
3248 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3249 	_testButton = Common::Rect(122, 90, 160, 118);
3250 	_turnRight = Common::Rect(128, 27, 173, 48);
3251 	_turnLeft = Common::Rect(128, 53, 173, 80);
3252 	_currentSelection = ((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRCorrectFreqSet;
3253 	_tested = false;
3254 
3255 	switch (_currentSelection) {
3256 	case 0:
3257 		_staticData.navFrameIndex = 105;
3258 		break;
3259 	case 1:
3260 		_staticData.navFrameIndex = 107;
3261 		break;
3262 	case 2:
3263 		_staticData.navFrameIndex = 109;
3264 		break;
3265 	case 3:
3266 		_staticData.navFrameIndex = 111;
3267 		break;
3268 	case 4:
3269 		_staticData.navFrameIndex = 113;
3270 		break;
3271 	case 5:
3272 		_staticData.navFrameIndex = 115;
3273 		break;
3274 	case 6:
3275 		_staticData.navFrameIndex = 116;
3276 		break;
3277 	case 7:
3278 		_staticData.navFrameIndex = 118;
3279 		break;
3280 	}
3281 }
3282 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3283 int MachineRoomHarmonicsInterface::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3284 	if (_turnRight.contains(pointLocation)) {
3285 		_staticData.navFrameIndex = 103;
3286 		viewWindow->invalidateWindow(false);
3287 
3288 		// TODO: Delay
3289 
3290 		_staticData.navFrameIndex = 104;
3291 		viewWindow->invalidateWindow(false);
3292 
3293 		// TODO: Delay
3294 
3295 		_currentSelection++;
3296 		if (_currentSelection > 7)
3297 			_currentSelection = 0;
3298 
3299 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRCorrectFreqSet = _currentSelection;
3300 		_tested = false;
3301 
3302 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRUsedHarmonicsInterface = 1;
3303 
3304 		switch (_currentSelection) {
3305 		case 0:
3306 			_staticData.navFrameIndex = 105;
3307 			break;
3308 		case 1:
3309 			_staticData.navFrameIndex = 107;
3310 			break;
3311 		case 2:
3312 			_staticData.navFrameIndex = 109;
3313 			break;
3314 		case 3:
3315 			_staticData.navFrameIndex = 111;
3316 			break;
3317 		case 4:
3318 			_staticData.navFrameIndex = 113;
3319 			break;
3320 		case 5:
3321 			_staticData.navFrameIndex = 115;
3322 			break;
3323 		case 6:
3324 			_staticData.navFrameIndex = 116;
3325 			break;
3326 		case 7:
3327 			_staticData.navFrameIndex = 118;
3328 			break;
3329 		}
3330 
3331 		viewWindow->invalidateWindow(false);
3332 		return SC_TRUE;
3333 	}
3334 
3335 	if (_turnLeft.contains(pointLocation)) {
3336 		_staticData.navFrameIndex = 104;
3337 		viewWindow->invalidateWindow(false);
3338 
3339 		// TODO: Delay
3340 
3341 		_staticData.navFrameIndex = 103;
3342 		viewWindow->invalidateWindow(false);
3343 
3344 		// TODO: Delay
3345 
3346 		_currentSelection--;
3347 		if (_currentSelection < 0)
3348 			_currentSelection = 7;
3349 
3350 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRCorrectFreqSet = _currentSelection;
3351 		_tested = false;
3352 
3353 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRUsedHarmonicsInterface = 1;
3354 
3355 		switch (_currentSelection) {
3356 		case 0:
3357 			_staticData.navFrameIndex = 105;
3358 			break;
3359 		case 1:
3360 			_staticData.navFrameIndex = 107;
3361 			break;
3362 		case 2:
3363 			_staticData.navFrameIndex = 109;
3364 			break;
3365 		case 3:
3366 			_staticData.navFrameIndex = 111;
3367 			break;
3368 		case 4:
3369 			_staticData.navFrameIndex = 113;
3370 			break;
3371 		case 5:
3372 			_staticData.navFrameIndex = 115;
3373 			break;
3374 		case 6:
3375 			_staticData.navFrameIndex = 116;
3376 			break;
3377 		case 7:
3378 			_staticData.navFrameIndex = 118;
3379 			break;
3380 		}
3381 
3382 		viewWindow->invalidateWindow(false);
3383 		return SC_TRUE;
3384 	}
3385 
3386 	if (_testButton.contains(pointLocation) && _currentSelection != 5 && !_tested) {
3387 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRUsedHarmonicsInterface = 1;
3388 
3389 		// Play the proper sound effect
3390 		int fileID = -1;
3391 		switch (_currentSelection) {
3392 		case 0:
3393 			fileID = 6;
3394 			break;
3395 		case 1:
3396 			fileID = 7;
3397 			break;
3398 		case 2:
3399 			fileID = 8;
3400 			break;
3401 		case 3:
3402 			fileID = 9;
3403 			break;
3404 		case 4:
3405 			fileID = 10;
3406 			break;
3407 		case 6:
3408 			fileID = 11;
3409 			break;
3410 		case 7:
3411 			fileID = 12;
3412 			break;
3413 		}
3414 
3415 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, fileID), 128);
3416 
3417 		// Increment the frame to display the results
3418 		_staticData.navFrameIndex++;
3419 		viewWindow->invalidateWindow(false);
3420 
3421 		_tested = true;
3422 
3423 		// Set the score flag
3424 		if (_currentSelection == 2)
3425 			((SceneViewWindow *)viewWindow)->getGlobalFlags().scoreResearchMorphSculpture = 1;
3426 
3427 		return SC_TRUE;
3428 	}
3429 
3430 	// Return the player to the original position (depth zero)
3431 	DestinationScene destData;
3432 	destData.destinationScene = _staticData.location;
3433 	destData.destinationScene.depth = 0;
3434 	destData.transitionType = TRANSITION_NONE;
3435 	destData.transitionData = -1;
3436 	destData.transitionStartFrame = -1;
3437 	destData.transitionLength = -1;
3438 	((SceneViewWindow *)viewWindow)->moveToDestination(destData);
3439 	return SC_TRUE;
3440 }
3441 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3442 int MachineRoomHarmonicsInterface::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3443 	if (_turnRight.contains(pointLocation))
3444 		return kCursorArrowRight;
3445 
3446 	if (_turnLeft.contains(pointLocation))
3447 		return kCursorArrowRight;
3448 
3449 	if (_testButton.contains(pointLocation) && _currentSelection != 5 && !_tested)
3450 		return kCursorFinger;
3451 
3452 	return kCursorPutDown;
3453 }
3454 
3455 class MachineRoomHarmonicsZoomIn : public SceneBase {
3456 public:
3457 	MachineRoomHarmonicsZoomIn(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
3458 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3459 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3460 
3461 private:
3462 	Common::Rect _clickRegion;
3463 	DestinationScene _clickDestination;
3464 };
3465 
MachineRoomHarmonicsZoomIn(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3466 MachineRoomHarmonicsZoomIn::MachineRoomHarmonicsZoomIn(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
3467 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3468 	_clickRegion = Common::Rect(90, 60, 178, 134);
3469 	_clickDestination.destinationScene = _staticData.location;
3470 	_clickDestination.destinationScene.depth = 1;
3471 	_clickDestination.transitionType = TRANSITION_NONE;
3472 	_clickDestination.transitionData = -1;
3473 	_clickDestination.transitionStartFrame = -1;
3474 	_clickDestination.transitionLength = -1;
3475 }
3476 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3477 int MachineRoomHarmonicsZoomIn::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3478 	if (_clickRegion.contains(pointLocation))
3479 		((SceneViewWindow *)viewWindow)->moveToDestination(_clickDestination);
3480 
3481 	return SC_FALSE;
3482 }
3483 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3484 int MachineRoomHarmonicsZoomIn::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3485 	if (_clickRegion.contains(pointLocation))
3486 		return kCursorMagnifyingGlass;
3487 
3488 	return kCursorArrow;
3489 }
3490 
3491 class SpaceDoor : public SceneBase {
3492 public:
3493 	SpaceDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
3494 			int left = -1, int top = -1, int right = -1, int bottom = -1, int openFrame = -1, int closedFrame = -1, int depth = -1,
3495 			int transitionType = -1, int transitionData = -1, int transitionStartFrame = -1, int transitionLength = -1,
3496 			int doorFlag = -1, int doorFlagValue = 0);
3497 	int mouseDown(Window *viewWindow, const Common::Point &pointLocation);
3498 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3499 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3500 
3501 private:
3502 	bool _clicked;
3503 	Common::Rect _clickable;
3504 	DestinationScene _destData;
3505 	int _openFrame;
3506 	int _closedFrame;
3507 	int _doorFlag;
3508 	int _doorFlagValue;
3509 };
3510 
SpaceDoor(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int left,int top,int right,int bottom,int openFrame,int closedFrame,int depth,int transitionType,int transitionData,int transitionStartFrame,int transitionLength,int doorFlag,int doorFlagValue)3511 SpaceDoor::SpaceDoor(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
3512 		int left, int top, int right, int bottom, int openFrame, int closedFrame, int depth,
3513 		int transitionType, int transitionData, int transitionStartFrame, int transitionLength,
3514 		int doorFlag, int doorFlagValue) :
3515 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3516 	_clicked = false;
3517 	_openFrame = openFrame;
3518 	_closedFrame = closedFrame;
3519 	_doorFlag = doorFlag;
3520 	_doorFlagValue = doorFlagValue;
3521 	_clickable = Common::Rect(left, top, right, bottom);
3522 	_destData.destinationScene = _staticData.location;
3523 	_destData.destinationScene.depth = depth;
3524 	_destData.transitionType = transitionType;
3525 	_destData.transitionData = transitionData;
3526 	_destData.transitionStartFrame = transitionStartFrame;
3527 	_destData.transitionLength = transitionLength;
3528 }
3529 
mouseDown(Window * viewWindow,const Common::Point & pointLocation)3530 int SpaceDoor::mouseDown(Window *viewWindow, const Common::Point &pointLocation) {
3531 	if (_clickable.contains(pointLocation)) {
3532 		_clicked = true;
3533 		return SC_TRUE;
3534 	}
3535 
3536 	return SC_FALSE;
3537 }
3538 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3539 int SpaceDoor::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3540 	if (_clicked) {
3541 		// If we are facing the scanning room door and we have Arthur, automatically recall
3542 		// to the future apartment
3543 		if (_staticData.location.timeZone == 6 && _staticData.location.environment == 3 &&
3544 				_staticData.location.node == 9 && _staticData.location.facing == 0 &&
3545 				_staticData.location.orientation == 0 && _staticData.location.depth == 0 &&
3546 				((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemBioChipAI)) {
3547 			((SceneViewWindow *)viewWindow)->timeSuitJump(4);
3548 			return SC_TRUE;
3549 		}
3550 
3551 		if (_doorFlag < 0 || ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_doorFlag) == _doorFlagValue) {
3552 			// Change the still frame to the new one
3553 			if (_openFrame >= 0) {
3554 				_staticData.navFrameIndex = _openFrame;
3555 				viewWindow->invalidateWindow(false);
3556 				_vm->_sound->playSynchronousSoundEffect("BITDATA/AILAB/AI_LOCK.BTA");
3557 			}
3558 
3559 			((SceneViewWindow *)viewWindow)->moveToDestination(_destData);
3560 		} else {
3561 			// Display the closed frame
3562 			if (_closedFrame >= 0) {
3563 				_staticData.navFrameIndex = _closedFrame;
3564 				viewWindow->invalidateWindow(false);
3565 			}
3566 		}
3567 
3568 		_clicked = false;
3569 		return SC_TRUE;
3570 	}
3571 
3572 	return SC_FALSE;
3573 }
3574 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3575 int SpaceDoor::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3576 	if (_clickable.contains(pointLocation))
3577 		return kCursorFinger;
3578 
3579 	return kCursorArrow;
3580 }
3581 
3582 class ScanningRoomNexusDoorToGlobe : public SceneBase {
3583 public:
3584 	ScanningRoomNexusDoorToGlobe(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation);
3585 };
3586 
ScanningRoomNexusDoorToGlobe(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3587 ScanningRoomNexusDoorToGlobe::ScanningRoomNexusDoorToGlobe(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) :
3588 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3589 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiSCConversationStatus == 3)
3590 		_staticData.destForward.destinationScene = Location(-1, -1, -1, -1, -1, -1);
3591 }
3592 
3593 class MachineRoomEntry : public SceneBase {
3594 public:
3595 	MachineRoomEntry(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation, int soundID = -1);
3596 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
3597 	int timerCallback(Window *viewWindow);
3598 
3599 private:
3600 	int _soundID;
3601 	bool _die;
3602 };
3603 
MachineRoomEntry(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int soundID)3604 MachineRoomEntry::MachineRoomEntry(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation, int soundID) :
3605 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3606 	_soundID = soundID;
3607 	_die = false;
3608 }
3609 
postEnterRoom(Window * viewWindow,const Location & priorLocation)3610 int MachineRoomEntry::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
3611 	// If the machine room is not pressurized, flag ourselves for death
3612 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().aiMRPressurized == 0) {
3613 		_die = true;
3614 		((SceneViewWindow *)viewWindow)->_disableArthur = true;
3615 		return SC_TRUE;
3616 	}
3617 
3618 	// Otherwise, notify the player they have entered a pressurized room and their oxygen has replenished
3619 	if (_staticData.location.node != priorLocation.node) {
3620 		((SceneViewWindow *)viewWindow)->displayLiveText(_vm->getString(IDS_AI_ENTERING_PRES_ENV_TEXT));
3621 		((SceneViewWindow *)viewWindow)->getGlobalFlags().aiOxygenTimer = GC_AIHW_STARTING_VALUE;
3622 	}
3623 
3624 	return SC_TRUE;
3625 }
3626 
timerCallback(Window * viewWindow)3627 int MachineRoomEntry::timerCallback(Window *viewWindow) {
3628 	// If we have not pressurized the room, kill the player
3629 	if (_die) {
3630 		((SceneViewWindow *)viewWindow)->showDeathScene(41);
3631 		return SC_DEATH;
3632 	}
3633 
3634 	return SC_TRUE;
3635 }
3636 
3637 class DockingBayPlaySoundEntering : public SceneBase {
3638 public:
3639 	DockingBayPlaySoundEntering(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
3640 			int soundFileNameID = -1, int flagOffset = -1);
3641 	int postEnterRoom(Window *viewWindow, const Location &priorLocation);
3642 
3643 private:
3644 	int _soundFileNameID;
3645 	int _flagOffset;
3646 };
3647 
DockingBayPlaySoundEntering(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int soundFileNameID,int flagOffset)3648 DockingBayPlaySoundEntering::DockingBayPlaySoundEntering(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
3649 		int soundFileNameID, int flagOffset) :
3650 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3651 	_soundFileNameID = soundFileNameID;
3652 	_flagOffset = flagOffset;
3653 
3654 	if (((SceneViewWindow *)viewWindow)->getGlobalFlags().generalWalkthroughMode == 1)
3655 		_staticData.destForward.destinationScene = Location(-1, -1, -1, -1, -1, -1);
3656 }
3657 
postEnterRoom(Window * viewWindow,const Location & priorLocation)3658 int DockingBayPlaySoundEntering::postEnterRoom(Window *viewWindow, const Location &priorLocation) {
3659 	if (_flagOffset >= 0 && ((SceneViewWindow *)viewWindow)->getGlobalFlagByte(_flagOffset) == 0) {
3660 		_vm->_sound->playSynchronousSoundEffect(_vm->getFilePath(_staticData.location.timeZone, _staticData.location.environment, _soundFileNameID));
3661 		((SceneViewWindow *)viewWindow)->setGlobalFlagByte(_flagOffset, 1);
3662 	}
3663 
3664 	return SC_TRUE;
3665 }
3666 
3667 class MachineRoomPlayAnim : public SceneBase {
3668 public:
3669 	MachineRoomPlayAnim(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
3670 			int left = -1, int top = -1, int right = -1, int bottom = -1, int animID = -1);
3671 	int mouseUp(Window *viewWindow, const Common::Point &pointLocation);
3672 	int specifyCursor(Window *viewWindow, const Common::Point &pointLocation);
3673 
3674 private:
3675 	Common::Rect _clickable;
3676 	int _animID;
3677 };
3678 
MachineRoomPlayAnim(BuriedEngine * vm,Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation,int left,int top,int right,int bottom,int animID)3679 MachineRoomPlayAnim::MachineRoomPlayAnim(BuriedEngine *vm, Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation,
3680 		int left, int top, int right, int bottom, int animID) :
3681 		SceneBase(vm, viewWindow, sceneStaticData, priorLocation) {
3682 	_clickable = Common::Rect(left, top, right, bottom);
3683 	_animID = animID;
3684 }
3685 
mouseUp(Window * viewWindow,const Common::Point & pointLocation)3686 int MachineRoomPlayAnim::mouseUp(Window *viewWindow, const Common::Point &pointLocation) {
3687 	if (_clickable.contains(pointLocation) && _animID >= 0) {
3688 		((SceneViewWindow *)viewWindow)->playSynchronousAnimation(_animID);
3689 		return SC_TRUE;
3690 	}
3691 
3692 	return SC_FALSE;
3693 }
3694 
specifyCursor(Window * viewWindow,const Common::Point & pointLocation)3695 int MachineRoomPlayAnim::specifyCursor(Window *viewWindow, const Common::Point &pointLocation) {
3696 	if (_clickable.contains(pointLocation))
3697 		return kCursorFinger;
3698 
3699 	return kCursorArrow;
3700 }
3701 
initializeAILabTimeZoneAndEnvironment(Window * viewWindow,int environment)3702 bool SceneViewWindow::initializeAILabTimeZoneAndEnvironment(Window *viewWindow, int environment) {
3703 	if (environment == -1) {
3704 		GlobalFlags &flags = ((SceneViewWindow *)viewWindow)->getGlobalFlags();
3705 
3706 		flags.aiHWStingerID = 0;
3707 		flags.aiHWStingerChannelID = 0;
3708 		flags.aiCRStingerID = 0;
3709 		flags.aiCRStingerChannelID = 0;
3710 		flags.aiDBStingerID = 0;
3711 		flags.aiDBStingerChannelID = 0;
3712 		flags.aiOxygenTimer = kAIHWStartingValue;
3713 		flags.aiCRPressurized = flags.generalWalkthroughMode;
3714 		flags.aiCRPressurizedAttempted = 0;
3715 		flags.aiMRPressurized = flags.generalWalkthroughMode;
3716 		flags.aiIceMined = 0;
3717 		flags.aiOxygenReserves = 1;
3718 		flags.aiSCHeardInitialSpeech = 0;
3719 		flags.aiMRCorrectFreqSet = 4;
3720 		flags.aiSCConversationStatus = 0;
3721 		flags.aiSCHeardNexusDoorComment = 0;
3722 		flags.aiSCHeardNexusDoorCode = 0;
3723 		flags.aiNXPlayedBrainComment = 0;
3724 		flags.aiDBPlayedSecondArthur = 0;
3725 		flags.aiDBPlayedThirdArthur = 0;
3726 		flags.aiDBPlayedFourthArthur = 0;
3727 		flags.aiCRGrabbedMetalBar = ((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemMetalBar) ? 1 : 0;
3728 		flags.aiICGrabbedWaterCanister = (((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemWaterCanEmpty) || ((GameUIWindow *)viewWindow->getParent())->_inventoryWindow->isItemInInventory(kItemWaterCanFull)) ? 1 : 0;
3729 	} else if (environment == 1) {
3730 		((SceneViewWindow *)viewWindow)->getGlobalFlags().scoreEnteredSpaceStation = 1;
3731 	}
3732 
3733 	return true;
3734 }
3735 
startAILabAmbient(int oldTimeZone,int oldEnvironment,int environment,bool fade)3736 bool SceneViewWindow::startAILabAmbient(int oldTimeZone, int oldEnvironment, int environment, bool fade) {
3737 	_vm->_sound->setAmbientSound(_vm->getFilePath(6, environment, SF_AMBIENT), fade, 64);
3738 	return true;
3739 }
3740 
checkCustomSpaceStationAICommentDependencies(const Location & commentLocation,const AIComment & commentData)3741 bool SceneViewWindow::checkCustomSpaceStationAICommentDependencies(const Location &commentLocation, const AIComment &commentData) {
3742 	switch (commentData.dependencyFlagOffsetB) {
3743 	case 1: // After failing to pressurize from SW panel interface, before using mining controls
3744 		return _globalFlags.aiSWAttemptedPresMR == 1 && _globalFlags.aiICUsedMiningControls == 1;
3745 	case 2: // Never used oxygen before
3746 		return _globalFlags.aiICRefilledOxygen == 0;
3747 	case 3: // If no water canister is in our inventory
3748 		return !((GameUIWindow *)getParent())->_inventoryWindow->isItemInInventory(kItemWaterCanFull) && !((GameUIWindow *)getParent())->_inventoryWindow->isItemInInventory(kItemWaterCanEmpty);
3749 	case 4: // Have not used pressurization interface
3750 		return _globalFlags.aiSWAttemptedPresMR == 0;
3751 	case 5: // If tried biomass, not enough reserve oxygen
3752 		return _globalFlags.aiSWAttemptedPresMR == 1 && _globalFlags.aiOxygenReserves == 0;
3753 	case 6: // If tried biomass, not enough reserve, has not run mining sequence
3754 		return _globalFlags.aiSWAttemptedPresMR == 1 && _globalFlags.aiOxygenReserves == 0 && _globalFlags.aiICUsedMiningControls == 0;
3755 	case 7: // If tried biomass, not enough reserve, has run mining sequence, has not run processing sequence
3756 		return _globalFlags.aiSWAttemptedPresMR == 1 && _globalFlags.aiOxygenReserves == 0 && _globalFlags.aiICUsedMiningControls == 1 && _globalFlags.aiICProcessedOxygen == 0;
3757 	case 8: // If we have not pressurized the machine room
3758 		return _globalFlags.aiMRPressurized == 0;
3759 	case 9: // If we have not revealed the diagram
3760 		return _globalFlags.scoreFoundSculptureDiagram == 0;
3761 	case 10: // If we have not revealed the diagram or used the harmonics interface
3762 		return _globalFlags.scoreFoundSculptureDiagram == 0 && _globalFlags.aiMRUsedHarmonicsInterface == 0;
3763 	case 11: // After we have recorded evidence
3764 		return _globalFlags.scoreFoundSculptureDiagram == 1;
3765 	case 12: // Before using mining control, after having tried to pressurize biomass room
3766 		// clone2727: This was mistakenly cut out of the original
3767 		return _globalFlags.aiICUsedMiningControls == 0 && _globalFlags.aiSWAttemptedPresMR == 1;
3768 	}
3769 
3770 	return false;
3771 }
3772 
constructAILabSceneObject(Window * viewWindow,const LocationStaticData & sceneStaticData,const Location & priorLocation)3773 SceneBase *SceneViewWindow::constructAILabSceneObject(Window *viewWindow, const LocationStaticData &sceneStaticData, const Location &priorLocation) {
3774 	// Special scene for the trial version
3775 	if (_vm->isTrial())
3776 		return new TrialRecallScene(_vm, viewWindow, sceneStaticData, priorLocation);
3777 
3778 	switch (sceneStaticData.classID) {
3779 	case 0:
3780 		// Default scene
3781 		break;
3782 	case 1:
3783 		return new UseCheeseGirlPropellant(_vm, viewWindow, sceneStaticData, priorLocation);
3784 	case 3:
3785 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 172, 46, 262, 136, 87, -1, 1, TRANSITION_VIDEO, 2, -1, -1, -1, -1);
3786 	case 4:
3787 		return new PlayArthurOffsetTimed(_vm, viewWindow, sceneStaticData, priorLocation, 127, offsetof(GlobalFlags, aiHWStingerID), offsetof(GlobalFlags, aiHWStingerChannelID), 4, 10, 1); // 1.01 uses a delay of 2, clone2727 likes that better
3788 	case 5:
3789 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 144, 30, 268, 152, 88, -1, 1, TRANSITION_VIDEO, 4, -1, -1, -1, -1);
3790 	case 6:
3791 		return new PlaySoundExitingFromScene(_vm, viewWindow, sceneStaticData, priorLocation, 14);
3792 	case 7:
3793 		return new HabitatWingLockedDoor(_vm, viewWindow, sceneStaticData, priorLocation, 99, 12, 13, 166, 32, 286, 182);
3794 	case 8:
3795 		return new HabitatWingLockedDoor(_vm, viewWindow, sceneStaticData, priorLocation, 100, 12, 13, 130, 48, 290, 189);
3796 	case 9:
3797 		return new HabitatWingIceteroidDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3798 	case 11:
3799 		return new BaseOxygenTimer(_vm, viewWindow, sceneStaticData, priorLocation);
3800 	case 12:
3801 		return new BaseOxygenTimerInSpace(_vm, viewWindow, sceneStaticData, priorLocation);
3802 	case 20:
3803 		return new PlayArthurOffsetCapacitance(_vm, viewWindow, sceneStaticData, priorLocation, 127, offsetof(GlobalFlags, aiCRStingerID), offsetof(GlobalFlags, aiCRStingerChannelID), 4, 11, 1);
3804 	case 21:
3805 		return new CapacitanceToHabitatDoorClosed(_vm, viewWindow, sceneStaticData, priorLocation);
3806 	case 22:
3807 		return new CapacitanceToHabitatDoorOpen(_vm, viewWindow, sceneStaticData, priorLocation);
3808 	case 23:
3809 		return new ClickChangeSceneCapacitance(_vm, viewWindow, sceneStaticData, priorLocation, 122, 32, 310, 140, kCursorMagnifyingGlass, 6, 2, 3, 0, 1, 1, TRANSITION_VIDEO, 3, -1, -1);
3810 	case 24:
3811 		return new CapacitancePanelInterface(_vm, viewWindow, sceneStaticData, priorLocation);
3812 	case 25:
3813 		return new CapacitanceDockingBayDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3814 	case 26:
3815 		return new PlaySoundExitingFromScene(_vm, viewWindow, sceneStaticData, priorLocation, 14);
3816 	case 27:
3817 		return new PlayArthurOffsetCapacitance(_vm, viewWindow, sceneStaticData, priorLocation, 127, offsetof(GlobalFlags, aiCRStingerID), offsetof(GlobalFlags, aiCRStingerChannelID), 4, 11, 1, offsetof(GlobalFlags, aiCRGrabbedMetalBar), 73, 320, 40);
3818 	case 28:
3819 		return new PlayArthurOffsetCapacitance(_vm, viewWindow, sceneStaticData, priorLocation, 127, offsetof(GlobalFlags, aiCRStingerID), offsetof(GlobalFlags, aiCRStingerChannelID), 4, 11, 1, offsetof(GlobalFlags, aiCRGrabbedMetalBar), 66, 241, 25);
3820 	case 30:
3821 		return new PlaySoundEnteringScene(_vm, viewWindow, sceneStaticData, priorLocation, 5, offsetof(GlobalFlags, aiDBPlayedFirstArthur));
3822 	case 31:
3823 		return new SpaceDoor(_vm, viewWindow, sceneStaticData, priorLocation, 174, 70, 256, 152, 166, -1, 1, TRANSITION_VIDEO, 0, -1, -1, -1, 0);
3824 	case 32:
3825 		return new PlaySoundExitingFromScene(_vm, viewWindow, sceneStaticData, priorLocation, 14);
3826 	case 33:
3827 		return new SpaceDoor(_vm, viewWindow, sceneStaticData, priorLocation, 185, 42, 253, 110, 167, -1, 1, TRANSITION_VIDEO, 1, -1, -1, -1, 0);
3828 	case 35:
3829 		return new DockingBayPlaySoundEntering(_vm, viewWindow, sceneStaticData, priorLocation, 4, offsetof(GlobalFlags, aiDBPlayedMomComment));
3830 	case 36:
3831 		return new PlaySoundEnteringScene(_vm, viewWindow, sceneStaticData, priorLocation, 6, offsetof(GlobalFlags, aiDBPlayedSecondArthur));
3832 	case 37:
3833 		return new PlaySoundEnteringScene(_vm, viewWindow, sceneStaticData, priorLocation, 7, offsetof(GlobalFlags, aiDBPlayedThirdArthur));
3834 	case 38:
3835 		return new PlaySoundEnteringScene(_vm, viewWindow, sceneStaticData, priorLocation, 8, offsetof(GlobalFlags, aiDBPlayedFourthArthur));
3836 	case 39:
3837 		return new DisableForwardMovement(_vm, viewWindow, sceneStaticData, priorLocation, offsetof(GlobalFlags, generalWalkthroughMode), 1);
3838 	case 40:
3839 		return new ScanningRoomEntryScan(_vm, viewWindow, sceneStaticData, priorLocation);
3840 	case 41:
3841 		return new ScanningRoomWalkWarning(_vm, viewWindow, sceneStaticData, priorLocation);
3842 	case 42:
3843 		return new ScanningRoomDockingBayDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3844 	case 43:
3845 		return new ScanningRoomScienceWingDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3846 	case 44:
3847 		return new ArthurScanningRoomConversation(_vm, viewWindow, sceneStaticData, priorLocation);
3848 	case 45:
3849 		return new ScanningRoomNexusDoorNormalFacing(_vm, viewWindow, sceneStaticData, priorLocation);
3850 	case 46:
3851 		return new ScanningRoomNexusDoorZoomInCodePad(_vm, viewWindow, sceneStaticData, priorLocation);
3852 	case 47:
3853 		return new ScanningRoomNexusDoorCodePad(_vm, viewWindow, sceneStaticData, priorLocation);
3854 	case 48:
3855 		return new ScanningRoomNexusDoorPullHandle(_vm, viewWindow, sceneStaticData, priorLocation);
3856 	case 49:
3857 		return new ScanningRoomNexusDoorToGlobe(_vm, viewWindow, sceneStaticData, priorLocation);
3858 	case 50:
3859 		return new IceteroidPodTimed(_vm, viewWindow, sceneStaticData, priorLocation, 174, 96, 246, 118, 1, 6, 6, 1, 0, 1, 0);
3860 	case 51:
3861 		return new IceteroidPodTimed(_vm, viewWindow, sceneStaticData, priorLocation, 174, 96, 246, 118, 3, 6, 6, 0, 0, 1, 0);
3862 	case 52:
3863 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 164, 40, 276, 140, -1, -1, 1, TRANSITION_VIDEO, 0, -1, -1, -1, -1);
3864 	case 53:
3865 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 164, 40, 276, 140, -1, -1, 1, TRANSITION_VIDEO, 2, -1, -1, -1, -1);
3866 	case 54:
3867 		return new PlaySoundExitingFromSceneDeux(_vm, viewWindow, sceneStaticData, priorLocation, 14);
3868 	case 55:
3869 		return new IceteroidElevatorExtremeControls(_vm, viewWindow, sceneStaticData, priorLocation, 6, 6, 6, 0, 1, 0, 6);
3870 	case 56:
3871 		return new IceteroidElevatorExtremeControls(_vm, viewWindow, sceneStaticData, priorLocation, 6, 6, 3, 0, 1, 0, 5, 6, 6, 2, 0, 1, 0, 7);
3872 	case 57:
3873 		return new IceteroidElevatorExtremeControls(_vm, viewWindow, sceneStaticData, priorLocation, -1, -1, -1, -1, -1, -1, -1, 6, 6, 6, 0, 1, 0, 4);
3874 	case 58:
3875 		return new IceteroidZoomInMineControls(_vm, viewWindow, sceneStaticData, priorLocation);
3876 	case 59:
3877 		return new IceteroidMineControls(_vm, viewWindow, sceneStaticData, priorLocation);
3878 	case 60:
3879 		return new BaseOxygenTimer(_vm, viewWindow, sceneStaticData, priorLocation);
3880 	case 61:
3881 		return new IceteroidZoomInDispenser(_vm, viewWindow, sceneStaticData, priorLocation);
3882 	case 62:
3883 		return new IceteroidDispenserControls(_vm, viewWindow, sceneStaticData, priorLocation);
3884 	case 63:
3885 		return new IceteroidPodTimed(_vm, viewWindow, sceneStaticData, priorLocation, 174, 96, 246, 118, 14, 6, 6, 5, 0, 1, 0);
3886 	case 64:
3887 		return new IceteroidPodTimed(_vm, viewWindow, sceneStaticData, priorLocation, 174, 96, 246, 118, 15, 6, 6, 4, 0, 1, 0);
3888 	case 65:
3889 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 164, 26, 268, 124, -1, -1, 1, TRANSITION_VIDEO, 13, -1, -1, -1, -1);
3890 	case 66:
3891 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 164, 26, 268, 124, -1, -1, 1, TRANSITION_VIDEO, 16, -1, -1, -1, -1);
3892 	case 67:
3893 		return new TakeWaterCanister(_vm, viewWindow, sceneStaticData, priorLocation);
3894 	case 68:
3895 		return new PlaySoundExitingFromSceneDeux(_vm, viewWindow, sceneStaticData, priorLocation, 14);
3896 	case 69:
3897 		return new PlaySoundExitingForward(_vm, viewWindow, sceneStaticData, priorLocation, 14);
3898 	case 70:
3899 		return new SpaceDoorTimer(_vm, viewWindow, sceneStaticData, priorLocation, 92, 92, 212, 189, 48, -1, 1, TRANSITION_VIDEO, 0, -1, -1, -1, -1);
3900 	case 71:
3901 		return new ScienceWingZoomIntoPanel(_vm, viewWindow, sceneStaticData, priorLocation);
3902 	case 72:
3903 		return new ScienceWingPanelInterface(_vm, viewWindow, sceneStaticData, priorLocation);
3904 	case 73:
3905 		return new ScienceWingMachineRoomDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3906 	case 74:
3907 		return new ScienceWingStingersTimed(_vm, viewWindow, sceneStaticData, priorLocation);
3908 	case 75:
3909 		return new HabitatWingLockedDoor(_vm, viewWindow, sceneStaticData, priorLocation, 51, 4, 5, 146, 0, 396, 84);
3910 	case 80:
3911 		// Scene exists, but is just the default one
3912 		break;
3913 	case 81:
3914 		return new MachineRoomExitDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3915 	case 82:
3916 		return new MachineRoomPlayAnim(_vm, viewWindow, sceneStaticData, priorLocation, 156, 30, 251, 125, 2);
3917 	case 83:
3918 		return new MachineRoomPlayAnim(_vm, viewWindow, sceneStaticData, priorLocation, 184, 38, 272, 126, 3);
3919 	case 84:
3920 		return new MachineRoomTamperedSculpture(_vm, viewWindow, sceneStaticData, priorLocation);
3921 	case 85:
3922 		return new MachineRoomHarmonicsInterface(_vm, viewWindow, sceneStaticData, priorLocation);
3923 	case 86:
3924 		return new MachineRoomHarmonicsZoomIn(_vm, viewWindow, sceneStaticData, priorLocation);
3925 	case 87:
3926 		return new MachineRoomEntry(_vm, viewWindow, sceneStaticData, priorLocation);
3927 	case 90:
3928 		return new NexusDoor(_vm, viewWindow, sceneStaticData, priorLocation);
3929 	case 91:
3930 		return new NexusPuzzle(_vm, viewWindow, sceneStaticData, priorLocation);
3931 	case 92:
3932 		return new NexusEnd(_vm, viewWindow, sceneStaticData, priorLocation);
3933 	case 93:
3934 		return new BaseOxygenTimer(_vm, viewWindow, sceneStaticData, priorLocation);
3935 	case 100:
3936 		return new TakeWaterCanister(_vm, viewWindow, sceneStaticData, priorLocation);
3937 	default:
3938 		warning("Unknown AI lab scene object %d", sceneStaticData.classID);
3939 		break;
3940 	}
3941 
3942 	return new SceneBase(_vm, viewWindow, sceneStaticData, priorLocation);
3943 }
3944 
3945 } // End of namespace Buried
3946