aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--devtools/create_titanic/create_titanic_dat.cpp39
-rw-r--r--dists/engine-data/titanic.datbin2792935 -> 2793322 bytes
-rw-r--r--engines/bladerunner/aesc.cpp139
-rw-r--r--engines/bladerunner/aesc.h68
-rw-r--r--engines/bladerunner/bladerunner.cpp79
-rw-r--r--engines/bladerunner/bladerunner.h4
-rw-r--r--engines/bladerunner/module.mk2
-rw-r--r--engines/bladerunner/overlays.cpp146
-rw-r--r--engines/bladerunner/overlays.h74
-rw-r--r--engines/bladerunner/scene.cpp1
-rw-r--r--engines/bladerunner/script/scene/ct01.cpp1
-rw-r--r--engines/bladerunner/script/script.cpp7
-rw-r--r--engines/bladerunner/slice_renderer.cpp28
-rw-r--r--engines/bladerunner/slice_renderer.h5
-rw-r--r--engines/bladerunner/view.cpp2
-rw-r--r--engines/bladerunner/view.h2
-rw-r--r--engines/bladerunner/vqa_decoder.cpp175
-rw-r--r--engines/bladerunner/vqa_decoder.h48
-rw-r--r--engines/bladerunner/vqa_player.cpp79
-rw-r--r--engines/bladerunner/vqa_player.h4
-rw-r--r--engines/sci/detection_tables.h5
-rw-r--r--engines/sci/engine/features.h11
-rw-r--r--engines/sci/resource_audio.cpp31
-rw-r--r--engines/sci/sound/audio32.cpp16
-rw-r--r--engines/titanic/carry/eye.cpp9
-rw-r--r--engines/titanic/debugger.cpp19
-rw-r--r--engines/titanic/debugger.h5
-rw-r--r--engines/titanic/npcs/maitre_d.cpp5
-rw-r--r--engines/titanic/pet_control/pet_frame.cpp7
-rw-r--r--engines/titanic/pet_control/pet_load.cpp2
-rw-r--r--engines/titanic/pet_control/pet_load_save.cpp2
-rw-r--r--engines/titanic/pet_control/pet_quit.cpp4
-rw-r--r--engines/titanic/pet_control/pet_save.cpp2
-rw-r--r--engines/titanic/pet_control/pet_sound.cpp10
-rw-r--r--engines/titanic/star_control/star_camera.h2
-rw-r--r--engines/titanic/support/files_manager.cpp7
-rw-r--r--engines/titanic/support/strings.h10
-rw-r--r--engines/titanic/titanic.cpp4
-rw-r--r--engines/wage/detection_tables.h4
-rw-r--r--engines/wage/script.cpp35
-rw-r--r--engines/wage/script.h4
-rw-r--r--engines/wage/sound.cpp21
-rw-r--r--engines/wage/sound.h4
-rw-r--r--engines/wage/wage.cpp10
-rw-r--r--engines/wage/wage.h7
-rw-r--r--engines/wage/world.cpp6
-rw-r--r--graphics/macgui/mactext.cpp4
47 files changed, 937 insertions, 212 deletions
diff --git a/devtools/create_titanic/create_titanic_dat.cpp b/devtools/create_titanic/create_titanic_dat.cpp
index 3d5e4476c9..b9d21d7ca8 100644
--- a/devtools/create_titanic/create_titanic_dat.cpp
+++ b/devtools/create_titanic/create_titanic_dat.cpp
@@ -56,7 +56,7 @@
* ASCIIZ - name of the resource
*/
-#define VERSION_NUMBER 2
+#define VERSION_NUMBER 3
#define HEADER_SIZE 0x1380
Common::File inputFile, outputFile;
@@ -615,7 +615,7 @@ static const BedheadEntry OFF_RESTING_D_WRONG[1] = {
{ "Any", "Any", "Any", "ClosedWrong", 59, 70 }
};
-static const char *const STRINGS_EN[141] = {
+static const char *const STRINGS_EN[151] = {
"",
"You are standing outside the Pellerator.",
"I'm sorry, you cannot enter this pellerator at present as a bot is in the way.",
@@ -761,10 +761,20 @@ static const char *const STRINGS_EN[141] = {
"Saved Chevron: ",
"Current location: ",
"A hot",
- "A cold"
+ "A cold",
+ "Load the game.",
+ "Save the game.",
+ "Empty",
+ "Quit the game.",
+ "Are you sure you want to quit?",
+ "Change the volume settings",
+ "Master volume",
+ "Music volume",
+ "Parrot volume",
+ "Speech volume"
};
-static const char *const STRINGS_DE[186] = {
+static const char *const STRINGS_DE[197] = {
"",
"Sie befinden sich vor dem Pellerator.",
"Wir bedauern, da ein Bot den Weg versperrt, ist Ihnen der "
@@ -848,7 +858,6 @@ static const char *const STRINGS_DE[186] = {
"Leider ist es nicht m\xF6""glich den T\xFC""r-Bot von diesem Ort aus herbeizurufen.",
"Leider ist es nicht m\xF6""glich den Klingel-Bot von diesem Ort aus herbeizurufen.",
"Es ist niemand hier mit dem du sprechen k\xF6""nntest",
- "Spricht mit ",
"Im Gespr\xE4""ch mit ",
"der T\xFC""r-Bot",
"der Empfangs-Bot",
@@ -891,7 +900,7 @@ static const char *const STRINGS_DE[186] = {
"Rufe Pellerator",
"Gehe zum Grund des Brunnens",
"Gehe zur Oberfl\xE4""che des Brunnens",
- "Gehe zu deiner Kabine"
+ "Gehe zu deiner Kabine",
"Gehe zur Bar",
"Gehe zum Promenadendeck",
"Gehe zum Baumgarten",
@@ -900,11 +909,11 @@ static const char *const STRINGS_DE[186] = {
"Die Papagei-Lobby",
"Das Zimmer des Erschaffers",
"Die Br\xFC""cke",
- "Der Kielraum"
+ "Der Kielraum",
"Das Skulpturenzimmer",
"Der Baumgarten",
"Der Grund des Brunnens",
- "Das Promenadendeck"
+ "Das Promenadendeck",
"Das First-Class-Restaurant",
"Titanias Zimmer",
"Die Bar",
@@ -928,6 +937,16 @@ static const char *const STRINGS_DE[186] = {
"Derzeitige Position: ",
"Eine hei\xDF""e",
"Eine kalte",
+ "Laden Sie das Spiel.",
+ "Speichern Sie das Spiel.",
+ "Leer",
+ "Beenden Sie das Spiel.",
+ "Sind Sie sicher, da\xDF"" Sie das Spiel verlassen m\XF6""chten?",
+ "\xC4""ndern der Lautst\xE4""rkeeinstellungen",
+ "Grundlautst\xE4""rke",
+ "Musiklautst\xE4""rke",
+ "Papageienlautst\xE4""rke",
+ "Sprachlautst\xE4""rke",
"Sommer",
"Herbst",
@@ -1550,8 +1569,8 @@ void writeData() {
writeStringArray("TEXT/ITEM_NAMES", ITEM_NAMES, 46);
writeStringArray("TEXT/ITEM_IDS", ITEM_IDS, 40);
writeStringArray("TEXT/ROOM_NAMES", ROOM_NAMES, 34);
- writeStringArray("TEXT/STRINGS", STRINGS_EN, 141);
- writeStringArray("TEXT/STRINGS/DE", STRINGS_DE, 186);
+ writeStringArray("TEXT/STRINGS", STRINGS_EN, 151);
+ writeStringArray("TEXT/STRINGS/DE", STRINGS_DE, 197);
const int TEXT_PHRASES[3] = { 0x61D3C8, 0x618340, 0x61B1E0 };
const int TEXT_REPLACEMENTS1[3] = { 0x61D9B0, 0x61C788, 0x61B7C8 };
const int TEXT_REPLACEMENTS2[3] = { 0x61DD20, 0x61CAF8, 0x61BB38 };
diff --git a/dists/engine-data/titanic.dat b/dists/engine-data/titanic.dat
index 2a9d60122b..2d5ea73117 100644
--- a/dists/engine-data/titanic.dat
+++ b/dists/engine-data/titanic.dat
Binary files differ
diff --git a/engines/bladerunner/aesc.cpp b/engines/bladerunner/aesc.cpp
new file mode 100644
index 0000000000..d653d1df35
--- /dev/null
+++ b/engines/bladerunner/aesc.cpp
@@ -0,0 +1,139 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/aesc.h"
+
+#include "common/stream.h"
+
+namespace BladeRunner {
+
+AESC::AESC(BladeRunnerEngine *vm, int size) : _vm(vm) {
+ _dataSize = size;
+ _data = new uint8[size];
+ _entries.reserve(8);
+}
+
+AESC::~AESC() {
+ delete[] _data;
+}
+
+void AESC::readVqa(Common::SeekableReadStream *stream) {
+ uint8* dataPtr = _data;
+ int dataSize = _dataSize;
+
+ int entriesCount = stream->readUint32LE();
+
+ if (entriesCount == 0) {
+ return;
+ }
+
+ entriesCount = MIN(entriesCount, 7);
+ _entries.resize(entriesCount);
+
+ for (Common::Array<Entry>::iterator entry = _entries.begin(); entry != _entries.end(); entry++) {
+ stream->read(&entry->palette, sizeof(Color256) * 16);
+
+ entry->x = stream->readUint16LE();
+ entry->y = stream->readUint16LE();
+ entry->width = stream->readUint16LE();
+ entry->height = stream->readUint16LE();
+ entry->z = stream->readUint16LE();
+
+ int entryDataSize = stream->readUint16LE();
+
+ int pixelCount = entry->width * entry->height;
+
+ if (pixelCount > dataSize) { // to big to fit
+ entry->width = 0;
+ entry->height = 0;
+ entry->data = _data;
+ continue;
+ // there is a issue in the game code, because it's not skipping data of entry in this case
+ }
+
+ int pos = stream->pos();
+ dataSize -= pixelCount;
+ entry->data = dataPtr;
+ do {
+ uint8 count = stream->readByte();
+ if (count & 0x80) { // repeat same data
+ uint8 colors = stream->readByte();
+ for (uint8 j = 0; j < (count & 0x7F) + 1; j++) {
+ *(dataPtr++) = colors >> 4; // upper 4 bit
+ *(dataPtr++) = colors & 0xF; // lower 4 bit
+ pixelCount -= 2;
+ }
+ } else { // copy data
+ for (uint8 j = 0; j < count + 1; j++) {
+ uint8 colors = stream->readByte();
+ *(dataPtr++) = colors >> 4; // upper 4 bit
+ *(dataPtr++) = colors & 0xF; // lower 4 bit
+ pixelCount -= 2;
+ }
+ }
+ } while (pixelCount > 0);
+ stream->seek(pos + entryDataSize, SEEK_SET);
+ }
+}
+
+//TODO:
+//bool AESC::isAffectingArea(int x, int y, int width, int height, int z) {
+// int xx = x >> 1;
+// int yy = y >> 1;
+// if (_entries.empty()) {
+// return false;
+// }
+//
+// for(int i = 0; i < _entries.size(); i++) {
+// Entry &entry = _entries[i];
+// if (entry.z < z) {
+// if (entry.width < (width >> 1) + xx) {
+// if (entry.width + entry.x > xx) {
+// if (entry.height < (height >> 1) + yy) {
+// if(entry.height + entry.y > yy) {
+// return true;
+// }
+// }
+// }
+// }
+// }
+// }
+// return false;
+//}
+
+void AESC::getColor(Color256 *outColor, uint16 x, uint16 y, uint16 z) {
+ Color256 color = { 0, 0, 0 };
+ for (Common::Array<Entry>::iterator entry = _entries.begin(); entry != _entries.end(); entry++) {
+ uint16 x1 = (x / 2) - entry->x;
+ uint16 y1 = (y / 2) - entry->y;
+ if ( x1 < entry->width && y1 < entry->height && z > entry->z) {
+ int colorIndex = entry->data[y1 * entry->width + x1];
+ Color256 entryColor = entry->palette[colorIndex];
+ color.r += entryColor.r;
+ color.g += entryColor.g;
+ color.b += entryColor.b;
+ }
+ }
+ *outColor = color;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/aesc.h b/engines/bladerunner/aesc.h
new file mode 100644
index 0000000000..d3f926b190
--- /dev/null
+++ b/engines/bladerunner/aesc.h
@@ -0,0 +1,68 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_AESC_H
+#define BLADERUNNER_AESC_H
+
+#include "bladerunner/color.h"
+
+#include "common/array.h"
+
+namespace Common {
+class ReadStream;
+}
+
+namespace BladeRunner {
+class BladeRunnerEngine;
+
+class AESC {
+public:
+ struct Entry
+ {
+ Color256 palette[16];
+ uint16 x;
+ uint16 y;
+ uint16 width;
+ uint16 height;
+ uint16 z;
+ uint8 *data;
+ };
+
+ BladeRunnerEngine *_vm;
+
+ Common::Array<Entry> _entries;
+ uint8 *_data;
+ int _dataSize;
+
+public:
+ AESC(BladeRunnerEngine *vm, int size);
+ ~AESC();
+
+ void readVqa(Common::SeekableReadStream *stream);
+ void getColor(Color256 *outColor, uint16 x, uint16 y, uint16 z);
+
+ //TODO
+ //bool isAffectingArea(int x, int y, int width, int height, int unk);
+};
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index 7fe3f9ed2e..121ad8128e 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -24,6 +24,7 @@
#include "bladerunner/actor.h"
#include "bladerunner/adq.h"
+#include "bladerunner/aesc.h"
#include "bladerunner/ambient_sounds.h"
#include "bladerunner/audio_mixer.h"
#include "bladerunner/audio_player.h"
@@ -43,6 +44,7 @@
#include "bladerunner/mouse.h"
#include "bladerunner/outtake.h"
#include "bladerunner/obstacles.h"
+#include "bladerunner/overlays.h"
#include "bladerunner/regions.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
@@ -69,7 +71,6 @@
#include "graphics/pixelformat.h"
-
namespace BladeRunner {
BladeRunnerEngine::BladeRunnerEngine(OSystem *syst)
@@ -79,10 +80,13 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst)
_gameIsRunning = true;
_playerLosesControlCounter = 0;
+ //TODO(peterkohaut): move these to init
+
_crimesDatabase = nullptr;
_sceneScript = new SceneScript(this);
_settings = new Settings(this);
_lights = new Lights(this);
+ _aesc = new AESC(this, 0x8000);
_combat = new Combat(this);
_adq = new ADQ(this);
_obstacles = new Obstacles(this);
@@ -122,6 +126,7 @@ BladeRunnerEngine::~BladeRunnerEngine() {
delete _obstacles;
delete _adq;
delete _combat;
+ delete _aesc;
delete _lights;
delete _settings;
delete _sceneScript;
@@ -235,7 +240,8 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
if (!openArchive("SPCHSFX.TLK"))
return false;
- // TODO: Video overlays
+ _overlays = new Overlays(this);
+ _overlays->init();
_zbuffer = new ZBuffer();
_zbuffer->init(640, 480);
@@ -325,14 +331,17 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
// TODO: Support cdframes
r = _sliceAnimations->openHDFrames();
- if (!r)
+ if (!r) {
return false;
+ }
r = _sliceAnimations->openCoreAnim();
- if (!r)
+ if (!r) {
return false;
+ }
_sliceRenderer = new SliceRenderer(this);
+ _sliceRenderer->setAESC(_aesc);
_crimesDatabase = new CrimesDatabase(this, "CLUES", _gameInfo->getClueCount());
@@ -430,7 +439,8 @@ void BladeRunnerEngine::shutdown() {
delete _ambientSounds;
- // TODO: Delete overlays
+ delete _overlays;
+ _overlays = nullptr;
delete _audioSpeech;
@@ -639,10 +649,11 @@ void BladeRunnerEngine::gameTick() {
}
(void)backgroundChanged;
blit(_surfaceInterface, _surfaceGame);
+
// TODO: remove zbuffer draw
// _surfaceGame.copyRectToSurface(_zbuffer->getData(), 1280, 0, 0, 640, 480);
- // TODO: Render overlays
+ _overlays->tick();
if (!inDialogueMenu) {
actorsUpdate();
@@ -703,14 +714,14 @@ void BladeRunnerEngine::gameTick() {
switch (sceneObject->_sceneObjectType) {
case SceneObjectTypeActor:
color = 0b111110000000000;
- drawBBox(a, b, _view, &_surface2, color);
- _mainFont->drawColor(_textActorNames->getText(sceneObject->_sceneObjectId - SCENE_OBJECTS_ACTORS_OFFSET), _surface2, pos.x, pos.y, color);
+ drawBBox(a, b, _view, &_surfaceGame, color);
+ _mainFont->drawColor(_textActorNames->getText(sceneObject->_sceneObjectId - SCENE_OBJECTS_ACTORS_OFFSET), _surfaceGame, pos.x, pos.y, color);
break;
case SceneObjectTypeItem:
char itemText[40];
- drawBBox(a, b, _view, &_surface2, color);
+ drawBBox(a, b, _view, &_surfaceGame, color);
sprintf(itemText, "item %i", sceneObject->_sceneObjectId - SCENE_OBJECTS_ITEMS_OFFSET);
- _mainFont->drawColor(itemText, _surface2, pos.x, pos.y, color);
+ _mainFont->drawColor(itemText, _surfaceGame, pos.x, pos.y, color);
break;
case SceneObjectTypeObject:
color = 0b011110111101111;
@@ -719,11 +730,11 @@ void BladeRunnerEngine::gameTick() {
if (sceneObject->_isClickable) {
color = 0b000001111100000;
}
- drawBBox(a, b, _view, &_surface2, color);
- _mainFont->drawColor(_scene->objectGetName(sceneObject->_sceneObjectId - SCENE_OBJECTS_OBJECTS_OFFSET), _surface2, pos.x, pos.y, color);
+ drawBBox(a, b, _view, &_surfaceGame, color);
+ _mainFont->drawColor(_scene->objectGetName(sceneObject->_sceneObjectId - SCENE_OBJECTS_OBJECTS_OFFSET), _surfaceGame, pos.x, pos.y, color);
break;
}
- _surface2.frameRect(sceneObject->_screenRectangle, color);
+ _surfaceGame.frameRect(sceneObject->_screenRectangle, color);
}
}
@@ -731,16 +742,15 @@ void BladeRunnerEngine::gameTick() {
for (int i = 0; i < 10; i++) {
Region *region = &_scene->_regions->_regions[i];
if (!region->_present) continue;
- _surface2.frameRect(region->_rectangle, 0b000000000011111);
+ _surfaceGame.frameRect(region->_rectangle, 0b000000000011111);
}
for (int i = 0; i < 10; i++) {
Region *region = &_scene->_exits->_regions[i];
if (!region->_present) continue;
- _surface2.frameRect(region->_rectangle, 0b111111111111111);
+ _surfaceGame.frameRect(region->_rectangle, 0b111111111111111);
}
-
//draw walkboxes
for (int i = 0; i < _scene->_set->_walkboxCount; i++) {
Walkbox *walkbox = &_scene->_set->_walkboxes[i];
@@ -748,9 +758,9 @@ void BladeRunnerEngine::gameTick() {
for (int j = 0; j < walkbox->_vertexCount; j++) {
Vector3 start = _view->calculateScreenPosition(walkbox->_vertices[j]);
Vector3 end = _view->calculateScreenPosition(walkbox->_vertices[(j + 1) % walkbox->_vertexCount]);
- _surface2.drawLine(start.x, start.y, end.x, end.y, 0b111111111100000);
+ _surfaceGame.drawLine(start.x, start.y, end.x, end.y, 0b111111111100000);
Vector3 pos = _view->calculateScreenPosition(0.5 * (start + end));
- _mainFont->drawColor(walkbox->_name, _surface2, pos.x, pos.y, 0b111111111100000);
+ _mainFont->drawColor(walkbox->_name, _surfaceGame, pos.x, pos.y, 0b111111111100000);
}
}
@@ -776,12 +786,12 @@ void BladeRunnerEngine::gameTick() {
int colorB = (light->_color.b * 31.0f);
int color = (colorR << 10) + (colorG << 5) + colorB;
- drawBBox(posOrigin - size, posOrigin + size, _view, &_surface2, color);
+ drawBBox(posOrigin - size, posOrigin + size, _view, &_surfaceGame, color);
Vector3 posOriginT = _view->calculateScreenPosition(posOrigin);
Vector3 posTargetT = _view->calculateScreenPosition(posTarget);
- _surface2.drawLine(posOriginT.x, posOriginT.y, posTargetT.x, posTargetT.y, color);
- _mainFont->drawColor(light->_name, _surface2, posOriginT.x, posOriginT.y, color);
+ _surfaceGame.drawLine(posOriginT.x, posOriginT.y, posTargetT.x, posTargetT.y, color);
+ _mainFont->drawColor(light->_name, _surfaceGame, posOriginT.x, posOriginT.y, color);
}
//draw waypoints
@@ -792,11 +802,34 @@ void BladeRunnerEngine::gameTick() {
Vector3 pos = waypoint->_position;
Vector3 size = Vector3(5.0f, 5.0f, 5.0f);
int color = 0b111111111111111;
- drawBBox(pos - size, pos + size, _view, &_surface2, color);
+ drawBBox(pos - size, pos + size, _view, &_surfaceGame, color);
Vector3 spos = _view->calculateScreenPosition(pos);
char waypointText[40];
sprintf(waypointText, "waypoint %i", i);
- _mainFont->drawColor(waypointText, _surface2, spos.x, spos.y, color);
+ _mainFont->drawColor(waypointText, _surfaceGame, spos.x, spos.y, color);
+ }
+#endif
+#if 0
+ //draw aesc
+ for (uint i = 0; i < _aesc->_entries.size(); i++) {
+ AESC::Entry &entry = _aesc->_entries[i];
+ int j = 0;
+ for (int y = 0; y < entry.height; y++) {
+ for (int x = 0; x < entry.width; x++) {
+ Common::Rect r((entry.x + x) * 2, (entry.y + y) * 2, (entry.x + x) * 2 + 2, (entry.y + y) * 2 + 2);
+
+ int ec = entry.data[j++];
+ Color256 color = entry.palette[ec];
+ int bladeToScummVmConstant = 256 / 16;
+
+ Graphics::PixelFormat _pixelFormat = createRGB555();
+ int color555 = _pixelFormat.RGBToColor(
+ CLIP(color.r * bladeToScummVmConstant, 0, 255),
+ CLIP(color.g * bladeToScummVmConstant, 0, 255),
+ CLIP(color.b * bladeToScummVmConstant, 0, 255));
+ _surfaceGame.fillRect(r, color555);
+ }
+ }
}
#endif
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index 5164f353dd..066937ca38 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -50,6 +50,7 @@ enum AnimationModes {
class Actor;
class ADQ;
+class AESC;
class AIScripts;
class AmbientSounds;
class AudioMixer;
@@ -68,6 +69,7 @@ class Items;
class Lights;
class Mouse;
class Obstacles;
+class Overlays;
class Scene;
class SceneObjects;
class SceneScript;
@@ -92,6 +94,7 @@ public:
int _playerLosesControlCounter;
ADQ *_adq;
+ AESC *_aesc;
AIScripts *_aiScripts;
AmbientSounds *_ambientSounds;
AudioMixer *_audioMixer;
@@ -110,6 +113,7 @@ public:
Font *_mainFont;
Mouse *_mouse;
Obstacles *_obstacles;
+ Overlays *_overlays;
Scene *_scene;
SceneObjects *_sceneObjects;
SceneScript *_sceneScript;
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk
index 61a95352bf..711ddd3346 100644
--- a/engines/bladerunner/module.mk
+++ b/engines/bladerunner/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/bladerunner
MODULE_OBJS = \
adq.o \
+ aesc.o \
actor.o \
actor_clues.o \
actor_combat.o \
@@ -38,6 +39,7 @@ MODULE_OBJS = \
movement_track.o \
obstacles.o \
outtake.o \
+ overlays.o \
regions.o \
scene.o \
scene_objects.o \
diff --git a/engines/bladerunner/overlays.cpp b/engines/bladerunner/overlays.cpp
new file mode 100644
index 0000000000..946cbe266d
--- /dev/null
+++ b/engines/bladerunner/overlays.cpp
@@ -0,0 +1,146 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/overlays.h"
+
+#include "bladerunner/bladerunner.h"
+
+#include "bladerunner/archive.h"
+#include "bladerunner/vqa_player.h"
+
+#include "graphics/surface.h"
+
+namespace BladeRunner {
+
+Overlays::Overlays(BladeRunnerEngine *vm)
+ : _vm(vm)
+{
+}
+
+bool Overlays::init() {
+ reset();
+ _videos.resize(kOverlayVideos);
+
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ _videos[i].vqaPlayer = nullptr;
+ resetSingle(i);
+ }
+
+ return true;
+}
+
+Overlays::~Overlays() {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ resetSingle(i);
+ }
+ _videos.clear();
+ reset();
+}
+
+int Overlays::play(const Common::String &name, int loopId, int loopForever, int a5, int a6) {
+ int id = mix_id(name);
+ int index = findById(id);
+ if (index < 0) {
+ index = findEmpty();
+ if (index < 0) {
+ return index;
+ }
+ _videos[index].id = id;
+ _videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceGame);
+
+ // repeat forever
+ _videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr);
+ _videos[index].loaded = true;
+ }
+
+ Common::String resourceName = Common::String::format("%s.VQA", name.c_str());
+ _videos[index].vqaPlayer->open(resourceName);
+ _videos[index].vqaPlayer->setLoop(
+ loopId,
+ loopForever ? -1 : 0,
+ a5 ? kLoopSetModeImmediate : kLoopSetModeEnqueue,
+ nullptr, nullptr);
+
+ return index;
+}
+
+void Overlays::remove(const Common::String &name) {
+ int id = mix_id(name);
+ int index = findById(id);
+ if (index >= 0) {
+ resetSingle(index);
+ }
+}
+
+void Overlays::tick() {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ if (_videos[i].loaded) {
+ int frame = _videos[i].vqaPlayer->update(true);
+ if (frame < 0) {
+ resetSingle(i);
+ }
+ }
+ }
+}
+
+int Overlays::findById(int id) const {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ if (_videos[i].loaded && _videos[i].id == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int Overlays::findEmpty() const {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ if (!_videos[i].loaded) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void Overlays::resetSingle(int i) {
+ assert(i >= 0 && i < (int)_videos.size());
+ if (_videos[i].vqaPlayer) {
+ delete _videos[i].vqaPlayer;
+ _videos[i].vqaPlayer = nullptr;
+ }
+ _videos[i].loaded = false;
+ _videos[i].id = 0;
+ _videos[i].field2 = -1;
+}
+
+void Overlays::resetAll() {
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ if (_videos[i].loaded) {
+ resetSingle(i);
+ }
+ }
+}
+
+void Overlays::reset() {
+ _videos.clear();
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/overlays.h b/engines/bladerunner/overlays.h
new file mode 100644
index 0000000000..9be515e036
--- /dev/null
+++ b/engines/bladerunner/overlays.h
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_OVERLAYS_H
+#define BLADERUNNER_OVERLAYS_H
+
+#include "common/array.h"
+#include "common/str.h"
+
+namespace Graphics {
+ struct Surface;
+}
+
+namespace BladeRunner {
+
+class BladeRunnerEngine;
+class VQAPlayer;
+
+struct OverlayVideo {
+ bool loaded;
+ VQAPlayer *vqaPlayer;
+ // char name[13];
+ int32 id;
+ int field0;
+ int field1;
+ int field2;
+};
+
+class Overlays {
+ static const int kOverlayVideos = 5;
+
+ BladeRunnerEngine *_vm;
+ Common::Array<OverlayVideo> _videos;
+
+public:
+ Overlays(BladeRunnerEngine *vm);
+ bool init();
+ ~Overlays();
+
+ int play(const Common::String &name, int a3, int a4, int a5, int a6);
+ void remove(const Common::String &name);
+ void tick();
+
+private:
+ int findById(int32 id) const;
+ int findEmpty() const;
+
+ void resetSingle(int i);
+ void resetAll();
+ void reset();
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp
index 54bc97abe4..de3d89291b 100644
--- a/engines/bladerunner/scene.cpp
+++ b/engines/bladerunner/scene.cpp
@@ -210,6 +210,7 @@ int Scene::advanceFrame() {
blit(_vm->_surfaceInterface, _vm->_surfaceGame);
_vqaPlayer->updateZBuffer(_vm->_zbuffer);
_vqaPlayer->updateView(_vm->_view);
+ _vqaPlayer->updateAESC(_vm->_aesc);
_vqaPlayer->updateLights(_vm->_lights);
}
if (_specialLoopMode && _specialLoopMode != kSceneLoopMode2 && _specialLoopMode != kSceneLoopModeSpinner) {
diff --git a/engines/bladerunner/script/scene/ct01.cpp b/engines/bladerunner/script/scene/ct01.cpp
index 5a2c62cfbb..21e6fc7600 100644
--- a/engines/bladerunner/script/scene/ct01.cpp
+++ b/engines/bladerunner/script/scene/ct01.cpp
@@ -366,7 +366,6 @@ void SceneScriptCT01::SceneFrameAdvanced(int frame) {
} else {
Ambient_Sounds_Play_Sound(66, Random_Query(33, 50), 0, 0, 0);
}
-
}
}
}
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 72f4e50a53..25d78e4991 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -38,6 +38,7 @@
#include "bladerunner/items.h"
#include "bladerunner/item_pickup.h"
#include "bladerunner/movement_track.h"
+#include "bladerunner/overlays.h"
#include "bladerunner/regions.h"
#include "bladerunner/set.h"
#include "bladerunner/settings.h"
@@ -818,13 +819,11 @@ bool ScriptBase::Music_Is_Playing() {
}
void ScriptBase::Overlay_Play(const char *overlay, int a2, int a3, int a4, int a5) {
- //TODO
- warning("Overlay_Play(%s, %d, %d, %d, %d)", overlay, a2, a3, a4, a5);
+ _vm->_overlays->play(overlay, a2, a3, a4, a5);
}
void ScriptBase::Overlay_Remove(const char *overlay) {
- //TODO
- warning("Overlay_Remove(%s)", overlay);
+ _vm->_overlays->remove(overlay);
}
void ScriptBase::Scene_Loop_Set_Default(int loopId) {
diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp
index e0845eeba3..34c910742c 100644
--- a/engines/bladerunner/slice_renderer.cpp
+++ b/engines/bladerunner/slice_renderer.cpp
@@ -22,6 +22,7 @@
#include "bladerunner/slice_renderer.h"
+#include "bladerunner/aesc.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/lights.h"
#include "bladerunner/set_effects.h"
@@ -46,6 +47,10 @@ SliceRenderer::SliceRenderer(BladeRunnerEngine *vm) {
SliceRenderer::~SliceRenderer() {
}
+void SliceRenderer::setAESC(AESC *aesc) {
+ _aesc = aesc;
+}
+
void SliceRenderer::setView(const View &view) {
_view = view;
}
@@ -349,6 +354,8 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
_modelMatrix
);
+ Vector3 cameraPosition(_view._cameraPosition.x, _view._cameraPosition.z, _view._cameraPosition.y); // not a bug
+
SliceRendererLights sliceRendererLights = SliceRendererLights(_lights);
_lights->setupFrame(_view._frame);
@@ -364,7 +371,7 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
float setEffectsColorCoeficient;
Color setEffectColor;
_setEffects->calculateColor(
- _view._cameraPosition,
+ cameraPosition,
Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
&setEffectsColorCoeficient,
&setEffectColor);
@@ -401,7 +408,7 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
if (sliceLineIterator._currentY & 1) {
_setEffects->calculateColor(
- _view._cameraPosition,
+ cameraPosition,
Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
&setEffectsColorCoeficient,
&setEffectColor);
@@ -416,7 +423,7 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
_setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
if (frameY >= 0 && frameY < 480) {
- drawSlice((int)sliceLine, true, frameLinePtr, zBufferLinePtr);
+ drawSlice((int)sliceLine, true, frameLinePtr, zBufferLinePtr, frameY);
}
sliceLineIterator.advance();
@@ -480,7 +487,7 @@ void SliceRenderer::drawOnScreen(int animationId, int animationFrame, int screen
while (currentSlice < _frameSliceCount) {
if (currentY >= 0 && currentY < 480) {
memset(lineZbuffer, 0xFF, 640 * 2);
- drawSlice(currentSlice, false, frameLinePtr, lineZbuffer);
+ drawSlice(currentSlice, false, frameLinePtr, lineZbuffer, currentY);
currentSlice += sliceStep;
currentY--;
frameLinePtr -= 640;
@@ -488,7 +495,7 @@ void SliceRenderer::drawOnScreen(int animationId, int animationFrame, int screen
}
}
-void SliceRenderer::drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr) {
+void SliceRenderer::drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr, int y) {
if (slice < 0 || (uint32)slice >= _frameSliceCount)
return;
@@ -523,14 +530,15 @@ void SliceRenderer::drawSlice(int slice, bool advanced, uint16 *frameLinePtr, ui
if (vertexZ >= 0 && vertexZ < 65536) {
int color555 = palette.color555[p[2]];
if (advanced) {
- Color256 color = palette.color[p[2]];
+ Color256 aescColor = { 0, 0, 0 };
+ _aesc->getColor(&aescColor, vertexX, y, vertexZ);
- color.r = (int)(_setEffectColor.r + _lightsColor.r * color.r) >> 16;
- color.g = (int)(_setEffectColor.g + _lightsColor.g * color.g) >> 16;
- color.b = (int)(_setEffectColor.b + _lightsColor.b * color.b) >> 16;
+ Color256 color = palette.color[p[2]];
+ color.r = ((int)(_setEffectColor.r + _lightsColor.r * color.r) >> 16) + aescColor.r;
+ color.g = ((int)(_setEffectColor.g + _lightsColor.g * color.g) >> 16) + aescColor.g;
+ color.b = ((int)(_setEffectColor.b + _lightsColor.b * color.b) >> 16) + aescColor.b;
int bladeToScummVmConstant = 256 / 32;
-
color555 = _pixelFormat.RGBToColor(CLIP(color.r * bladeToScummVmConstant, 0, 255), CLIP(color.g * bladeToScummVmConstant, 0, 255), CLIP(color.b * bladeToScummVmConstant, 0, 255));
}
for (int x = previousVertexX; x != vertexX; ++x) {
diff --git a/engines/bladerunner/slice_renderer.h b/engines/bladerunner/slice_renderer.h
index 1a876de543..fbdcdf3617 100644
--- a/engines/bladerunner/slice_renderer.h
+++ b/engines/bladerunner/slice_renderer.h
@@ -38,6 +38,7 @@ class MemoryReadStream;
namespace BladeRunner {
+class AESC;
class BladeRunnerEngine;
class Lights;
class SetEffects;
@@ -51,6 +52,7 @@ class SliceRenderer {
float _facing;
float _scale;
+ AESC *_aesc;
View _view;
Lights *_lights;
SetEffects *_setEffects;
@@ -87,12 +89,13 @@ class SliceRenderer {
Graphics::PixelFormat _pixelFormat;
Matrix3x2 calculateFacingRotationMatrix();
- void drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr);
+ void drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr, int y);
public:
SliceRenderer(BladeRunnerEngine *vm);
~SliceRenderer();
+ void setAESC(AESC *aesc);
void setView(const View &view);
void setLights(Lights *lights);
void setSetEffects(SetEffects *setEffects);
diff --git a/engines/bladerunner/view.cpp b/engines/bladerunner/view.cpp
index ed5cef9e3d..11cd99c9fc 100644
--- a/engines/bladerunner/view.cpp
+++ b/engines/bladerunner/view.cpp
@@ -27,7 +27,7 @@
namespace BladeRunner {
-bool View::read(Common::ReadStream *stream) {
+bool View::readVqa(Common::ReadStream *stream) {
_frame = stream->readUint32LE();
float d[12];
diff --git a/engines/bladerunner/view.h b/engines/bladerunner/view.h
index eb68aa9eb6..9d53d0852f 100644
--- a/engines/bladerunner/view.h
+++ b/engines/bladerunner/view.h
@@ -44,7 +44,7 @@ public:
float _viewportHalfHeight;
float _viewportDistance;
- bool read(Common::ReadStream *stream);
+ bool readVqa(Common::ReadStream *stream);
Vector3 calculateScreenPosition(Vector3 worldPosition);
private:
diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp
index 377251714b..53751afcd6 100644
--- a/engines/bladerunner/vqa_decoder.cpp
+++ b/engines/bladerunner/vqa_decoder.cpp
@@ -22,6 +22,7 @@
#include "bladerunner/vqa_decoder.h"
+#include "bladerunner/aesc.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/decompress_lcw.h"
#include "bladerunner/decompress_lzo.h"
@@ -127,6 +128,9 @@ VQADecoder::VQADecoder(Graphics::Surface *surface) :
}
VQADecoder::~VQADecoder() {
+ for (uint i = 0; i < _codebooks.size(); ++i) {
+ delete[] _codebooks[i].data;
+ }
delete _audioTrack;
delete _videoTrack;
delete[] _frameInfo;
@@ -190,8 +194,9 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) {
return true;
}
-void VQADecoder::decodeVideoFrame() {
- _videoTrack->decodeVideoFrame();
+void VQADecoder::decodeVideoFrame(int frame, bool forceDraw) {
+ _decodingFrame = frame;
+ _videoTrack->decodeVideoFrame(forceDraw);
}
void VQADecoder::decodeZBuffer(ZBuffer *zbuffer) {
@@ -206,11 +211,15 @@ void VQADecoder::decodeView(View *view) {
_videoTrack->decodeView(view);
}
+void VQADecoder::decodeAESC(AESC *aesc) {
+ _videoTrack->decodeAESC(aesc);
+}
+
void VQADecoder::decodeLights(Lights *lights) {
_videoTrack->decodeLights(lights);
}
-void VQADecoder::readPacket(int skipFlags) {
+void VQADecoder::readPacket(uint readFlags) {
IFFChunkHeader chd;
if (remain(_s) < 8) {
@@ -227,15 +236,15 @@ void VQADecoder::readPacket(int skipFlags) {
bool rc = false;
// Video track
switch (chd.id) {
- case kAESC: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readAESC(_s, chd.size); break;
- case kLITE: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readLITE(_s, chd.size); break;
- case kVIEW: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVIEW(_s, chd.size); break;
- case kVQFL: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFL(_s, chd.size); break;
- case kVQFR: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFR(_s, chd.size); break;
- case kZBUF: rc = skipFlags & 1 ? _s->skip(roundup(chd.size)) : _videoTrack->readZBUF(_s, chd.size); break;
+ case kAESC: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readAESC(_s, chd.size); break;
+ case kLITE: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readLITE(_s, chd.size); break;
+ case kVIEW: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVIEW(_s, chd.size); break;
+ case kVQFL: rc = ((readFlags & kVQAReadVideo ) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFL(_s, chd.size, readFlags); break;
+ case kVQFR: rc = ((readFlags & kVQAReadVideo ) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readVQFR(_s, chd.size, readFlags); break;
+ case kZBUF: rc = ((readFlags & kVQAReadCustom) == 0) ? _s->skip(roundup(chd.size)) : _videoTrack->readZBUF(_s, chd.size); break;
// Sound track
- case kSN2J: rc = skipFlags & 2 ? _s->skip(roundup(chd.size)) : _audioTrack->readSN2J(_s, chd.size); break;
- case kSND2: rc = skipFlags & 2 ? _s->skip(roundup(chd.size)) : _audioTrack->readSND2(_s, chd.size); break;
+ case kSN2J: rc = ((readFlags & kVQAReadAudio) == 0) ? _s->skip(roundup(chd.size)) : _audioTrack->readSN2J(_s, chd.size); break;
+ case kSND2: rc = ((readFlags & kVQAReadAudio) == 0) ? _s->skip(roundup(chd.size)) : _audioTrack->readSND2(_s, chd.size); break;
default:
rc = false;
_s->skip(roundup(chd.size));
@@ -248,14 +257,16 @@ void VQADecoder::readPacket(int skipFlags) {
} while (chd.id != kVQFR);
}
-void VQADecoder::readFrame(int frame, int skipFlags) {
+void VQADecoder::readFrame(int frame, uint readFlags) {
if (frame < 0 || frame >= numFrames()) {
error("frame %d out of bounds, frame count is %d", frame, numFrames());
}
uint32 frameOffset = 2 * (_frameInfo[frame] & 0x0FFFFFFF);
_s->seek(frameOffset);
- readPacket(skipFlags);
+
+ _readingFrame = frame;
+ readPacket(readFlags);
}
bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) {
@@ -284,10 +295,6 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) {
_header.maxCBFZSize = s->readUint32LE();
_header.unk5 = s->readUint32LE();
- if (_header.offsetX || _header.offsetY) {
- debug("_header.offsetX, _header.offsetY: %d %d", _header.offsetX, _header.offsetY);
- }
-
// if (_header.unk3 || _header.unk4 != 4 || _header.unk5 || _header.flags != 0x0014)
if (false) {
debug("_header.version %d", _header.version);
@@ -325,7 +332,7 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size) {
return true;
}
-bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size) {
+bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 size, uint readFlags) {
IFFChunkHeader chd;
while (size >= 8) {
@@ -335,8 +342,8 @@ bool VQADecoder::VQAVideoTrack::readVQFR(Common::SeekableReadStream *s, uint32 s
bool rc = false;
switch (chd.id) {
- case kCBFZ: rc = readCBFZ(s, chd.size); break;
- case kVPTR: rc = readVPTR(s, chd.size); break;
+ case kCBFZ: rc = ((readFlags & kVQAReadCodebook ) == 0) ? s->skip(roundup(chd.size)) : readCBFZ(s, chd.size); break;
+ case kVPTR: rc = ((readFlags & kVQAReadVectorPointerTable) == 0) ? s->skip(roundup(chd.size)) : readVPTR(s, chd.size); break;
default:
s->skip(roundup(chd.size));
}
@@ -421,6 +428,22 @@ bool VQADecoder::readLINF(Common::SeekableReadStream *s, uint32 size) {
return true;
}
+VQADecoder::CodebookInfo &VQADecoder::codebookInfoForFrame(int frame) {
+ assert(frame < numFrames());
+ assert(!_codebooks.empty());
+
+ CodebookInfo *ci = nullptr;
+ uint count = _codebooks.size();
+ for (uint i = 0; i != count; ++i) {
+ if (frame >= _codebooks[count - i - 1].frame) {
+ return _codebooks[count - i - 1];
+ }
+ }
+
+ assert(ci && "No codebook found");
+ return _codebooks[0];
+}
+
bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size) {
IFFChunkHeader chd;
@@ -428,17 +451,23 @@ bool VQADecoder::readCINF(Common::SeekableReadStream *s, uint32 size) {
if (chd.id != kCINH || chd.size != 8u)
return false;
- _clipInfo.clipCount = s->readUint16LE();
+ uint16 codebookCount = s->readUint16LE();
+ _codebooks.resize(codebookCount);
+
s->skip(6);
readIFFChunkHeader(_s, &chd);
- if (chd.id != kCIND || chd.size != 6u * _clipInfo.clipCount)
+ if (chd.id != kCIND || chd.size != 6u * codebookCount)
return false;
- for (int i = 0; i != _clipInfo.clipCount; ++i) {
- uint16 a = s->readUint16LE();
- uint32 b = s->readUint32LE();
- debug("VQADecoder::readCINF() i: %d a: 0x%04x b: 0x%08x", i, a, b);
+ for (int i = 0; i != codebookCount; ++i) {
+ _codebooks[i].frame = s->readUint16LE();
+ _codebooks[i].size = s->readUint32LE();
+ _codebooks[i].data = nullptr;
+
+ // debug("Codebook %2d: %4d %8d", i, _codebooks[i].frame, _codebooks[i].size);
+
+ assert(_codebooks[i].frame < numFrames());
}
return true;
@@ -538,11 +567,11 @@ bool VQADecoder::readMFCI(Common::SeekableReadStream *s, uint32 size) {
}
VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface) {
- VQADecoder::Header *header = &vqaDecoder->_header;
-
+ _vqaDecoder = vqaDecoder;
_surface = surface;
_hasNewFrame = false;
+ VQADecoder::Header *header = &vqaDecoder->_header;
_numFrames = header->numFrames;
_width = header->width;
_height = header->height;
@@ -557,7 +586,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surfa
_maxCBFZSize = header->maxCBFZSize;
_maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize;
- _codebookSize = 0;
_codebook = nullptr;
_cbfz = nullptr;
_zbufChunk = nullptr;
@@ -570,19 +598,18 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surfa
_zbufChunk = new uint8[roundup(_maxZBUFChunkSize)];
_viewData = nullptr;
+ _aescData = nullptr;
_lightsData = nullptr;
}
VQADecoder::VQAVideoTrack::~VQAVideoTrack() {
- delete[] _codebook;
delete[] _cbfz;
delete[] _zbufChunk;
delete[] _vpointer;
- if (_viewData)
- delete[] _viewData;
- if (_lightsData)
- delete[] _lightsData;
+ delete[] _viewData;
+ delete[] _aescData;
+ delete[] _lightsData;
}
uint16 VQADecoder::VQAVideoTrack::getWidth() const {
@@ -593,10 +620,6 @@ uint16 VQADecoder::VQAVideoTrack::getHeight() const {
return _height;
}
-int VQADecoder::VQAVideoTrack::getCurFrame() const {
- return _curFrame;
-}
-
int VQADecoder::VQAVideoTrack::getFrameCount() const {
return _numFrames;
}
@@ -605,15 +628,14 @@ Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const {
return _frameRate;
}
-void VQADecoder::VQAVideoTrack::decodeVideoFrame() {
- if (_hasNewFrame) {
+void VQADecoder::VQAVideoTrack::decodeVideoFrame(bool forceDraw) {
+ if (_hasNewFrame || forceDraw) {
decodeFrame((uint16*)_surface->getPixels());
- _curFrame++;
_hasNewFrame = false;
}
}
-bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size) {
+bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size, uint readFlags) {
IFFChunkHeader chd;
while (size >= 8) {
@@ -643,16 +665,22 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s
return false;
}
- if (!_codebook) {
- _codebookSize = 2 * _maxBlocks * _blockW * _blockH;
- _codebook = new uint8[_codebookSize];
+ CodebookInfo &codebookInfo = _vqaDecoder->codebookInfoForFrame(_vqaDecoder->_readingFrame);
+ if (codebookInfo.data) {
+ s->skip(roundup(size));
+ return true;
}
- if (!_cbfz)
+
+ uint32 codebookSize = 2 * _maxBlocks * _blockW * _blockH;
+ codebookInfo.data = new uint8[codebookSize];
+
+ if (!_cbfz) {
_cbfz = new uint8[roundup(_maxCBFZSize)];
+ }
s->read(_cbfz, roundup(size));
- decompress_lcw(_cbfz, size, _codebook, _codebookSize);
+ decompress_lcw(_cbfz, size, codebookInfo.data, codebookSize);
return true;
}
@@ -671,22 +699,23 @@ bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 s
}
void VQADecoder::VQAVideoTrack::decodeZBuffer(ZBuffer *zbuffer) {
- if (_maxZBUFChunkSize == 0)
+ if (_maxZBUFChunkSize == 0) {
return;
+ }
zbuffer->decodeData(_zbufChunk, _zbufChunkSize);
}
bool VQADecoder::VQAVideoTrack::readVIEW(Common::SeekableReadStream *s, uint32 size) {
- if (size != 56)
+ if (size != 56) {
return false;
+ }
if (_viewData) {
delete[] _viewData;
- _viewData = nullptr;
}
- _viewDataSize = size;
+ _viewDataSize = roundup(size);
_viewData = new uint8[_viewDataSize];
s->read(_viewData, _viewDataSize);
@@ -694,30 +723,47 @@ bool VQADecoder::VQAVideoTrack::readVIEW(Common::SeekableReadStream *s, uint32 s
}
void VQADecoder::VQAVideoTrack::decodeView(View *view) {
- if (!view || !_viewData)
+ if (!view || !_viewData) {
return;
+ }
Common::MemoryReadStream s(_viewData, _viewDataSize);
- view->read(&s);
+ view->readVqa(&s);
delete[] _viewData;
_viewData = nullptr;
}
bool VQADecoder::VQAVideoTrack::readAESC(Common::SeekableReadStream *s, uint32 size) {
- debug("VQADecoder::readAESC(%d)", size);
+ if (_aescData) {
+ delete[] _aescData;
+ }
+
+ _aescDataSize = roundup(size);
+ _aescData = new uint8[_aescDataSize];
+ s->read(_aescData, _aescDataSize);
- s->skip(roundup(size));
return true;
}
+void VQADecoder::VQAVideoTrack::decodeAESC(AESC *aesc) {
+ if (!aesc || !_aescData) {
+ return;
+ }
+
+ Common::MemoryReadStream s(_aescData, _aescDataSize);
+ aesc->readVqa(&s);
+
+ delete[] _aescData;
+ _aescData = nullptr;
+}
+
bool VQADecoder::VQAVideoTrack::readLITE(Common::SeekableReadStream *s, uint32 size) {
if (_lightsData) {
delete[] _lightsData;
- _lightsData = nullptr;
}
- _lightsDataSize = size;
+ _lightsDataSize = roundup(size);
_lightsData = new uint8[_lightsDataSize];
s->read(_lightsData, _lightsDataSize);
@@ -726,8 +772,9 @@ bool VQADecoder::VQAVideoTrack::readLITE(Common::SeekableReadStream *s, uint32 s
void VQADecoder::VQAVideoTrack::decodeLights(Lights *lights) {
- if (!lights || !_lightsData)
+ if (!lights || !_lightsData) {
return;
+ }
Common::MemoryReadStream s(_lightsData, _lightsDataSize);
lights->readVqa(&s);
@@ -741,8 +788,9 @@ bool VQADecoder::VQAVideoTrack::readVPTR(Common::SeekableReadStream *s, uint32 s
if (size > _maxVPTRSize)
return false;
- if (!_vpointer)
+ if (!_vpointer) {
_vpointer = new uint8[roundup(_maxVPTRSize)];
+ }
_vpointerSize = size;
s->read(_vpointer, roundup(size));
@@ -764,7 +812,7 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBl
int blocks_per_line = frame_width / block_width;
do {
- uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX / 2;
+ uint32 frame_x = dstBlock % blocks_per_line * block_width + _offsetX;
uint32 frame_y = dstBlock / blocks_per_line * block_height + _offsetY;
uint32 dst_offset = frame_x + frame_y * frame_stride;
@@ -791,6 +839,13 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(uint16 *frame, unsigned int dstBl
}
bool VQADecoder::VQAVideoTrack::decodeFrame(uint16 *frame) {
+ CodebookInfo &codebookInfo = _vqaDecoder->codebookInfoForFrame(_vqaDecoder->_decodingFrame);
+
+ if (!codebookInfo.data) {
+ _vqaDecoder->readFrame(codebookInfo.frame, kVQAReadCodebook);
+ }
+
+ _codebook = codebookInfo.data;
if (!_codebook || !_vpointer)
return false;
diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h
index d7086d1b9f..4e070647a6 100644
--- a/engines/bladerunner/vqa_decoder.h
+++ b/engines/bladerunner/vqa_decoder.h
@@ -35,6 +35,7 @@
#include "graphics/surface.h"
#include "video/video_decoder.h"
+#include "aesc.h"
namespace BladeRunner {
@@ -42,6 +43,15 @@ class Lights;
class View;
class ZBuffer;
+enum VQADecoderSkipFlags {
+ kVQAReadCodebook = 1,
+ kVQAReadVectorPointerTable = 2,
+ kVQAReadCustom = 4,
+ kVQAReadVideo = kVQAReadCodebook|kVQAReadVectorPointerTable|kVQAReadCustom,
+ kVQAReadAudio = 8,
+ kVQAReadAll = kVQAReadVideo|kVQAReadAudio
+};
+
class VQADecoder {
public:
VQADecoder(Graphics::Surface *surface);
@@ -49,12 +59,13 @@ public:
bool loadStream(Common::SeekableReadStream *s);
- void readFrame(int frame, int skipFlags);
+ void readFrame(int frame, uint readFlags = kVQAReadAll);
- void decodeVideoFrame();
+ void decodeVideoFrame(int frame, bool forceDraw = false);
void decodeZBuffer(ZBuffer *zbuffer);
Audio::SeekableAudioStream *decodeAudioFrame();
void decodeView(View *view);
+ void decodeAESC(AESC *aesc);
void decodeLights(Lights *lights);
uint16 numFrames() const { return _header.numFrames; }
@@ -118,8 +129,10 @@ private:
}
};
- struct ClipInfo {
- uint16 clipCount;
+ struct CodebookInfo {
+ uint16 frame;
+ uint32 size;
+ uint8 *data;
};
class VQAVideoTrack;
@@ -129,8 +142,11 @@ private:
Graphics::Surface *_surface;
Header _header;
+ int _readingFrame;
+ int _decodingFrame;
LoopInfo _loopInfo;
- ClipInfo _clipInfo;
+
+ Common::Array<CodebookInfo> _codebooks;
uint32 *_frameInfo;
@@ -141,7 +157,7 @@ private:
VQAVideoTrack *_videoTrack;
VQAAudioTrack *_audioTrack;
- void readPacket(int skipFlags);
+ void readPacket(uint readFlags);
bool readVQHD(Common::SeekableReadStream *s, uint32 size);
bool readMSCI(Common::SeekableReadStream *s, uint32 size);
@@ -152,6 +168,8 @@ private:
bool readLNIN(Common::SeekableReadStream *s, uint32 size);
bool readCLIP(Common::SeekableReadStream *s, uint32 size);
+ CodebookInfo &codebookInfoForFrame(int frame);
+
class VQAVideoTrack {
public:
VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface);
@@ -159,16 +177,18 @@ private:
uint16 getWidth() const;
uint16 getHeight() const;
- int getCurFrame() const;
+
int getFrameCount() const;
- void decodeVideoFrame();
+
+ void decodeVideoFrame(bool forceDraw);
void decodeZBuffer(ZBuffer *zbuffer);
void decodeView(View *view);
+ void decodeAESC(AESC *aesc);
void decodeLights(Lights *lights);
- bool readVQFR(Common::SeekableReadStream *s, uint32 size);
+ bool readVQFR(Common::SeekableReadStream *s, uint32 size, uint readFlags);
bool readVPTR(Common::SeekableReadStream *s, uint32 size);
- bool readVQFL(Common::SeekableReadStream *s, uint32 size);
+ bool readVQFL(Common::SeekableReadStream *s, uint32 size, uint readFlags);
bool readCBFZ(Common::SeekableReadStream *s, uint32 size);
bool readZBUF(Common::SeekableReadStream *s, uint32 size);
bool readVIEW(Common::SeekableReadStream *s, uint32 size);
@@ -181,6 +201,7 @@ private:
bool useAudioSync() const { return false; }
private:
+ VQADecoder *_vqaDecoder;
Graphics::Surface *_surface;
bool _hasNewFrame;
@@ -195,7 +216,6 @@ private:
uint32 _maxCBFZSize;
uint32 _maxZBUFChunkSize;
- uint32 _codebookSize;
uint8 *_codebook;
uint8 *_cbfz;
bool _zbufChunkComplete;
@@ -208,9 +228,11 @@ private:
int _curFrame;
uint8 *_viewData;
- uint32 _viewDataSize;
+ uint32 _viewDataSize;
uint8 *_lightsData;
- uint32 _lightsDataSize;
+ uint32 _lightsDataSize;
+ uint8 *_aescData;
+ uint32 _aescDataSize;
void VPTRWriteBlock(uint16 *frame, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha = false);
bool decodeFrame(uint16 *frame);
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index 12baa26d76..51766d6e28 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -49,6 +49,7 @@ bool VQAPlayer::open(const Common::String &name) {
_repeatsCount = 0;
_loop = -1;
+ _frame = -1;
_frameBegin = -1;
_frameEnd = _decoder.numFrames() - 1;
_frameEndQueued = -1;
@@ -70,8 +71,9 @@ void VQAPlayer::close() {
_s = nullptr;
}
-int VQAPlayer::update() {
+int VQAPlayer::update(bool forceDraw) {
uint32 now = 60 * _vm->_system->getMillis();
+ int result = -1;
if (_frameNext < 0) {
_frameNext = _frameBegin;
@@ -101,47 +103,48 @@ int VQAPlayer::update() {
}
}
- return -1;
- }
-
- if (_frameNext > _frameEnd) {
- return -3;
- }
-
- if (now < _frameNextTime) {
- return -1;
- }
-
- int frame = _frameNext;
- _decoder.readFrame(_frameNext, 0x2);
- _decoder.decodeVideoFrame();
-
- int audioPreloadFrames = 14;
-
- if (_hasAudio) {
- if (!_audioStarted) {
- for (int i = 0; i < audioPreloadFrames; i++) {
- if (_frameNext + i < _frameEnd) {
- _decoder.readFrame(_frameNext + i, 0x1);
- queueAudioFrame(_decoder.decodeAudioFrame());
+ result = -1;
+ } else if (_frameNext > _frameEnd) {
+ result = -3;
+ } else if (now < _frameNextTime) {
+ result = -1;
+ } else {
+ _frame = _frameNext;
+ _decoder.readFrame(_frameNext, kVQAReadVideo);
+ _decoder.decodeVideoFrame(_frameNext);
+
+ int audioPreloadFrames = 14;
+
+ if (_hasAudio) {
+ if (!_audioStarted) {
+ for (int i = 0; i < audioPreloadFrames; i++) {
+ if (_frameNext + i < _frameEnd) {
+ _decoder.readFrame(_frameNext + i, kVQAReadAudio);
+ queueAudioFrame(_decoder.decodeAudioFrame());
+ }
}
+ _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream);
+ _audioStarted = true;
}
- _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream);
- _audioStarted = true;
+ if (_frameNext + audioPreloadFrames < _frameEnd) {
+ _decoder.readFrame(_frameNext + audioPreloadFrames, kVQAReadAudio);
+ queueAudioFrame(_decoder.decodeAudioFrame());
+ }
+ }
+ if (_frameNextTime == 0) {
+ _frameNextTime = now + 60000 / 15;
}
- if (_frameNext + audioPreloadFrames < _frameEnd) {
- _decoder.readFrame(_frameNext + audioPreloadFrames, 0x1);
- queueAudioFrame(_decoder.decodeAudioFrame());
+ else {
+ _frameNextTime += 60000 / 15;
}
+ _frameNext++;
+ result = _frame;
}
- if (_frameNextTime == 0) {
- _frameNextTime = now + 60000 / 15;
- } else {
- _frameNextTime += 60000 / 15;
+ if (result < 0 && forceDraw && _frame != -1) {
+ _decoder.decodeVideoFrame(_frame, true);
+ result = _frame;
}
-
- _frameNext++;
- return frame;
+ return result;
}
void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) {
@@ -152,6 +155,10 @@ void VQAPlayer::updateView(View *view) {
_decoder.decodeView(view);
}
+void VQAPlayer::updateAESC(AESC *aesc) {
+ _decoder.decodeAESC(aesc);
+}
+
void VQAPlayer::updateLights(Lights *lights) {
_decoder.decodeLights(lights);
}
diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h
index b4365670e8..1be47bd87e 100644
--- a/engines/bladerunner/vqa_player.h
+++ b/engines/bladerunner/vqa_player.h
@@ -52,6 +52,7 @@ class VQAPlayer {
const uint16 *_zBuffer;
Audio::QueuingAudioStream *_audioStream;
+ int _frame;
int _frameNext;
int _frameBegin;
int _frameEnd;
@@ -102,9 +103,10 @@ public:
bool open(const Common::String &name);
void close();
- int update();
+ int update(bool forceDraw = false);
void updateZBuffer(ZBuffer *zbuffer);
void updateView(View *view);
+ void updateAESC(AESC *aesc);
void updateLights(Lights *lights);
bool setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopSetMode, void(*callback)(void *, int, int), void *callbackData);
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 91ce6785d7..d4e4a4f3c4 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -843,9 +843,8 @@ static const struct ADGameDescription SciGameDescriptions[] = {
GUIO_NOLAUNCHLOAD, \
GUIO_NOASPECT, \
GAMEOPTION_HQ_VIDEO)
-#define GUIO_GK2 GUIO8(GUIO_NOSUBTITLES, \
- GUIO_NOSFX, \
- GUIO_NOSPEECHVOLUME, \
+#define GUIO_GK2 GUIO7(GUIO_NOSUBTITLES, \
+ GUIO_LINKSPEECHTOSFX, \
GUIO_NOMIDI, \
GUIO_NOASPECT, \
GAMEOPTION_ORIGINAL_SAVELOAD, \
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index 41a4b6014b..92cc45a162 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -110,6 +110,17 @@ public:
}
}
+ inline bool gameScriptsControlMasterVolume() const {
+ switch (g_sci->getGameId()) {
+ case GID_LSL7:
+ case GID_PHANTASMAGORIA2:
+ case GID_TORIN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
inline bool hasSci3Audio() const {
return getSciVersion() == SCI_VERSION_3 || g_sci->getGameId() == GID_GK2;
}
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 9fd5dc00e6..ddaec1e971 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -482,13 +482,17 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
// and points to garbage in the RESOURCE.AUD. The affected audio36
// assets seem to be able to load successfully from one of the later
// CDs, so just ignore the map on this disc
- if (g_sci->getGameId() == GID_PQSWAT && map->_volumeNumber == 1 && map->_mapNumber == 405) {
+ if (g_sci->getGameId() == GID_PQSWAT &&
+ g_sci->getLanguage() == Common::EN_ANY &&
+ map->_volumeNumber == 1 &&
+ map->_mapNumber == 405) {
continue;
}
- // At least version 1.00 of GK2 has multiple invalid audio36 map
- // entries on CD 6
+ // At least version 1.00 of the US release of GK2 has multiple
+ // invalid audio36 map entries on CD 6
if (g_sci->getGameId() == GID_GK2 &&
+ g_sci->getLanguage() == Common::EN_ANY &&
map->_volumeNumber == 6 &&
offset + syncSize >= srcSize) {
@@ -496,6 +500,27 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
continue;
}
+ // Map 2020 on CD 1 of the German release of GK2 is invalid. This
+ // content does not appear to ever be used by the game (it does not
+ // even exist in the US release), and there is a correct copy of it
+ // on CD 6, so just ignore the bad copy on CD 1
+ if (g_sci->getGameId() == GID_GK2 &&
+ g_sci->getLanguage() == Common::DE_DEU &&
+ map->_volumeNumber == 1 &&
+ map->_mapNumber == 2020) {
+ continue;
+ }
+
+ // Map 800 and 4176 contain content that was cut from the game. The
+ // French version of the game includes map files from the US
+ // release, but the audio resources are French so the maps don't
+ // match. Since the content was never used, just ignore these maps
+ // everywhere
+ if (g_sci->getGameId() == GID_PHANTASMAGORIA2 &&
+ (map->_mapNumber == 800 || map->_mapNumber == 4176)) {
+ continue;
+ }
+
addResource(id, src, offset + syncSize, 0, map->getLocationName());
}
}
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index 7622305adb..c3f9eb4098 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -181,10 +181,18 @@ Audio32::Audio32(ResourceManager *resMan) :
}
_useModifiedAttenuation = g_sci->_features->usesModifiedAudioAttenuation();
- // The mixer stream type is given as `kSFXSoundType` so that audio from
- // Audio32 will be mixed at the same standard volume as the video players
- // (which must use `kSFXSoundType` as well).
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+ // In games where scripts premultiply master audio volumes into the volumes
+ // of the individual audio channels sent to the mixer, Audio32 needs to use
+ // the kPlainSoundType so that the master SFX volume is not applied twice.
+ // Otherwise, we simply pass along master volume changes to the ScummVM
+ // mixer for the kSFXSoundType and allow it to control master volume.
+ // (The volume of the kSFXSoundType in the mixer still needs to be updated
+ // for games that control master volumes themselves so that videos will play
+ // at the same volume as the rest of the game.)
+ const Audio::Mixer::SoundType soundType = g_sci->_features->gameScriptsControlMasterVolume() ? Audio::Mixer::kPlainSoundType : Audio::Mixer::kSFXSoundType;
+
+ _mixer->playStream(soundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
Audio32::~Audio32() {
diff --git a/engines/titanic/carry/eye.cpp b/engines/titanic/carry/eye.cpp
index 148d2ea154..9bad0e480c 100644
--- a/engines/titanic/carry/eye.cpp
+++ b/engines/titanic/carry/eye.cpp
@@ -22,9 +22,11 @@
#include "titanic/carry/eye.h"
#include "titanic/game/head_slot.h"
-#include "titanic/pet_control/pet_control.h"
-#include "titanic/game/transport/lift.h"
+#include "titanic/game/light.h"
#include "titanic/game/television.h"
+#include "titanic/game/transport/lift.h"
+#include "titanic/pet_control/pet_control.h"
+
namespace Titanic {
@@ -109,7 +111,8 @@ bool CEye::ActMsg(CActMsg *msg) {
playSound("z#47.wav");
CActMsg actMsg("Eye Removed");
- actMsg.execute("1stClassState");
+ actMsg.execute("1stClassState", CLight::_type,
+ MSGFLAG_CLASS_DEF | MSGFLAG_SCAN);
} else {
_eyeFlag = false;
diff --git a/engines/titanic/debugger.cpp b/engines/titanic/debugger.cpp
index 15d098a99a..a8b580b636 100644
--- a/engines/titanic/debugger.cpp
+++ b/engines/titanic/debugger.cpp
@@ -44,6 +44,7 @@ Debugger::Debugger(TitanicEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("movie", WRAP_METHOD(Debugger, cmdMovie));
registerCmd("sound", WRAP_METHOD(Debugger, cmdSound));
registerCmd("cheat", WRAP_METHOD(Debugger, cmdCheat));
+ registerCmd("frame", WRAP_METHOD(Debugger, cmdFrame));
}
int Debugger::strToInt(const char *s) {
@@ -346,4 +347,22 @@ bool Debugger::cmdCheat(int argc, const char **argv) {
return false;
}
+bool Debugger::cmdFrame(int argc, const char **argv) {
+ if (argc == 3) {
+ CGameObject *obj = dynamic_cast<CGameObject *>(
+ g_vm->_window->_project->findByName(argv[1]));
+
+ if (obj) {
+ obj->loadFrame(strToInt(argv[2]));
+ return false;
+ } else {
+ debugPrintf("Object not found\n");
+ return true;
+ }
+ } else {
+ debugPrintf("frame <object> <frame number>");
+ return true;
+ }
+}
+
} // End of namespace Titanic
diff --git a/engines/titanic/debugger.h b/engines/titanic/debugger.h
index 3e53feec2a..cd9da2b2ab 100644
--- a/engines/titanic/debugger.h
+++ b/engines/titanic/debugger.h
@@ -115,6 +115,11 @@ private:
* Change to the cheat room
*/
bool cmdCheat(int argc, const char **argv);
+
+ /**
+ * Set the movie frame for a given object
+ */
+ bool cmdFrame(int argc, const char **argv);
protected:
TitanicEngine *_vm;
public:
diff --git a/engines/titanic/npcs/maitre_d.cpp b/engines/titanic/npcs/maitre_d.cpp
index e944af81c1..a45f48523a 100644
--- a/engines/titanic/npcs/maitre_d.cpp
+++ b/engines/titanic/npcs/maitre_d.cpp
@@ -78,6 +78,11 @@ void CMaitreD::load(SimpleFile *file) {
_timerId = file->readNumber();
CTrueTalkNPC::load(file);
+
+ // WORKAROUND: The back view of the MaitreD from close to the table is dodgy
+ // in the original. And unneeded anyway, since he's also part of the background
+ if (_name == "MaitreLoop03")
+ _visible = false;
}
bool CMaitreD::RestaurantMusicChanged(CRestaurantMusicChanged *msg) {
diff --git a/engines/titanic/pet_control/pet_frame.cpp b/engines/titanic/pet_control/pet_frame.cpp
index 9088cfe126..738116ed8f 100644
--- a/engines/titanic/pet_control/pet_frame.cpp
+++ b/engines/titanic/pet_control/pet_frame.cpp
@@ -143,8 +143,11 @@ bool CPetFrame::setPetControl(CPetControl *petControl) {
void CPetFrame::setArea(PetArea newArea) {
resetArea();
- if ((uint)newArea < _petAreas.size())
- _modeButtons[_petAreas[newArea]].setMode(MODE_SELECTED);
+
+ for (uint idx = 0; idx < _modeButtons.size(); ++idx) {
+ if (_petAreas[idx] == newArea)
+ _modeButtons[idx].setMode(MODE_SELECTED);
+ }
}
void CPetFrame::resetArea() {
diff --git a/engines/titanic/pet_control/pet_load.cpp b/engines/titanic/pet_control/pet_load.cpp
index 1d81435bed..6c24c575c9 100644
--- a/engines/titanic/pet_control/pet_load.cpp
+++ b/engines/titanic/pet_control/pet_load.cpp
@@ -52,7 +52,7 @@ bool CPetLoad::MouseButtonUpMsg(const Point &pt) {
}
void CPetLoad::getTooltip(CTextControl *text) {
- text->setText("Load the game.");
+ text->setText(LOAD_THE_GAME);
}
void CPetLoad::execute() {
diff --git a/engines/titanic/pet_control/pet_load_save.cpp b/engines/titanic/pet_control/pet_load_save.cpp
index aa438c06d3..d918478fb1 100644
--- a/engines/titanic/pet_control/pet_load_save.cpp
+++ b/engines/titanic/pet_control/pet_load_save.cpp
@@ -117,7 +117,7 @@ Rect CPetLoadSave::getSlotBounds(int index) {
void CPetLoadSave::resetSlots() {
for (int idx = 0; idx < SAVEGAME_SLOTS_COUNT; ++idx) {
- _slotNames[idx].setText("Empty");
+ _slotNames[idx].setText(EMPTY);
_slotInUse[idx] = false;
// Try and open up the savegame for access
diff --git a/engines/titanic/pet_control/pet_quit.cpp b/engines/titanic/pet_control/pet_quit.cpp
index 0d94474f99..b180bf8dc8 100644
--- a/engines/titanic/pet_control/pet_quit.cpp
+++ b/engines/titanic/pet_control/pet_quit.cpp
@@ -53,7 +53,7 @@ bool CPetQuit::reset() {
setName("PetExit", pet);
uint col = getPetSection()->getColor(0);
- _text.setText("Are you sure you want to quit?");
+ _text.setText(SURE_YOU_WANT_TO_QUIT);
_text.setLineColor(0, col);
_btnYes.reset("PetQuitOut", pet, MODE_UNSELECTED);
@@ -84,7 +84,7 @@ bool CPetQuit::MouseButtonUpMsg(const Point &pt) {
}
void CPetQuit::getTooltip(CTextControl *text) {
- text->setText("Quit the game.");
+ text->setText(QUIT_THE_GAME);
}
} // End of namespace Titanic
diff --git a/engines/titanic/pet_control/pet_save.cpp b/engines/titanic/pet_control/pet_save.cpp
index 00dbfa6b4a..16fe092b24 100644
--- a/engines/titanic/pet_control/pet_save.cpp
+++ b/engines/titanic/pet_control/pet_save.cpp
@@ -65,7 +65,7 @@ void CPetSave::highlightCurrent(const Point &pt) {
}
void CPetSave::getTooltip(CTextControl *text) {
- text->setText("Save the game.");
+ text->setText(SAVE_THE_GAME);
}
void CPetSave::highlightSave(int index) {
diff --git a/engines/titanic/pet_control/pet_sound.cpp b/engines/titanic/pet_control/pet_sound.cpp
index 1ba557ab14..085ee649b2 100644
--- a/engines/titanic/pet_control/pet_sound.cpp
+++ b/engines/titanic/pet_control/pet_sound.cpp
@@ -65,25 +65,25 @@ bool CPetSound::setup(CPetControl *petControl, CPetGlyphs *owner) {
_textMasterVolume.setBounds(rect);
_textMasterVolume.resize(3);
_textMasterVolume.setHasBorder(false);
- _textMasterVolume.setText("Master volume");
+ _textMasterVolume.setText(MASTER_VOLUME);
rect.translate(0, 20);
_textMusicVolume.setBounds(rect);
_textMusicVolume.resize(3);
_textMusicVolume.setHasBorder(false);
- _textMusicVolume.setText("Music volume");
+ _textMusicVolume.setText(MUSIC_VOLUME);
rect.translate(0, 20);
_textParrotVolume.setBounds(rect);
_textParrotVolume.resize(3);
_textParrotVolume.setHasBorder(false);
- _textParrotVolume.setText("Parrot volume");
+ _textParrotVolume.setText(PARROT_VOLUME);
rect.translate(0, 20);
_textSpeechVolume.setBounds(rect);
_textSpeechVolume.resize(3);
_textSpeechVolume.setHasBorder(false);
- _textSpeechVolume.setText("Speech volume");
+ _textSpeechVolume.setText(SPEECH_VOLUME);
return true;
}
@@ -276,7 +276,7 @@ bool CPetSound::MouseButtonUpMsg(const Point &pt) {
}
void CPetSound::getTooltip(CTextControl *text) {
- text->setText("Change the volume settings.");
+ text->setText(CHANGE_VOLUME_SETTINGS);
}
} // End of namespace Titanic
diff --git a/engines/titanic/star_control/star_camera.h b/engines/titanic/star_control/star_camera.h
index 6cf0183f0a..b22abe6eff 100644
--- a/engines/titanic/star_control/star_camera.h
+++ b/engines/titanic/star_control/star_camera.h
@@ -31,7 +31,7 @@ namespace Titanic {
class CCameraMover;
class CErrorCode;
-class CNavigationInfo;
+struct CNavigationInfo;
class FPoint;
class SimpleFile;
diff --git a/engines/titanic/support/files_manager.cpp b/engines/titanic/support/files_manager.cpp
index eebd56c1fa..fbfb7e0f61 100644
--- a/engines/titanic/support/files_manager.cpp
+++ b/engines/titanic/support/files_manager.cpp
@@ -45,11 +45,16 @@ bool CFilesManager::loadResourceIndex() {
uint headerId = _datFile.readUint32BE();
_version = _datFile.readUint16LE();
- if (headerId != MKTAG('S', 'V', 'T', 'N') || _version < 1) {
+ if (headerId != MKTAG('S', 'V', 'T', 'N')) {
g_vm->GUIError("titanic.dat has invalid contents");
return false;
}
+ if (_version != 3) {
+ g_vm->GUIError("titanic.dat is out of date");
+ return false;
+ }
+
// Read in entries
uint offset, size, flags;
char c;
diff --git a/engines/titanic/support/strings.h b/engines/titanic/support/strings.h
index 65d6550e1e..b7a775cc99 100644
--- a/engines/titanic/support/strings.h
+++ b/engines/titanic/support/strings.h
@@ -170,6 +170,16 @@ enum StringId {
CURRENT_LOCATION,
A_HOT,
A_COLD,
+ LOAD_THE_GAME,
+ SAVE_THE_GAME,
+ EMPTY,
+ QUIT_THE_GAME,
+ SURE_YOU_WANT_TO_QUIT,
+ CHANGE_VOLUME_SETTINGS,
+ MASTER_VOLUME,
+ MUSIC_VOLUME,
+ PARROT_VOLUME,
+ SPEECH_VOLUME,
// German version only
DE_SUMMER,
diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp
index de28e073a9..67bdf82fa0 100644
--- a/engines/titanic/titanic.cpp
+++ b/engines/titanic/titanic.cpp
@@ -191,7 +191,7 @@ bool TitanicEngine::canLoadGameStateCurrently() {
return false;
if (screenMan && screenMan->_inputHandler->isLocked())
return false;
- if (!gameManager->isntTransitioning())
+ if (!gameManager || !gameManager->isntTransitioning())
return false;
CProjectItem *project = gameManager->_project;
@@ -210,6 +210,8 @@ bool TitanicEngine::canLoadGameStateCurrently() {
bool TitanicEngine::canSaveGameStateCurrently() {
CGameManager *gameManager = _window->_gameManager;
+ if (!gameManager)
+ return false;
return gameManager->_gameState._petActive &&
canLoadGameStateCurrently();
diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h
index b21169b35f..d163e382ca 100644
--- a/engines/wage/detection_tables.h
+++ b/engines/wage/detection_tables.h
@@ -112,9 +112,9 @@ static const ADGameDescription gameDescriptions[] = {
FANGAME("Mountain of Mayhem", "634211b004371635d191ae0687035501", 750003), // Original file name "Mountain of Mayhem †"
// No way to pass through the first screen
FANGAME("Nightcrawler Ned", "8423fc015c395bd6be54a7ea69170d99", 366542),
- // Crash on startup
+ // No player in the world
FANGAMEN("Parrot Talk", "PARROT TALK V1", "c38c090be8c078d931905c93bc0689f5", 118936),
- // Crash on startup
+ // No player in the world
FANGAMEN("Parrot Talk", "PARROT TALKV2", "5ec1df9e2d6d0dcf1a040a95500d9551", 118884),
FANGAME("Pavilion", "a980e60a291c0a7b949474177affa134", 231687),
FANGAMEN("Pencils", "Pencils.99", "09dbcdbefe20536c2db1b1a4fb4e5ed3", 408551),
diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp
index 3405c8bf47..9f8093c50c 100644
--- a/engines/wage/script.cpp
+++ b/engines/wage/script.cpp
@@ -50,6 +50,8 @@
#include "wage/script.h"
#include "wage/world.h"
+#include "common/config-manager.h"
+#include "common/file.h"
#include "common/stream.h"
namespace Wage {
@@ -74,8 +76,7 @@ Common::String Script::Operand::toString() {
}
}
-Script::Script(Common::SeekableReadStream *data) : _data(data) {
- _engine = NULL;
+Script::Script(Common::SeekableReadStream *data, int num, WageEngine *engine) : _data(data), _engine(engine) {
_world = NULL;
_loopCount = 0;
@@ -85,6 +86,29 @@ Script::Script(Common::SeekableReadStream *data) : _data(data) {
_handled = false;
convertToText();
+
+ if (ConfMan.getBool("dump_scripts")) {
+ Common::DumpFile out;
+ Common::String name;
+
+ if (num == -1)
+ name = Common::String::format("./dumps/%s-global.txt", _engine->getTargetName());
+ else
+ name = Common::String::format("./dumps/%s-%d.txt", _engine->getTargetName(), num);
+
+ if (!out.open(name)) {
+ warning("Can not open dump file %s", name.c_str());
+ return;
+ }
+
+ for (uint i = 0; i < _scriptText.size(); i++) {
+ out.write(_scriptText[i]->line.c_str(), strlen(_scriptText[i]->line.c_str()));
+ out.writeByte('\n');
+ }
+
+ out.flush();
+ out.close();
+ }
}
Script::~Script() {
@@ -149,12 +173,11 @@ Common::String Script::preprocessInputText(Common::String inputText) {
return inputText;
}
-bool Script::execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick, WageEngine *engine) {
+bool Script::execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick) {
_world = world;
_loopCount = loopCount;
_inputText = inputText;
_inputClick = inputClick;
- _engine = engine;
_handled = false;
Common::String input;
@@ -165,7 +188,7 @@ bool Script::execute(World *world, int loopCount, Common::String *inputText, Des
}
_data->seek(12);
- while (_data->pos() < _data->size()) {
+ while (_data->pos() < _data->size() && !_engine->_shouldQuit) {
printLine(_data->pos());
byte command = _data->readByte();
@@ -232,7 +255,7 @@ bool Script::execute(World *world, int loopCount, Common::String *inputText, Des
if (_world->_globalScript != this) {
debug(1, "Executing global script...");
- bool globalHandled = _world->_globalScript->execute(_world, _loopCount, &input, _inputClick, _engine);
+ bool globalHandled = _world->_globalScript->execute(_world, _loopCount, &input, _inputClick);
if (globalHandled)
_handled = true;
} else if (!input.empty()) {
diff --git a/engines/wage/script.h b/engines/wage/script.h
index e796195b7f..df7ec7e4d6 100644
--- a/engines/wage/script.h
+++ b/engines/wage/script.h
@@ -52,7 +52,7 @@ namespace Wage {
class Script {
public:
- Script(Common::SeekableReadStream *data);
+ Script(Common::SeekableReadStream *data, int num, WageEngine *engine);
~Script();
private:
@@ -130,7 +130,7 @@ private:
public:
void print();
void printLine(int offset);
- bool execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick, WageEngine *engine);
+ bool execute(World *world, int loopCount, Common::String *inputText, Designed *inputClick);
private:
Common::String preprocessInputText(Common::String inputText);
diff --git a/engines/wage/sound.cpp b/engines/wage/sound.cpp
index fd6adaea19..9f5ed3497c 100644
--- a/engines/wage/sound.cpp
+++ b/engines/wage/sound.cpp
@@ -49,6 +49,7 @@
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
#include "common/stream.h"
+#include "common/system.h"
#include "wage/wage.h"
#include "wage/entities.h"
@@ -91,8 +92,26 @@ void WageEngine::playSound(Common::String soundName) {
Audio::AudioStream *stream = Audio::makeRawStream(s->_data, s->_size, 11000, Audio::FLAG_UNSIGNED);
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &s->_handle, stream,
+ _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, stream,
-1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+
+ while (_mixer->isSoundHandleActive(_soundHandle) && !_shouldQuit) {
+ Common::Event event;
+
+ _eventMan->pollEvent(event);
+
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ if (saveDialog())
+ _shouldQuit = true;
+ break;
+ default:
+ break;
+ }
+
+ _system->updateScreen();
+ _system->delayMillis(10);
+ }
}
void WageEngine::updateSoundTimerForScene(Scene *scene, bool firstTime) {
diff --git a/engines/wage/sound.h b/engines/wage/sound.h
index 101b5a0db6..ada5a3c0cb 100644
--- a/engines/wage/sound.h
+++ b/engines/wage/sound.h
@@ -48,8 +48,6 @@
#ifndef WAGE_SOUND_H
#define WAGE_SOUND_H
-#include "audio/mixer.h"
-
namespace Wage {
class Sound {
@@ -60,8 +58,6 @@ public:
Common::String _name;
uint _size;
byte *_data;
-
- Audio::SoundHandle _handle;
};
} // End of namespace Wage
diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp
index 7f9fb073f5..c5f3673255 100644
--- a/engines/wage/wage.cpp
+++ b/engines/wage/wage.cpp
@@ -123,6 +123,8 @@ Common::Error WageEngine::run() {
if (!_world->loadWorld(_resManager))
return Common::kNoGameDataFoundError;
+ _shouldQuit = false;
+
_gui = new Gui(this);
_temporarilyHidden = true;
@@ -140,8 +142,6 @@ Common::Error WageEngine::run() {
processTurn(&input, NULL);
_temporarilyHidden = false;
- _shouldQuit = false;
-
while (!_shouldQuit) {
_debugger->onFrame();
@@ -431,7 +431,7 @@ void WageEngine::processTurnInternal(Common::String *textInput, Designed *clickI
bool monsterWasNull = (_monster == NULL);
Script *script = playerScene->_script != NULL ? playerScene->_script : _world->_globalScript;
- bool handled = script->execute(_world, _loopCount++, textInput, clickInput, this);
+ bool handled = script->execute(_world, _loopCount++, textInput, clickInput);
playerScene = _world->_player->_currentScene;
@@ -445,6 +445,10 @@ void WageEngine::processTurnInternal(Common::String *textInput, Designed *clickI
regen();
Common::String input("look");
processTurnInternal(&input, NULL);
+
+ if (_shouldQuit)
+ return;
+
redrawScene();
_temporarilyHidden = false;
} else if (_loopCount == 1) {
diff --git a/engines/wage/wage.h b/engines/wage/wage.h
index 4c93399ad7..cb4e8a3520 100644
--- a/engines/wage/wage.h
+++ b/engines/wage/wage.h
@@ -49,6 +49,7 @@
#define WAGE_WAGE_H
#include "engines/engine.h"
+#include "audio/mixer.h"
#include "common/debug.h"
#include "common/endian.h"
#include "common/rect.h"
@@ -126,6 +127,8 @@ public:
void processTurn(Common::String *textInput, Designed *clickInput);
void regen();
+ const char *getTargetName() { return _targetName.c_str(); }
+
private:
bool loadWorld(Common::MacResManager *resMan);
void performInitialSetup();
@@ -191,6 +194,8 @@ public:
bool _isGameOver;
bool _commandWasQuick;
+ bool _shouldQuit;
+
Common::String _inputText;
void playSound(Common::String soundName);
@@ -233,7 +238,7 @@ private:
Common::MacResManager *_resManager;
- bool _shouldQuit;
+ Audio::SoundHandle _soundHandle;
};
// Example console class
diff --git a/engines/wage/world.cpp b/engines/wage/world.cpp
index c0c802ff8d..fa8cfd57a1 100644
--- a/engines/wage/world.cpp
+++ b/engines/wage/world.cpp
@@ -132,7 +132,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
// Load global script
res = resMan->getResource(MKTAG('G','C','O','D'), resArray[0]);
- _globalScript = new Script(res);
+ _globalScript = new Script(res, -1, _engine);
// TODO: read creator
@@ -209,7 +209,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
res = resMan->getResource(MKTAG('A','C','O','D'), *iter);
if (res != NULL)
- scene->_script = new Script(res);
+ scene->_script = new Script(res, *iter, _engine);
res = resMan->getResource(MKTAG('A','T','X','T'), *iter);
if (res != NULL) {
@@ -267,7 +267,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
if (_chrs.empty()) {
error("loadWorld: and I have no characters");
}
- _player = _chrs[0];
+ _player = _orderedChrs[0];
}
diff --git a/graphics/macgui/mactext.cpp b/graphics/macgui/mactext.cpp
index e2b945d28f..69e2dce932 100644
--- a/graphics/macgui/mactext.cpp
+++ b/graphics/macgui/mactext.cpp
@@ -244,6 +244,7 @@ void MacText::reallocSurface() {
if (_surface->w < _textMaxWidth || _surface->h < _textMaxHeight) {
// realloc surface and copy old content
ManagedSurface *n = new ManagedSurface(_textMaxWidth, _textMaxHeight);
+ n->clear(_bgcolor);
n->blitFrom(*_surface, Common::Point(0, 0));
delete _surface;
@@ -416,7 +417,8 @@ void MacText::clearText() {
_textLines.clear();
_str.clear();
- _surface->clear(_bgcolor);
+ if (_surface)
+ _surface->clear(_bgcolor);
recalcDims();
}