1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "bladerunner/ui/kia.h"
24 
25 #include "bladerunner/actor.h"
26 #include "bladerunner/audio_player.h"
27 #include "bladerunner/bladerunner.h"
28 #include "bladerunner/combat.h"
29 #include "bladerunner/font.h"
30 #include "bladerunner/game_constants.h"
31 #include "bladerunner/game_flags.h"
32 #include "bladerunner/game_info.h"
33 #include "bladerunner/mouse.h"
34 #include "bladerunner/savefile.h"
35 #include "bladerunner/scene.h"
36 #include "bladerunner/shape.h"
37 #include "bladerunner/script/kia_script.h"
38 #include "bladerunner/settings.h"
39 #include "bladerunner/slice_renderer.h"
40 #include "bladerunner/text_resource.h"
41 #include "bladerunner/time.h"
42 #include "bladerunner/ui/kia_log.h"
43 #include "bladerunner/ui/kia_section_base.h"
44 #include "bladerunner/ui/kia_section_clues.h"
45 #include "bladerunner/ui/kia_section_crimes.h"
46 #include "bladerunner/ui/kia_section_diagnostic.h"
47 #include "bladerunner/ui/kia_section_help.h"
48 #include "bladerunner/ui/kia_section_load.h"
49 #include "bladerunner/ui/kia_section_settings.h"
50 #include "bladerunner/ui/kia_section_pogo.h"
51 #include "bladerunner/ui/kia_section_save.h"
52 #include "bladerunner/ui/kia_section_suspects.h"
53 #include "bladerunner/ui/ui_image_picker.h"
54 #include "bladerunner/vqa_player.h"
55 #include "bladerunner/subtitles.h"
56 
57 #include "common/str.h"
58 #include "common/keyboard.h"
59 #include "common/debug.h"
60 
61 #include "graphics/scaler.h"
62 
63 namespace BladeRunner {
64 
65 const char *KIA::kPogo = "POGO";
66 
KIA(BladeRunnerEngine * vm)67 KIA::KIA(BladeRunnerEngine *vm) {
68 	_vm = vm;
69 
70 	_script = new KIAScript(_vm);
71 	_log = new KIALog(_vm);
72 	_shapes = new Shapes(_vm);
73 	_playerPhotographs = new Shapes(_vm);
74 
75 	_forceOpen = false;
76 	_currentSectionId = kKIASectionNone;
77 	_lastSectionIdKIA = kKIASectionCrimes;
78 	_lastSectionIdOptions = kKIASectionSettings;
79 	_playerVqaTimeLast = _vm->_time->currentSystem();
80 	_playerVqaFrame = 0;
81 	_playerVisualizerState = 0;
82 	_playerPhotographId = -1;
83 	_playerSliceModelId = -1;
84 	_playerSliceModelAngle = 0.0f;
85 	_timeLast = _vm->_time->currentSystem();
86 	_playerActorDialogueQueuePosition = 0;
87 	_playerActorDialogueQueueSize = 0;
88 	_playerActorDialogueState = 0;
89 	_currentSection = nullptr;
90 	_mainVqaPlayer = nullptr;
91 	_playerVqaPlayer = nullptr;
92 	_transitionId = 0;
93 
94 	_pogoPos = 0;
95 
96 	// original imageCount was 22. We add +1 to have a description box for objects in cut content
97 	// We don't have separated cases here, for _vm->_cutContent since that causes assertion fault if
98 	// loading a "restored content" save game in a "original game" version
99 	_buttons = new UIImagePicker(_vm, 23);
100 
101 	_crimesSection     = new KIASectionCrimes(_vm, _vm->_playerActor->_clues);
102 	_suspectsSection   = new KIASectionSuspects(_vm, _vm->_playerActor->_clues);
103 	_cluesSection      = new KIASectionClues(_vm, _vm->_playerActor->_clues);
104 	_settingsSection   = new KIASectionSettings(_vm);
105 	_helpSection       = new KIASectionHelp(_vm);
106 	_saveSection       = new KIASectionSave(_vm);
107 	_loadSection       = new KIASectionLoad(_vm);
108 	_diagnosticSection = new KIASectionDiagnostic(_vm);
109 	_pogoSection       = new KIASectionPogo(_vm);
110 
111 	for (int i = 0; i < kPlayerActorDialogueQueueCapacity; ++i) {
112 		_playerActorDialogueQueue[i].actorId    = -1;
113 		_playerActorDialogueQueue[i].sentenceId = -1;
114 	}
115 }
116 
~KIA()117 KIA::~KIA() {
118 	if (isOpen()) {
119 		unload();
120 	}
121 
122 	_thumbnail.free();
123 	delete _crimesSection;
124 	delete _suspectsSection;
125 	delete _cluesSection;
126 	delete _settingsSection;
127 	delete _helpSection;
128 	delete _saveSection;
129 	delete _loadSection;
130 	delete _diagnosticSection;
131 	delete _pogoSection;
132 	_playerImage.free();
133 	delete _buttons;
134 	delete _shapes;
135 	delete _playerPhotographs;
136 	delete _log;
137 	delete _script;
138 }
139 
reset()140 void KIA::reset() {
141 	_lastSectionIdKIA = kKIASectionCrimes;
142 	_lastSectionIdOptions = kKIASectionSettings;
143 	_playerImage.free();
144 	_playerVqaFrame = 0;
145 	_playerVisualizerState = 0;
146 	_playerSliceModelAngle = 0.0f;
147 
148 	_crimesSection->reset();
149 	_suspectsSection->reset();
150 	_cluesSection->reset();
151 }
152 
openLastOpened()153 void KIA::openLastOpened() {
154 	open(_lastSectionIdKIA);
155 }
156 
open(KIASections sectionId)157 void KIA::open(KIASections sectionId) {
158 	if (_currentSectionId == sectionId) {
159 		return;
160 	}
161 
162 	if (sectionId == kKIASectionNone) {
163 		unload();
164 		return;
165 	}
166 
167 	if (!isOpen()) {
168 		init();
169 	}
170 
171 	switch (_currentSectionId) {
172 	case kKIASectionCrimes:
173 		_crimesSection->saveToLog();
174 		break;
175 	case kKIASectionSuspects:
176 		_suspectsSection->saveToLog();
177 		break;
178 	case kKIASectionClues:
179 		_cluesSection->saveToLog();
180 		break;
181 	default:
182 		break;
183 	}
184 
185 	if (sectionId != kKIASectionCrimes && sectionId != kKIASectionSuspects && sectionId != kKIASectionClues) {
186 		playerReset();
187 	}
188 
189 	_transitionId = getTransitionId(_currentSectionId, sectionId);
190 	const char *name = getSectionVqaName(sectionId);
191 	if (getSectionVqaName(_currentSectionId) != name) {
192 		if (_mainVqaPlayer) {
193 			_mainVqaPlayer->close();
194 			delete _mainVqaPlayer;
195 			_mainVqaPlayer = nullptr;
196 		}
197 
198 		_mainVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, name);
199 		_mainVqaPlayer->open();
200 	}
201 
202 	if (_transitionId) {
203 		playTransitionSound(_transitionId);
204 		_mainVqaPlayer->setLoop(getVqaLoopTransition(_transitionId), -1, kLoopSetModeImmediate, nullptr, nullptr);
205 		_mainVqaPlayer->setLoop(getVqaLoopMain(sectionId), -1, kLoopSetModeEnqueue, loopEnded, this);
206 	} else {
207 		int loopId = getVqaLoopMain(sectionId);
208 		_mainVqaPlayer->setLoop(loopId, -1, kLoopSetModeImmediate, nullptr, nullptr);
209 		_mainVqaPlayer->setLoop(loopId + 1, -1, kLoopSetModeJustStart, nullptr, nullptr);
210 	}
211 
212 	_buttons->resetImages();
213 	createButtons(sectionId);
214 	switchSection(sectionId);
215 	_currentSectionId = sectionId;
216 
217 	if (sectionId == kKIASectionCrimes || sectionId == kKIASectionSuspects || sectionId == kKIASectionClues) {
218 		_lastSectionIdKIA = _currentSectionId;
219 	}
220 
221 	if (sectionId == kKIASectionSettings || sectionId == kKIASectionHelp || sectionId == kKIASectionSave || sectionId == kKIASectionLoad) {
222 		 _lastSectionIdOptions = _currentSectionId;
223 	}
224 }
225 
isOpen() const226 bool KIA::isOpen() const {
227 	return _currentSectionId != kKIASectionNone;
228 }
229 
tick()230 void KIA::tick() {
231 	if (!isOpen()) {
232 		return;
233 	}
234 
235 	uint32 timeNow = _vm->_time->currentSystem();
236 	// unsigned difference is intentional
237 	uint32 timeDiff = timeNow - _timeLast;
238 
239 	if (_playerActorDialogueQueueSize == _playerActorDialogueQueuePosition) {
240 		_playerActorDialogueState = 0;
241 	} else if (_playerActorDialogueState == 0) {
242 		if (_playerSliceModelId == -1 && _playerPhotographId == -1 && _playerImage.getPixels() == nullptr) {
243 			_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxBEEP16), 70, 0, 0, 50, 0);
244 		}
245 		_playerActorDialogueState = 1;
246 	} else if (_playerActorDialogueState == 200) {
247 		if (!_vm->_actors[_playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId]->isSpeeching()) {
248 			if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) {
249 				_playerActorDialogueQueuePosition = (_playerActorDialogueQueuePosition + 1) % kPlayerActorDialogueQueueCapacity;
250 			}
251 			if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) {
252 				_vm->_actors[_playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId]->speechPlay(_playerActorDialogueQueue[_playerActorDialogueQueuePosition].sentenceId, true);
253 			}
254 		}
255 	} else {
256 		_playerActorDialogueState += timeDiff;
257 
258 		if (_playerActorDialogueState >= 200) {
259 			_playerActorDialogueState = 200;
260 			_vm->_actors[_playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId]->speechPlay(_playerActorDialogueQueue[_playerActorDialogueQueuePosition].sentenceId, true);
261 		}
262 	}
263 
264 	uint32 timeDiffDiv48 = (timeNow < _playerVqaTimeLast) ? 0u : (timeNow - _playerVqaTimeLast) / 48;
265 	if (timeDiffDiv48 > 0u) {
266 		_playerVqaTimeLast = timeNow;
267 		if (_playerActorDialogueQueueSize == _playerActorDialogueQueuePosition || _playerSliceModelId != -1 || _playerPhotographId != -1 || _playerImage.getPixels() != nullptr) {
268 			if (_playerVisualizerState > 0) {
269 				_playerVisualizerState = (_playerVisualizerState < timeDiffDiv48) ? 0u : MAX<uint32>(_playerVisualizerState - timeDiffDiv48, 0u);
270 			}
271 		} else {
272 			if (_playerVisualizerState < 2) {
273 				_playerVisualizerState = MIN<uint32>(_playerVisualizerState + timeDiffDiv48, 2u);
274 			}
275 		}
276 
277 		if ( _playerSliceModelId != -1 || _playerPhotographId != -1 || _playerImage.getPixels() != nullptr) {
278 			if (_playerVqaFrame < 8) {
279 				int newVqaFrame  = MIN<uint32>(timeDiffDiv48 + _playerVqaFrame, 8u);
280 				if (_playerVqaFrame <= 0 && newVqaFrame > 0) {
281 					_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxMECHAN1), 100, 70, 70, 50, 0);
282 				}
283 				_playerVqaFrame = newVqaFrame;
284 			}
285 		} else {
286 			if (_playerVqaFrame > 0) {
287 				int newVqaFrame = (_playerVqaFrame < timeDiffDiv48) ? 0 : MAX<uint32>(_playerVqaFrame - timeDiffDiv48, 0u);
288 				if (_playerVqaFrame >= 8 && newVqaFrame < 8) {
289 					_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxMECHAN1C), 100, 70, 70, 50, 0);
290 				}
291 				_playerVqaFrame = newVqaFrame;
292 			}
293 		}
294 	}
295 
296 	_mainVqaPlayer->update(false);
297 	blit(_vm->_surfaceBack, _vm->_surfaceFront);
298 
299 	Common::Point mouse = _vm->getMousePos();
300 
301 	if (!_transitionId) {
302 		_buttons->handleMouseAction(mouse.x, mouse.y, false, false, false);
303 		if (_buttons->hasHoveredImage()) {
304 			_vm->_mouse->setCursor(1);
305 		} else {
306 			_vm->_mouse->setCursor(0);
307 		}
308 		if (_currentSection) {
309 			_currentSection->handleMouseMove(mouse.x, mouse.y);
310 		}
311 	}
312 
313 	if (_vm->_gameFlags->query(kFlagKIAPrivacyAddon)) {
314 		_shapes->get(40)->draw(_vm->_surfaceFront, 0, 0);
315 		_shapes->get(41)->draw(_vm->_surfaceFront, 211, 447);
316 	}
317 	if (_currentSectionId != kKIASectionQuit && _transitionId != 14) {
318 		if (_vm->_settings->getDifficulty() > kGameDifficultyEasy) {
319 			_vm->_mainFont->drawString(&_vm->_surfaceFront, Common::String::format("%04d", _vm->_gameVars[kVariableChinyen]), 580, 341, _vm->_surfaceFront.w, _vm->_surfaceFront.format.RGBToColor(80, 96, 136));
320 		} else {
321 			_shapes->get(39)->draw(_vm->_surfaceFront, 583, 342);
322 		}
323 	}
324 
325 	_playerVqaPlayer->seekToFrame(_playerVqaFrame);
326 	_playerVqaPlayer->update(true, true);
327 
328 	_playerSliceModelAngle += (float)(timeDiff) * 1.0f/400.0f;
329 	while (_playerSliceModelAngle >= 2 * M_PI) {
330 		_playerSliceModelAngle -= (float)(2 * M_PI);
331 	}
332 
333 	if (_playerVqaFrame == 8) {
334 		if (_playerSliceModelId != -1) {
335 			_vm->_sliceRenderer->drawOnScreen(_playerSliceModelId, 0, 585, 80, _playerSliceModelAngle, 100.0, _vm->_surfaceFront);
336 		} else if (_playerPhotographId != -1) {
337 			const Shape *playerPhotograph = _playerPhotographs->get(_playerPhotographId);
338 			int width  = playerPhotograph->getWidth();
339 			int height  = playerPhotograph->getHeight();
340 			playerPhotograph->draw(_vm->_surfaceFront, 590 - width / 2, 80 - height / 2);
341 		} else if (_playerImage.getPixels() != nullptr) {
342 			_vm->_surfaceFront.fillRect(Common::Rect(549, 49, 631, 111), _vm->_surfaceFront.format.RGBToColor(255, 255, 255));
343 			_vm->_surfaceFront.copyRectToSurface(_playerImage.getPixels(), _playerImage.pitch, 550, 50, _playerImage.w,  _playerImage.h);
344 		}
345 	}
346 
347 	if (_playerVisualizerState == 1) {
348 		_shapes->get(51)->draw(_vm->_surfaceFront, 576, 174);
349 	} else if (_playerVisualizerState == 2) {
350 		_shapes->get(50)->draw(_vm->_surfaceFront, 576, 174);
351 		_shapes->get(_vm->_rnd.getRandomNumberRng(90, 105))->draw(_vm->_surfaceFront, 576, 174);
352 	}
353 	if (!_transitionId) {
354 		_buttons->draw(_vm->_surfaceFront);
355 		if (_currentSection) {
356 			_currentSection->draw(_vm->_surfaceFront);
357 		}
358 	}
359 	if (_vm->_settings->getAmmo(0) > 0) {
360 		if (_vm->_settings->getAmmoType() == 0) {
361 			_shapes->get(42)->draw(_vm->_surfaceFront, 147, 405);
362 		} else {
363 			_shapes->get(45)->draw(_vm->_surfaceFront, 140, 446);
364 		}
365 	}
366 	if (_vm->_settings->getAmmo(1) > 0) {
367 		if (_vm->_settings->getAmmoType() == 1) {
368 			_shapes->get(43)->draw(_vm->_surfaceFront, 167, 394);
369 		} else {
370 			_shapes->get(46)->draw(_vm->_surfaceFront, 160, 446);
371 		}
372 	}
373 	if (_vm->_settings->getAmmo(2) > 0) {
374 		if (_vm->_settings->getAmmoType() == 2) {
375 			_shapes->get(44)->draw(_vm->_surfaceFront, 189, 385);
376 		} else {
377 			_shapes->get(47)->draw(_vm->_surfaceFront, 182, 446);
378 		}
379 	}
380 	_vm->_mainFont->drawString(&_vm->_surfaceFront, "1.00", 438, 471, _vm->_surfaceFront.w, _vm->_surfaceFront.format.RGBToColor(56, 56, 56)); // 1.01 is DVD version, but only cd handling routines were changed, no game logic
381 	if (!_transitionId) {
382 		_buttons->drawTooltip(_vm->_surfaceFront, mouse.x, mouse.y);
383 	}
384 	_vm->_mouse->draw(_vm->_surfaceFront, mouse.x, mouse.y);
385 
386 	_vm->_subtitles->tick(_vm->_surfaceFront);
387 
388 	_vm->blitToScreen(_vm->_surfaceFront);
389 
390 	_timeLast = timeNow;
391 }
392 
resume()393 void KIA::resume() {
394 	// vqaPlayer::clear(this->_vqaPlayerMain);
395 	if (_transitionId) {
396 		_mainVqaPlayer->setLoop(getVqaLoopTransition(_transitionId), -1, kLoopSetModeImmediate, nullptr, nullptr);
397 		_mainVqaPlayer->setLoop(getVqaLoopMain(_currentSectionId), -1, kLoopSetModeEnqueue, loopEnded, this);
398 	} else {
399 		_mainVqaPlayer->setLoop(getVqaLoopMain(_currentSectionId), -1, kLoopSetModeImmediate, nullptr, nullptr);
400 		_mainVqaPlayer->setLoop(getVqaLoopMain(_currentSectionId) + 1, -1, kLoopSetModeJustStart, nullptr, nullptr);
401 	}
402 }
403 
handleMouseDown(int mouseX,int mouseY,bool mainButton)404 void KIA::handleMouseDown(int mouseX, int mouseY, bool mainButton) {
405 	if (!isOpen()) {
406 		return;
407 	}
408 	if (mainButton) {
409 		_buttons->handleMouseAction(mouseX, mouseY, true, false, false);
410 	}
411 	if (_currentSection) {
412 		_currentSection->handleMouseDown(mainButton);
413 	}
414 }
415 
handleMouseUp(int mouseX,int mouseY,bool mainButton)416 void KIA::handleMouseUp(int mouseX, int mouseY, bool mainButton) {
417 	if (!isOpen()) {
418 		return;
419 	}
420 	if (mainButton) {
421 		_buttons->handleMouseAction(mouseX, mouseY, false, true, false);
422 	}
423 	if (_currentSection) {
424 		_currentSection->handleMouseUp(mainButton);
425 	}
426 	if (_currentSection && _currentSection->_scheduledSwitch) {
427 		if (_currentSectionId == kKIASectionCrimes) {
428 			open(kKIASectionSuspects);
429 			_suspectsSection->selectSuspect(_crimesSection->_suspectSelected);
430 			_log->next();
431 			_log->clearFuture();
432 		} else if (_currentSectionId == kKIASectionSuspects) {
433 			open(kKIASectionCrimes);
434 			_crimesSection->selectCrime(_suspectsSection->_crimeSelected);
435 			_log->next();
436 			_log->clearFuture();
437 		} else {
438 			open(kKIASectionNone);
439 		}
440 	}
441 }
442 
handleMouseScroll(int mouseX,int mouseY,int direction)443 void KIA::handleMouseScroll(int mouseX, int mouseY, int direction) {
444 	if (!isOpen()) {
445 		return;
446 	}
447 	if (_currentSection) {
448 		_currentSection->handleMouseScroll(direction);
449 	}
450 }
451 
handleKeyUp(const Common::KeyState & kbd)452 void KIA::handleKeyUp(const Common::KeyState &kbd) {
453 	if (!isOpen()) {
454 		return;
455 	}
456 
457 	if (_currentSection) {
458 		_currentSection->handleKeyUp(kbd);
459 	}
460 }
461 
handleKeyDown(const Common::KeyState & kbd)462 void KIA::handleKeyDown(const Common::KeyState &kbd) {
463 	if (!isOpen()) {
464 		return;
465 	}
466 
467 	if (toupper(kbd.ascii) != kPogo[_pogoPos]) {
468 		_pogoPos = 0;
469 	}
470 	if (_currentSectionId != kKIASectionSave) {
471 		if (toupper(kbd.ascii) == kPogo[_pogoPos]) {
472 			++_pogoPos;
473 			if (!kPogo[_pogoPos]) {
474 				open(kKIASectionPogo);
475 				_pogoPos = 0;
476 			}
477 		}
478 	}
479 
480 	switch (kbd.keycode) {
481 	case Common::KEYCODE_ESCAPE:
482 		if (!_forceOpen) {
483 			open(kKIASectionNone);
484 		}
485 		break;
486 
487 	case Common::KEYCODE_F1:
488 		open(kKIASectionHelp);
489 		break;
490 
491 	case Common::KEYCODE_F2:
492 		if (!_forceOpen) {
493 			open(kKIASectionSave);
494 		}
495 		break;
496 	case Common::KEYCODE_F3:
497 		open(kKIASectionLoad);
498 		break;
499 
500 	case Common::KEYCODE_F10:
501 		open(kKIASectionQuit);
502 		break;
503 
504 	case Common::KEYCODE_F4:
505 		if (_currentSectionId != kKIASectionCrimes) {
506 			if (!_forceOpen) {
507 				open(kKIASectionCrimes);
508 				_log->next();
509 				_log->clearFuture();
510 			}
511 		}
512 		break;
513 
514 	case Common::KEYCODE_F5:
515 		if (_currentSectionId != kKIASectionSuspects) {
516 			if (!_forceOpen) {
517 				open(kKIASectionSuspects);
518 				_log->next();
519 				_log->clearFuture();
520 			}
521 		}
522 		break;
523 
524 	case Common::KEYCODE_F6:
525 		if (_currentSectionId != kKIASectionClues) {
526 			if (!_forceOpen) {
527 				open(kKIASectionClues);
528 				_log->next();
529 				_log->clearFuture();
530 			}
531 		}
532 		break;
533 
534 	default:
535 		if (_currentSection) {
536 			_currentSection->handleKeyDown(kbd);
537 		}
538 		break;
539 	}
540 
541 	if (_currentSection && _currentSection->_scheduledSwitch) {
542 		open(kKIASectionNone);
543 	}
544 }
545 
playerReset()546 void KIA::playerReset() {
547 	if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) {
548 		int actorId = _playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId;
549 		if (_vm->_actors[actorId]->isSpeeching()) {
550 			_vm->_actors[actorId]->speechStop();
551 		}
552 	}
553 
554 	_playerActorDialogueQueueSize = _playerActorDialogueQueuePosition;
555 	_playerSliceModelId = -1;
556 	_playerPhotographId = -1;
557 	_playerImage.free();
558 	_playerActorDialogueState = 0;
559 	if (_vm->_cutContent) {
560 		_buttons->resetImage(22);
561 	}
562 }
563 
playActorDialogue(int actorId,int sentenceId)564 void KIA::playActorDialogue(int actorId, int sentenceId) {
565 	int newQueueSize = (_playerActorDialogueQueueSize + 1) % kPlayerActorDialogueQueueCapacity;
566 	if (newQueueSize != _playerActorDialogueQueuePosition) {
567 		_playerActorDialogueQueue[_playerActorDialogueQueueSize].actorId = actorId;
568 		_playerActorDialogueQueue[_playerActorDialogueQueueSize].sentenceId = sentenceId;
569 		_playerActorDialogueQueueSize = newQueueSize;
570 	}
571 }
572 
playSliceModel(int sliceModelId)573 void KIA::playSliceModel(int sliceModelId) {
574 	if (_playerVqaFrame == 8) {
575 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxBEEP1), 70, 0, 0, 50, 0);
576 	}
577 	_playerSliceModelId = sliceModelId;
578 	if (_vm->_cutContent) {
579 		_buttons->defineImage(22, Common::Rect(530, 32, 635, 126), nullptr, nullptr, nullptr, _vm->_textClueTypes->getText(3)); // "OBJECT"
580 	}
581 }
582 
playPhotograph(int photographId)583 void KIA::playPhotograph(int photographId) {
584 	if (_playerVqaFrame == 8) {
585 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxBEEP1), 70, 0, 0, 50, 0);
586 	}
587 	_playerPhotographId = photographId;
588 }
589 
playImage(const Graphics::Surface & image)590 void KIA::playImage(const Graphics::Surface &image) {
591 	if (image.w != 80) {
592 		Graphics::Surface *tmp = image.scale(80, 60);
593 		_playerImage.copyFrom(*tmp);
594 		tmp->free();
595 		delete tmp;
596 	} else {
597 		_playerImage.copyFrom(image);
598 	}
599 	_playerImage.convertToInPlace(screenPixelFormat());
600 }
601 
scrambleSuspectsName(const char * name)602 const char *KIA::scrambleSuspectsName(const char *name) {
603 	static char buffer[32];
604 
605 	unsigned char *bufferPtr = (unsigned char *)buffer;
606 	const unsigned char *namePtr = (const unsigned char *)name;
607 
608 	for (int i = 0 ; i < 6; ++i) {
609 		if (_vm->_language == Common::RU_RUS && _vm->_russianCP1251) {
610 			// Algorithm added by Siberian Studio in R4 patch
611 			if (*namePtr >= 0xC0) {
612 				unsigned char upper = *namePtr & 0xDF;
613 				if (upper < 201) {
614 					*bufferPtr++ = upper - 143; /* Map А-И to 1-9 */
615 				} else {
616 					*bufferPtr++ = upper - 136; /* Map Й-Я to A-W */
617 				}
618 			} else {
619 				*bufferPtr++ = '0';
620 			}
621 		} else {
622 			if (Common::isAlpha(*namePtr)) {
623 				char upper = toupper(*namePtr);
624 				if ( upper < 'J' ) {
625 					*bufferPtr++ = upper - 16; /* Map A-I to 1-9 */
626 				} else {
627 					*bufferPtr++ = upper - 9;  /* Map J-Z to A-Q */
628 				}
629 			} else {
630 				*bufferPtr++ = '0';
631 			}
632 		}
633 		if (*namePtr) {
634 			++namePtr;
635 		}
636 		if (i == 1) {
637 			*bufferPtr++ = '-';
638 		}
639 	}
640 	*bufferPtr = 0;
641 	return buffer;
642 }
643 
mouseDownCallback(int buttonId,void * callbackData)644 void KIA::mouseDownCallback(int buttonId, void *callbackData) {
645 	KIA *self = (KIA *)callbackData;
646 	switch (buttonId) {
647 	case 0:
648 	case 6:
649 		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxBUTN4P), 100, -65, -65, 50, 0);
650 		break;
651 	case 1:
652 	case 2:
653 	case 3:
654 	case 4:
655 	case 5:
656 	case 7:
657 	case 8:
658 	case 9:
659 	case 10:
660 	case 11:
661 	case 12:
662 	case 13:
663 	case 14:
664 		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxBUTN5P), 70, 0, 0, 50, 0);
665 		if (buttonId == 12) {
666 			int endTrackId = self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxSHUTDOWN), 70, 0, 0, 50, 0);
667 
668 			self->_vm->_surfaceFront.fillRect(Common::Rect(0, 0, 640, 480), 0);
669 			self->_vm->blitToScreen(self->_vm->_surfaceFront);
670 
671 			if (endTrackId != -1) {
672 				// wait until the full clip has played (similar to the original)
673 				uint32 timeNow = self->_vm->_time->currentSystem();
674 				uint32 waittime = 16;
675 				while (self->_vm->_audioPlayer->isActive(endTrackId)) {
676 					if (self->_vm->_noDelayMillisFramelimiter) {
677 						while (self->_vm->_time->currentSystem() - timeNow < waittime) { }
678 					} else {
679 						self->_vm->_system->delayMillis(waittime);
680 					}
681 				}
682 			}
683 		}
684 		break;
685 	case 15:
686 		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxBUTN4P), 70, 0, 0, 50, 0);
687 		break;
688 	default:
689 		break;
690 	}
691 }
692 
mouseUpCallback(int buttonId,void * callbackData)693 void KIA::mouseUpCallback(int buttonId, void *callbackData) {
694 	KIA *self = (KIA *)callbackData;
695 	switch (buttonId) {
696 	case 0:
697 	case 6:
698 		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxBUTN4R), 100, -65, -65, 50, 0);
699 		break;
700 	case 1:
701 	case 2:
702 	case 3:
703 	case 4:
704 	case 5:
705 	case 7:
706 	case 8:
707 	case 9:
708 	case 10:
709 	case 11:
710 	case 12:
711 	case 13:
712 	case 14:
713 		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxBUTN5R), 70, 0, 0, 50, 0);
714 		break;
715 	case 15:
716 		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxBUTN4R), 100, 0, 0, 50, 0);
717 		break;
718 	default:
719 		break;
720 	}
721 	self->buttonClicked(buttonId);
722 }
723 
loopEnded(void * callbackData,int frame,int loopId)724 void KIA::loopEnded(void *callbackData, int frame, int loopId) {
725 	KIA *self = (KIA *)callbackData;
726 	self->_mainVqaPlayer->setLoop(self->getVqaLoopMain(self->_currentSectionId) + 1, -1, kLoopSetModeJustStart, nullptr, nullptr);
727 	self->_transitionId = 0;
728 }
729 
init()730 void KIA::init() {
731 	createThumbnailFromScreen(&_thumbnail);
732 
733 	if (!_vm->openArchive("MODE.MIX")) {
734 		return;
735 	}
736 
737 	playerReset();
738 	_playerVqaFrame = 0;
739 	_playerVqaTimeLast = _vm->_time->currentSystem();
740 	_timeLast = _vm->_time->currentSystem();
741 
742 	if (_vm->_gameFlags->query(kFlagKIAPrivacyAddon) && !_vm->_gameFlags->query(kFlagKIAPrivacyAddonIntro)) {
743 		_vm->_gameFlags->set(kFlagKIAPrivacyAddonIntro);
744 		playPrivateAddon();
745 	}
746 
747 	_shapes->load("kiaopt.shp");
748 	_playerPhotographs->load("photos.shp");
749 
750 	_buttons->activate(nullptr, nullptr, mouseDownCallback, mouseUpCallback, this);
751 	_vm->_mouse->setCursor(0);
752 	if (_playerVqaPlayer == nullptr) {
753 		_playerVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, "kiaover.vqa");
754 		_playerVqaPlayer->open();
755 		_playerVqaPlayer->setLoop(0, -1, kLoopSetModeJustStart, nullptr, nullptr);
756 	}
757 	_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxELECTRO1), 70, 0, 0, 50, 0);
758 
759 	_vm->_time->pause();
760 }
761 
unload()762 void KIA::unload() {
763 	_thumbnail.free();
764 
765 	if (!isOpen()) {
766 		return;
767 	}
768 
769 	_forceOpen = false;
770 
771 	if (_currentSection) {
772 		_currentSection->close();
773 		_currentSection = nullptr;
774 	}
775 
776 	_buttons->resetImages();
777 	_buttons->deactivate();
778 
779 	_shapes->unload();
780 	_playerPhotographs->unload();
781 
782 	delete _mainVqaPlayer;
783 	_mainVqaPlayer = nullptr;
784 
785 	delete _playerVqaPlayer;
786 	_playerVqaPlayer = nullptr;
787 
788 	_vm->closeArchive("MODE.MIX");
789 
790 	_currentSectionId = kKIASectionNone;
791 
792 	_vm->_time->resume();
793 
794 	if (!_vm->_settings->isLoadingGame() && _vm->_gameIsRunning) {
795 		_vm->_scene->resume();
796 	}
797 }
798 
createButtons(int sectionId)799 void KIA::createButtons(int sectionId) {
800 	Common::Rect kiaButton6(  66,  00, 122,  44);
801 	Common::Rect kiaButton7( 191,  29, 233,  70);
802 	Common::Rect kiaButton8( 234,  29, 278,  70);
803 	Common::Rect kiaButton9( 278,  29, 321,  70);
804 	Common::Rect kiaButton10(322,  29, 365,  70);
805 	Common::Rect kiaButton11(366,  29, 410,  70);
806 	Common::Rect kiaButton12(420, 286, 472, 328);
807 	Common::Rect kiaButton13(334, 286, 386, 328);
808 	Common::Rect kiaButton14(411,  29, 453,  70);
809 	Common::Rect kiaButton15(264,   9, 304,  26);
810 	Common::Rect kiaButton16(140, 406, 160, 479);
811 	Common::Rect kiaButton17(161, 406, 180, 479);
812 	Common::Rect kiaButton18(181, 406, 202, 479);
813 	Common::Rect kiaButton19(575, 307, 606, 350);
814 	Common::Rect kiaButton21(211, 443, 291, 479);
815 
816 	const Shape *shapeUp = nullptr;
817 	const Shape *shapeHovered = nullptr;
818 	const Shape *shapeDown = nullptr;
819 
820 	switch (sectionId) {
821 	case kKIASectionCrimes:
822 	case kKIASectionSuspects:
823 	case kKIASectionClues:
824 		_buttons->defineImage(0, kiaButton6, nullptr, nullptr, _shapes->get(1), _vm->_textKIA->getText(23));
825 
826 		if (_vm->_cutContent && _playerSliceModelId != -1) {
827 			_buttons->defineImage(22, Common::Rect(530, 32, 635, 126), nullptr, nullptr, nullptr, _vm->_textClueTypes->getText(3)); // "OBJECT"
828 		}
829 
830 		if (sectionId == kKIASectionCrimes) {
831 			shapeUp = _shapes->get(2);
832 			shapeHovered = _shapes->get(2);
833 			shapeDown = _shapes->get(10);
834 		} else {
835 			shapeUp = nullptr;
836 			shapeHovered = nullptr;
837 			shapeDown = _shapes->get(18);
838 		}
839 		_buttons->defineImage(1, kiaButton7, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(24));
840 
841 		if (sectionId == kKIASectionSuspects) {
842 			shapeUp = _shapes->get(3);
843 			shapeHovered = _shapes->get(3);
844 			shapeDown = _shapes->get(11);
845 		} else {
846 			shapeUp = nullptr;
847 			shapeHovered = nullptr;
848 			shapeDown = _shapes->get(19);
849 		}
850 		_buttons->defineImage(2, kiaButton8, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(25));
851 
852 		if (sectionId == kKIASectionClues) {
853 			shapeUp = _shapes->get(4);
854 			shapeHovered = _shapes->get(4);
855 			shapeDown = _shapes->get(12);
856 		} else {
857 			shapeUp = nullptr;
858 			shapeHovered = nullptr;
859 			shapeDown = _shapes->get(20);
860 		}
861 		_buttons->defineImage(3, kiaButton9, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(26));
862 
863 		_buttons->defineImage(4, kiaButton10, nullptr, nullptr, _shapes->get(21), _vm->_textKIA->getText(27));
864 
865 		_buttons->defineImage(5, kiaButton11, nullptr, nullptr, _shapes->get(22), _vm->_textKIA->getText(28));
866 
867 		_buttons->defineImage(14, kiaButton14, nullptr, nullptr, _shapes->get(23), _vm->_textKIA->getText(29));
868 
869 		break;
870 	case kKIASectionSettings:
871 	case kKIASectionHelp:
872 	case kKIASectionSave:
873 	case kKIASectionLoad:
874 	case kKIASectionDiagnostic:
875 	case kKIASectionPogo:
876 		_buttons->defineImage(6, kiaButton6, nullptr, nullptr, _shapes->get(0), _vm->_textKIA->getText(37));
877 
878 		if (sectionId == kKIASectionSettings) {
879 			shapeUp = _shapes->get(5);
880 			shapeHovered = _shapes->get(5);
881 			shapeDown = _shapes->get(13);
882 		} else {
883 			shapeUp = nullptr;
884 			shapeHovered = nullptr;
885 			shapeDown = _shapes->get(24);
886 		}
887 		_buttons->defineImage(7, kiaButton7, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(38));
888 
889 		if (sectionId == kKIASectionHelp) {
890 			shapeUp = _shapes->get(6);
891 			shapeHovered = _shapes->get(6);
892 			shapeDown = _shapes->get(14);
893 		} else {
894 			shapeUp = nullptr;
895 			shapeHovered = nullptr;
896 			shapeDown = _shapes->get(25);
897 		}
898 		_buttons->defineImage(8, kiaButton8, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(41));
899 
900 		if (sectionId == kKIASectionSave) {
901 			shapeUp = _shapes->get(7);
902 			shapeHovered = _shapes->get(7);
903 			shapeDown = _shapes->get(15);
904 		} else {
905 			shapeUp = nullptr;
906 			shapeHovered = nullptr;
907 			shapeDown = _shapes->get(26);
908 		}
909 		_buttons->defineImage(9, kiaButton9, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(39));
910 
911 		if (sectionId == kKIASectionLoad) {
912 			shapeUp = _shapes->get(8);
913 			shapeHovered = _shapes->get(8);
914 			shapeDown = _shapes->get(16);
915 		} else {
916 			shapeUp = nullptr;
917 			shapeHovered = nullptr;
918 			shapeDown = _shapes->get(27);
919 		}
920 		_buttons->defineImage(10, kiaButton10, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(40));
921 
922 		_buttons->defineImage(11, kiaButton11, nullptr, nullptr, _shapes->get(28), _vm->_textKIA->getText(42));
923 
924 		_buttons->defineImage(14, kiaButton14, nullptr, nullptr, _shapes->get(29), _vm->_textKIA->getText(29));
925 
926 		break;
927 	case kKIASectionQuit:
928 		_buttons->defineImage(12, kiaButton12, _shapes->get(124), _shapes->get(124), _shapes->get(48), _vm->_textKIA->getText(42));
929 
930 		_buttons->defineImage(13, kiaButton13, _shapes->get(125), _shapes->get(125), _shapes->get(49), _vm->_textKIA->getText(29));
931 			break;
932 	}
933 
934 	if (sectionId != kKIASectionQuit) {
935 		_buttons->defineImage(15, kiaButton15, nullptr, nullptr, _shapes->get(38), _vm->_textKIA->getText(43));
936 
937 		_buttons->defineImage(19, kiaButton19, nullptr, nullptr, nullptr, _vm->_textKIA->getText(44));
938 
939 		if (_vm->_settings->getAmmo(0) > 0) {
940 			_buttons->defineImage(16, kiaButton16, nullptr, nullptr, nullptr, _vm->_textKIA->getText(50));
941 		}
942 		Common::String tooltip;
943 		if (_vm->_settings->getAmmo(1) > 0) {
944 			if (_vm->_settings->getDifficulty() > kGameDifficultyEasy) {
945 				tooltip = Common::String::format("%d", _vm->_settings->getAmmo(1));
946 			} else {
947 				tooltip = _vm->_textKIA->getText(50);
948 			}
949 			_buttons->defineImage(17, kiaButton17, nullptr, nullptr, nullptr, tooltip.c_str());
950 		}
951 		if (_vm->_settings->getAmmo(2) > 0) {
952 			if (_vm->_settings->getDifficulty() > kGameDifficultyEasy) {
953 				tooltip = Common::String::format("%d", _vm->_settings->getAmmo(2));
954 			} else {
955 				tooltip = _vm->_textKIA->getText(50);
956 			}
957 			_buttons->defineImage(18, kiaButton18, nullptr, nullptr, nullptr, tooltip.c_str());
958 		}
959 		if (_vm->_gameFlags->query(kFlagKIAPrivacyAddon)) {
960 			_buttons->defineImage(21, kiaButton21, nullptr, nullptr, nullptr, nullptr);
961 		}
962 	}
963 }
964 
buttonClicked(int buttonId)965 void KIA::buttonClicked(int buttonId) {
966 	int soundId = 0;
967 
968 	if (!isOpen()) {
969 		return;
970 	}
971 	switch (buttonId) {
972 	case 0:
973 		open(kKIASectionSettings);
974 		break;
975 	case 1:
976 		if (_currentSectionId != kKIASectionCrimes) {
977 			open(kKIASectionCrimes);
978 			_log->next();
979 			_log->clearFuture();
980 		}
981 		break;
982 	case 2:
983 		if (_currentSectionId != kKIASectionSuspects) {
984 			open(kKIASectionSuspects);
985 			_log->next();
986 			_log->clearFuture();
987 		}
988 		break;
989 	case 3:
990 		if (_currentSectionId != kKIASectionClues) {
991 			open(kKIASectionClues);
992 			_log->next();
993 			_log->clearFuture();
994 		}
995 		break;
996 	case 4:
997 		if (_log->hasPrev()) {
998 			int kiaLogPrevType = _log->getPrevType();
999 			switch (kiaLogPrevType) {
1000 			case 2:
1001 				open(kKIASectionCrimes);
1002 				_log->prev();
1003 				_crimesSection->loadFromLog();
1004 				break;
1005 			case 1:
1006 				open(kKIASectionSuspects);
1007 				_log->prev();
1008 				_suspectsSection->loadFromLog();
1009 				break;
1010 			case 0:
1011 				open(kKIASectionClues);
1012 				_log->prev();
1013 				_cluesSection->loadFromLog();
1014 				break;
1015 			}
1016 		}
1017 		break;
1018 	case 5:
1019 		if (_log->hasNext()) {
1020 			int kiaLogNextType = _log->getNextType();
1021 			switch (kiaLogNextType) {
1022 			case 2:
1023 				open(kKIASectionCrimes);
1024 				_log->next();
1025 				_crimesSection->loadFromLog();
1026 				break;
1027 			case 1:
1028 				open(kKIASectionSuspects);
1029 				_log->next();
1030 				_suspectsSection->loadFromLog();
1031 				break;
1032 			case 0:
1033 				open(kKIASectionClues);
1034 				_log->next();
1035 				_cluesSection->loadFromLog();
1036 				break;
1037 			}
1038 		}
1039 		break;
1040 	case 6:
1041 		if (!_forceOpen) {
1042 			open(_lastSectionIdKIA);
1043 		}
1044 		break;
1045 	case 7:
1046 		open(kKIASectionSettings);
1047 		break;
1048 	case 8:
1049 		open(kKIASectionHelp);
1050 		break;
1051 	case 9:
1052 		if (!_forceOpen) {
1053 			open(kKIASectionSave);
1054 		}
1055 		break;
1056 	case 10:
1057 		open(kKIASectionLoad);
1058 		break;
1059 	case 11:
1060 		open(kKIASectionQuit);
1061 		break;
1062 	case 12:
1063 		_vm->_gameIsRunning = false;
1064 		open(kKIASectionNone);
1065 		break;
1066 	case 13:
1067 		open(_lastSectionIdOptions);
1068 		break;
1069 	case 14:
1070 		if (!_forceOpen) {
1071 			open(kKIASectionNone);
1072 		}
1073 		break;
1074 	case 15:
1075 		open(kKIASectionDiagnostic);
1076 		break;
1077 	case 16:
1078 		_vm->_settings->setAmmoType(0);
1079 		if (_vm->_rnd.getRandomNumber(1)) {
1080 			soundId = _vm->_combat->getHitSound();
1081 		} else {
1082 			soundId = _vm->_combat->getMissSound();
1083 		}
1084 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 70, 0, 0, 50, 0);
1085 		break;
1086 	case 17:
1087 		_vm->_settings->setAmmoType(1);
1088 		if (_vm->_rnd.getRandomNumber(1)) {
1089 			soundId = _vm->_combat->getHitSound();
1090 		} else {
1091 			soundId = _vm->_combat->getMissSound();
1092 		}
1093 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 70, 0, 0, 50, 0);
1094 		break;
1095 	case 18:
1096 		_vm->_settings->setAmmoType(2);
1097 		if (_vm->_rnd.getRandomNumber(1)) {
1098 			soundId = _vm->_combat->getHitSound();
1099 		} else {
1100 			soundId = _vm->_combat->getMissSound();
1101 		}
1102 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 70, 0, 0, 50, 0);
1103 		break;
1104 	case 19:
1105 		return;
1106 	case 20:
1107 		playerReset();
1108 		break;
1109 	case 21:
1110 		playPrivateAddon();
1111 		break;
1112 	case 22:
1113 		if (_vm->_cutContent) {
1114 			// play audio description
1115 			playObjectDescription();
1116 		}
1117 		break;
1118 	}
1119 }
1120 
switchSection(int sectionId)1121 void KIA::switchSection(int sectionId) {
1122 	if (_currentSection) {
1123 		_currentSection->close();
1124 	}
1125 	switch (sectionId) {
1126 	case kKIASectionCrimes:
1127 		_currentSection = _crimesSection;
1128 		break;
1129 	case kKIASectionSuspects:
1130 		_currentSection = _suspectsSection;
1131 		break;
1132 	case kKIASectionClues:
1133 		_currentSection = _cluesSection;
1134 		break;
1135 	case kKIASectionSettings:
1136 		_currentSection = _settingsSection;
1137 		break;
1138 	case kKIASectionHelp:
1139 		_currentSection = _helpSection;
1140 		break;
1141 	case kKIASectionSave:
1142 		_currentSection = _saveSection;
1143 		break;
1144 	case kKIASectionLoad:
1145 		_currentSection = _loadSection;
1146 		break;
1147 	case kKIASectionQuit:
1148 		_currentSection = nullptr;
1149 		break;
1150 	case kKIASectionDiagnostic:
1151 		_currentSection = _diagnosticSection;
1152 		break;
1153 	case kKIASectionPogo:
1154 		_currentSection = _pogoSection;
1155 		break;
1156 	default:
1157 		_currentSection = nullptr;
1158 		break;
1159 	}
1160 	if (_currentSection) {
1161 		_currentSection->open();
1162 	}
1163 }
1164 
getSectionVqaName(int sectionId)1165 const char *KIA::getSectionVqaName(int sectionId) {
1166 	switch (sectionId) {
1167 	case kKIASectionCrimes:
1168 		return "kia_crim.vqa";
1169 	case kKIASectionSuspects:
1170 		return "kia_susp.vqa";
1171 	case kKIASectionClues:
1172 		return "kia_clue.vqa";
1173 	case kKIASectionSettings:
1174 	case kKIASectionHelp:
1175 	case kKIASectionSave:
1176 	case kKIASectionLoad:
1177 	case kKIASectionQuit:
1178 	case kKIASectionDiagnostic:
1179 	case kKIASectionPogo:
1180 		return "kia_ingm.vqa";
1181 	default:
1182 		return nullptr;
1183 	}
1184 }
1185 
getVqaLoopMain(int sectionId)1186 int KIA::getVqaLoopMain(int sectionId) {
1187 	switch (sectionId) {
1188 	case kKIASectionCrimes:
1189 	case kKIASectionSuspects:
1190 	case kKIASectionClues:
1191 		return 3;
1192 	case kKIASectionSettings:
1193 	case kKIASectionHelp:
1194 	case kKIASectionSave:
1195 	case kKIASectionLoad:
1196 	case kKIASectionDiagnostic:
1197 	case kKIASectionPogo:
1198 		return 4;
1199 	case kKIASectionQuit:
1200 		return 7;
1201 	default:
1202 		return 0;
1203 	}
1204 }
1205 
getVqaLoopTransition(int transitionId)1206 int KIA::getVqaLoopTransition(int transitionId) {
1207 	switch (transitionId) {
1208 	case 0:
1209 	case 2:
1210 	case 7:
1211 	case 8:
1212 		return 0;
1213 	case 1:
1214 	case 4:
1215 	case 5:
1216 	case 9:
1217 		return 1;
1218 	case 3:
1219 	case 10:
1220 	case 11:
1221 	case 12:
1222 		return 2;
1223 	case 6:
1224 		return 3;
1225 	case 13:
1226 		return 6;
1227 	default:
1228 		return 0;
1229 	}
1230 }
1231 
getTransitionId(int oldSectionId,int newSectionId)1232 int KIA::getTransitionId(int oldSectionId, int newSectionId) {
1233 	switch (oldSectionId) {
1234 	case kKIASectionNone:
1235 		return 0;
1236 	case kKIASectionCrimes:
1237 		switch (newSectionId) {
1238 		case kKIASectionCrimes:
1239 			return 0;
1240 		case kKIASectionSuspects:
1241 			return 1;
1242 		case kKIASectionClues:
1243 			return 2;
1244 		case kKIASectionSettings:
1245 		case kKIASectionHelp:
1246 		case kKIASectionSave:
1247 		case kKIASectionLoad:
1248 		case kKIASectionDiagnostic:
1249 		case kKIASectionPogo:
1250 			return 3;
1251 		case kKIASectionQuit:
1252 			return 13;
1253 		}
1254 		return 0;
1255 	case kKIASectionSuspects:
1256 		switch (newSectionId) {
1257 		case kKIASectionCrimes:
1258 			return 4;
1259 		case kKIASectionSuspects:
1260 			return 0;
1261 		case kKIASectionClues:
1262 			return 5;
1263 		case kKIASectionSettings:
1264 		case kKIASectionHelp:
1265 		case kKIASectionSave:
1266 		case kKIASectionLoad:
1267 		case kKIASectionDiagnostic:
1268 		case kKIASectionPogo:
1269 			return 6;
1270 		case kKIASectionQuit:
1271 			return 13;
1272 		}
1273 		return 0;
1274 	case kKIASectionClues:
1275 		switch (newSectionId) {
1276 		case kKIASectionCrimes:
1277 			return 7;
1278 		case kKIASectionSuspects:
1279 			return 8;
1280 		case kKIASectionClues:
1281 			return 0;
1282 		case kKIASectionSettings:
1283 		case kKIASectionHelp:
1284 		case kKIASectionSave:
1285 		case kKIASectionLoad:
1286 		case kKIASectionDiagnostic:
1287 		case kKIASectionPogo:
1288 			return 9;
1289 		case kKIASectionQuit:
1290 			return 13;
1291 		}
1292 		return 0;
1293 	case kKIASectionSettings:
1294 	case kKIASectionHelp:
1295 	case kKIASectionSave:
1296 	case kKIASectionLoad:
1297 	case kKIASectionDiagnostic:
1298 	case kKIASectionPogo:
1299 		switch (newSectionId) {
1300 		case kKIASectionCrimes:
1301 			return 10;
1302 		case kKIASectionSuspects:
1303 			return 11;
1304 		case kKIASectionClues:
1305 			return 12;
1306 		case kKIASectionSettings:
1307 		case kKIASectionHelp:
1308 		case kKIASectionSave:
1309 		case kKIASectionLoad:
1310 		case kKIASectionDiagnostic:
1311 		case kKIASectionPogo:
1312 			return 0;
1313 		case kKIASectionQuit:
1314 			return 13;
1315 		}
1316 		return 0;
1317 	case kKIASectionQuit:
1318 		if (newSectionId != kKIASectionQuit) {
1319 			return 14;
1320 		}
1321 	}
1322 	return 0;
1323 }
1324 
playTransitionSound(int transitionId)1325 void KIA::playTransitionSound(int transitionId) {
1326 	switch (transitionId) {
1327 	case 1:
1328 	case 2:
1329 	case 3:
1330 	case 4:
1331 	case 5:
1332 	case 6:
1333 	case 7:
1334 	case 8:
1335 	case 9:
1336 	case 10:
1337 	case 11:
1338 	case 12:
1339 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxPANEL1),  100, 0, 0, 50, 0);
1340 		break;
1341 	case 13:
1342 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxPANEL2),  100, 0, 0, 50, 0);
1343 		break;
1344 	case 14:
1345 		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxPANOPEN), 100, 0, 0, 50, 0);
1346 		break;
1347 	}
1348 }
1349 
playPrivateAddon()1350 void KIA::playPrivateAddon() {
1351 	playerReset();
1352 	playSliceModel(524);
1353 	playActorDialogue(kActorBulletBob, 2060);
1354 	playActorDialogue(kActorBulletBob, 2070);
1355 }
1356 
playObjectDescription()1357 void KIA::playObjectDescription() {
1358 	if (_playerSliceModelId == -1) {
1359 		return;
1360 	}
1361 	switch (_playerSliceModelId) {
1362 	case kModelAnimationShellCasings:
1363 		playActorDialogue(kActorMcCoy, 8730);
1364 		break;
1365 	case kModelAnimationCandy:
1366 		playActorDialogue(kActorMcCoy, 8735);
1367 		break;
1368 	case kModelAnimationToyDog:
1369 		playActorDialogue(kActorMcCoy, 8740);
1370 		break;
1371 	case kModelAnimationChopstickWrapper:
1372 		playActorDialogue(kActorMcCoy, 8745);
1373 		break;
1374 	case kModelAnimationReferenceLetter:
1375 		playActorDialogue(kActorMcCoy, 8750);
1376 		break;
1377 	case kModelAnimationChromeDebris:
1378 		playActorDialogue(kActorMcCoy, 8755);
1379 		break;
1380 	case kModelAnimationLicensePlate:
1381 		playActorDialogue(kActorMcCoy, 8760);
1382 		break;
1383 	case kModelAnimationDragonflyEarring:
1384 		playActorDialogue(kActorMcCoy, 8765);
1385 		break;
1386 	case kModelAnimationDetonatorWire:
1387 		playActorDialogue(kActorMcCoy, 8770);
1388 		break;
1389 	case kModelAnimationKingstonKitchenBox:
1390 		playActorDialogue(kActorMcCoy, 8775);
1391 		break;
1392 	case kModelAnimationTyrellSalesPamphletKIA:
1393 		playActorDialogue(kActorMcCoy, 8780);
1394 		break;
1395 	case kModelAnimationRadiationGoggles:
1396 		playActorDialogue(kActorMcCoy, 8785);
1397 		break;
1398 	case kModelAnimationDogCollar:
1399 		playActorDialogue(kActorMcCoy, 8790);
1400 		break;
1401 	case kModelAnimationMaggieBracelet:
1402 		playActorDialogue(kActorMcCoy, 8795);
1403 		break;
1404 	case kModelAnimationEnvelope:
1405 		playActorDialogue(kActorMcCoy, 8800);
1406 		break;
1407 	case kModelAnimationWeaponsOrderForm:
1408 		// fall through
1409 	case kModelAnimationRequisitionForm:
1410 		// fall through
1411 	case kModelAnimationOriginalShippingForm:
1412 		// fall through
1413 	case kModelAnimationOriginalRequisitionForm:
1414 		playActorDialogue(kActorMcCoy, 8805); // A requisition form
1415 		break;
1416 	case kModelAnimationHysteriaToken:
1417 		playActorDialogue(kActorMcCoy, 8810);
1418 		break;
1419 	case kModelAnimationRagDoll:
1420 		playActorDialogue(kActorMcCoy, 8815);
1421 		break;
1422 	case kModelAnimationCheese:
1423 		playActorDialogue(kActorMcCoy, 8820);
1424 		break;
1425 	case kModelAnimationDragonflyBelt:
1426 		playActorDialogue(kActorMcCoy, 8825);
1427 		break;
1428 	case kModelAnimationStrangeScale:
1429 		playActorDialogue(kActorMcCoy, 8830);
1430 		break;
1431 	case kModelAnimationDektorasCard:
1432 		playActorDialogue(kActorMcCoy, 8835);
1433 		break;
1434 	case kModelAnimationLetter:
1435 		// fall through
1436 	case kModelAnimationGrigoriansNote:
1437 		playActorDialogue(kActorMcCoy, 8840);
1438 		break;
1439 	case kModelAnimationCollectionReceipt:
1440 		playActorDialogue(kActorMcCoy, 8845);
1441 		break;
1442 	case kModelAnimationGordosLighterReplicant:
1443 		// fall through
1444 	case kModelAnimationGordosLighterHuman:
1445 		playActorDialogue(kActorMcCoy, 8850);
1446 		break;
1447 //	case kModelAnimationBadge: // This is never discovered in-game, and uses same model as Holden's badge
1448 //		playActorDialogue(kActorMcCoy, 8855); // Baker's Badge
1449 //		break;
1450 	case kModelAnimationBadge:
1451 		playActorDialogue(kActorMcCoy, 8860);
1452 		break;
1453 	case kModelAnimationLichenDogWrapper:
1454 		playActorDialogue(kActorMcCoy, 8865);
1455 		break;
1456 	case kModelAnimationFolder:
1457 		playActorDialogue(kActorMcCoy, 8870);
1458 		break;
1459 	case kModelAnimationCandyWrapper:
1460 		playActorDialogue(kActorMcCoy, 8875);
1461 		break;
1462 	case kModelAnimationFlaskOfAbsinthe:
1463 		playActorDialogue(kActorMcCoy, 8880);
1464 		break;
1465 	case kModelAnimationPowerSource:
1466 		playActorDialogue(kActorMcCoy, 8885);
1467 		break;
1468 	case kModelAnimationBomb: // TODO - does this ever appear in KIA?
1469 		playActorDialogue(kActorMcCoy, 8890);
1470 		break;
1471 	case kModelAnimationGarterSnake:
1472 		playActorDialogue(kActorMcCoy, 8895);
1473 		break;
1474 	case kModelAnimationSlug:
1475 		playActorDialogue(kActorMcCoy, 8900);
1476 		break;
1477 	case kModelAnimationGoldfish:
1478 		playActorDialogue(kActorMcCoy, 8905);
1479 		break;
1480 	case kModelAnimationDNAEvidence01OutOf6:
1481 //		fall through
1482 //	case kModelAnimationDNAEvidence02OutOf6:
1483 //		fall through
1484 	case kModelAnimationDNAEvidence03OutOf6:
1485 //		fall through
1486 	case kModelAnimationDNAEvidence04OutOf6:
1487 //		fall through
1488 //	case kModelAnimationDNAEvidence05OutOf6:
1489 //		fall through
1490 	case kModelAnimationDNAEvidenceComplete:
1491 //		fall through
1492 	case kModelAnimationSpinnerKeys:
1493 //		fall through
1494 	case kModelAnimationBriefcase:
1495 //		fall through
1496 	case kModelAnimationCrystalsCigarette:
1497 //		fall through
1498 	case kModelAnimationVideoDisc:
1499 //		fall through
1500 	default:
1501 		playActorDialogue(kActorMcCoy, 8525);
1502 		break;
1503 	}
1504 }
1505 
1506 } // End of namespace BladeRunner
1507