aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision
diff options
context:
space:
mode:
Diffstat (limited to 'engines/zvision')
-rw-r--r--engines/zvision/configure.engine2
-rw-r--r--engines/zvision/core/clock.h10
-rw-r--r--engines/zvision/core/console.cpp159
-rw-r--r--engines/zvision/core/console.h4
-rw-r--r--engines/zvision/core/events.cpp150
-rw-r--r--engines/zvision/detection.cpp149
-rw-r--r--engines/zvision/detection.h43
-rw-r--r--engines/zvision/detection_tables.h277
-rw-r--r--engines/zvision/file/lzss_read_stream.cpp5
-rw-r--r--engines/zvision/file/save_manager.cpp (renamed from engines/zvision/core/save_manager.cpp)145
-rw-r--r--engines/zvision/file/save_manager.h (renamed from engines/zvision/core/save_manager.h)20
-rw-r--r--engines/zvision/file/search_manager.cpp85
-rw-r--r--engines/zvision/file/search_manager.h21
-rw-r--r--engines/zvision/graphics/cursors/cursor.cpp40
-rw-r--r--engines/zvision/graphics/cursors/cursor.h1
-rw-r--r--engines/zvision/graphics/cursors/cursor_manager.cpp42
-rw-r--r--engines/zvision/graphics/cursors/cursor_manager.h4
-rw-r--r--engines/zvision/graphics/effects/fog.cpp18
-rw-r--r--engines/zvision/graphics/effects/fog.h5
-rw-r--r--engines/zvision/graphics/effects/light.cpp6
-rw-r--r--engines/zvision/graphics/effects/light.h4
-rw-r--r--engines/zvision/graphics/effects/wave.cpp4
-rw-r--r--engines/zvision/graphics/effects/wave.h4
-rw-r--r--engines/zvision/graphics/graphics_effect.h (renamed from engines/zvision/graphics/effect.h)14
-rw-r--r--engines/zvision/graphics/render_manager.cpp873
-rw-r--r--engines/zvision/graphics/render_manager.h148
-rw-r--r--engines/zvision/graphics/render_table.cpp21
-rw-r--r--engines/zvision/graphics/truetype_font.cpp265
-rw-r--r--engines/zvision/module.mk22
-rw-r--r--engines/zvision/scripting/actions.cpp557
-rw-r--r--engines/zvision/scripting/actions.h35
-rw-r--r--engines/zvision/scripting/control.cpp1
-rw-r--r--engines/zvision/scripting/control.h5
-rw-r--r--engines/zvision/scripting/controls/fist_control.cpp58
-rw-r--r--engines/zvision/scripting/controls/fist_control.h6
-rw-r--r--engines/zvision/scripting/controls/hotmov_control.cpp53
-rw-r--r--engines/zvision/scripting/controls/hotmov_control.h5
-rw-r--r--engines/zvision/scripting/controls/input_control.cpp58
-rw-r--r--engines/zvision/scripting/controls/input_control.h10
-rw-r--r--engines/zvision/scripting/controls/lever_control.cpp7
-rw-r--r--engines/zvision/scripting/controls/lever_control.h1
-rw-r--r--engines/zvision/scripting/controls/paint_control.cpp12
-rw-r--r--engines/zvision/scripting/controls/paint_control.h1
-rw-r--r--engines/zvision/scripting/controls/safe_control.cpp57
-rw-r--r--engines/zvision/scripting/controls/safe_control.h8
-rw-r--r--engines/zvision/scripting/controls/save_control.cpp13
-rw-r--r--engines/zvision/scripting/controls/titler_control.cpp8
-rw-r--r--engines/zvision/scripting/controls/titler_control.h1
-rw-r--r--engines/zvision/scripting/effects/animation_effect.cpp (renamed from engines/zvision/scripting/sidefx/animation_node.cpp)167
-rw-r--r--engines/zvision/scripting/effects/animation_effect.h (renamed from engines/zvision/scripting/sidefx/animation_node.h)15
-rw-r--r--engines/zvision/scripting/effects/distort_effect.cpp (renamed from engines/zvision/scripting/sidefx/distort_node.cpp)7
-rw-r--r--engines/zvision/scripting/effects/distort_effect.h (renamed from engines/zvision/scripting/sidefx/distort_node.h)4
-rw-r--r--engines/zvision/scripting/effects/music_effect.cpp (renamed from engines/zvision/scripting/sidefx/music_node.cpp)170
-rw-r--r--engines/zvision/scripting/effects/music_effect.h (renamed from engines/zvision/scripting/sidefx/music_node.h)39
-rw-r--r--engines/zvision/scripting/effects/region_effect.cpp (renamed from engines/zvision/scripting/sidefx/region_node.cpp)6
-rw-r--r--engines/zvision/scripting/effects/region_effect.h (renamed from engines/zvision/scripting/sidefx/region_node.h)10
-rw-r--r--engines/zvision/scripting/effects/syncsound_effect.cpp (renamed from engines/zvision/scripting/sidefx/syncsound_node.cpp)6
-rw-r--r--engines/zvision/scripting/effects/syncsound_effect.h (renamed from engines/zvision/scripting/sidefx/syncsound_node.h)6
-rw-r--r--engines/zvision/scripting/effects/timer_effect.cpp (renamed from engines/zvision/scripting/sidefx/timer_node.cpp)4
-rw-r--r--engines/zvision/scripting/effects/timer_effect.h (renamed from engines/zvision/scripting/sidefx/timer_node.h)4
-rw-r--r--engines/zvision/scripting/effects/ttytext_effect.cpp (renamed from engines/zvision/scripting/sidefx/ttytext_node.cpp)46
-rw-r--r--engines/zvision/scripting/effects/ttytext_effect.h (renamed from engines/zvision/scripting/sidefx/ttytext_node.h)8
-rw-r--r--engines/zvision/scripting/menu.cpp (renamed from engines/zvision/core/menu.cpp)352
-rw-r--r--engines/zvision/scripting/menu.h (renamed from engines/zvision/core/menu.h)34
-rw-r--r--engines/zvision/scripting/scr_file_handling.cpp89
-rw-r--r--engines/zvision/scripting/script_manager.cpp251
-rw-r--r--engines/zvision/scripting/script_manager.h48
-rw-r--r--engines/zvision/scripting/scripting_effect.h (renamed from engines/zvision/scripting/sidefx.h)48
-rw-r--r--engines/zvision/sound/zork_raw.cpp41
-rw-r--r--engines/zvision/sound/zork_raw.h14
-rw-r--r--engines/zvision/text/string_manager.cpp14
-rw-r--r--engines/zvision/text/string_manager.h3
-rw-r--r--engines/zvision/text/subtitles.cpp (renamed from engines/zvision/graphics/subtitles.cpp)11
-rw-r--r--engines/zvision/text/subtitles.h (renamed from engines/zvision/graphics/subtitles.h)2
-rw-r--r--engines/zvision/text/text.cpp536
-rw-r--r--engines/zvision/text/text.h73
-rw-r--r--engines/zvision/text/truetype_font.cpp265
-rw-r--r--engines/zvision/text/truetype_font.h (renamed from engines/zvision/graphics/truetype_font.h)26
-rw-r--r--engines/zvision/video/rlf_decoder.cpp62
-rw-r--r--engines/zvision/video/rlf_decoder.h8
-rw-r--r--engines/zvision/video/video.cpp25
-rw-r--r--engines/zvision/video/zork_avi_decoder.cpp21
-rw-r--r--engines/zvision/zvision.cpp520
-rw-r--r--engines/zvision/zvision.h125
84 files changed, 3533 insertions, 2964 deletions
diff --git a/engines/zvision/configure.engine b/engines/zvision/configure.engine
index 02e31943af..226870c3fd 100644
--- a/engines/zvision/configure.engine
+++ b/engines/zvision/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine zvision "ZVision" no "" "" "freetype2 16bit"
+add_engine zvision "Z-Vision" yes "" "" "freetype2 16bit"
diff --git a/engines/zvision/core/clock.h b/engines/zvision/core/clock.h
index cbf52be560..ae8c968111 100644
--- a/engines/zvision/core/clock.h
+++ b/engines/zvision/core/clock.h
@@ -67,14 +67,14 @@ public:
}
/**
- * Pause the clock. Any future delta times will take this pause into account.
- * Has no effect if the clock is already paused.
- */
+ * Un-pause the clock.
+ * Has no effect if the clock is already un-paused.
+ */
void start();
/**
- * Un-pause the clock.
- * Has no effect if the clock is already un-paused.
+ * Pause the clock. Any future delta times will take this pause into account.
+ * Has no effect if the clock is already paused.
*/
void stop();
};
diff --git a/engines/zvision/core/console.cpp b/engines/zvision/core/console.cpp
index 4dd10d6f40..336541d82a 100644
--- a/engines/zvision/core/console.cpp
+++ b/engines/zvision/core/console.cpp
@@ -52,6 +52,10 @@ Console::Console(ZVision *engine) : GUI::Debugger(), _engine(engine) {
registerCmd("setpanoramascale", WRAP_METHOD(Console, cmdSetPanoramaScale));
registerCmd("location", WRAP_METHOD(Console, cmdLocation));
registerCmd("dumpfile", WRAP_METHOD(Console, cmdDumpFile));
+ registerCmd("dumpfiles", WRAP_METHOD(Console, cmdDumpFiles));
+ registerCmd("dumpimage", WRAP_METHOD(Console, cmdDumpImage));
+ registerCmd("statevalue", WRAP_METHOD(Console, cmdStateValue));
+ registerCmd("stateflag", WRAP_METHOD(Console, cmdStateFlag));
}
bool Console::cmdLoadVideo(int argc, const char **argv) {
@@ -78,12 +82,14 @@ bool Console::cmdLoadSound(int argc, const char **argv) {
Audio::AudioStream *soundStream = makeRawZorkStream(argv[1], _engine);
Audio::SoundHandle handle;
_engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream, -1, 100, 0, DisposeAfterUse::YES, false, false);
-
} else if (argc == 4) {
int isStereo = atoi(argv[3]);
Common::File *file = new Common::File();
- file->open(argv[1]);
+ if (!_engine->getSearchManager()->openFile(*file, argv[1])) {
+ warning("File not found: %s", argv[1]);
+ return true;
+ }
Audio::AudioStream *soundStream = makeRawZorkStream(file, atoi(argv[2]), isStereo == 0 ? false : true);
Audio::SoundHandle handle;
@@ -103,8 +109,10 @@ bool Console::cmdRawToWav(int argc, const char **argv) {
}
Common::File file;
- if (!file.open(argv[1]))
+ if (!_engine->getSearchManager()->openFile(file, argv[1])) {
+ warning("File not found: %s", argv[1]);
return true;
+ }
Audio::AudioStream *audioStream = makeRawZorkStream(argv[1], _engine);
@@ -133,6 +141,10 @@ bool Console::cmdRawToWav(int argc, const char **argv) {
output.writeUint32LE(file.size() * 2);
int16 *buffer = new int16[file.size()];
audioStream->readBuffer(buffer, file.size());
+#ifndef SCUMM_LITTLE_ENDIAN
+ for (int i = 0; i < file.size(); ++i)
+ buffer[i] = TO_LE_16(buffer[i]);
+#endif
output.write(buffer, file.size() * 2);
delete[] buffer;
@@ -194,7 +206,7 @@ bool Console::cmdLocation(int argc, const char **argv) {
Common::String scrFile = Common::String::format("%c%c%c%c.scr", curLocation.world, curLocation.room, curLocation.node, curLocation.view);
debugPrintf("Current location: world '%c', room '%c', node '%c', view '%c', offset %d, script %s\n",
curLocation.world, curLocation.room, curLocation.node, curLocation.view, curLocation.offset, scrFile.c_str());
-
+
if (argc != 6) {
debugPrintf("Use %s <char: world> <char: room> <char:node> <char:view> <int: x offset> to change your location\n", argv[0]);
return true;
@@ -205,6 +217,20 @@ bool Console::cmdLocation(int argc, const char **argv) {
return true;
}
+void dumpFile(Common::SeekableReadStream *s, const char *outName) {
+ byte *buffer = new byte[s->size()];
+ s->read(buffer, s->size());
+
+ Common::DumpFile dumpFile;
+ dumpFile.open(outName);
+
+ dumpFile.write(buffer, s->size());
+ dumpFile.flush();
+ dumpFile.close();
+
+ delete[] buffer;
+}
+
bool Console::cmdDumpFile(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Use %s <fileName> to dump a file\n", argv[0]);
@@ -217,17 +243,126 @@ bool Console::cmdDumpFile(int argc, const char **argv) {
return true;
}
- byte *buffer = new byte[f.size()];
- f.read(buffer, f.size());
+ dumpFile(&f, argv[1]);
- Common::DumpFile dumpFile;
- dumpFile.open(argv[1]);
+ return true;
+}
- dumpFile.write(buffer, f.size());
- dumpFile.flush();
- dumpFile.close();
+bool Console::cmdDumpFiles(int argc, const char **argv) {
+ Common::String fileName;
+ Common::SeekableReadStream *in;
- delete[] buffer;
+ if (argc != 2) {
+ debugPrintf("Use %s <file extension> to dump all files with a specific extension\n", argv[0]);
+ return true;
+ }
+
+ SearchManager::MatchList fileList;
+ _engine->getSearchManager()->listMembersWithExtension(fileList, argv[1]);
+
+ for (SearchManager::MatchList::iterator iter = fileList.begin(); iter != fileList.end(); ++iter) {
+ fileName = iter->_value.name;
+ debugPrintf("Dumping %s\n", fileName.c_str());
+
+ in = iter->_value.arch->createReadStreamForMember(iter->_value.name);
+ if (in)
+ dumpFile(in, fileName.c_str());
+ delete in;
+ }
+
+ return true;
+}
+
+bool Console::cmdDumpImage(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Use %s <TGA/TGZ name> to dump a Z-Vision TGA/TGZ image into a regular BMP image\n", argv[0]);
+ return true;
+ }
+
+ Common::String fileName = argv[1];
+ if (!fileName.hasSuffix(".tga")) {
+ debugPrintf("%s is not an image file", argv[1]);
+ }
+
+ Common::File f;
+ if (!_engine->getSearchManager()->openFile(f, argv[1])) {
+ warning("File not found: %s", argv[1]);
+ return true;
+ }
+
+ Graphics::Surface surface;
+ _engine->getRenderManager()->readImageToSurface(argv[1], surface, false);
+
+ // Open file
+ Common::DumpFile out;
+
+ fileName.setChar('b', fileName.size() - 3);
+ fileName.setChar('m', fileName.size() - 2);
+ fileName.setChar('p', fileName.size() - 1);
+
+ out.open(fileName);
+
+ // Write BMP header
+ out.writeByte('B');
+ out.writeByte('M');
+ out.writeUint32LE(surface.h * surface.pitch + 54);
+ out.writeUint32LE(0);
+ out.writeUint32LE(54);
+ out.writeUint32LE(40);
+ out.writeUint32LE(surface.w);
+ out.writeUint32LE(surface.h);
+ out.writeUint16LE(1);
+ out.writeUint16LE(16);
+ out.writeUint32LE(0);
+ out.writeUint32LE(0);
+ out.writeUint32LE(0);
+ out.writeUint32LE(0);
+ out.writeUint32LE(0);
+ out.writeUint32LE(0);
+
+ // Write pixel data to BMP
+ out.write(surface.getPixels(), surface.pitch * surface.h);
+
+ out.flush();
+ out.close();
+
+ surface.free();
+
+ return true;
+}
+
+bool Console::cmdStateValue(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Use %s <valuenum> to show the value of a state variable\n", argv[0]);
+ debugPrintf("Use %s <valuenum> <newvalue> to set the value of a state variable\n", argv[0]);
+ return true;
+ }
+
+ int valueNum = atoi(argv[1]);
+ int newValue = (argc > 2) ? atoi(argv[2]) : -1;
+
+ if (argc == 2)
+ debugPrintf("[%d] = %d\n", valueNum, _engine->getScriptManager()->getStateValue(valueNum));
+ else if (argc == 3)
+ _engine->getScriptManager()->setStateValue(valueNum, newValue);
+
+ return true;
+}
+
+bool Console::cmdStateFlag(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Use %s <flagnum> to show the value of a state flag\n", argv[0]);
+ debugPrintf("Use %s <flagnum> <newvalue> to set the value of a state flag\n", argv[0]);
+ return true;
+ }
+
+ int valueNum = atoi(argv[1]);
+ int newValue = (argc > 2) ? atoi(argv[2]) : -1;
+
+ if (argc == 2)
+ debugPrintf("[%d] = %d\n", valueNum, _engine->getScriptManager()->getStateFlag(valueNum));
+ else if (argc == 3)
+ _engine->getScriptManager()->setStateFlag(valueNum, newValue);
return true;
}
diff --git a/engines/zvision/core/console.h b/engines/zvision/core/console.h
index 299bd6127f..ac834185a0 100644
--- a/engines/zvision/core/console.h
+++ b/engines/zvision/core/console.h
@@ -46,6 +46,10 @@ private:
bool cmdSetPanoramaScale(int argc, const char **argv);
bool cmdLocation(int argc, const char **argv);
bool cmdDumpFile(int argc, const char **argv);
+ bool cmdDumpFiles(int argc, const char **argv);
+ bool cmdDumpImage(int argc, const char **argv);
+ bool cmdStateValue(int argc, const char **argv);
+ bool cmdStateFlag(int argc, const char **argv);
};
} // End of namespace ZVision
diff --git a/engines/zvision/core/events.cpp b/engines/zvision/core/events.cpp
index c66e61a61a..cc1c00b6d0 100644
--- a/engines/zvision/core/events.cpp
+++ b/engines/zvision/core/events.cpp
@@ -28,8 +28,9 @@
#include "zvision/graphics/cursors/cursor_manager.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/scripting/script_manager.h"
-#include "zvision/core/menu.h"
+#include "zvision/scripting/menu.h"
#include "zvision/sound/zork_raw.h"
+#include "zvision/text/string_manager.h"
#include "common/events.h"
#include "common/system.h"
@@ -39,23 +40,50 @@
namespace ZVision {
+void ZVision::pushKeyToCheatBuf(uint8 key) {
+ for (int i = 0; i < KEYBUF_SIZE - 1; i++)
+ _cheatBuffer[i] = _cheatBuffer[i + 1];
+
+ _cheatBuffer[KEYBUF_SIZE - 1] = key;
+}
+
+bool ZVision::checkCode(const char *code) {
+ int codeLen = strlen(code);
+
+ if (codeLen > KEYBUF_SIZE)
+ return false;
+
+ for (int i = 0; i < codeLen; i++)
+ if (code[i] != _cheatBuffer[KEYBUF_SIZE - codeLen + i] && code[i] != '?')
+ return false;
+
+ return true;
+}
+
+uint8 ZVision::getBufferedKey(uint8 pos) {
+ if (pos >= KEYBUF_SIZE)
+ return 0;
+ else
+ return _cheatBuffer[KEYBUF_SIZE - pos - 1];
+}
+
void ZVision::shortKeys(Common::Event event) {
if (event.kbd.hasFlags(Common::KBD_CTRL)) {
switch (event.kbd.keycode) {
case Common::KEYCODE_s:
- if (getMenuBarEnable() & menuBar_Save)
+ if (_menu->getEnable() & kMenubarSave)
_scriptManager->changeLocation('g', 'j', 's', 'e', 0);
break;
case Common::KEYCODE_r:
- if (getMenuBarEnable() & menuBar_Restore)
+ if (_menu->getEnable() & kMenubarRestore)
_scriptManager->changeLocation('g', 'j', 'r', 'e', 0);
break;
case Common::KEYCODE_p:
- if (getMenuBarEnable() & menuBar_Settings)
+ if (_menu->getEnable() & kMenubarSettings)
_scriptManager->changeLocation('g', 'j', 'p', 'e', 0);
break;
case Common::KEYCODE_q:
- if (getMenuBarEnable() & menuBar_Exit)
+ if (_menu->getEnable() & kMenubarExit)
ifQuit();
break;
default:
@@ -65,16 +93,21 @@ void ZVision::shortKeys(Common::Event event) {
}
void ZVision::cheatCodes(uint8 key) {
+ Location loc = _scriptManager->getCurrentLocation();
+ // Do not process cheat codes while in the game menus
+ if (loc.world == 'g' && loc.room == 'j')
+ return;
+
pushKeyToCheatBuf(key);
if (getGameId() == GID_GRANDINQUISITOR) {
if (checkCode("IMNOTDEAF")) {
// Unknown cheat
- showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented"));
+ _renderManager->showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented"));
}
if (checkCode("3100OPB")) {
- showDebugMsg(Common::String::format("Current location: %c%c%c%c",
+ _renderManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c",
_scriptManager->getStateValue(StateKey_World),
_scriptManager->getStateValue(StateKey_Room),
_scriptManager->getStateValue(StateKey_Node),
@@ -91,9 +124,9 @@ void ZVision::cheatCodes(uint8 key) {
}
// There are 3 more cheats in script files:
- // - "EAT ME": gjcr.scr
- // - "WHOAMI": hp1e.scr
- // - "HUISOK": uh1f.scr
+ // - "WHOAMI": gjcr.scr
+ // - "HUISOK": hp1e.scr
+ // - "EAT ME": uh1f.scr
} else if (getGameId() == GID_NEMESIS) {
if (checkCode("CHLOE")) {
_scriptManager->changeLocation('t', 'm', '2', 'g', 0);
@@ -101,7 +134,7 @@ void ZVision::cheatCodes(uint8 key) {
}
if (checkCode("77MASSAVE")) {
- showDebugMsg(Common::String::format("Current location: %c%c%c%c",
+ _renderManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c",
_scriptManager->getStateValue(StateKey_World),
_scriptManager->getStateValue(StateKey_Room),
_scriptManager->getStateValue(StateKey_Node),
@@ -118,9 +151,8 @@ void ZVision::cheatCodes(uint8 key) {
}
if (checkCode("HELLOSAILOR")) {
- Location loc = _scriptManager->getCurrentLocation();
Audio::AudioStream *soundStream;
- if (loc.world == 'v' && loc.room == 'b' && loc.node == '1' && loc.view == '0') {
+ if (loc == "vb10") {
soundStream = makeRawZorkStream("v000hpta.raw", this);
} else {
soundStream = makeRawZorkStream("v000hnta.raw", this);
@@ -130,21 +162,29 @@ void ZVision::cheatCodes(uint8 key) {
}
}
- if (checkCode("FRAME"))
- showDebugMsg(Common::String::format("FPS: ???, not implemented"));
+ if (checkCode("FRAME")) {
+ Common::String fpsStr = Common::String::format("FPS: %d", getFPS());
+ _renderManager->showDebugMsg(fpsStr);
+ }
+
+ if (checkCode("COMPUTERARCH"))
+ _renderManager->showDebugMsg("COMPUTERARCH: var-viewer not implemented");
+ // This cheat essentially toggles the GOxxxx cheat below
if (checkCode("XYZZY"))
_scriptManager->setStateValue(StateKey_DebugCheats, 1 - _scriptManager->getStateValue(StateKey_DebugCheats));
- if (checkCode("COMPUTERARCH"))
- showDebugMsg(Common::String::format("COMPUTERARCH: var-viewer not implemented"));
-
if (_scriptManager->getStateValue(StateKey_DebugCheats) == 1)
if (checkCode("GO????"))
_scriptManager->changeLocation(getBufferedKey(3),
getBufferedKey(2),
getBufferedKey(1),
getBufferedKey(0), 0);
+
+ // Show the Venus screen when "?" or "/" is pressed while inside the temple world
+ if (_scriptManager->getStateValue(StateKey_VenusEnable) == 1)
+ if (getBufferedKey(0) == 0xBF && _scriptManager->getStateValue(StateKey_World) == 't')
+ _scriptManager->changeLocation('g', 'j', 'h', 'e', 0);
}
void ZVision::processEvents() {
@@ -194,19 +234,24 @@ void ZVision::processEvents() {
case Common::KEYCODE_LEFT:
case Common::KEYCODE_RIGHT:
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA)
- _kbdVelocity = (_event.kbd.keycode == Common::KEYCODE_LEFT ?
- -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) :
- _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
+ _keyboardVelocity = (_event.kbd.keycode == Common::KEYCODE_LEFT ?
+ -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) :
+ _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
break;
case Common::KEYCODE_UP:
case Common::KEYCODE_DOWN:
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT)
- _kbdVelocity = (_event.kbd.keycode == Common::KEYCODE_UP ?
- -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) :
- _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
+ _keyboardVelocity = (_event.kbd.keycode == Common::KEYCODE_UP ?
+ -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) :
+ _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2;
break;
+ case Common::KEYCODE_F10: {
+ Common::String fpsStr = Common::String::format("FPS: %d", getFPS());
+ _renderManager->showDebugMsg(fpsStr);
+ }
+ break;
default:
break;
}
@@ -226,12 +271,12 @@ void ZVision::processEvents() {
case Common::KEYCODE_LEFT:
case Common::KEYCODE_RIGHT:
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA)
- _kbdVelocity = 0;
+ _keyboardVelocity = 0;
break;
case Common::KEYCODE_UP:
case Common::KEYCODE_DOWN:
if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT)
- _kbdVelocity = 0;
+ _keyboardVelocity = 0;
break;
default:
break;
@@ -279,26 +324,33 @@ void ZVision::onMouseMove(const Common::Point &pos) {
// |
// ^
- if (_workingWindow.contains(pos)) {
- cursorWasChanged = _scriptManager->onMouseMove(pos, imageCoord);
+ // Clip the horizontal mouse position to the working window
+ Common::Point clippedPos = pos;
+ clippedPos.x = CLIP<int16>(pos.x, _workingWindow.left + 1, _workingWindow.right - 1);
+
+ if (_workingWindow.contains(clippedPos)) {
+ cursorWasChanged = _scriptManager->onMouseMove(clippedPos, imageCoord);
RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
if (renderState == RenderTable::PANORAMA) {
- if (pos.x >= _workingWindow.left && pos.x < _workingWindow.left + ROTATION_SCREEN_EDGE_OFFSET) {
+ if (clippedPos.x >= _workingWindow.left && clippedPos.x < _workingWindow.left + ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.x - (ROTATION_SCREEN_EDGE_OFFSET + _workingWindow.left)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MIN(((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (clippedPos.x - _workingWindow.left)) - mspeed).toInt(), -1);
+
_cursorManager->changeCursor(CursorIndex_Left);
cursorWasChanged = true;
- } else if (pos.x <= _workingWindow.right && pos.x > _workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET) {
+ } else if (clippedPos.x <= _workingWindow.right && clippedPos.x > _workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.x - (_workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MAX((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (clippedPos.x - _workingWindow.right + ROTATION_SCREEN_EDGE_OFFSET)).toInt(), 1);
_cursorManager->changeCursor(CursorIndex_Right);
cursorWasChanged = true;
@@ -306,21 +358,23 @@ void ZVision::onMouseMove(const Common::Point &pos) {
_mouseVelocity = 0;
}
} else if (renderState == RenderTable::TILT) {
- if (pos.y >= _workingWindow.top && pos.y < _workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET) {
+ if (clippedPos.y >= _workingWindow.top && clippedPos.y < _workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.y - (_workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MIN(((Common::Rational(mspeed, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.top)) - mspeed).toInt(), -1);
_cursorManager->changeCursor(CursorIndex_UpArr);
cursorWasChanged = true;
- } else if (pos.y <= _workingWindow.bottom && pos.y > _workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET) {
+ } else if (clippedPos.y <= _workingWindow.bottom && clippedPos.y > _workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET) {
int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4;
- if (mspeed <= 0)
- mspeed = 400 >> 4;
- _mouseVelocity = (((pos.y - (_workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7;
+ if (mspeed <= 0) {
+ mspeed = 25;
+ }
+ _mouseVelocity = MAX((Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.bottom + ROTATION_SCREEN_EDGE_OFFSET)).toInt(), 1);
_cursorManager->changeCursor(CursorIndex_DownArr);
cursorWasChanged = true;
@@ -441,4 +495,12 @@ uint8 ZVision::getZvisionKey(Common::KeyCode scummKeyCode) {
return 0;
}
+bool ZVision::ifQuit() {
+ if (_renderManager->askQuestion(_stringManager->getTextLine(StringManager::ZVISION_STR_EXITPROMT))) {
+ quitGame();
+ return true;
+ }
+ return false;
+}
+
} // End of namespace ZVision
diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp
index ebf5bdcfdd..f44e653c2a 100644
--- a/engines/zvision/detection.cpp
+++ b/engines/zvision/detection.cpp
@@ -24,9 +24,10 @@
#include "base/plugins.h"
+#include "engines/advancedDetector.h"
+
#include "zvision/zvision.h"
-#include "zvision/detection.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/script_manager.h"
#include "common/translation.h"
@@ -36,143 +37,43 @@
namespace ZVision {
-uint32 ZVision::getFeatures() const {
- return _gameDescription->desc.flags;
-}
+struct ZVisionGameDescription {
+ ADGameDescription desc;
+ ZVisionGameId gameId;
+};
+ZVisionGameId ZVision::getGameId() const {
+ return _gameDescription->gameId;
+}
Common::Language ZVision::getLanguage() const {
return _gameDescription->desc.language;
}
+uint32 ZVision::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
} // End of namespace ZVision
-static const PlainGameDescriptor zVisionGames[] = {
- {"zvision", "ZVision Game"},
- {"znemesis", "Zork Nemesis: The Forbidden Lands"},
- {"zgi", "Zork: Grand Inquisitor"},
- {0, 0}
-};
-
-namespace ZVision {
-
-static const ZVisionGameDescription gameDescriptions[] = {
-
- {
- // Zork Nemesis English version
- {
- "znemesis",
- 0,
- AD_ENTRY1s("CSCR.ZFS", "88226e51a205d2e50c67a5237f3bd5f2", 2397741),
- Common::EN_ANY,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Nemesis English demo version
- {
- "znemesis",
- "Demo",
- AD_ENTRY1s("SCRIPTS.ZFS", "64f1e881394e9462305104f99513c833", 380539),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_DEMO,
- GUIO1(GUIO_NONE)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Grand Inquisitor English CD version
- {
- "zgi",
- "CD",
- AD_ENTRY1s("SCRIPTS.ZFS", "81efd40ecc3d22531e211368b779f17f", 8336944),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor English demo version
- {
- "zgi",
- "Demo",
- AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_DEMO,
- GUIO1(GUIO_NONE)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor English DVD version
- {
- "zgi",
- "DVD",
- AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- AD_TABLE_END_MARKER,
- GID_NONE
- }
-};
-
-} // End of namespace ZVision
-
-static const char *directoryGlobs[] = {
- "znemscr",
- 0
-};
-
-static const ExtraGuiOption ZVisionExtraGuiOption = {
- _s("Use original save/load screens"),
- _s("Use the original save/load screens, instead of the ScummVM ones"),
- "originalsaveload",
- false
-};
-
-static const ExtraGuiOption ZVisionExtraGuiOption2 = {
- _s("Double FPS"),
- _s("Halve the update delay"),
- "doublefps",
- false
-};
+#include "zvision/detection_tables.h"
class ZVisionMetaEngine : public AdvancedMetaEngine {
public:
- ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), zVisionGames) {
+ ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), ZVision::zVisionGames, ZVision::optionsList) {
_maxScanDepth = 2;
- _directoryGlobs = directoryGlobs;
+ _directoryGlobs = ZVision::directoryGlobs;
_singleid = "zvision";
}
virtual const char *getName() const {
- return "ZVision";
+ return "Z-Vision";
}
virtual const char *getOriginalCopyright() const {
- return "ZVision Activision (C) 1996";
+ return "Z-Vision (C) 1996 Activision";
}
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
void removeSaveState(const char *target, int slot) const;
@@ -202,7 +103,7 @@ Common::Error ZVision::ZVision::loadGameState(int slot) {
}
Common::Error ZVision::ZVision::saveGameState(int slot, const Common::String &desc) {
- _saveManager->saveGame(slot, desc);
+ _saveManager->saveGame(slot, desc, false);
return Common::kNoError;
}
@@ -223,13 +124,6 @@ bool ZVisionMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADG
return gd != 0;
}
-const ExtraGuiOptions ZVisionMetaEngine::getExtraGuiOptions(const Common::String &target) const {
- ExtraGuiOptions options;
- options.push_back(ZVisionExtraGuiOption);
- options.push_back(ZVisionExtraGuiOption2);
- return options;
-}
-
SaveStateList ZVisionMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
ZVision::SaveGameHeader header;
@@ -308,6 +202,11 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
if (successfulRead) {
SaveStateDescriptor desc(slot, header.saveName);
+ // Do not allow save slot 0 (used for auto-saving) to be deleted or
+ // overwritten.
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+
desc.setThumbnail(header.thumbnail);
if (header.version > 0) {
diff --git a/engines/zvision/detection.h b/engines/zvision/detection.h
deleted file mode 100644
index f80cac79ec..0000000000
--- a/engines/zvision/detection.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef ZVISION_DETECTION_H
-#define ZVISION_DETECTION_H
-
-#include "engines/advancedDetector.h"
-
-namespace ZVision {
-
-enum ZVisionGameId {
- GID_NONE = 0,
- GID_NEMESIS = 1,
- GID_GRANDINQUISITOR = 2
-};
-
-struct ZVisionGameDescription {
- ADGameDescription desc;
- ZVisionGameId gameId;
-};
-
-}
-
-#endif
diff --git a/engines/zvision/detection_tables.h b/engines/zvision/detection_tables.h
new file mode 100644
index 0000000000..06bc58ee7f
--- /dev/null
+++ b/engines/zvision/detection_tables.h
@@ -0,0 +1,277 @@
+/* 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 ZVISION_DETECTION_TABLES_H
+#define ZVISION_DETECTION_TABLES_H
+
+namespace ZVision {
+
+static const PlainGameDescriptor zVisionGames[] = {
+ { "zvision", "Z-Vision Game" },
+ { "znemesis", "Zork Nemesis: The Forbidden Lands" },
+ { "zgi", "Zork: Grand Inquisitor" },
+ { 0, 0 }
+};
+
+static const char *directoryGlobs[] = {
+ "znemscr",
+ 0
+};
+
+#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
+#define GAMEOPTION_DOUBLE_FPS GUIO_GAMEOPTIONS2
+#define GAMEOPTION_ENABLE_VENUS GUIO_GAMEOPTIONS3
+#define GAMEOPTION_DISABLE_ANIM_WHILE_TURNING GUIO_GAMEOPTIONS4
+#define GAMEOPTION_USE_HIRES_MPEG_MOVIES GUIO_GAMEOPTIONS5
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+
+ {
+ GAMEOPTION_ORIGINAL_SAVELOAD,
+ {
+ _s("Use original save/load screens"),
+ _s("Use the original save/load screens instead of the ScummVM interface"),
+ "originalsaveload",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_DOUBLE_FPS,
+ {
+ _s("Double FPS"),
+ _s("Increase framerate from 30 to 60 FPS"),
+ "doublefps",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_ENABLE_VENUS,
+ {
+ _s("Enable Venus"),
+ _s("Enable the Venus help system"),
+ "venusenabled",
+ true
+ }
+ },
+
+ {
+ GAMEOPTION_DISABLE_ANIM_WHILE_TURNING,
+ {
+ _s("Disable animation while turning"),
+ _s("Disable animation while turning in panorama mode"),
+ "noanimwhileturning",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_USE_HIRES_MPEG_MOVIES,
+ {
+ _s("Use high resolution MPEG video"),
+ _s("Use MPEG video from the DVD version, instead of lower resolution AVI"),
+ "mpegmovies",
+ true
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+static const ZVisionGameDescription gameDescriptions[] = {
+
+ {
+ // Zork Nemesis English version
+ {
+ "znemesis",
+ 0,
+ AD_ENTRY1s("CSCR.ZFS", "88226e51a205d2e50c67a5237f3bd5f2", 2397741),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis French version
+ {
+ "znemesis",
+ 0,
+ {
+ { "CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873 },
+ { "NEMESIS.STR", 0, "333bcb17bbb7f57cae742fbbe44f56f3", 9219 },
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis German version
+ {
+ "znemesis",
+ 0,
+ {
+ { "CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873 },
+ { "NEMESIS.STR", 0, "3d1a12b907751653866cffc6d4dfb331", 9505 },
+ AD_LISTEND
+ },
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis Italian version
+ {
+ "znemesis",
+ 0,
+ {
+ { "CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873 },
+ { "NEMESIS.STR", 0, "7c568feca8d9f9ae855c47183612c305", 9061 },
+ AD_LISTEND
+ },
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis English demo version
+ {
+ "znemesis",
+ "Demo",
+ AD_ENTRY1s("SCRIPTS.ZFS", "64f1e881394e9462305104f99513c833", 380539),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Grand Inquisitor English CD version
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "81efd40ecc3d22531e211368b779f17f", 8336944),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor French CD version, reported by ulrichh on IRC
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "4d1ec4ade7ecc9ee9ec591d43ca3d213", 8338133),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor German CD version, reported by breit in bug #6760
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "b7ac7e331b9b7f884590b0b325b560c8", 8338133),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor Spanish CD version, reported by dianiu in bug #6764
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "5cdc4b99c1134053af135aae71326fd1", 8338141),
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor English DVD version
+ {
+ "zgi",
+ "DVD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING, GAMEOPTION_USE_HIRES_MPEG_MOVIES)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor English demo version
+ {
+ "zgi",
+ "Demo",
+ AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ AD_TABLE_END_MARKER,
+ GID_NONE
+ }
+};
+
+} // End of namespace ZVision
+
+#endif
diff --git a/engines/zvision/file/lzss_read_stream.cpp b/engines/zvision/file/lzss_read_stream.cpp
index 6f27eaa765..ca10af7d72 100644
--- a/engines/zvision/file/lzss_read_stream.cpp
+++ b/engines/zvision/file/lzss_read_stream.cpp
@@ -31,8 +31,9 @@ LzssReadStream::LzssReadStream(Common::SeekableReadStream *source)
// It's convention to set the starting cursor position to blockSize - 16
_windowCursor(0x0FEE),
_eosFlag(false) {
- // Clear the window to null
- memset(_window, 0, BLOCK_SIZE);
+ // All values up to _windowCursor inits by 0x20
+ memset(_window, 0x20, _windowCursor);
+ memset(_window + _windowCursor, 0, BLOCK_SIZE - _windowCursor);
}
uint32 LzssReadStream::decompressBytes(byte *destination, uint32 numberOfBytes) {
diff --git a/engines/zvision/core/save_manager.cpp b/engines/zvision/file/save_manager.cpp
index 20bd39fde5..d169679e28 100644
--- a/engines/zvision/core/save_manager.cpp
+++ b/engines/zvision/file/save_manager.cpp
@@ -22,8 +22,8 @@
#include "common/scummsys.h"
-#include "zvision/core/save_manager.h"
#include "zvision/zvision.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/script_manager.h"
#include "zvision/graphics/render_manager.h"
@@ -69,7 +69,7 @@ bool SaveManager::scummVMSaveLoadDialog(bool isSave) {
return false;
if (isSave) {
- saveGame(slot, desc);
+ saveGame(slot, desc, false);
return true;
} else {
Common::ErrorCode result = loadGame(slot).getCode();
@@ -77,54 +77,34 @@ bool SaveManager::scummVMSaveLoadDialog(bool isSave) {
}
}
-void SaveManager::saveGame(uint slot, const Common::String &saveName) {
- // The games only support 20 slots
- //assert(slot <= 1 && slot <= 20);
+void SaveManager::saveGame(uint slot, const Common::String &saveName, bool useSaveBuffer) {
+ if (!_tempSave && useSaveBuffer)
+ return;
Common::SaveFileManager *saveFileManager = g_system->getSavefileManager();
Common::OutSaveFile *file = saveFileManager->openForSaving(_engine->generateSaveFileName(slot));
- writeSaveGameHeader(file, saveName);
+ writeSaveGameHeader(file, saveName, useSaveBuffer);
- _engine->getScriptManager()->serialize(file);
+ if (useSaveBuffer)
+ file->write(_tempSave->getData(), _tempSave->size());
+ else
+ _engine->getScriptManager()->serialize(file);
file->finalize();
delete file;
-}
-
-void SaveManager::saveGame(uint slot, const Common::String &saveName, Common::MemoryWriteStreamDynamic *stream) {
- Common::SaveFileManager *saveFileManager = g_system->getSavefileManager();
- Common::OutSaveFile *file = saveFileManager->openForSaving(_engine->generateSaveFileName(slot));
-
- writeSaveGameHeader(file, saveName);
-
- file->write(stream->getData(), stream->size());
- file->finalize();
- delete file;
-}
-
-void SaveManager::saveGameBuffered(uint slot, const Common::String &saveName) {
- if (_tempSave) {
- saveGame(slot, saveName, _tempSave);
+ if (useSaveBuffer)
flushSaveBuffer();
- }
+
+ _lastSaveTime = g_system->getMillis();
}
void SaveManager::autoSave() {
- Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(_engine->generateAutoSaveFileName());
-
- writeSaveGameHeader(file, "auto");
-
- _engine->getScriptManager()->serialize(file);
-
- // Cleanup
- file->finalize();
- delete file;
+ saveGame(0, "Auto save", false);
}
-void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName) {
-
+void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName, bool useSaveBuffer) {
file->writeUint32BE(SAVEGAME_ID);
// Write version
@@ -134,8 +114,11 @@ void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::S
file->writeString(saveName);
file->writeByte(0);
- // Create a thumbnail and save it
- Graphics::saveThumbnail(*file);
+ // Save the game thumbnail
+ if (useSaveBuffer)
+ file->write(_tempThumbnail->getData(), _tempThumbnail->size());
+ else
+ Graphics::saveThumbnail(*file);
// Write out the save date/time
TimeDate td;
@@ -147,15 +130,27 @@ void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::S
file->writeSint16LE(td.tm_min);
}
-Common::Error SaveManager::loadGame(uint slot) {
- // The games only support 20 slots
- //assert(slot <= 1 && slot <= 20);
+Common::Error SaveManager::loadGame(int slot) {
+ Common::SeekableReadStream *saveFile = NULL;
- Common::SeekableReadStream *saveFile = getSlotFile(slot);
- if (saveFile == 0) {
- return Common::kPathDoesNotExist;
+ if (slot >= 0) {
+ saveFile = getSlotFile(slot);
+ } else {
+ saveFile = _engine->getSearchManager()->openFile("r.svr");
+ if (!saveFile) {
+ Common::File *restoreFile = new Common::File();
+ if (!restoreFile->open("r.svr")) {
+ delete restoreFile;
+ return Common::kPathDoesNotExist;
+ }
+
+ saveFile = restoreFile;
+ }
}
+ if (!saveFile)
+ return Common::kPathDoesNotExist;
+
// Read the header
SaveGameHeader header;
if (!readSaveGameHeader(saveFile, header)) {
@@ -170,33 +165,27 @@ Common::Error SaveManager::loadGame(uint slot) {
if (header.thumbnail)
delete header.thumbnail;
- return Common::kNoError;
-}
-
-Common::Error SaveManager::loadGame(const Common::String &saveName) {
- Common::File *saveFile = _engine->getSearchManager()->openFile(saveName);
- if (saveFile == NULL) {
- saveFile = new Common::File;
- if (!saveFile->open(saveName)) {
- delete saveFile;
- return Common::kPathDoesNotExist;
+ if (_engine->getGameId() == GID_NEMESIS && scriptManager->getCurrentLocation() == "tv2f") {
+ // WORKAROUND for script bug #6793: location tv2f (stairs) has two states:
+ // one at the top of the stairs, and one at the bottom. When the player
+ // goes to the bottom of the stairs, the screen changes, and hotspot
+ // 4652 (exit opposite the stairs) is enabled. However, the variable that
+ // controls the state (2408) is reset when the player goes down the stairs.
+ // Furthermore, the room's initialization script disables the stair exit
+ // control (4652). This leads to an impossible situation, where all the
+ // exit controls are disabled, and the player can't more anywhere. Thus,
+ // when loading a game in that room, we check for that impossible
+ // situation, which only occurs after the player has moved down the stairs,
+ // and fix it here by setting the correct background, and enabling the
+ // stair exit hotspot.
+ if ((scriptManager->getStateFlag(2411) & Puzzle::DISABLED) &&
+ (scriptManager->getStateFlag(2408) & Puzzle::DISABLED) &&
+ (scriptManager->getStateFlag(4652) & Puzzle::DISABLED)) {
+ _engine->getRenderManager()->setBackgroundImage("tv2fb21c.tga");
+ scriptManager->unsetStateFlag(4652, Puzzle::DISABLED);
}
}
- // Read the header
- SaveGameHeader header;
- if (!readSaveGameHeader(saveFile, header)) {
- return Common::kUnknownError;
- }
-
- ScriptManager *scriptManager = _engine->getScriptManager();
- // Update the state table values
- scriptManager->deserialize(saveFile);
-
- delete saveFile;
- if (header.thumbnail)
- delete header.thumbnail;
-
return Common::kNoError;
}
@@ -216,7 +205,7 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea
return true;
}
if (tag != SAVEGAME_ID) {
- warning("File is not a ZVision save file. Aborting load");
+ warning("File is not a Z-Vision save file. Aborting load");
return false;
}
@@ -226,7 +215,13 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea
// Check that the save version isn't newer than this binary
if (header.version > SAVE_VERSION) {
uint tempVersion = header.version;
- GUI::MessageDialog dialog(Common::String::format("This save file uses version %u, but this engine only supports up to version %d. You will need an updated version of the engine to use this save file.", tempVersion, SAVE_VERSION), "OK");
+ GUI::MessageDialog dialog(
+ Common::String::format(
+ "This save file uses version %u, but this engine only "
+ "supports up to version %d. You will need an updated version "
+ "of the engine to use this save file.", tempVersion, SAVE_VERSION
+ ),
+ "OK");
dialog.runModal();
}
@@ -277,18 +272,20 @@ Common::SeekableReadStream *SaveManager::getSlotFile(uint slot) {
}
void SaveManager::prepareSaveBuffer() {
- if (_tempSave)
- delete _tempSave;
+ delete _tempThumbnail;
+ _tempThumbnail = new Common::MemoryWriteStreamDynamic;
+ Graphics::saveThumbnail(*_tempThumbnail);
+ delete _tempSave;
_tempSave = new Common::MemoryWriteStreamDynamic;
-
_engine->getScriptManager()->serialize(_tempSave);
}
void SaveManager::flushSaveBuffer() {
- if (_tempSave)
- delete _tempSave;
+ delete _tempThumbnail;
+ _tempThumbnail = NULL;
+ delete _tempSave;
_tempSave = NULL;
}
diff --git a/engines/zvision/core/save_manager.h b/engines/zvision/file/save_manager.h
index 75841331e7..9e816373ea 100644
--- a/engines/zvision/core/save_manager.h
+++ b/engines/zvision/file/save_manager.h
@@ -48,13 +48,18 @@ struct SaveGameHeader {
class SaveManager {
public:
- SaveManager(ZVision *engine) : _engine(engine), _tempSave(NULL) {}
+ SaveManager(ZVision *engine) : _engine(engine), _tempSave(NULL), _tempThumbnail(NULL), _lastSaveTime(0) {}
~SaveManager() {
flushSaveBuffer();
}
+ uint32 getLastSaveTime() const {
+ return _lastSaveTime;
+ }
+
private:
ZVision *_engine;
+ uint32 _lastSaveTime;
static const uint32 SAVEGAME_ID;
enum {
@@ -62,13 +67,13 @@ private:
SAVE_VERSION = 1
};
+ Common::MemoryWriteStreamDynamic *_tempThumbnail;
Common::MemoryWriteStreamDynamic *_tempSave;
public:
/**
* Called every room change. Saves the state of the room just before
- * we switched rooms. Uses ZVision::generateAutoSaveFileName() to
- * create the save file name.
+ * the room changes.
*/
void autoSave();
/**
@@ -79,17 +84,14 @@ public:
* @param slot The save slot this save pertains to. Must be [1, 20]
* @param saveName The internal name for this save. This is NOT the name of the actual save file.
*/
- void saveGame(uint slot, const Common::String &saveName);
- void saveGame(uint slot, const Common::String &saveName, Common::MemoryWriteStreamDynamic *stream);
- void saveGameBuffered(uint slot, const Common::String &saveName);
+ void saveGame(uint slot, const Common::String &saveName, bool useSaveBuffer);
/**
* Loads the state data from the save file that slot references. Uses
* ZVision::generateSaveFileName(slot) to get the save file name.
*
* @param slot The save slot to load. Must be [1, 20]
*/
- Common::Error loadGame(uint slot);
- Common::Error loadGame(const Common::String &saveName);
+ Common::Error loadGame(int slot);
Common::SeekableReadStream *getSlotFile(uint slot);
bool readSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &header);
@@ -98,7 +100,7 @@ public:
void flushSaveBuffer();
bool scummVMSaveLoadDialog(bool isSave);
private:
- void writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName);
+ void writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName, bool useSaveBuffer);
};
} // End of namespace ZVision
diff --git a/engines/zvision/file/search_manager.cpp b/engines/zvision/file/search_manager.cpp
index 30c269c290..821b85b053 100644
--- a/engines/zvision/file/search_manager.cpp
+++ b/engines/zvision/file/search_manager.cpp
@@ -62,19 +62,6 @@ SearchManager::~SearchManager() {
_archList.clear();
}
-void SearchManager::addPatch(const Common::String &src, const Common::String &dst) {
- Common::String lowerCaseName = dst;
- lowerCaseName.toLowercase();
-
- SearchManager::MatchList::iterator it = _files.find(lowerCaseName);
-
- if (it != _files.end()) {
- lowerCaseName = src;
- lowerCaseName.toLowercase();
- _files[lowerCaseName] = it->_value;
- }
-}
-
void SearchManager::addFile(const Common::String &name, Common::Archive *arch) {
bool addArch = true;
Common::List<Common::Archive *>::iterator it = _archList.begin();
@@ -147,9 +134,10 @@ bool SearchManager::hasFile(const Common::String &name) {
return false;
}
-void SearchManager::loadZix(const Common::String &name) {
+bool SearchManager::loadZix(const Common::String &name) {
Common::File file;
- file.open(name);
+ if (!file.open(name))
+ return false;
Common::String line;
@@ -160,7 +148,7 @@ void SearchManager::loadZix(const Common::String &name) {
}
if (file.eos())
- return;
+ error("Corrupt ZIX file: %s", name.c_str());
Common::Array<Common::Archive *> archives;
@@ -169,37 +157,47 @@ void SearchManager::loadZix(const Common::String &name) {
line.trim();
if (line.matchString("----------*", true))
break;
- else if (line.matchString("DIR:*", true)) {
- Common::String path(line.c_str() + 5);
+ else if (line.matchString("DIR:*", true) || line.matchString("CD0:*", true) || line.matchString("CD1:*", true) || line.matchString("CD2:*", true)) {
Common::Archive *arc;
- char tempPath[128];
- strcpy(tempPath, path.c_str());
+
+ Common::String path(line.c_str() + 5);
for (uint i = 0; i < path.size(); i++)
- if (tempPath[i] == '\\')
- tempPath[i] = '/';
+ if (path[i] == '\\')
+ path.setChar('/', i);
+
+ // Check if NEMESIS.ZIX/MEDIUM.ZIX refers to the znemesis folder, and
+ // check the game root folder instead
+ if (path.hasPrefix("znemesis/"))
+ path = Common::String(path.c_str() + 9);
+
+ // Check if INQUIS.ZIX refers to the ZGI folder, and check the game
+ // root folder instead
+ if (path.hasPrefix("zgi/"))
+ path = Common::String(path.c_str() + 4);
+ if (path.hasPrefix("zgi_e/"))
+ path = Common::String(path.c_str() + 6);
- path = Common::String(tempPath);
if (path.size() && path[0] == '.')
path.deleteChar(0);
if (path.size() && path[0] == '/')
path.deleteChar(0);
-
- if (path.matchString("*.zfs", true))
- arc = new ZfsArchive(path);
- else {
- if (path.size()) {
- if (path[path.size() - 1] == '\\' || path[path.size() - 1] == '/')
- path.deleteLastChar();
- if (path.size())
- for (Common::List<Common::String>::iterator it = _dirList.begin(); it != _dirList.end(); ++it)
- if (path.equalsIgnoreCase(*it)) {
- path = *it;
- break;
- }
+ if (path.size() && path.hasSuffix("/"))
+ path.deleteLastChar();
+
+ // Handle paths in case-sensitive file systems (bug #6775)
+ if (path.size()) {
+ for (Common::List<Common::String>::iterator it = _dirList.begin(); it != _dirList.end(); ++it) {
+ if (path.equalsIgnoreCase(*it)) {
+ path = *it;
+ break;
+ }
}
+ }
+ if (path.matchString("*.zfs", true)) {
+ arc = new ZfsArchive(path);
+ } else {
path = Common::String::format("%s/%s", _root.c_str(), path.c_str());
-
arc = new Common::FSDirectory(path);
}
archives.push_back(arc);
@@ -207,7 +205,7 @@ void SearchManager::loadZix(const Common::String &name) {
}
if (file.eos())
- return;
+ error("Corrupt ZIX file: %s", name.c_str());
while (!file.eos()) {
line = file.readLine();
@@ -220,6 +218,8 @@ void SearchManager::loadZix(const Common::String &name) {
}
}
}
+
+ return true;
}
void SearchManager::addDir(const Common::String &name) {
@@ -265,7 +265,7 @@ void SearchManager::addDir(const Common::String &name) {
void SearchManager::listDirRecursive(Common::List<Common::String> &_list, const Common::FSNode &fsNode, int depth) {
Common::FSList fsList;
- if ( fsNode.getChildren(fsList) ) {
+ if (fsNode.getChildren(fsList)) {
_list.push_back(fsNode.getPath());
@@ -275,4 +275,11 @@ void SearchManager::listDirRecursive(Common::List<Common::String> &_list, const
}
}
+void SearchManager::listMembersWithExtension(MatchList &fileList, Common::String extension) {
+ for (SearchManager::MatchList::iterator it = _files.begin(); it != _files.end(); ++it) {
+ if (it->_key.hasSuffix(extension))
+ fileList[it->_key] = it->_value;
+ }
+}
+
} // End of namespace ZVision
diff --git a/engines/zvision/file/search_manager.h b/engines/zvision/file/search_manager.h
index fdd70fd381..0d0ab14d31 100644
--- a/engines/zvision/file/search_manager.h
+++ b/engines/zvision/file/search_manager.h
@@ -39,33 +39,30 @@ public:
void addFile(const Common::String &name, Common::Archive *arch);
void addDir(const Common::String &name);
- void addPatch(const Common::String &src, const Common::String &dst);
Common::File *openFile(const Common::String &name);
bool openFile(Common::File &file, const Common::String &name);
bool hasFile(const Common::String &name);
- void loadZix(const Common::String &name);
-
-private:
-
- void listDirRecursive(Common::List<Common::String> &dirList, const Common::FSNode &fsNode, int depth);
+ bool loadZix(const Common::String &name);
struct Node {
Common::String name;
Common::Archive *arch;
};
- Common::List<Common::String> _dirList;
-
typedef Common::HashMap<Common::String, Node, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> MatchList;
- Common::List<Common::Archive *> _archList;
- MatchList _files;
-
- Common::String _root;
+ void listMembersWithExtension(MatchList &fileList, Common::String extension);
private:
+
+ void listDirRecursive(Common::List<Common::String> &dirList, const Common::FSNode &fsNode, int depth);
+
+ Common::List<Common::String> _dirList;
+ Common::List<Common::Archive *> _archList;
+ Common::String _root;
+ MatchList _files;
};
}
diff --git a/engines/zvision/graphics/cursors/cursor.cpp b/engines/zvision/graphics/cursors/cursor.cpp
index 07323b45c4..2c011668ac 100644
--- a/engines/zvision/graphics/cursors/cursor.cpp
+++ b/engines/zvision/graphics/cursors/cursor.cpp
@@ -36,35 +36,6 @@ ZorkCursor::ZorkCursor()
_hotspotY(0) {
}
-ZorkCursor::ZorkCursor(const Common::String &fileName)
- : _width(0),
- _height(0),
- _hotspotX(0),
- _hotspotY(0) {
- Common::File file;
- if (!file.open(fileName))
- return;
-
- uint32 magic = file.readUint32BE();
- if (magic != MKTAG('Z', 'C', 'R', '1')) {
- warning("%s is not a Zork Cursor file", fileName.c_str());
- return;
- }
-
- _hotspotX = file.readUint16LE();
- _hotspotY = file.readUint16LE();
- _width = file.readUint16LE();
- _height = file.readUint16LE();
-
- uint dataSize = _width * _height * sizeof(uint16);
- _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
- uint32 bytesRead = file.read(_surface.getPixels(), dataSize);
- assert(bytesRead == dataSize);
-
- // Convert to RGB 565
- _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
-}
-
ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName)
: _width(0),
_height(0),
@@ -72,7 +43,7 @@ ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName)
_hotspotY(0) {
Common::File file;
if (!engine->getSearchManager()->openFile(file, fileName))
- return;
+ error("Cursor file %s does not exist", fileName.c_str());
uint32 magic = file.readUint32BE();
if (magic != MKTAG('Z', 'C', 'R', '1')) {
@@ -86,12 +57,15 @@ ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName)
_height = file.readUint16LE();
uint dataSize = _width * _height * sizeof(uint16);
- _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+ _surface.create(_width, _height, engine->_resourcePixelFormat);
uint32 bytesRead = file.read(_surface.getPixels(), dataSize);
assert(bytesRead == dataSize);
- // Convert to RGB 565
- _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+#ifndef SCUMM_LITTLE_ENDIAN
+ int16 *buffer = (int16 *)_surface.getPixels();
+ for (uint32 i = 0; i < dataSize / 2; ++i)
+ buffer[i] = FROM_LE_16(buffer[i]);
+#endif
}
ZorkCursor::ZorkCursor(const ZorkCursor &other) {
diff --git a/engines/zvision/graphics/cursors/cursor.h b/engines/zvision/graphics/cursors/cursor.h
index 0c1e99411f..6e0083520a 100644
--- a/engines/zvision/graphics/cursors/cursor.h
+++ b/engines/zvision/graphics/cursors/cursor.h
@@ -39,7 +39,6 @@ namespace ZVision {
class ZorkCursor {
public:
ZorkCursor();
- ZorkCursor(const Common::String &fileName);
ZorkCursor(ZVision *engine, const Common::String &fileName);
ZorkCursor(const ZorkCursor &other);
~ZorkCursor();
diff --git a/engines/zvision/graphics/cursors/cursor_manager.cpp b/engines/zvision/graphics/cursors/cursor_manager.cpp
index 92fd461c72..eeab18f4ba 100644
--- a/engines/zvision/graphics/cursors/cursor_manager.cpp
+++ b/engines/zvision/graphics/cursors/cursor_manager.cpp
@@ -37,7 +37,7 @@ const char *CursorManager::_cursorNames[NUM_CURSORS] = { "active", "arrow", "bac
"hright", "hup", "idle", "leftarrow", "rightarrow", "suggest_surround", "suggest_tilt", "turnaround", "zuparrow"
};
-const char *CursorManager::_zgiCursorFileNames[NUM_CURSORS] = { "g0gbc011.zcr", "g0gac001.zcr", "g0gac021.zcr", "g0gac031.zcr", "g0gac041.zcr", "g0gac051.zcr", "g0gac061.zcr", "g0gac071.zcr", "g0gac081.zcr",
+const char *CursorManager::_zgiCursorFileNames[NUM_CURSORS] = { "g0gbc011.zcr", "g0gac011.zcr", "g0gac021.zcr", "g0gac031.zcr", "g0gac041.zcr", "g0gac051.zcr", "g0gac061.zcr", "g0gac071.zcr", "g0gac081.zcr",
"g0gac091.zcr", "g0gac101.zcr", "g0gac011.zcr", "g0gac111.zcr", "g0gac121.zcr", "g0gac131.zcr", "g0gac141.zcr", "g0gac151.zcr", "g0gac161.zcr"
};
@@ -45,7 +45,7 @@ const char *CursorManager::_zNemCursorFileNames[NUM_CURSORS] = { "00act", "arrow
"hright", "hup", "00idle", "left", "right", "ssurr", "stilt", "turn", "up"
};
-CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat *pixelFormat)
+CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat pixelFormat)
: _engine(engine),
_pixelFormat(pixelFormat),
_cursorIsPushed(false),
@@ -55,6 +55,11 @@ CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat *pixel
for (int i = 0; i < NUM_CURSORS; i++) {
if (_engine->getGameId() == GID_NEMESIS) {
Common::String name;
+ if (i == 1) {
+ // Cursors "arrowa.zcr" and "arrowb.zcr" are missing
+ _cursors[i][0] = _cursors[i][1] = ZorkCursor();
+ continue;
+ }
name = Common::String::format("%sa.zcr", _zNemCursorFileNames[i]);
_cursors[i][0] = ZorkCursor(_engine, name); // Up cursor
name = Common::String::format("%sb.zcr", _zNemCursorFileNames[i]);
@@ -106,7 +111,7 @@ void CursorManager::initialize() {
}
void CursorManager::changeCursor(const ZorkCursor &cursor) {
- CursorMan.replaceCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(), cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor(), false, _pixelFormat);
+ CursorMan.replaceCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(), cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor(), false, &_pixelFormat);
}
void CursorManager::cursorDown(bool pushed) {
@@ -119,31 +124,30 @@ void CursorManager::cursorDown(bool pushed) {
}
void CursorManager::changeCursor(int id) {
- int _id = id;
-
- if (_item &&
- (_id == CursorIndex_Active ||
- _id == CursorIndex_Idle ||
- _id == CursorIndex_HandPu)) {
-
- if (_id == CursorIndex_Idle)
- _id = CursorIndex_ItemIdle;
- else
- _id = CursorIndex_ItemAct;
+ if (_item && (id == CursorIndex_Active ||
+ id == CursorIndex_Idle ||
+ id == CursorIndex_HandPu)) {
+ if (id == CursorIndex_Idle) {
+ id = CursorIndex_ItemIdle;
+ } else {
+ id = CursorIndex_ItemAct;
+ }
}
- if (_currentCursor != _id ||
- ((_id == CursorIndex_ItemAct || _id == CursorIndex_ItemIdle) && _lastitem != _item)) {
- _currentCursor = _id;
+ if (_currentCursor != id || ((id == CursorIndex_ItemAct || id == CursorIndex_ItemIdle) && _lastitem != _item)) {
+ _currentCursor = id;
_lastitem = _item;
changeCursor(_cursors[_currentCursor][_cursorIsPushed]);
}
}
int CursorManager::getCursorId(const Common::String &name) {
- for (int i = 0; i < NUM_CURSORS; i++)
- if (name.equals(_cursorNames[i]))
+ for (int i = 0; i < NUM_CURSORS; i++) {
+ if (name.equals(_cursorNames[i])) {
return i;
+ }
+ }
+
return CursorIndex_Idle;
}
diff --git a/engines/zvision/graphics/cursors/cursor_manager.h b/engines/zvision/graphics/cursors/cursor_manager.h
index bbfa085c23..35c605baf8 100644
--- a/engines/zvision/graphics/cursors/cursor_manager.h
+++ b/engines/zvision/graphics/cursors/cursor_manager.h
@@ -58,7 +58,7 @@ enum CursorIndex {
*/
class CursorManager {
public:
- CursorManager(ZVision *engine, const Graphics::PixelFormat *pixelFormat);
+ CursorManager(ZVision *engine, const Graphics::PixelFormat pixelFormat);
private:
static const int NUM_CURSORS = 18;
@@ -67,7 +67,7 @@ private:
ZorkCursor _cursors[NUM_CURSORS + 2][2];
ZVision *_engine;
- const Graphics::PixelFormat *_pixelFormat;
+ const Graphics::PixelFormat _pixelFormat;
bool _cursorIsPushed;
int _item;
int _lastitem;
diff --git a/engines/zvision/graphics/effects/fog.cpp b/engines/zvision/graphics/effects/fog.cpp
index f59e82a4a0..7b65f60f24 100644
--- a/engines/zvision/graphics/effects/fog.cpp
+++ b/engines/zvision/graphics/effects/fog.cpp
@@ -31,7 +31,7 @@
namespace ZVision {
FogFx::FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::String &clouds):
- Effect(engine, key, region, ported) {
+ GraphicsEffect(engine, key, region, ported) {
_map = Map;
@@ -79,10 +79,10 @@ const Graphics::Surface *FogFx::draw(const Graphics::Surface &srcSubRect) {
if (it->inEffect) {
// Not 100% equivalent, but looks nice and not buggy
uint8 sr, sg, sb;
- _engine->_pixelFormat.colorToRGB(lineBuf[i], sr, sg, sb);
+ _engine->_resourcePixelFormat.colorToRGB(lineBuf[i], sr, sg, sb);
uint16 fogColor = *(uint16 *)_fog.getBasePtr((i + _pos) % _fog.w, j);
uint8 dr, dg, db;
- _engine->_pixelFormat.colorToRGB(_colorMap[fogColor & 0x1F], dr, dg, db);
+ _engine->_resourcePixelFormat.colorToRGB(_colorMap[fogColor & 0x1F], dr, dg, db);
uint16 fr = dr + sr;
if (fr > 255)
fr = 255;
@@ -92,7 +92,7 @@ const Graphics::Surface *FogFx::draw(const Graphics::Surface &srcSubRect) {
uint16 fb = db + sb;
if (fb > 255)
fb = 255;
- lineBuf[i] = _engine->_pixelFormat.RGBToColor(fr, fg, fb);
+ lineBuf[i] = _engine->_resourcePixelFormat.RGBToColor(fr, fg, fb);
}
cnt++;
if (cnt >= it->count) {
@@ -138,14 +138,14 @@ void FogFx::update() {
// Not 100% equivalent, but looks nice and not buggy
- _colorMap[31] = _engine->_pixelFormat.RGBToColor(_r << 3, _g << 3, _b << 3);
+ _colorMap[31] = _engine->_resourcePixelFormat.RGBToColor(_r << 3, _g << 3, _b << 3);
for (uint8 i = 0; i < 31; i++) {
float perc = (float)i / 31.0;
- uint8 cr = (float)_r * perc;
- uint8 cg = (float)_g * perc;
- uint8 cb = (float)_b * perc;
- _colorMap[i] = _engine->_pixelFormat.RGBToColor(cr << 3, cg << 3, cb << 3);
+ uint8 cr = (uint8)((float)_r * perc);
+ uint8 cg = (uint8)((float)_g * perc);
+ uint8 cb = (uint8)((float)_b * perc);
+ _colorMap[i] = _engine->_resourcePixelFormat.RGBToColor(cr << 3, cg << 3, cb << 3);
}
}
diff --git a/engines/zvision/graphics/effects/fog.h b/engines/zvision/graphics/effects/fog.h
index 45d6f9596d..498347609e 100644
--- a/engines/zvision/graphics/effects/fog.h
+++ b/engines/zvision/graphics/effects/fog.h
@@ -23,13 +23,14 @@
#ifndef ZVISION_FOG_H
#define ZVISION_FOG_H
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class FogFx : public Effect {
+// Used by Zork: Nemesis for the mixing chamber gas effect in the gas puzzle (location tt5e, when the blinds are down)
+class FogFx : public GraphicsEffect {
public:
FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::String &clouds);
diff --git a/engines/zvision/graphics/effects/light.cpp b/engines/zvision/graphics/effects/light.cpp
index 00b3811d65..39341687f8 100644
--- a/engines/zvision/graphics/effects/light.cpp
+++ b/engines/zvision/graphics/effects/light.cpp
@@ -30,7 +30,7 @@
namespace ZVision {
LightFx::LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD, int8 maxD):
- Effect(engine, key, region, ported) {
+ GraphicsEffect(engine, key, region, ported) {
_map = Map;
_delta = delta;
_up = true;
@@ -59,10 +59,10 @@ const Graphics::Surface *LightFx::draw(const Graphics::Surface &srcSubRect) {
if (_pos < 0) {
uint8 cc = ((-_pos) & 0x1F) << 3;
- dcolor = _engine->_pixelFormat.RGBToColor(cc, cc, cc);
+ dcolor = _engine->_resourcePixelFormat.RGBToColor(cc, cc, cc);
} else {
uint8 cc = (_pos & 0x1F) << 3;
- dcolor = _engine->_pixelFormat.RGBToColor(cc, cc, cc);
+ dcolor = _engine->_resourcePixelFormat.RGBToColor(cc, cc, cc);
}
for (uint16 j = 0; j < _surface.h; j++) {
diff --git a/engines/zvision/graphics/effects/light.h b/engines/zvision/graphics/effects/light.h
index ae87d66cb3..cd73a585ec 100644
--- a/engines/zvision/graphics/effects/light.h
+++ b/engines/zvision/graphics/effects/light.h
@@ -23,13 +23,13 @@
#ifndef LIGHTFX_H_INCLUDED
#define LIGHTFX_H_INCLUDED
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class LightFx : public Effect {
+class LightFx : public GraphicsEffect {
public:
LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD = -127, int8 maxD = 127);
diff --git a/engines/zvision/graphics/effects/wave.cpp b/engines/zvision/graphics/effects/wave.cpp
index 1b3aa040e8..d2887b3112 100644
--- a/engines/zvision/graphics/effects/wave.cpp
+++ b/engines/zvision/graphics/effects/wave.cpp
@@ -30,7 +30,7 @@
namespace ZVision {
WaveFx::WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd):
- Effect(engine, key, region, ported) {
+ GraphicsEffect(engine, key, region, ported) {
_frame = 0;
_frameCount = frames;
@@ -54,7 +54,7 @@ WaveFx::WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, in
int16 dx = (x - quarterWidth);
int16 dy = (y - quarterHeight);
- _ampls[i][x + y * _halfWidth] = ampl * sin(sqrt(dx * dx / (float)centerX + dy * dy / (float)centerY) / (-waveln * 3.1415926) + phase);
+ _ampls[i][x + y * _halfWidth] = (int8)(ampl * sin(sqrt(dx * dx / (float)centerX + dy * dy / (float)centerY) / (-waveln * 3.1415926) + phase));
}
phase += spd;
}
diff --git a/engines/zvision/graphics/effects/wave.h b/engines/zvision/graphics/effects/wave.h
index 2e813ed5b6..8e912372d7 100644
--- a/engines/zvision/graphics/effects/wave.h
+++ b/engines/zvision/graphics/effects/wave.h
@@ -24,13 +24,13 @@
#define WAVEFX_H_INCLUDED
#include "common/array.h"
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class WaveFx : public Effect {
+class WaveFx : public GraphicsEffect {
public:
WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd);
diff --git a/engines/zvision/graphics/effect.h b/engines/zvision/graphics/graphics_effect.h
index c6653c6037..bfa266b11d 100644
--- a/engines/zvision/graphics/effect.h
+++ b/engines/zvision/graphics/graphics_effect.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef EFFECT_H_INCLUDED
-#define EFFECT_H_INCLUDED
+#ifndef GRAPHICS_EFFECT_H_INCLUDED
+#define GRAPHICS_EFFECT_H_INCLUDED
#include "common/rect.h"
#include "common/list.h"
@@ -33,13 +33,13 @@ namespace ZVision {
class ZVision;
-class Effect {
+class GraphicsEffect {
public:
- Effect(ZVision *engine, uint32 key, Common::Rect region, bool ported) : _engine(engine), _key(key), _region(region), _ported(ported) {
- _surface.create(_region.width(), _region.height(), _engine->_pixelFormat);
+ GraphicsEffect(ZVision *engine, uint32 key, Common::Rect region, bool ported) : _engine(engine), _key(key), _region(region), _ported(ported) {
+ _surface.create(_region.width(), _region.height(), _engine->_resourcePixelFormat);
}
- virtual ~Effect() {}
+ virtual ~GraphicsEffect() {}
uint32 getKey() {
return _key;
@@ -80,4 +80,4 @@ typedef Common::List<EffectMapUnit> EffectMap;
} // End of namespace ZVision
-#endif // EFFECT_H_INCLUDED
+#endif // GRAPHICS_EFFECT_H_INCLUDED
diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp
index e2ad13a330..f978ef7844 100644
--- a/engines/zvision/graphics/render_manager.cpp
+++ b/engines/zvision/graphics/render_manager.cpp
@@ -39,71 +39,75 @@
namespace ZVision {
-RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat)
+RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat, bool doubleFPS)
: _engine(engine),
_system(engine->_system),
- _wrkWidth(workingWindow.width()),
- _wrkHeight(workingWindow.height()),
- _screenCenterX(_wrkWidth / 2),
- _screenCenterY(_wrkHeight / 2),
+ _screenCenterX(_workingWindow.width() / 2),
+ _screenCenterY(_workingWindow.height() / 2),
_workingWindow(workingWindow),
_pixelFormat(pixelFormat),
- _bkgWidth(0),
- _bkgHeight(0),
- _bkgOff(0),
- _renderTable(_wrkWidth, _wrkHeight) {
+ _backgroundWidth(0),
+ _backgroundHeight(0),
+ _backgroundOffset(0),
+ _renderTable(_workingWindow.width(), _workingWindow.height()),
+ _doubleFPS(doubleFPS),
+ _subid(0) {
- _wrkWnd.create(_wrkWidth, _wrkHeight, _pixelFormat);
- _effectWnd.create(_wrkWidth, _wrkHeight, _pixelFormat);
- _outWnd.create(_wrkWidth, _wrkHeight, _pixelFormat);
- _menuWnd.create(windowWidth, workingWindow.top, _pixelFormat);
- _subWnd.create(windowWidth, windowHeight - workingWindow.bottom, _pixelFormat);
+ _backgroundSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat);
+ _effectSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat);
+ _warpedSceneSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat);
+ _menuSurface.create(windowWidth, workingWindow.top, _pixelFormat);
- _menuWndRect = Common::Rect(0, 0, windowWidth, workingWindow.top);
- _subWndRect = Common::Rect(0, workingWindow.bottom, windowWidth, windowHeight);
+ _menuArea = Common::Rect(0, 0, windowWidth, workingWindow.top);
- _subid = 0;
+ initSubArea(windowWidth, windowHeight, workingWindow);
}
RenderManager::~RenderManager() {
- _curBkg.free();
- _wrkWnd.free();
- _effectWnd.free();
- _outWnd.free();
- _menuWnd.free();
- _subWnd.free();
+ _currentBackgroundImage.free();
+ _backgroundSurface.free();
+ _effectSurface.free();
+ _warpedSceneSurface.free();
+ _menuSurface.free();
+ _subtitleSurface.free();
}
-void RenderManager::renderBackbufferToScreen() {
- Graphics::Surface *out = &_outWnd;
- Graphics::Surface *in = &_wrkWnd;
+void RenderManager::renderSceneToScreen() {
+ Graphics::Surface *out = &_warpedSceneSurface;
+ Graphics::Surface *in = &_backgroundSurface;
Common::Rect outWndDirtyRect;
+ // If we have graphical effects, we apply them using a temporary buffer
if (!_effects.empty()) {
bool copied = false;
- Common::Rect windRect(_wrkWidth, _wrkHeight);
- for (effectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
+ Common::Rect windowRect(_workingWindow.width(), _workingWindow.height());
+
+ for (EffectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
Common::Rect rect = (*it)->getRegion();
- Common::Rect scrPlace = rect;
- if ((*it)->isPort())
- scrPlace = bkgRectToScreen(scrPlace);
- if (windRect.intersects(scrPlace)) {
+ Common::Rect screenSpaceLocation = rect;
+
+ if ((*it)->isPort()) {
+ screenSpaceLocation = transformBackgroundSpaceRectToScreenSpace(screenSpaceLocation);
+ }
+
+ if (windowRect.intersects(screenSpaceLocation)) {
if (!copied) {
copied = true;
- _effectWnd.copyFrom(_wrkWnd);
- in = &_effectWnd;
+ _effectSurface.copyFrom(_backgroundSurface);
+ in = &_effectSurface;
}
const Graphics::Surface *post;
if ((*it)->isPort())
- post = (*it)->draw(_curBkg.getSubArea(rect));
+ post = (*it)->draw(_currentBackgroundImage.getSubArea(rect));
else
- post = (*it)->draw(_effectWnd.getSubArea(rect));
- blitSurfaceToSurface(*post, _effectWnd, scrPlace.left, scrPlace.top);
- scrPlace.clip(windRect);
- if (_wrkWndDirtyRect .isEmpty()) {
- _wrkWndDirtyRect = scrPlace;
+ post = (*it)->draw(_effectSurface.getSubArea(rect));
+ Common::Rect empty;
+ blitSurfaceToSurface(*post, empty, _effectSurface, screenSpaceLocation.left, screenSpaceLocation.top);
+ screenSpaceLocation.clip(windowRect);
+ if (_backgroundSurfaceDirtyRect .isEmpty()) {
+ _backgroundSurfaceDirtyRect = screenSpaceLocation;
} else {
- _wrkWndDirtyRect.extend(scrPlace);
+ _backgroundSurfaceDirtyRect.extend(screenSpaceLocation);
}
}
}
@@ -111,25 +115,40 @@ void RenderManager::renderBackbufferToScreen() {
RenderTable::RenderState state = _renderTable.getRenderState();
if (state == RenderTable::PANORAMA || state == RenderTable::TILT) {
- if (!_wrkWndDirtyRect.isEmpty()) {
- _renderTable.mutateImage(&_outWnd, in);
- out = &_outWnd;
- outWndDirtyRect = Common::Rect(_wrkWidth, _wrkHeight);
+ if (!_backgroundSurfaceDirtyRect.isEmpty()) {
+ _renderTable.mutateImage(&_warpedSceneSurface, in);
+ out = &_warpedSceneSurface;
+ outWndDirtyRect = Common::Rect(_workingWindow.width(), _workingWindow.height());
}
} else {
out = in;
- outWndDirtyRect = _wrkWndDirtyRect;
+ outWndDirtyRect = _backgroundSurfaceDirtyRect;
}
if (!outWndDirtyRect.isEmpty()) {
- _system->copyRectToScreen(out->getBasePtr(outWndDirtyRect.left, outWndDirtyRect.top), out->pitch,
- outWndDirtyRect.left + _workingWindow.left,
- outWndDirtyRect.top + _workingWindow.top,
- outWndDirtyRect.width(),
- outWndDirtyRect.height());
+ Common::Rect rect(
+ outWndDirtyRect.left + _workingWindow.left,
+ outWndDirtyRect.top + _workingWindow.top,
+ outWndDirtyRect.left + _workingWindow.left + outWndDirtyRect.width(),
+ outWndDirtyRect.top + _workingWindow.top + outWndDirtyRect.height()
+ );
+ copyToScreen(*out, rect, outWndDirtyRect.left, outWndDirtyRect.top);
}
}
+void RenderManager::copyToScreen(const Graphics::Surface &surface, Common::Rect &rect, int16 srcLeft, int16 srcTop) {
+ // Convert the surface to RGB565, if needed
+ Graphics::Surface *outSurface = surface.convertTo(_engine->_screenPixelFormat);
+ _system->copyRectToScreen(outSurface->getBasePtr(srcLeft, srcTop),
+ outSurface->pitch,
+ rect.left,
+ rect.top,
+ rect.width(),
+ rect.height());
+ outSurface->free();
+ delete outSurface;
+}
+
void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY) {
Graphics::Surface surface;
readImageToSurface(fileName, surface);
@@ -157,97 +176,8 @@ void RenderManager::renderImageToBackground(const Common::String &fileName, int1
}
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) {
- Common::File file;
-
- if (!_engine->getSearchManager()->openFile(file, fileName)) {
- warning("Could not open file %s", fileName.c_str());
- return;
- }
-
- // Read the magic number
- // Some files are true TGA, while others are TGZ
- uint32 fileType = file.readUint32BE();
-
- uint32 imageWidth;
- uint32 imageHeight;
- Image::TGADecoder tga;
- uint16 *buffer;
bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA;
- // All ZVision images are in RGB 555
- Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
- destination.format = pixelFormat555;
-
- bool isTGZ;
-
- // Check for TGZ files
- if (fileType == MKTAG('T', 'G', 'Z', '\0')) {
- isTGZ = true;
-
- // TGZ files have a header and then Bitmap data that is compressed with LZSS
- uint32 decompressedSize = file.readSint32LE();
- imageWidth = file.readSint32LE();
- imageHeight = file.readSint32LE();
-
- LzssReadStream lzssStream(&file);
- buffer = (uint16 *)(new uint16[decompressedSize]);
- lzssStream.read(buffer, decompressedSize);
- } else {
- isTGZ = false;
-
- // Reset the cursor
- file.seek(0);
-
- // Decode
- if (!tga.loadStream(file)) {
- warning("Error while reading TGA image");
- return;
- }
-
- Graphics::Surface tgaSurface = *(tga.getSurface());
- imageWidth = tgaSurface.w;
- imageHeight = tgaSurface.h;
-
- buffer = (uint16 *)tgaSurface.getPixels();
- }
-
- // Flip the width and height if transposed
- if (isTransposed) {
- uint16 temp = imageHeight;
- imageHeight = imageWidth;
- imageWidth = temp;
- }
-
- // If the destination internal buffer is the same size as what we're copying into it,
- // there is no need to free() and re-create
- if (imageWidth != destination.w || imageHeight != destination.h) {
- destination.create(imageWidth, imageHeight, pixelFormat555);
- }
-
- // If transposed, 'un-transpose' the data while copying it to the destination
- // Otherwise, just do a simple copy
- if (isTransposed) {
- uint16 *dest = (uint16 *)destination.getPixels();
-
- for (uint32 y = 0; y < imageHeight; ++y) {
- uint32 columnIndex = y * imageWidth;
-
- for (uint32 x = 0; x < imageWidth; ++x) {
- dest[columnIndex + x] = buffer[x * imageHeight + y];
- }
- }
- } else {
- memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel);
- }
-
- // Cleanup
- if (isTGZ) {
- delete[] buffer;
- } else {
- tga.destroy();
- }
-
- // Convert in place to RGB 565 from RGB 555
- destination.convertToInPlace(_pixelFormat);
+ readImageToSurface(fileName, destination, isTransposed);
}
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed) {
@@ -266,9 +196,8 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
uint32 imageHeight;
Image::TGADecoder tga;
uint16 *buffer;
- // All ZVision images are in RGB 555
- Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
- destination.format = pixelFormat555;
+ // All Z-Vision images are in RGB 555
+ destination.format = _engine->_resourcePixelFormat;
bool isTGZ;
@@ -277,13 +206,17 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
isTGZ = true;
// TGZ files have a header and then Bitmap data that is compressed with LZSS
- uint32 decompressedSize = file.readSint32LE();
+ uint32 decompressedSize = file.readSint32LE() / 2;
imageWidth = file.readSint32LE();
imageHeight = file.readSint32LE();
LzssReadStream lzssStream(&file);
buffer = (uint16 *)(new uint16[decompressedSize]);
- lzssStream.read(buffer, decompressedSize);
+ lzssStream.read(buffer, 2 * decompressedSize);
+#ifndef SCUMM_LITTLE_ENDIAN
+ for (uint32 i = 0; i < decompressedSize; ++i)
+ buffer[i] = FROM_LE_16(buffer[i]);
+#endif
} else {
isTGZ = false;
@@ -313,7 +246,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
// If the destination internal buffer is the same size as what we're copying into it,
// there is no need to free() and re-create
if (imageWidth != destination.w || imageHeight != destination.h) {
- destination.create(imageWidth, imageHeight, pixelFormat555);
+ destination.create(imageWidth, imageHeight, _engine->_resourcePixelFormat);
}
// If transposed, 'un-transpose' the data while copying it to the destination
@@ -329,7 +262,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
}
}
} else {
- memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel);
+ memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * destination.format.bytesPerPixel);
}
// Cleanup
@@ -338,9 +271,6 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
} else {
tga.destroy();
}
-
- // Convert in place to RGB 565 from RGB 555
- destination.convertToInPlace(_pixelFormat);
}
const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &point) {
@@ -354,20 +284,20 @@ const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &
}
if (state == RenderTable::PANORAMA) {
- newPoint += (Common::Point(_bkgOff - _screenCenterX, 0));
+ newPoint += (Common::Point(_backgroundOffset - _screenCenterX, 0));
} else if (state == RenderTable::TILT) {
- newPoint += (Common::Point(0, _bkgOff - _screenCenterY));
+ newPoint += (Common::Point(0, _backgroundOffset - _screenCenterY));
}
- if (_bkgWidth)
- newPoint.x %= _bkgWidth;
- if (_bkgHeight)
- newPoint.y %= _bkgHeight;
+ if (_backgroundWidth)
+ newPoint.x %= _backgroundWidth;
+ if (_backgroundHeight)
+ newPoint.y %= _backgroundHeight;
if (newPoint.x < 0)
- newPoint.x += _bkgWidth;
+ newPoint.x += _backgroundWidth;
if (newPoint.y < 0)
- newPoint.y += _bkgHeight;
+ newPoint.y += _backgroundHeight;
return newPoint;
} else {
@@ -380,18 +310,18 @@ RenderTable *RenderManager::getRenderTable() {
}
void RenderManager::setBackgroundImage(const Common::String &fileName) {
- readImageToSurface(fileName, _curBkg);
- _bkgWidth = _curBkg.w;
- _bkgHeight = _curBkg.h;
- _bkgDirtyRect = Common::Rect(_bkgWidth, _bkgHeight);
+ readImageToSurface(fileName, _currentBackgroundImage);
+ _backgroundWidth = _currentBackgroundImage.w;
+ _backgroundHeight = _currentBackgroundImage.h;
+ _backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
}
void RenderManager::setBackgroundPosition(int offset) {
RenderTable::RenderState state = _renderTable.getRenderState();
if (state == RenderTable::TILT || state == RenderTable::PANORAMA)
- if (_bkgOff != offset)
- _bkgDirtyRect = Common::Rect(_bkgWidth, _bkgHeight);
- _bkgOff = offset;
+ if (_backgroundOffset != offset)
+ _backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
+ _backgroundOffset = offset;
_engine->getScriptManager()->setStateValue(StateKey_ViewPos, offset);
}
@@ -400,9 +330,9 @@ uint32 RenderManager::getCurrentBackgroundOffset() {
RenderTable::RenderState state = _renderTable.getRenderState();
if (state == RenderTable::PANORAMA) {
- return _bkgOff;
+ return _backgroundOffset;
} else if (state == RenderTable::TILT) {
- return _bkgOff;
+ return _backgroundOffset;
} else {
return 0;
}
@@ -454,10 +384,6 @@ void RenderManager::scaleBuffer(const void *src, void *dst, uint32 srcWidth, uin
}
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y) {
-
- if (src.format != dst.format)
- return;
-
Common::Rect srcRect = _srcRect;
if (srcRect.isEmpty())
srcRect = Common::Rect(src.w, src.h);
@@ -468,8 +394,10 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (srcRect.isEmpty() || !srcRect.isValidRect())
return;
+ Graphics::Surface *srcAdapted = src.convertTo(dst.format);
+
// Copy srcRect from src surface to dst surface
- const byte *srcBuffer = (const byte *)src.getBasePtr(srcRect.left, srcRect.top);
+ const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);
int xx = _x;
int yy = _y;
@@ -479,8 +407,11 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (yy < 0)
yy = 0;
- if (_x >= dst.w || _y >= dst.h)
+ if (_x >= dst.w || _y >= dst.h) {
+ srcAdapted->free();
+ delete srcAdapted;
return;
+ }
byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);
@@ -488,17 +419,16 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
int32 h = srcRect.height();
for (int32 y = 0; y < h; y++) {
- memcpy(dstBuffer, srcBuffer, w * src.format.bytesPerPixel);
- srcBuffer += src.pitch;
+ memcpy(dstBuffer, srcBuffer, w * srcAdapted->format.bytesPerPixel);
+ srcBuffer += srcAdapted->pitch;
dstBuffer += dst.pitch;
}
+
+ srcAdapted->free();
+ delete srcAdapted;
}
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey) {
-
- if (src.format != dst.format)
- return;
-
Common::Rect srcRect = _srcRect;
if (srcRect.isEmpty())
srcRect = Common::Rect(src.w, src.h);
@@ -509,10 +439,11 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (srcRect.isEmpty() || !srcRect.isValidRect())
return;
- uint32 _keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);
+ Graphics::Surface *srcAdapted = src.convertTo(dst.format);
+ uint32 keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);
// Copy srcRect from src surface to dst surface
- const byte *srcBuffer = (const byte *)src.getBasePtr(srcRect.left, srcRect.top);
+ const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);
int xx = _x;
int yy = _y;
@@ -522,8 +453,11 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
if (yy < 0)
yy = 0;
- if (_x >= dst.w || _y >= dst.h)
+ if (_x >= dst.w || _y >= dst.h) {
+ srcAdapted->free();
+ delete srcAdapted;
return;
+ }
byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);
@@ -531,12 +465,12 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
int32 h = srcRect.height();
for (int32 y = 0; y < h; y++) {
- switch (src.format.bytesPerPixel) {
+ switch (srcAdapted->format.bytesPerPixel) {
case 1: {
const uint *srcTemp = (const uint *)srcBuffer;
uint *dstTemp = (uint *)dstBuffer;
for (int32 x = 0; x < w; x++) {
- if (*srcTemp != _keycolor)
+ if (*srcTemp != keycolor)
*dstTemp = *srcTemp;
srcTemp++;
dstTemp++;
@@ -548,7 +482,7 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
const uint16 *srcTemp = (const uint16 *)srcBuffer;
uint16 *dstTemp = (uint16 *)dstBuffer;
for (int32 x = 0; x < w; x++) {
- if (*srcTemp != _keycolor)
+ if (*srcTemp != keycolor)
*dstTemp = *srcTemp;
srcTemp++;
dstTemp++;
@@ -560,7 +494,7 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
const uint32 *srcTemp = (const uint32 *)srcBuffer;
uint32 *dstTemp = (uint32 *)dstBuffer;
for (int32 x = 0; x < w; x++) {
- if (*srcTemp != _keycolor)
+ if (*srcTemp != keycolor)
*dstTemp = *srcTemp;
srcTemp++;
dstTemp++;
@@ -571,60 +505,32 @@ void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Com
default:
break;
}
- srcBuffer += src.pitch;
+ srcBuffer += srcAdapted->pitch;
dstBuffer += dst.pitch;
}
-}
-void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, dst, x, y);
+ srcAdapted->free();
+ delete srcAdapted;
}
-void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y, uint32 colorkey) {
+void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, int32 colorkey) {
Common::Rect empt;
- blitSurfaceToSurface(src, empt, dst, x, y, colorkey);
-}
-
-void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, _curBkg, x, y);
- Common::Rect dirty(src.w, src.h);
- dirty.translate(x, y);
- if (_bkgDirtyRect.isEmpty())
- _bkgDirtyRect = dirty;
+ if (colorkey >= 0)
+ blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y, colorkey);
else
- _bkgDirtyRect.extend(dirty);
-}
-
-void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, uint32 colorkey) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, _curBkg, x, y, colorkey);
+ blitSurfaceToSurface(src, empt, _currentBackgroundImage, x, y);
Common::Rect dirty(src.w, src.h);
dirty.translate(x, y);
- if (_bkgDirtyRect.isEmpty())
- _bkgDirtyRect = dirty;
+ if (_backgroundDirtyRect.isEmpty())
+ _backgroundDirtyRect = dirty;
else
- _bkgDirtyRect.extend(dirty);
-}
-
-void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect) {
- if (src.w == _dstRect.width() && src.h == _dstRect.height())
- blitSurfaceToBkg(src, _dstRect.left, _dstRect.top);
- else {
- Graphics::Surface *tmp = new Graphics::Surface;
- tmp->create(_dstRect.width(), _dstRect.height(), src.format);
- scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height());
- blitSurfaceToBkg(*tmp, _dstRect.left, _dstRect.top);
- tmp->free();
- delete tmp;
- }
+ _backgroundDirtyRect.extend(dirty);
}
-void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, uint32 colorkey) {
- if (src.w == _dstRect.width() && src.h == _dstRect.height())
+void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, int32 colorkey) {
+ if (src.w == _dstRect.width() && src.h == _dstRect.height()) {
blitSurfaceToBkg(src, _dstRect.left, _dstRect.top, colorkey);
- else {
+ } else {
Graphics::Surface *tmp = new Graphics::Surface;
tmp->create(_dstRect.width(), _dstRect.height(), src.format);
scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height());
@@ -634,160 +540,163 @@ void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const C
}
}
-void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y) {
+void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, int32 colorkey) {
Common::Rect empt;
- blitSurfaceToSurface(src, empt, _menuWnd, x, y);
- Common::Rect dirty(src.w, src.h);
- dirty.translate(x, y);
- if (_menuWndDirtyRect.isEmpty())
- _menuWndDirtyRect = dirty;
+ if (colorkey >= 0)
+ blitSurfaceToSurface(src, empt, _menuSurface, x, y, colorkey);
else
- _menuWndDirtyRect.extend(dirty);
-}
-
-void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, uint32 colorkey) {
- Common::Rect empt;
- blitSurfaceToSurface(src, empt, _menuWnd, x, y, colorkey);
+ blitSurfaceToSurface(src, empt, _menuSurface, x, y);
Common::Rect dirty(src.w, src.h);
dirty.translate(x, y);
- if (_menuWndDirtyRect.isEmpty())
- _menuWndDirtyRect = dirty;
+ if (_menuSurfaceDirtyRect.isEmpty())
+ _menuSurfaceDirtyRect = dirty;
else
- _menuWndDirtyRect.extend(dirty);
+ _menuSurfaceDirtyRect.extend(dirty);
}
Graphics::Surface *RenderManager::getBkgRect(Common::Rect &rect) {
Common::Rect dst = rect;
- dst.clip(_bkgWidth, _bkgHeight);
+ dst.clip(_backgroundWidth, _backgroundHeight);
if (dst.isEmpty() || !dst.isValidRect())
return NULL;
Graphics::Surface *srf = new Graphics::Surface;
- srf->create(dst.width(), dst.height(), _curBkg.format);
+ srf->create(dst.width(), dst.height(), _currentBackgroundImage.format);
- srf->copyRectToSurface(_curBkg, 0, 0, Common::Rect(dst));
+ srf->copyRectToSurface(_currentBackgroundImage, 0, 0, Common::Rect(dst));
return srf;
}
-Graphics::Surface *RenderManager::loadImage(Common::String &file) {
+Graphics::Surface *RenderManager::loadImage(Common::String file) {
Graphics::Surface *tmp = new Graphics::Surface;
readImageToSurface(file, *tmp);
return tmp;
}
-Graphics::Surface *RenderManager::loadImage(const char *file) {
- Common::String str = Common::String(file);
- return loadImage(str);
-}
-
-Graphics::Surface *RenderManager::loadImage(Common::String &file, bool transposed) {
+Graphics::Surface *RenderManager::loadImage(Common::String file, bool transposed) {
Graphics::Surface *tmp = new Graphics::Surface;
readImageToSurface(file, *tmp, transposed);
return tmp;
}
-Graphics::Surface *RenderManager::loadImage(const char *file, bool transposed) {
- Common::String str = Common::String(file);
- return loadImage(str, transposed);
-}
-
-void RenderManager::prepareBkg() {
- _bkgDirtyRect.clip(_bkgWidth, _bkgHeight);
+void RenderManager::prepareBackground() {
+ _backgroundDirtyRect.clip(_backgroundWidth, _backgroundHeight);
RenderTable::RenderState state = _renderTable.getRenderState();
if (state == RenderTable::PANORAMA) {
- Common::Rect viewPort(_wrkWidth, _wrkHeight);
- viewPort.translate(-(_screenCenterX - _bkgOff), 0);
- Common::Rect drawRect = _bkgDirtyRect;
+ // Calculate the visible portion of the background
+ Common::Rect viewPort(_workingWindow.width(), _workingWindow.height());
+ viewPort.translate(-(_screenCenterX - _backgroundOffset), 0);
+ Common::Rect drawRect = _backgroundDirtyRect;
drawRect.clip(viewPort);
- if (!drawRect.isEmpty())
- blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, _screenCenterX - _bkgOff + drawRect.left, drawRect.top);
+ // Render the visible portion
+ if (!drawRect.isEmpty()) {
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - _backgroundOffset + drawRect.left, drawRect.top);
+ }
- _wrkWndDirtyRect = _bkgDirtyRect;
- _wrkWndDirtyRect.translate(_screenCenterX - _bkgOff, 0);
+ // Mark the dirty portion of the surface
+ _backgroundSurfaceDirtyRect = _backgroundDirtyRect;
+ _backgroundSurfaceDirtyRect.translate(_screenCenterX - _backgroundOffset, 0);
- if (_bkgOff < _screenCenterX) {
- viewPort.moveTo(-(_screenCenterX - (_bkgOff + _bkgWidth)), 0);
- drawRect = _bkgDirtyRect;
+ // Panorama mode allows the user to spin in circles. Therefore, we need to render
+ // the portion of the image that wrapped to the other side of the screen
+ if (_backgroundOffset < _screenCenterX) {
+ viewPort.moveTo(-(_screenCenterX - (_backgroundOffset + _backgroundWidth)), 0);
+ drawRect = _backgroundDirtyRect;
drawRect.clip(viewPort);
if (!drawRect.isEmpty())
- blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, _screenCenterX - (_bkgOff + _bkgWidth) + drawRect.left, drawRect.top);
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - (_backgroundOffset + _backgroundWidth) + drawRect.left, drawRect.top);
- Common::Rect tmp = _bkgDirtyRect;
- tmp.translate(_screenCenterX - (_bkgOff + _bkgWidth), 0);
+ Common::Rect tmp = _backgroundDirtyRect;
+ tmp.translate(_screenCenterX - (_backgroundOffset + _backgroundWidth), 0);
if (!tmp.isEmpty())
- _wrkWndDirtyRect.extend(tmp);
+ _backgroundSurfaceDirtyRect.extend(tmp);
- } else if (_bkgWidth - _bkgOff < _screenCenterX) {
- viewPort.moveTo(-(_screenCenterX + _bkgWidth - _bkgOff), 0);
- drawRect = _bkgDirtyRect;
+ } else if (_backgroundWidth - _backgroundOffset < _screenCenterX) {
+ viewPort.moveTo(-(_screenCenterX + _backgroundWidth - _backgroundOffset), 0);
+ drawRect = _backgroundDirtyRect;
drawRect.clip(viewPort);
if (!drawRect.isEmpty())
- blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, _screenCenterX + _bkgWidth - _bkgOff + drawRect.left, drawRect.top);
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX + _backgroundWidth - _backgroundOffset + drawRect.left, drawRect.top);
- Common::Rect tmp = _bkgDirtyRect;
- tmp.translate(_screenCenterX + _bkgWidth - _bkgOff, 0);
+ Common::Rect tmp = _backgroundDirtyRect;
+ tmp.translate(_screenCenterX + _backgroundWidth - _backgroundOffset, 0);
if (!tmp.isEmpty())
- _wrkWndDirtyRect.extend(tmp);
+ _backgroundSurfaceDirtyRect.extend(tmp);
}
} else if (state == RenderTable::TILT) {
- Common::Rect viewPort(_wrkWidth, _wrkHeight);
- viewPort.translate(0, -(_screenCenterY - _bkgOff));
- Common::Rect drawRect = _bkgDirtyRect;
+ // Tilt doesn't allow wrapping, so we just do a simple clip
+ Common::Rect viewPort(_workingWindow.width(), _workingWindow.height());
+ viewPort.translate(0, -(_screenCenterY - _backgroundOffset));
+ Common::Rect drawRect = _backgroundDirtyRect;
drawRect.clip(viewPort);
if (!drawRect.isEmpty())
- blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, drawRect.left, _screenCenterY - _bkgOff + drawRect.top);
+ blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, drawRect.left, _screenCenterY - _backgroundOffset + drawRect.top);
- _wrkWndDirtyRect = _bkgDirtyRect;
- _wrkWndDirtyRect.translate(0, _screenCenterY - _bkgOff);
+ // Mark the dirty portion of the surface
+ _backgroundSurfaceDirtyRect = _backgroundDirtyRect;
+ _backgroundSurfaceDirtyRect.translate(0, _screenCenterY - _backgroundOffset);
} else {
- if (!_bkgDirtyRect.isEmpty())
- blitSurfaceToSurface(_curBkg, _bkgDirtyRect, _wrkWnd, _bkgDirtyRect.left, _bkgDirtyRect.top);
- _wrkWndDirtyRect = _bkgDirtyRect;
+ if (!_backgroundDirtyRect.isEmpty())
+ blitSurfaceToSurface(_currentBackgroundImage, _backgroundDirtyRect, _backgroundSurface, _backgroundDirtyRect.left, _backgroundDirtyRect.top);
+ _backgroundSurfaceDirtyRect = _backgroundDirtyRect;
}
- _bkgDirtyRect = Common::Rect();
+ // Clear the dirty rect since everything is clean now
+ _backgroundDirtyRect = Common::Rect();
- _wrkWndDirtyRect.clip(_wrkWidth, _wrkHeight);
+ _backgroundSurfaceDirtyRect.clip(_workingWindow.width(), _workingWindow.height());
}
void RenderManager::clearMenuSurface() {
- _menuWndDirtyRect = Common::Rect(0, 0, _menuWnd.w, _menuWnd.h);
- _menuWnd.fillRect(_menuWndDirtyRect, 0);
+ _menuSurfaceDirtyRect = Common::Rect(0, 0, _menuSurface.w, _menuSurface.h);
+ _menuSurface.fillRect(_menuSurfaceDirtyRect, 0);
}
void RenderManager::clearMenuSurface(const Common::Rect &r) {
- if (_menuWndDirtyRect.isEmpty())
- _menuWndDirtyRect = r;
+ if (_menuSurfaceDirtyRect.isEmpty())
+ _menuSurfaceDirtyRect = r;
else
- _menuWndDirtyRect.extend(r);
- _menuWnd.fillRect(r, 0);
+ _menuSurfaceDirtyRect.extend(r);
+ _menuSurface.fillRect(r, 0);
}
void RenderManager::renderMenuToScreen() {
- if (!_menuWndDirtyRect.isEmpty()) {
- _menuWndDirtyRect.clip(Common::Rect(_menuWnd.w, _menuWnd.h));
- if (!_menuWndDirtyRect.isEmpty())
- _system->copyRectToScreen(_menuWnd.getBasePtr(_menuWndDirtyRect.left, _menuWndDirtyRect.top), _menuWnd.pitch,
- _menuWndDirtyRect.left + _menuWndRect.left,
- _menuWndDirtyRect.top + _menuWndRect.top,
- _menuWndDirtyRect.width(),
- _menuWndDirtyRect.height());
- _menuWndDirtyRect = Common::Rect();
+ if (!_menuSurfaceDirtyRect.isEmpty()) {
+ _menuSurfaceDirtyRect.clip(Common::Rect(_menuSurface.w, _menuSurface.h));
+ if (!_menuSurfaceDirtyRect.isEmpty()) {
+ Common::Rect rect(
+ _menuSurfaceDirtyRect.left + _menuArea.left,
+ _menuSurfaceDirtyRect.top + _menuArea.top,
+ _menuSurfaceDirtyRect.left + _menuArea.left + _menuSurfaceDirtyRect.width(),
+ _menuSurfaceDirtyRect.top + _menuArea.top + _menuSurfaceDirtyRect.height()
+ );
+ copyToScreen(_menuSurface, rect, _menuSurfaceDirtyRect.left, _menuSurfaceDirtyRect.top);
+ }
+ _menuSurfaceDirtyRect = Common::Rect();
}
}
+void RenderManager::initSubArea(uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow) {
+ _workingWindow = workingWindow;
+
+ _subtitleSurface.free();
+
+ _subtitleSurface.create(windowWidth, windowHeight - workingWindow.bottom, _pixelFormat);
+ _subtitleArea = Common::Rect(0, workingWindow.bottom, windowWidth, windowHeight);
+}
+
uint16 RenderManager::createSubArea(const Common::Rect &area) {
_subid++;
- oneSub sub;
+ OneSubtitle sub;
sub.redraw = false;
sub.timer = -1;
sub.todelete = false;
@@ -799,18 +708,9 @@ uint16 RenderManager::createSubArea(const Common::Rect &area) {
}
uint16 RenderManager::createSubArea() {
- _subid++;
-
- oneSub sub;
- sub.redraw = false;
- sub.timer = -1;
- sub.todelete = false;
- sub.r = Common::Rect(_subWndRect.left, _subWndRect.top, _subWndRect.right, _subWndRect.bottom);
- sub.r.translate(-_workingWindow.left, -_workingWindow.top);
-
- _subsList[_subid] = sub;
-
- return _subid;
+ Common::Rect r(_subtitleArea.left, _subtitleArea.top, _subtitleArea.right, _subtitleArea.bottom);
+ r.translate(-_workingWindow.left, -_workingWindow.top);
+ return createSubArea(r);
}
void RenderManager::deleteSubArea(uint16 id) {
@@ -825,7 +725,7 @@ void RenderManager::deleteSubArea(uint16 id, int16 delay) {
void RenderManager::updateSubArea(uint16 id, const Common::String &txt) {
if (_subsList.contains(id)) {
- oneSub *sub = &_subsList[id];
+ OneSubtitle *sub = &_subsList[id];
sub->txt = txt;
sub->redraw = true;
}
@@ -833,7 +733,7 @@ void RenderManager::updateSubArea(uint16 id, const Common::String &txt) {
void RenderManager::processSubs(uint16 deltatime) {
bool redraw = false;
- for (subMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) {
+ for (SubtitleMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) {
if (it->_value.timer != -1) {
it->_value.timer -= deltatime;
if (it->_value.timer <= 0)
@@ -848,39 +748,41 @@ void RenderManager::processSubs(uint16 deltatime) {
}
if (redraw) {
- _subWnd.fillRect(Common::Rect(_subWnd.w, _subWnd.h), 0);
+ _subtitleSurface.fillRect(Common::Rect(_subtitleSurface.w, _subtitleSurface.h), 0);
- for (subMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) {
- oneSub *sub = &it->_value;
+ for (SubtitleMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) {
+ OneSubtitle *sub = &it->_value;
if (sub->txt.size()) {
- Graphics::Surface *rndr = new Graphics::Surface();
- rndr->create(sub->r.width(), sub->r.height(), _pixelFormat);
- _engine->getTextRenderer()->drawTxtInOneLine(sub->txt, *rndr);
- blitSurfaceToSurface(*rndr, _subWnd, sub->r.left - _subWndRect.left + _workingWindow.left, sub->r.top - _subWndRect.top + _workingWindow.top);
- rndr->free();
- delete rndr;
+ Graphics::Surface subtitleSurface;
+ subtitleSurface.create(sub->r.width(), sub->r.height(), _engine->_resourcePixelFormat);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(sub->txt, subtitleSurface);
+ Common::Rect empty;
+ blitSurfaceToSurface(subtitleSurface, empty, _subtitleSurface, sub->r.left - _subtitleArea.left + _workingWindow.left, sub->r.top - _subtitleArea.top + _workingWindow.top);
+ subtitleSurface.free();
}
sub->redraw = false;
}
- _system->copyRectToScreen(_subWnd.getPixels(), _subWnd.pitch,
- _subWndRect.left,
- _subWndRect.top,
- _subWnd.w,
- _subWnd.h);
+ Common::Rect rect(
+ _subtitleArea.left,
+ _subtitleArea.top,
+ _subtitleArea.left + _subtitleSurface.w,
+ _subtitleArea.top + _subtitleSurface.h
+ );
+ copyToScreen(_subtitleSurface, rect, 0, 0);
}
}
Common::Point RenderManager::getBkgSize() {
- return Common::Point(_bkgWidth, _bkgHeight);
+ return Common::Point(_backgroundWidth, _backgroundHeight);
}
-void RenderManager::addEffect(Effect *_effect) {
+void RenderManager::addEffect(GraphicsEffect *_effect) {
_effects.push_back(_effect);
}
void RenderManager::deleteEffect(uint32 ID) {
- for (effectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
+ for (EffectsList::iterator it = _effects.begin(); it != _effects.end(); it++) {
if ((*it)->getKey() == ID) {
delete *it;
it = _effects.erase(it);
@@ -888,54 +790,54 @@ void RenderManager::deleteEffect(uint32 ID) {
}
}
-Common::Rect RenderManager::bkgRectToScreen(const Common::Rect &src) {
+Common::Rect RenderManager::transformBackgroundSpaceRectToScreenSpace(const Common::Rect &src) {
Common::Rect tmp = src;
RenderTable::RenderState state = _renderTable.getRenderState();
if (state == RenderTable::PANORAMA) {
- if (_bkgOff < _screenCenterX) {
- Common::Rect rScreen(_screenCenterX + _bkgOff, _wrkHeight);
- Common::Rect lScreen(_wrkWidth - rScreen.width(), _wrkHeight);
- lScreen.translate(_bkgWidth - lScreen.width(), 0);
+ if (_backgroundOffset < _screenCenterX) {
+ Common::Rect rScreen(_screenCenterX + _backgroundOffset, _workingWindow.height());
+ Common::Rect lScreen(_workingWindow.width() - rScreen.width(), _workingWindow.height());
+ lScreen.translate(_backgroundWidth - lScreen.width(), 0);
lScreen.clip(src);
rScreen.clip(src);
if (rScreen.width() < lScreen.width()) {
- tmp.translate(_screenCenterX - _bkgOff - _bkgWidth, 0);
+ tmp.translate(_screenCenterX - _backgroundOffset - _backgroundWidth, 0);
} else {
- tmp.translate(_screenCenterX - _bkgOff, 0);
+ tmp.translate(_screenCenterX - _backgroundOffset, 0);
}
- } else if (_bkgWidth - _bkgOff < _screenCenterX) {
- Common::Rect rScreen(_screenCenterX - (_bkgWidth - _bkgOff), _wrkHeight);
- Common::Rect lScreen(_wrkWidth - rScreen.width(), _wrkHeight);
- lScreen.translate(_bkgWidth - lScreen.width(), 0);
+ } else if (_backgroundWidth - _backgroundOffset < _screenCenterX) {
+ Common::Rect rScreen(_screenCenterX - (_backgroundWidth - _backgroundOffset), _workingWindow.height());
+ Common::Rect lScreen(_workingWindow.width() - rScreen.width(), _workingWindow.height());
+ lScreen.translate(_backgroundWidth - lScreen.width(), 0);
lScreen.clip(src);
rScreen.clip(src);
if (lScreen.width() < rScreen.width()) {
- tmp.translate(_screenCenterX + (_bkgWidth - _bkgOff), 0);
+ tmp.translate(_screenCenterX + (_backgroundWidth - _backgroundOffset), 0);
} else {
- tmp.translate(_screenCenterX - _bkgOff, 0);
+ tmp.translate(_screenCenterX - _backgroundOffset, 0);
}
} else {
- tmp.translate(_screenCenterX - _bkgOff, 0);
+ tmp.translate(_screenCenterX - _backgroundOffset, 0);
}
} else if (state == RenderTable::TILT) {
- tmp.translate(0, (_screenCenterY - _bkgOff));
+ tmp.translate(0, (_screenCenterY - _backgroundOffset));
}
return tmp;
}
EffectMap *RenderManager::makeEffectMap(const Common::Point &xy, int16 depth, const Common::Rect &rect, int8 *_minComp, int8 *_maxComp) {
- Common::Rect bkgRect(_bkgWidth, _bkgHeight);
+ Common::Rect bkgRect(_backgroundWidth, _backgroundHeight);
if (!bkgRect.contains(xy))
return NULL;
if (!bkgRect.intersects(rect))
return NULL;
- uint16 color = *(uint16 *)_curBkg.getBasePtr(xy.x, xy.y);
+ uint16 color = *(uint16 *)_currentBackgroundImage.getBasePtr(xy.x, xy.y);
uint8 stC1, stC2, stC3;
- _curBkg.format.colorToRGB(color, stC1, stC2, stC3);
+ _currentBackgroundImage.format.colorToRGB(color, stC1, stC2, stC3);
EffectMap *newMap = new EffectMap;
EffectMapUnit unit;
@@ -953,11 +855,11 @@ EffectMap *RenderManager::makeEffectMap(const Common::Point &xy, int16 depth, co
uint8 depth8 = depth << 3;
for (int16 j = 0; j < h; j++) {
- uint16 *pix = (uint16 *)_curBkg.getBasePtr(rect.left, rect.top + j);
+ uint16 *pix = (uint16 *)_currentBackgroundImage.getBasePtr(rect.left, rect.top + j);
for (int16 i = 0; i < w; i++) {
uint16 curClr = pix[i];
uint8 cC1, cC2, cC3;
- _curBkg.format.colorToRGB(curClr, cC1, cC2, cC3);
+ _currentBackgroundImage.format.colorToRGB(curClr, cC1, cC2, cC3);
bool use = false;
@@ -1055,12 +957,261 @@ EffectMap *RenderManager::makeEffectMap(const Graphics::Surface &surf, uint16 tr
}
void RenderManager::markDirty() {
- _bkgDirtyRect = Common::Rect(_bkgWidth, _bkgHeight);
+ _backgroundDirtyRect = Common::Rect(_backgroundWidth, _backgroundHeight);
}
+#if 0
void RenderManager::bkgFill(uint8 r, uint8 g, uint8 b) {
- _curBkg.fillRect(Common::Rect(_curBkg.w, _curBkg.h), _curBkg.format.RGBToColor(r, g, b));
+ _currentBackgroundImage.fillRect(Common::Rect(_currentBackgroundImage.w, _currentBackgroundImage.h), _currentBackgroundImage.format.RGBToColor(r, g, b));
markDirty();
}
+#endif
+
+void RenderManager::timedMessage(const Common::String &str, uint16 milsecs) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ deleteSubArea(msgid, milsecs);
+}
+
+bool RenderManager::askQuestion(const Common::String &str) {
+ Graphics::Surface textSurface;
+ textSurface.create(_subtitleArea.width(), _subtitleArea.height(), _engine->_resourcePixelFormat);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(str, textSurface);
+ copyToScreen(textSurface, _subtitleArea, 0, 0);
+
+ _engine->stopClock();
+
+ int result = 0;
+
+ while (result == 0) {
+ Common::Event evnt;
+ while (_engine->getEventManager()->pollEvent(evnt)) {
+ if (evnt.type == Common::EVENT_KEYDOWN) {
+ // English: yes/no
+ // German: ja/nein
+ // Spanish: si/no
+ // French Nemesis: F4/any other key
+ // French ZGI: oui/non
+ switch (evnt.kbd.keycode) {
+ case Common::KEYCODE_y:
+ if (_engine->getLanguage() == Common::EN_ANY)
+ result = 2;
+ break;
+ case Common::KEYCODE_j:
+ if (_engine->getLanguage() == Common::DE_DEU)
+ result = 2;
+ break;
+ case Common::KEYCODE_s:
+ if (_engine->getLanguage() == Common::ES_ESP)
+ result = 2;
+ break;
+ case Common::KEYCODE_o:
+ if (_engine->getLanguage() == Common::FR_FRA && _engine->getGameId() == GID_GRANDINQUISITOR)
+ result = 2;
+ break;
+ case Common::KEYCODE_F4:
+ if (_engine->getLanguage() == Common::FR_FRA && _engine->getGameId() == GID_NEMESIS)
+ result = 2;
+ break;
+ case Common::KEYCODE_n:
+ result = 1;
+ break;
+ default:
+ if (_engine->getLanguage() == Common::FR_FRA && _engine->getGameId() == GID_NEMESIS)
+ result = 1;
+ break;
+ }
+ }
+ }
+ _system->updateScreen();
+ if (_doubleFPS)
+ _system->delayMillis(33);
+ else
+ _system->delayMillis(66);
+ }
+
+ // Draw over the text in order to clear it
+ textSurface.fillRect(Common::Rect(_subtitleArea.width(), _subtitleArea.height()), 0);
+ copyToScreen(textSurface, _subtitleArea, 0, 0);
+
+ // Free the surface
+ textSurface.free();
+
+ _engine->startClock();
+ return result == 2;
+}
+
+void RenderManager::delayedMessage(const Common::String &str, uint16 milsecs) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, str);
+ processSubs(0);
+ renderSceneToScreen();
+ _engine->stopClock();
+
+ uint32 stopTime = _system->getMillis() + milsecs;
+ while (_system->getMillis() < stopTime) {
+ Common::Event evnt;
+ while (_engine->getEventManager()->pollEvent(evnt)) {
+ if (evnt.type == Common::EVENT_KEYDOWN &&
+ (evnt.kbd.keycode == Common::KEYCODE_SPACE ||
+ evnt.kbd.keycode == Common::KEYCODE_RETURN ||
+ evnt.kbd.keycode == Common::KEYCODE_ESCAPE))
+ break;
+ }
+ _system->updateScreen();
+ if (_doubleFPS)
+ _system->delayMillis(33);
+ else
+ _system->delayMillis(66);
+ }
+ deleteSubArea(msgid);
+ _engine->startClock();
+}
+
+void RenderManager::showDebugMsg(const Common::String &msg, int16 delay) {
+ uint16 msgid = createSubArea();
+ updateSubArea(msgid, msg);
+ deleteSubArea(msgid, delay);
+}
+
+void RenderManager::updateRotation() {
+ int16 _velocity = _engine->getMouseVelocity() + _engine->getKeyboardVelocity();
+ ScriptManager *scriptManager = _engine->getScriptManager();
+
+ if (_doubleFPS)
+ _velocity /= 2;
+
+ if (_velocity) {
+ RenderTable::RenderState renderState = _renderTable.getRenderState();
+ if (renderState == RenderTable::PANORAMA) {
+ int16 startPosition = scriptManager->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition + (_renderTable.getPanoramaReverse() ? -_velocity : _velocity);
+
+ int16 zeroPoint = _renderTable.getPanoramaZeroPoint();
+ if (startPosition >= zeroPoint && newPosition < zeroPoint)
+ scriptManager->setStateValue(StateKey_Rounds, scriptManager->getStateValue(StateKey_Rounds) - 1);
+ if (startPosition <= zeroPoint && newPosition > zeroPoint)
+ scriptManager->setStateValue(StateKey_Rounds, scriptManager->getStateValue(StateKey_Rounds) + 1);
+
+ int16 screenWidth = getBkgSize().x;
+ if (screenWidth)
+ newPosition %= screenWidth;
+
+ if (newPosition < 0)
+ newPosition += screenWidth;
+
+ setBackgroundPosition(newPosition);
+ } else if (renderState == RenderTable::TILT) {
+ int16 startPosition = scriptManager->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition + _velocity;
+
+ int16 screenHeight = getBkgSize().y;
+ int16 tiltGap = (int16)_renderTable.getTiltGap();
+
+ if (newPosition >= (screenHeight - tiltGap))
+ newPosition = screenHeight - tiltGap;
+ if (newPosition <= tiltGap)
+ newPosition = tiltGap;
+
+ setBackgroundPosition(newPosition);
+ }
+ }
+}
+
+void RenderManager::checkBorders() {
+ RenderTable::RenderState renderState = _renderTable.getRenderState();
+ if (renderState == RenderTable::PANORAMA) {
+ int16 startPosition = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition;
+
+ int16 screenWidth = getBkgSize().x;
+
+ if (screenWidth)
+ newPosition %= screenWidth;
+
+ if (newPosition < 0)
+ newPosition += screenWidth;
+
+ if (startPosition != newPosition)
+ setBackgroundPosition(newPosition);
+ } else if (renderState == RenderTable::TILT) {
+ int16 startPosition = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
+
+ int16 newPosition = startPosition;
+
+ int16 screenHeight = getBkgSize().y;
+ int16 tiltGap = (int16)_renderTable.getTiltGap();
+
+ if (newPosition >= (screenHeight - tiltGap))
+ newPosition = screenHeight - tiltGap;
+ if (newPosition <= tiltGap)
+ newPosition = tiltGap;
+
+ if (startPosition != newPosition)
+ setBackgroundPosition(newPosition);
+ }
+}
+
+void RenderManager::rotateTo(int16 _toPos, int16 _time) {
+ if (_renderTable.getRenderState() != RenderTable::PANORAMA)
+ return;
+
+ if (_time == 0)
+ _time = 1;
+
+ int32 maxX = getBkgSize().x;
+ int32 curX = getCurrentBackgroundOffset();
+ int32 dx = 0;
+
+ if (curX == _toPos)
+ return;
+
+ if (curX > _toPos) {
+ if (curX - _toPos > maxX / 2)
+ dx = (_toPos + (maxX - curX)) / _time;
+ else
+ dx = -(curX - _toPos) / _time;
+ } else {
+ if (_toPos - curX > maxX / 2)
+ dx = -((maxX - _toPos) + curX) / _time;
+ else
+ dx = (_toPos - curX) / _time;
+ }
+
+ _engine->stopClock();
+
+ for (int16 i = 0; i <= _time; i++) {
+ if (i == _time)
+ curX = _toPos;
+ else
+ curX += dx;
+
+ if (curX < 0)
+ curX = maxX - curX;
+ else if (curX >= maxX)
+ curX %= maxX;
+
+ setBackgroundPosition(curX);
+
+ prepareBackground();
+ renderSceneToScreen();
+
+ _system->updateScreen();
+
+ _system->delayMillis(500 / _time);
+ }
+
+ _engine->startClock();
+}
+
+void RenderManager::upscaleRect(Common::Rect &rect) {
+ rect.top = rect.top * HIRES_WINDOW_HEIGHT / WINDOW_HEIGHT;
+ rect.left = rect.left * HIRES_WINDOW_WIDTH / WINDOW_WIDTH;
+ rect.bottom = rect.bottom * HIRES_WINDOW_HEIGHT / WINDOW_HEIGHT;
+ rect.right = rect.right * HIRES_WINDOW_WIDTH / WINDOW_WIDTH;
+}
} // End of namespace ZVision
diff --git a/engines/zvision/graphics/render_manager.h b/engines/zvision/graphics/render_manager.h
index 879a8643ce..33d8a88e78 100644
--- a/engines/zvision/graphics/render_manager.h
+++ b/engines/zvision/graphics/render_manager.h
@@ -24,14 +24,14 @@
#define ZVISION_RENDER_MANAGER_H
#include "zvision/graphics/render_table.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "common/rect.h"
#include "common/hashmap.h"
#include "graphics/surface.h"
-#include "effect.h"
+#include "graphics_effect.h"
class OSystem;
@@ -48,11 +48,11 @@ namespace ZVision {
class RenderManager {
public:
- RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat);
+ RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat, bool doubleFPS);
~RenderManager();
private:
- struct oneSub {
+ struct OneSubtitle {
Common::Rect r;
Common::String txt;
int16 timer;
@@ -60,87 +60,89 @@ private:
bool redraw;
};
- typedef Common::HashMap<uint16, oneSub> subMap;
- typedef Common::List<Effect *> effectsList;
+ typedef Common::HashMap<uint16, OneSubtitle> SubtitleMap;
+ typedef Common::List<GraphicsEffect *> EffectsList;
private:
ZVision *_engine;
OSystem *_system;
const Graphics::PixelFormat _pixelFormat;
- // A buffer for blitting background image to working window
- Graphics::Surface _wrkWnd;
+ /**
+ * A Rectangle centered inside the actual window. All in-game coordinates
+ * are given in this coordinate space. Also, all images are clipped to the
+ * edges of this Rectangle
+ */
+ Common::Rect _workingWindow;
+
+ // Center of the screen in the x direction
+ const int _screenCenterX;
+ // Center of the screen in the y direction
+ const int _screenCenterY;
- Common::Rect _wrkWndDirtyRect;
+ /** A buffer for background image that's being used to create the background */
+ Graphics::Surface _currentBackgroundImage;
+ Common::Rect _backgroundDirtyRect;
- // A buffer for mutate image by tilt or panorama renderers
- Graphics::Surface _outWnd;
+ /**
+ * The x1 or y1 offset of the subRectangle of the background that is currently displayed on the screen
+ * It will be x1 if PANORAMA, or y1 if TILT
+ */
+ int16 _backgroundOffset;
+ /** The width of the current background image */
+ uint16 _backgroundWidth;
+ /** The height of the current background image */
+ uint16 _backgroundHeight;
- Common::Rect _bkgDirtyRect;
+ // A buffer that holds the portion of the background that is used to render the final image
+ // If it's a normal scene, the pixels will be blitted directly to the screen
+ // If it's a panorma / tilt scene, the pixels will be first warped to _warpedSceneSurface
+ Graphics::Surface _backgroundSurface;
+ Common::Rect _backgroundSurfaceDirtyRect;
// A buffer for subtitles
- Graphics::Surface _subWnd;
+ Graphics::Surface _subtitleSurface;
- Common::Rect _subWndDirtyRect;
+ // Rectangle for subtitles area
+ Common::Rect _subtitleArea;
// A buffer for menu drawing
- Graphics::Surface _menuWnd;
+ Graphics::Surface _menuSurface;
+ Common::Rect _menuSurfaceDirtyRect;
- Common::Rect _menuWndDirtyRect;
+ // Rectangle for menu area
+ Common::Rect _menuArea;
// A buffer used for apply graphics effects
- Graphics::Surface _effectWnd;
+ Graphics::Surface _effectSurface;
- /** Width of the working window. Saved to prevent extraneous calls to _workingWindow.width() */
- const int _wrkWidth;
- /** Height of the working window. Saved to prevent extraneous calls to _workingWindow.height() */
- const int _wrkHeight;
- /** Center of the screen in the x direction */
- const int _screenCenterX;
- /** Center of the screen in the y direction */
- const int _screenCenterY;
+ // A buffer to store the result of the panorama / tilt warps
+ Graphics::Surface _warpedSceneSurface;
- /**
- * A Rectangle centered inside the actual window. All in-game coordinates
- * are given in this coordinate space. Also, all images are clipped to the
- * edges of this Rectangle
- */
- const Common::Rect _workingWindow;
-
- // Recatangle for subtitles area
- Common::Rect _subWndRect;
-
- // Recatangle for menu area
- Common::Rect _menuWndRect;
/** Used to warp the background image */
RenderTable _renderTable;
- // A buffer for background image
- Graphics::Surface _curBkg;
- /** The (x1,y1) coordinates of the subRectangle of the background that is currently displayed on the screen */
- int16 _bkgOff;
- /** The width of the current background image */
- uint16 _bkgWidth;
- /** The height of the current background image */
- uint16 _bkgHeight;
-
// Internal subtitles counter
uint16 _subid;
// Subtitle list
- subMap _subsList;
+ SubtitleMap _subsList;
// Visual effects list
- effectsList _effects;
+ EffectsList _effects;
+
+ bool _doubleFPS;
public:
void initialize();
/**
- * Renders the current state of the backbuffer to the screen
+ * Renders the scene to the screen
*/
- void renderBackbufferToScreen();
+ void renderSceneToScreen();
+
+ void copyToScreen(const Graphics::Surface &surface, Common::Rect &rect, int16 srcLeft, int16 srcTop);
/**
* Blits the image or a portion of the image to the background.
@@ -223,23 +225,20 @@ public:
// Blitting surface-to-surface methods
void blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int x, int y);
void blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey);
- void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y);
- void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y, uint32 colorkey);
// Blitting surface-to-background methods
- void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y);
- void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, uint32 colorkey);
+ void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, int32 colorkey = -1);
// Blitting surface-to-background methods with scale
- void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect);
- void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, uint32 colorkey);
+ void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, int32 colorkey = -1);
// Blitting surface-to-menu methods
- void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y);
- void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, uint32 colorkey);
+ void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, int32 colorkey = -1);
// Subtitles methods
+ void initSubArea(uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow);
+
// Create subtitle area and return ID
uint16 createSubArea(const Common::Rect &area);
uint16 createSubArea();
@@ -261,10 +260,8 @@ public:
Graphics::Surface *getBkgRect(Common::Rect &rect);
// Load image into new surface
- Graphics::Surface *loadImage(const char *file);
- Graphics::Surface *loadImage(Common::String &file);
- Graphics::Surface *loadImage(const char *file, bool transposed);
- Graphics::Surface *loadImage(Common::String &file, bool transposed);
+ Graphics::Surface *loadImage(Common::String file);
+ Graphics::Surface *loadImage(Common::String file, bool transposed);
// Clear whole/area of menu surface
void clearMenuSurface();
@@ -274,11 +271,10 @@ public:
void renderMenuToScreen();
// Copy needed portion of background surface to workingWindow surface
- void prepareBkg();
+ void prepareBackground();
/**
- * Reads an image file pixel data into a Surface buffer. In the process
- * it converts the pixel data from RGB 555 to RGB 565. Also, if the image
+ * Reads an image file pixel data into a Surface buffer. Also, if the image
* is transposed, it will un-transpose the pixel data. The function will
* call destination::create() if the dimensions of destination do not match
* up with the dimensions of the image.
@@ -289,8 +285,7 @@ public:
void readImageToSurface(const Common::String &fileName, Graphics::Surface &destination);
/**
- * Reads an image file pixel data into a Surface buffer. In the process
- * it converts the pixel data from RGB 555 to RGB 565. Also, if the image
+ * Reads an image file pixel data into a Surface buffer. Also, if the image
* is transposed, it will un-transpose the pixel data. The function will
* call destination::create() if the dimensions of destination do not match
* up with the dimensions of the image.
@@ -302,7 +297,7 @@ public:
void readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed);
// Add visual effect to effects list
- void addEffect(Effect *_effect);
+ void addEffect(GraphicsEffect *_effect);
// Delete effect(s) by ID (ID equal to slot of action:region that create this effect)
void deleteEffect(uint32 ID);
@@ -319,13 +314,26 @@ public:
EffectMap *makeEffectMap(const Graphics::Surface &surf, uint16 transp);
// Return background rectangle in screen coordinates
- Common::Rect bkgRectToScreen(const Common::Rect &src);
+ Common::Rect transformBackgroundSpaceRectToScreenSpace(const Common::Rect &src);
// Mark whole background surface as dirty
void markDirty();
- // Fille background surface by color
+#if 0
+ // Fill background surface by color
void bkgFill(uint8 r, uint8 g, uint8 b);
+#endif
+
+ bool askQuestion(const Common::String &str);
+ void delayedMessage(const Common::String &str, uint16 milsecs);
+ void timedMessage(const Common::String &str, uint16 milsecs);
+ void showDebugMsg(const Common::String &msg, int16 delay = 3000);
+
+ void checkBorders();
+ void rotateTo(int16 to, int16 time);
+ void updateRotation();
+
+ void upscaleRect(Common::Rect &rect);
};
} // End of namespace ZVision
diff --git a/engines/zvision/graphics/render_table.cpp b/engines/zvision/graphics/render_table.cpp
index c30e0bd472..df73247344 100644
--- a/engines/zvision/graphics/render_table.cpp
+++ b/engines/zvision/graphics/render_table.cpp
@@ -81,27 +81,6 @@ const Common::Point RenderTable::convertWarpedCoordToFlatCoord(const Common::Poi
return newPoint;
}
-uint16 mixTwoRGB(uint16 colorOne, uint16 colorTwo, float percentColorOne) {
- assert(percentColorOne < 1.0f);
-
- float rOne = float((colorOne & Graphics::ColorMasks<555>::kRedMask) >> Graphics::ColorMasks<555>::kRedShift);
- float rTwo = float((colorTwo & Graphics::ColorMasks<555>::kRedMask) >> Graphics::ColorMasks<555>::kRedShift);
- float gOne = float((colorOne & Graphics::ColorMasks<555>::kGreenMask) >> Graphics::ColorMasks<555>::kGreenShift);
- float gTwo = float((colorTwo & Graphics::ColorMasks<555>::kGreenMask) >> Graphics::ColorMasks<555>::kGreenShift);
- float bOne = float((colorOne & Graphics::ColorMasks<555>::kBlueMask) >> Graphics::ColorMasks<555>::kBlueShift);
- float bTwo = float((colorTwo & Graphics::ColorMasks<555>::kBlueMask) >> Graphics::ColorMasks<555>::kBlueShift);
-
- float rFinal = rOne * percentColorOne + rTwo * (1.0f - percentColorOne);
- float gFinal = gOne * percentColorOne + gTwo * (1.0f - percentColorOne);
- float bFinal = bOne * percentColorOne + bTwo * (1.0f - percentColorOne);
-
- uint16 returnColor = (byte(rFinal + 0.5f) << Graphics::ColorMasks<555>::kRedShift) |
- (byte(gFinal + 0.5f) << Graphics::ColorMasks<555>::kGreenShift) |
- (byte(bFinal + 0.5f) << Graphics::ColorMasks<555>::kBlueShift);
-
- return returnColor;
-}
-
void RenderTable::mutateImage(uint16 *sourceBuffer, uint16 *destBuffer, uint32 destWidth, const Common::Rect &subRect) {
uint32 destOffset = 0;
diff --git a/engines/zvision/graphics/truetype_font.cpp b/engines/zvision/graphics/truetype_font.cpp
deleted file mode 100644
index 2dbd7ca358..0000000000
--- a/engines/zvision/graphics/truetype_font.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "common/scummsys.h"
-#include "common/config-manager.h"
-#include "common/debug.h"
-#include "common/file.h"
-#include "common/system.h"
-#include "common/unzip.h"
-#include "graphics/font.h"
-#include "graphics/fonts/ttf.h"
-#include "graphics/surface.h"
-
-#include "zvision/zvision.h"
-#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/truetype_font.h"
-
-namespace ZVision {
-
-StyledTTFont::StyledTTFont(ZVision *engine) {
- _engine = engine;
- _style = 0;
- _font = NULL;
- _lineHeight = 0;
-}
-
-StyledTTFont::~StyledTTFont() {
- if (_font)
- delete _font;
-}
-
-bool StyledTTFont::loadFont(const Common::String &fontName, int32 point, uint style) {
- _style = style;
- return loadFont(fontName, point);
-}
-
-bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) {
- Common::String newFontName;
- if (fontName.matchString("*times new roman*", true) || fontName.matchString("*times*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "timesbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "timesbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "timesi.ttf";
- else
- newFontName = "times.ttf";
-
- } else if (fontName.matchString("*courier new*", true) || fontName.matchString("*courier*", true) || fontName.matchString("*ZorkDeath*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "courbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "courbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "couri.ttf";
- else
- newFontName = "cour.ttf";
-
- } else if (fontName.matchString("*century schoolbook*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "censcbkbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "censcbkbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "censcbki.ttf";
- else
- newFontName = "censcbk.ttf";
-
- } else if (fontName.matchString("*garamond*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "garabi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "garabd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "garai.ttf";
- else
- newFontName = "gara.ttf";
-
- } else if (fontName.matchString("*arial*", true) || fontName.matchString("*ZorkNormal*", true)) {
- if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC))
- newFontName = "arialbi.ttf";
- else if (_style & STTF_BOLD)
- newFontName = "arialbd.ttf";
- else if (_style & STTF_ITALIC)
- newFontName = "ariali.ttf";
- else
- newFontName = "arial.ttf";
-
- } else {
- debug("Could not identify font: %s. Reverting to Arial", fontName.c_str());
- newFontName = "arial.ttf";
- }
-
- bool sharp = (_style & STTF_SHARP) == STTF_SHARP;
-
- Common::File *file = _engine->getSearchManager()->openFile(newFontName);
-
- if (!file) {
- Common::SeekableReadStream *themeFile = nullptr;
- if (ConfMan.hasKey("themepath")) {
- Common::FSNode themePath(ConfMan.get("themepath"));
- if (themePath.exists()) {
- Common::FSNode scummModern = themePath.getChild("scummmodern.zip");
- if (scummModern.exists()) {
- themeFile = scummModern.createReadStream();
- }
- }
- }
- if (!themeFile) { // Fallback : Search for ScummModern.zip in SearchMan.
- themeFile = SearchMan.createReadStreamForMember("scummmodern.zip");
- }
- if (themeFile) {
- Common::Archive *themeArchive = Common::makeZipArchive(themeFile);
- if (themeArchive->hasFile("FreeSans.ttf")) {
- Common::SeekableReadStream *stream = nullptr;
- stream = themeArchive->createReadStreamForMember("FreeSans.ttf");
- Graphics::Font *_newFont = Graphics::loadTTFFont(*stream, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
- if (_newFont) {
- if (!_font)
- delete _font;
- _font = _newFont;
- }
- if (stream)
- delete stream;
- }
- delete themeArchive;
- themeArchive = nullptr;
- }
- } else {
- Graphics::Font *_newFont = Graphics::loadTTFFont(*file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
- if (_newFont) {
- if (!_font)
- delete _font;
- _font = _newFont;
- }
- delete file;
- }
-
- _fntName = fontName;
- _lineHeight = point;
-
- if (_font)
- return true;
- return false;
-}
-
-void StyledTTFont::setStyle(uint newStyle) {
- if ((_style & (STTF_BOLD | STTF_ITALIC | STTF_SHARP)) != (newStyle & (STTF_BOLD | STTF_ITALIC | STTF_SHARP))) {
- _style = newStyle;
- loadFont(_fntName, _lineHeight);
- } else {
- _style = newStyle;
- }
-}
-
-int StyledTTFont::getFontHeight() {
- if (_font)
- return _font->getFontHeight();
- return 0;
-}
-
-int StyledTTFont::getMaxCharWidth() {
- if (_font)
- return _font->getMaxCharWidth();
- return 0;
-}
-
-int StyledTTFont::getCharWidth(byte chr) {
- if (_font)
- return _font->getCharWidth(chr);
- return 0;
-}
-
-int StyledTTFont::getKerningOffset(byte left, byte right) {
- if (_font)
- return _font->getKerningOffset(left, right);
- return 0;
-}
-
-void StyledTTFont::drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color) {
- if (_font) {
- _font->drawChar(dst, chr, x, y, color);
- if (_style & STTF_UNDERLINE) {
- int16 pos = floor(_font->getFontHeight() * 0.87);
- int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
- dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color);
- }
- if (_style & STTF_STRIKEOUT) {
- int16 pos = floor(_font->getFontHeight() * 0.60);
- int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
- dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color);
- }
- }
-}
-
-void StyledTTFont::drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, Graphics::TextAlign align) {
- if (_font) {
- _font->drawString(dst, str, x, y, w, color, align);
- if (_style & STTF_UNDERLINE) {
- int16 pos = floor(_font->getFontHeight() * 0.87);
- int16 wd = MIN(_font->getStringWidth(str), w);
- int16 stX = x;
- if (align == Graphics::kTextAlignCenter)
- stX += (w - wd) / 2;
- else if (align == Graphics::kTextAlignRight)
- stX += (w - wd);
-
- int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
-
- dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color);
- }
- if (_style & STTF_STRIKEOUT) {
- int16 pos = floor(_font->getFontHeight() * 0.60);
- int16 wd = MIN(_font->getStringWidth(str), w);
- int16 stX = x;
- if (align == Graphics::kTextAlignCenter)
- stX += (w - wd) / 2;
- else if (align == Graphics::kTextAlignRight)
- stX += (w - wd);
-
- int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
-
- dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color);
- }
- }
-}
-
-int StyledTTFont::getStringWidth(const Common::String &str) {
- if (_font)
- return _font->getStringWidth(str);
- return 0;
-}
-
-Graphics::Surface *StyledTTFont::renderSolidText(const Common::String &str, uint32 color) {
- Graphics::Surface *tmp = new Graphics::Surface;
- if (_font) {
- int16 w = _font->getStringWidth(str);
- if (w && w < 1024) {
- tmp->create(w, _font->getFontHeight(), _engine->_pixelFormat);
- drawString(tmp, str, 0, 0, w, color);
- }
- }
- return tmp;
-}
-
-} // End of namespace ZVision
diff --git a/engines/zvision/module.mk b/engines/zvision/module.mk
index 00652f0824..93fba2879d 100644
--- a/engines/zvision/module.mk
+++ b/engines/zvision/module.mk
@@ -4,10 +4,9 @@ MODULE_OBJS := \
core/console.o \
core/clock.o \
core/events.o \
- core/menu.o \
- core/save_manager.o \
detection.o \
file/lzss_read_stream.o \
+ file/save_manager.o \
file/search_manager.o \
file/zfs_archive.o \
graphics/cursors/cursor_manager.o \
@@ -17,8 +16,6 @@ MODULE_OBJS := \
graphics/effects/wave.o \
graphics/render_manager.o \
graphics/render_table.o \
- graphics/subtitles.o \
- graphics/truetype_font.o \
scripting/actions.o \
scripting/control.o \
scripting/controls/fist_control.o \
@@ -32,19 +29,22 @@ MODULE_OBJS := \
scripting/controls/slot_control.o \
scripting/controls/titler_control.o \
scripting/inventory.o \
+ scripting/menu.o \
scripting/scr_file_handling.o \
scripting/script_manager.o \
- scripting/sidefx/animation_node.o \
- scripting/sidefx/distort_node.o \
- scripting/sidefx/music_node.o \
- scripting/sidefx/region_node.o \
- scripting/sidefx/syncsound_node.o \
- scripting/sidefx/timer_node.o \
- scripting/sidefx/ttytext_node.o \
+ scripting/effects/animation_effect.o \
+ scripting/effects/distort_effect.o \
+ scripting/effects/music_effect.o \
+ scripting/effects/region_effect.o \
+ scripting/effects/syncsound_effect.o \
+ scripting/effects/timer_effect.o \
+ scripting/effects/ttytext_effect.o \
sound/midi.o \
sound/zork_raw.o \
text/string_manager.o \
+ text/subtitles.o \
text/text.o \
+ text/truetype_font.o \
video/rlf_decoder.o \
video/video.o \
video/zork_avi_decoder.o \
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp
index 0422a2c028..e1380b0eb2 100644
--- a/engines/zvision/scripting/actions.cpp
+++ b/engines/zvision/scripting/actions.cpp
@@ -21,42 +21,44 @@
*/
#include "common/scummsys.h"
+#include "video/video_decoder.h"
#include "zvision/scripting/actions.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/sound/zork_raw.h"
-#include "zvision/video/zork_avi_decoder.h"
-#include "zvision/scripting/sidefx/timer_node.h"
-#include "zvision/scripting/sidefx/music_node.h"
-#include "zvision/scripting/sidefx/syncsound_node.h"
-#include "zvision/scripting/sidefx/animation_node.h"
-#include "zvision/scripting/sidefx/distort_node.h"
-#include "zvision/scripting/sidefx/ttytext_node.h"
-#include "zvision/scripting/sidefx/region_node.h"
+#include "zvision/file/save_manager.h"
+#include "zvision/scripting/menu.h"
+#include "zvision/scripting/effects/timer_effect.h"
+#include "zvision/scripting/effects/music_effect.h"
+#include "zvision/scripting/effects/syncsound_effect.h"
+#include "zvision/scripting/effects/animation_effect.h"
+#include "zvision/scripting/effects/distort_effect.h"
+#include "zvision/scripting/effects/ttytext_effect.h"
+#include "zvision/scripting/effects/region_effect.h"
#include "zvision/scripting/controls/titler_control.h"
#include "zvision/graphics/render_table.h"
-#include "zvision/graphics/effect.h"
+#include "zvision/graphics/graphics_effect.h"
#include "zvision/graphics/effects/fog.h"
#include "zvision/graphics/effects/light.h"
#include "zvision/graphics/effects/wave.h"
-#include "zvision/core/save_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
-#include "common/file.h"
-
-#include "audio/decoders/wave.h"
-
namespace ZVision {
+ResultAction::ResultAction(ZVision *engine, int32 slotKey) :
+ _engine(engine),
+ _slotKey(slotKey),
+ _scriptManager(engine->getScriptManager()) {
+}
+
//////////////////////////////////////////////////////////////////////////////
// ActionAdd
//////////////////////////////////////////////////////////////////////////////
-ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionAdd::ActionAdd(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
_value = 0;
@@ -64,7 +66,7 @@ ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line)
}
bool ActionAdd::execute() {
- _engine->getScriptManager()->setStateValue(_key, _engine->getScriptManager()->getStateValue(_key) + _value);
+ _scriptManager->setStateValue(_key, _scriptManager->getStateValue(_key) + _value);
return true;
}
@@ -72,23 +74,22 @@ bool ActionAdd::execute() {
// ActionAssign
//////////////////////////////////////////////////////////////////////////////
-ActionAssign::ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionAssign::ActionAssign(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
char buf[64];
memset(buf, 0, 64);
sscanf(line.c_str(), "%u, %s", &_key, buf);
- _value = new ValueSlot(_engine->getScriptManager(), buf);
+ _value = new ValueSlot(_scriptManager, buf);
}
ActionAssign::~ActionAssign() {
- if (_value)
- delete _value;
+ delete _value;
}
bool ActionAssign::execute() {
- _engine->getScriptManager()->setStateValue(_key, _value->getValue());
+ _scriptManager->setStateValue(_key, _value->getValue());
return true;
}
@@ -96,8 +97,8 @@ bool ActionAssign::execute() {
// ActionAttenuate
//////////////////////////////////////////////////////////////////////////////
-ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
_attenuation = 0;
@@ -105,10 +106,10 @@ ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::S
}
bool ActionAttenuate::execute() {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_key);
- if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) {
- MusicNode *mus = (MusicNode *)fx;
- mus->setVolume(255 - (abs(_attenuation) >> 7));
+ ScriptingEffect *fx = _scriptManager->getSideFX(_key);
+ if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) {
+ MusicNodeBASE *mus = (MusicNodeBASE *)fx;
+ mus->setVolume(255 * (10000 - abs(_attenuation)) / 10000 );
}
return true;
}
@@ -117,8 +118,8 @@ bool ActionAttenuate::execute() {
// ActionChangeLocation
//////////////////////////////////////////////////////////////////////////////
-ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_world = 'g';
_room = 'a';
_node = 'r';
@@ -130,7 +131,7 @@ ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const
bool ActionChangeLocation::execute() {
// We can't directly call ScriptManager::ChangeLocationIntern() because doing so clears all the Puzzles, and thus would corrupt the current puzzle checking
- _engine->getScriptManager()->changeLocation(_world, _room, _node, _view, _offset);
+ _scriptManager->changeLocation(_world, _room, _node, _view, _offset);
// Tell the puzzle system to stop checking any more puzzles
return false;
}
@@ -139,8 +140,8 @@ bool ActionChangeLocation::execute() {
// ActionCrossfade
//////////////////////////////////////////////////////////////////////////////
-ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_keyOne = 0;
_keyTwo = 0;
_oneStartVolume = 0;
@@ -156,9 +157,9 @@ ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::S
bool ActionCrossfade::execute() {
if (_keyOne) {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_keyOne);
- if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) {
- MusicNode *mus = (MusicNode *)fx;
+ ScriptingEffect *fx = _scriptManager->getSideFX(_keyOne);
+ if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) {
+ MusicNodeBASE *mus = (MusicNodeBASE *)fx;
if (_oneStartVolume >= 0)
mus->setVolume((_oneStartVolume * 255) / 100);
@@ -167,9 +168,9 @@ bool ActionCrossfade::execute() {
}
if (_keyTwo) {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_keyTwo);
- if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) {
- MusicNode *mus = (MusicNode *)fx;
+ ScriptingEffect *fx = _scriptManager->getSideFX(_keyTwo);
+ if (fx && fx->getType() == ScriptingEffect::SCRIPTING_EFFECT_AUDIO) {
+ MusicNodeBASE *mus = (MusicNodeBASE *)fx;
if (_twoStartVolume >= 0)
mus->setVolume((_twoStartVolume * 255) / 100);
@@ -183,8 +184,8 @@ bool ActionCrossfade::execute() {
// ActionCursor
//////////////////////////////////////////////////////////////////////////////
-ActionCursor::ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionCursor::ActionCursor(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
Common::String up = line;
up.toUppercase();
_action = 0;
@@ -215,10 +216,13 @@ bool ActionCursor::execute() {
// ActionDelayRender
//////////////////////////////////////////////////////////////////////////////
-ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_framesToDelay = 0;
sscanf(line.c_str(), "%u", &_framesToDelay);
+ // Limit to 10 frames maximum. This fixes the script bug in ZGI scene px10
+ // (outside Frobozz Electric building), where this is set to 100 (bug #6791).
+ _framesToDelay = MIN<uint32>(_framesToDelay, 10);
}
bool ActionDelayRender::execute() {
@@ -230,32 +234,15 @@ bool ActionDelayRender::execute() {
// ActionDisableControl
//////////////////////////////////////////////////////////////////////////////
-ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
}
bool ActionDisableControl::execute() {
- _engine->getScriptManager()->setStateFlag(_key, Puzzle::DISABLED);
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// ActionDisableVenus
-//////////////////////////////////////////////////////////////////////////////
-
-ActionDisableVenus::ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
- _key = 0;
-
- sscanf(line.c_str(), "%d", &_key);
-}
-
-bool ActionDisableVenus::execute() {
- _engine->getScriptManager()->setStateValue(_key, 0);
-
+ _scriptManager->setStateFlag(_key, Puzzle::DISABLED);
return true;
}
@@ -263,8 +250,8 @@ bool ActionDisableVenus::execute() {
// ActionDisplayMessage
//////////////////////////////////////////////////////////////////////////////
-ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_control = 0;
_msgid = 0;
@@ -272,7 +259,7 @@ ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const
}
bool ActionDisplayMessage::execute() {
- Control *ctrl = _engine->getScriptManager()->getControl(_control);
+ Control *ctrl = _scriptManager->getControl(_control);
if (ctrl && ctrl->getType() == Control::CONTROL_TITLER) {
TitlerControl *titler = (TitlerControl *)ctrl;
titler->setString(_msgid);
@@ -295,11 +282,11 @@ bool ActionDissolve::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionDistort
+// ActionDistort - only used by Zork: Nemesis for the "treatment" puzzle in the Sanitarium (aj30)
//////////////////////////////////////////////////////////////////////////////
-ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDistort::ActionDistort(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_distSlot = 0;
_speed = 0;
_startAngle = 60.0;
@@ -311,14 +298,14 @@ ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::Strin
}
ActionDistort::~ActionDistort() {
- _engine->getScriptManager()->killSideFx(_distSlot);
+ _scriptManager->killSideFx(_distSlot);
}
bool ActionDistort::execute() {
- if (_engine->getScriptManager()->getSideFX(_distSlot))
+ if (_scriptManager->getSideFX(_distSlot))
return true;
- _engine->getScriptManager()->addSideFX(new DistortNode(_engine, _distSlot, _speed, _startAngle, _endAngle, _startLineScale, _endLineScale));
+ _scriptManager->addSideFX(new DistortNode(_engine, _distSlot, _speed, _startAngle, _endAngle, _startLineScale, _endLineScale));
return true;
}
@@ -327,15 +314,15 @@ bool ActionDistort::execute() {
// ActionEnableControl
//////////////////////////////////////////////////////////////////////////////
-ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
}
bool ActionEnableControl::execute() {
- _engine->getScriptManager()->unsetStateFlag(_key, Puzzle::DISABLED);
+ _scriptManager->unsetStateFlag(_key, Puzzle::DISABLED);
return true;
}
@@ -343,13 +330,13 @@ bool ActionEnableControl::execute() {
// ActionFlushMouseEvents
//////////////////////////////////////////////////////////////////////////////
-ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotkey) :
- ResultAction(engine, slotkey) {
+ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotKey) :
+ ResultAction(engine, slotKey) {
}
bool ActionFlushMouseEvents::execute() {
- _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONUP);
- _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONDOWN);
+ _scriptManager->flushEvent(Common::EVENT_LBUTTONUP);
+ _scriptManager->flushEvent(Common::EVENT_LBUTTONDOWN);
return true;
}
@@ -357,13 +344,13 @@ bool ActionFlushMouseEvents::execute() {
// ActionInventory
//////////////////////////////////////////////////////////////////////////////
-ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionInventory::ActionInventory(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_type = -1;
_key = 0;
char buf[25];
- sscanf(line.c_str(), "%25s %d", buf, &_key);
+ sscanf(line.c_str(), "%24s %d", buf, &_key);
if (strcmp(buf, "add") == 0) {
_type = 0;
@@ -382,22 +369,22 @@ ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::S
bool ActionInventory::execute() {
switch (_type) {
case 0: // add
- _engine->getScriptManager()->inventoryAdd(_key);
+ _scriptManager->inventoryAdd(_key);
break;
case 1: // addi
- _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(_key));
+ _scriptManager->inventoryAdd(_scriptManager->getStateValue(_key));
break;
case 2: // drop
if (_key >= 0)
- _engine->getScriptManager()->inventoryDrop(_key);
+ _scriptManager->inventoryDrop(_key);
else
- _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(StateKey_InventoryItem));
+ _scriptManager->inventoryDrop(_scriptManager->getStateValue(StateKey_InventoryItem));
break;
case 3: // dropi
- _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(_key));
+ _scriptManager->inventoryDrop(_scriptManager->getStateValue(_key));
break;
case 4: // cycle
- _engine->getScriptManager()->inventoryCycle();
+ _scriptManager->inventoryCycle();
break;
default:
break;
@@ -406,41 +393,41 @@ bool ActionInventory::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionKill
+// ActionKill - only used by ZGI
//////////////////////////////////////////////////////////////////////////////
-ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionKill::ActionKill(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
_type = 0;
char keytype[25];
- sscanf(line.c_str(), "%25s", keytype);
+ sscanf(line.c_str(), "%24s", keytype);
if (keytype[0] == '"') {
if (!scumm_stricmp(keytype, "\"ANIM\""))
- _type = SideFX::SIDEFX_ANIM;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_ANIM;
else if (!scumm_stricmp(keytype, "\"AUDIO\""))
- _type = SideFX::SIDEFX_AUDIO;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_AUDIO;
else if (!scumm_stricmp(keytype, "\"DISTORT\""))
- _type = SideFX::SIDEFX_DISTORT;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_DISTORT;
else if (!scumm_stricmp(keytype, "\"PANTRACK\""))
- _type = SideFX::SIDEFX_PANTRACK;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_PANTRACK;
else if (!scumm_stricmp(keytype, "\"REGION\""))
- _type = SideFX::SIDEFX_REGION;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_REGION;
else if (!scumm_stricmp(keytype, "\"TIMER\""))
- _type = SideFX::SIDEFX_TIMER;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_TIMER;
else if (!scumm_stricmp(keytype, "\"TTYTEXT\""))
- _type = SideFX::SIDEFX_TTYTXT;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_TTYTXT;
else if (!scumm_stricmp(keytype, "\"ALL\""))
- _type = SideFX::SIDEFX_ALL;
+ _type = ScriptingEffect::SCRIPTING_EFFECT_ALL;
} else
_key = atoi(keytype);
}
bool ActionKill::execute() {
if (_type)
- _engine->getScriptManager()->killSideFxType((SideFX::SideFXType)_type);
+ _scriptManager->killSideFxType((ScriptingEffect::ScriptingEffectType)_type);
else
- _engine->getScriptManager()->killSideFx(_key);
+ _scriptManager->killSideFx(_key);
return true;
}
@@ -448,15 +435,15 @@ bool ActionKill::execute() {
// ActionMenuBarEnable
//////////////////////////////////////////////////////////////////////////////
-ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_menus = 0xFFFF;
sscanf(line.c_str(), "%hu", &_menus);
}
bool ActionMenuBarEnable::execute() {
- _engine->menuBarEnable(_menus);
+ _engine->getMenuHandler()->setEnable(_menus);
return true;
}
@@ -464,57 +451,76 @@ bool ActionMenuBarEnable::execute() {
// ActionMusic
//////////////////////////////////////////////////////////////////////////////
-ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global) :
- ResultAction(engine, slotkey),
- _volume(255),
+ActionMusic::ActionMusic(ZVision *engine, int32 slotKey, const Common::String &line, bool global) :
+ ResultAction(engine, slotKey),
_note(0),
_prog(0),
_universe(global) {
uint type = 0;
char fileNameBuffer[25];
uint loop = 0;
- uint volume = 255;
+ char volumeBuffer[15];
- sscanf(line.c_str(), "%u %25s %u %u", &type, fileNameBuffer, &loop, &volume);
+ // Volume is optional. If it doesn't appear, assume full volume
+ strcpy(volumeBuffer, "100");
- // type 4 are midi sound effect files
+ sscanf(line.c_str(), "%u %24s %u %14s", &type, fileNameBuffer, &loop, volumeBuffer);
+
+ // Type 4 actions are MIDI commands, not files. These are only used by
+ // Zork: Nemesis, for the flute and piano puzzles (tj4e and ve6f, as well
+ // as vr)
if (type == 4) {
_midi = true;
int note;
int prog;
- sscanf(line.c_str(), "%u %d %d %u", &type, &prog, &note, &volume);
- _volume = volume;
+ sscanf(line.c_str(), "%u %d %d %14s", &type, &prog, &note, volumeBuffer);
+ _volume = new ValueSlot(_scriptManager, volumeBuffer);
_note = note;
_prog = prog;
} else {
_midi = false;
_fileName = Common::String(fileNameBuffer);
_loop = loop == 1 ? true : false;
-
- // Volume is optional. If it doesn't appear, assume full volume
- if (volume != 255) {
- // Volume in the script files is mapped to [0, 100], but the ScummVM mixer uses [0, 255]
- _volume = volume * 255 / 100;
+ if (volumeBuffer[0] != '[' && atoi(volumeBuffer) > 100) {
+ // I thought I saw a case like this in Zork Nemesis, so
+ // let's guard against it.
+ warning("ActionMusic: Adjusting volume for %s from %s to 100", _fileName.c_str(), volumeBuffer);
+ strcpy(volumeBuffer, "100");
}
+ _volume = new ValueSlot(_scriptManager, volumeBuffer);
}
+
+ // WORKAROUND for a script bug in Zork Nemesis, rooms mq70/mq80.
+ // Fixes an edge case where the player goes to the dark room with the grue
+ // without holding a torch, and then quickly runs away before the grue's
+ // sound effect finishes. Fixes script bug #6794.
+ if (engine->getGameId() == GID_NEMESIS && _slotKey == 14822 && _scriptManager->getStateValue(_slotKey) == 2)
+ _scriptManager->setStateValue(_slotKey, 0);
+
}
ActionMusic::~ActionMusic() {
if (!_universe)
- _engine->getScriptManager()->killSideFx(_slotKey);
+ _scriptManager->killSideFx(_slotKey);
+ delete _volume;
}
bool ActionMusic::execute() {
- if (_engine->getScriptManager()->getSideFX(_slotKey))
- return true;
+ if (_scriptManager->getSideFX(_slotKey)) {
+ _scriptManager->killSideFx(_slotKey);
+ _scriptManager->setStateValue(_slotKey, 2);
+ }
+
+ uint volume = _volume->getValue();
if (_midi) {
- _engine->getScriptManager()->addSideFX(new MusicMidiNode(_engine, _slotKey, _prog, _note, _volume));
+ _scriptManager->addSideFX(new MusicMidiNode(_engine, _slotKey, _prog, _note, volume));
} else {
if (!_engine->getSearchManager()->hasFile(_fileName))
return true;
- _engine->getScriptManager()->addSideFX(new MusicNode(_engine, _slotKey, _fileName, _loop, _volume));
+ // Volume in the script files is mapped to [0, 100], but the ScummVM mixer uses [0, 255]
+ _scriptManager->addSideFX(new MusicNode(_engine, _slotKey, _fileName, _loop, volume * 255 / 100));
}
return true;
@@ -524,8 +530,8 @@ bool ActionMusic::execute() {
// ActionPanTrack
//////////////////////////////////////////////////////////////////////////////
-ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey),
+ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey),
_pos(0),
_musicSlot(0) {
@@ -533,14 +539,14 @@ ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::Str
}
ActionPanTrack::~ActionPanTrack() {
- _engine->getScriptManager()->killSideFx(_slotKey);
+ _scriptManager->killSideFx(_slotKey);
}
bool ActionPanTrack::execute() {
- if (_engine->getScriptManager()->getSideFX(_slotKey))
+ if (_scriptManager->getSideFX(_slotKey))
return true;
- _engine->getScriptManager()->addSideFX(new PanTrackNode(_engine, _slotKey, _musicSlot, _pos));
+ _scriptManager->addSideFX(new PanTrackNode(_engine, _slotKey, _musicSlot, _pos));
return true;
}
@@ -549,8 +555,8 @@ bool ActionPanTrack::execute() {
// ActionPreferences
//////////////////////////////////////////////////////////////////////////////
-ActionPreferences::ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPreferences::ActionPreferences(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
if (line.compareToIgnoreCase("save") == 0)
_save = true;
else
@@ -570,38 +576,38 @@ bool ActionPreferences::execute() {
// ActionPreloadAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_mask = 0;
_framerate = 0;
char fileName[25];
- // The two %*u are always 0 and dont seem to have a use
- sscanf(line.c_str(), "%25s %*u %*u %d %d", fileName, &_mask, &_framerate);
+ // The two %*u are usually 0 and dont seem to have a use
+ sscanf(line.c_str(), "%24s %*u %*u %d %d", fileName, &_mask, &_framerate);
- if (_mask > 0) {
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b);
- _mask = _engine->_pixelFormat.RGBToColor(r, g, b);
- }
+ // Mask 0 means "no transparency" in this case. Since we use a common blitting
+ // code for images and animations, we set it to -1 to avoid confusion with
+ // color 0, which is used as a mask in some images
+ if (_mask == 0)
+ _mask = -1;
_fileName = Common::String(fileName);
}
ActionPreloadAnimation::~ActionPreloadAnimation() {
- _engine->getScriptManager()->deleteSideFx(_slotKey);
+ _scriptManager->deleteSideFx(_slotKey);
}
bool ActionPreloadAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey);
+ AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_slotKey);
if (!nod) {
- nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate, false);
- _engine->getScriptManager()->addSideFX(nod);
+ nod = new AnimationEffect(_engine, _slotKey, _fileName, _mask, _framerate, false);
+ _scriptManager->addSideFX(nod);
} else
nod->stop();
- _engine->getScriptManager()->setStateValue(_slotKey, 2);
+ _scriptManager->setStateValue(_slotKey, 2);
return true;
}
@@ -609,18 +615,18 @@ bool ActionPreloadAnimation::execute() {
// ActionUnloadAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
}
bool ActionUnloadAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_key);
+ AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_key);
- if (nod && nod->getType() == SideFX::SIDEFX_ANIM)
- _engine->getScriptManager()->deleteSideFx(_key);
+ if (nod && nod->getType() == ScriptingEffect::SCRIPTING_EFFECT_ANIM)
+ _scriptManager->deleteSideFx(_key);
return true;
}
@@ -629,8 +635,8 @@ bool ActionUnloadAnimation::execute() {
// ActionPlayAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_x = 0;
_y = 0;
_x2 = 0;
@@ -645,28 +651,35 @@ ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const C
// The two %*u are always 0 and dont seem to have a use
sscanf(line.c_str(),
- "%25s %u %u %u %u %u %u %d %*u %*u %d %d",
+ "%24s %u %u %u %u %u %u %d %*u %*u %d %d",
fileName, &_x, &_y, &_x2, &_y2, &_start, &_end, &_loopCount, &_mask, &_framerate);
- if (_mask > 0) {
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b);
- _mask = _engine->_pixelFormat.RGBToColor(r, g, b);
- }
+ // Mask 0 means "no transparency" in this case. Since we use a common blitting
+ // code for images and animations, we set it to -1 to avoid confusion with
+ // color 0, which is used as a mask in some images
+ if (_mask == 0)
+ _mask = -1;
_fileName = Common::String(fileName);
+
+ // WORKAROUND for bug #6769, location me1g.scr (the "Alchemical debacle"
+ // video in ZGI). We only scale up by 2x, in AnimationEffect::process(),
+ // but the dimensions of the target frame are off by 2 pixels. We fix that
+ // here, so that the video can be scaled.
+ if (_fileName == "me1ga011.avi" && _y2 == 213)
+ _y2 = 215;
}
ActionPlayAnimation::~ActionPlayAnimation() {
- _engine->getScriptManager()->deleteSideFx(_slotKey);
+ _scriptManager->deleteSideFx(_slotKey);
}
bool ActionPlayAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey);
+ AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_slotKey);
if (!nod) {
- nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate);
- _engine->getScriptManager()->addSideFX(nod);
+ nod = new AnimationEffect(_engine, _slotKey, _fileName, _mask, _framerate);
+ _scriptManager->addSideFX(nod);
} else
nod->stop();
@@ -680,8 +693,8 @@ bool ActionPlayAnimation::execute() {
// ActionPlayPreloadAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_controlKey = 0;
_x1 = 0;
_y1 = 0;
@@ -697,7 +710,7 @@ ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 sl
}
bool ActionPlayPreloadAnimation::execute() {
- AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_controlKey);
+ AnimationEffect *nod = (AnimationEffect *)_scriptManager->getSideFX(_controlKey);
if (nod)
nod->addPlayNode(_slotKey, _x1, _y1, _x2, _y2, _startFrame, _endFrame, _loopCount);
@@ -716,11 +729,11 @@ bool ActionQuit::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionRegion
+// ActionRegion - only used by Zork: Nemesis
//////////////////////////////////////////////////////////////////////////////
-ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRegion::ActionRegion(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_delay = 0;
_type = 0;
_unk1 = 0;
@@ -738,20 +751,20 @@ ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String
}
ActionRegion::~ActionRegion() {
- _engine->getScriptManager()->killSideFx(_slotKey);
+ _scriptManager->killSideFx(_slotKey);
}
bool ActionRegion::execute() {
- if (_engine->getScriptManager()->getSideFX(_slotKey))
+ if (_scriptManager->getSideFX(_slotKey))
return true;
- Effect *effct = NULL;
+ GraphicsEffect *effect = NULL;
switch (_type) {
case 0: {
uint16 centerX, centerY, frames;
double amplitude, waveln, speed;
sscanf(_custom.c_str(), "%hu,%hu,%hu,%lf,%lf,%lf,", &centerX, &centerY, &frames, &amplitude, &waveln, &speed);
- effct = new WaveFx(_engine, _slotKey, _rect, _unk1, frames, centerX, centerY, amplitude, waveln, speed);
+ effect = new WaveFx(_engine, _slotKey, _rect, _unk1, frames, centerX, centerY, amplitude, waveln, speed);
}
break;
case 1: {
@@ -763,7 +776,7 @@ bool ActionRegion::execute() {
int8 minD;
int8 maxD;
EffectMap *_map = _engine->getRenderManager()->makeEffectMap(Common::Point(aX, aY), aD, _rect, &minD, &maxD);
- effct = new LightFx(_engine, _slotKey, _rect, _unk1, _map, atoi(_custom.c_str()), minD, maxD);
+ effect = new LightFx(_engine, _slotKey, _rect, _unk1, _map, atoi(_custom.c_str()), minD, maxD);
}
break;
case 9: {
@@ -779,16 +792,16 @@ bool ActionRegion::execute() {
_rect.setHeight(tempMask.h);
EffectMap *_map = _engine->getRenderManager()->makeEffectMap(tempMask, 0);
- effct = new FogFx(_engine, _slotKey, _rect, _unk1, _map, Common::String(buf));
+ effect = new FogFx(_engine, _slotKey, _rect, _unk1, _map, Common::String(buf));
}
break;
default:
break;
}
- if (effct) {
- _engine->getScriptManager()->addSideFX(new RegionNode(_engine, _slotKey, effct, _delay));
- _engine->getRenderManager()->addEffect(effct);
+ if (effect) {
+ _scriptManager->addSideFX(new RegionNode(_engine, _slotKey, effect, _delay));
+ _engine->getRenderManager()->addEffect(effect);
}
return true;
@@ -798,22 +811,21 @@ bool ActionRegion::execute() {
// ActionRandom
//////////////////////////////////////////////////////////////////////////////
-ActionRandom::ActionRandom(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRandom::ActionRandom(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char maxBuffer[64];
memset(maxBuffer, 0, 64);
sscanf(line.c_str(), "%s", maxBuffer);
- _max = new ValueSlot(_engine->getScriptManager(), maxBuffer);
+ _max = new ValueSlot(_scriptManager, maxBuffer);
}
ActionRandom::~ActionRandom() {
- if (_max)
- delete _max;
+ delete _max;
}
bool ActionRandom::execute() {
uint randNumber = _engine->getRandomSource()->getRandomNumber(_max->getValue());
- _engine->getScriptManager()->setStateValue(_slotKey, randNumber);
+ _scriptManager->setStateValue(_slotKey, randNumber);
return true;
}
@@ -821,15 +833,15 @@ bool ActionRandom::execute() {
// ActionRestoreGame
//////////////////////////////////////////////////////////////////////////////
-ActionRestoreGame::ActionRestoreGame(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRestoreGame::ActionRestoreGame(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char buf[128];
sscanf(line.c_str(), "%s", buf);
_fileName = Common::String(buf);
}
bool ActionRestoreGame::execute() {
- _engine->getSaveManager()->loadGame(_fileName);
+ _engine->getSaveManager()->loadGame(-1);
return false;
}
@@ -837,8 +849,8 @@ bool ActionRestoreGame::execute() {
// ActionRotateTo
//////////////////////////////////////////////////////////////////////////////
-ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_time = 0;
_toPos = 0;
@@ -846,7 +858,7 @@ ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::Str
}
bool ActionRotateTo::execute() {
- _engine->rotateTo(_toPos, _time);
+ _engine->getRenderManager()->rotateTo(_toPos, _time);
return true;
}
@@ -855,27 +867,18 @@ bool ActionRotateTo::execute() {
// ActionSetPartialScreen
//////////////////////////////////////////////////////////////////////////////
-ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_x = 0;
_y = 0;
char fileName[25];
- int color;
- sscanf(line.c_str(), "%u %u %25s %*u %d", &_x, &_y, fileName, &color);
+ sscanf(line.c_str(), "%u %u %24s %*u %d", &_x, &_y, fileName, &_backgroundColor);
_fileName = Common::String(fileName);
- if (color >= 0) {
- byte r, g, b;
- Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(color, r, g, b);
- _backgroundColor = _engine->_pixelFormat.RGBToColor(r, g, b);
- } else {
- _backgroundColor = color;
- }
-
- if (color > 65535) {
+ if (_backgroundColor > 65535) {
warning("Background color for ActionSetPartialScreen is bigger than a uint16");
}
}
@@ -904,10 +907,10 @@ bool ActionSetPartialScreen::execute() {
// ActionSetScreen
//////////////////////////////////////////////////////////////////////////////
-ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char fileName[25];
- sscanf(line.c_str(), "%25s", fileName);
+ sscanf(line.c_str(), "%24s", fileName);
_fileName = Common::String(fileName);
}
@@ -919,35 +922,17 @@ bool ActionSetScreen::execute() {
}
//////////////////////////////////////////////////////////////////////////////
-// ActionSetVenus
-//////////////////////////////////////////////////////////////////////////////
-
-ActionSetVenus::ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
- _key = 0;
-
- sscanf(line.c_str(), "%d", &_key);
-}
-
-bool ActionSetVenus::execute() {
- if (_engine->getScriptManager()->getStateValue(_key))
- _engine->getScriptManager()->setStateValue(StateKey_Venus, _key);
-
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
// ActionStop
//////////////////////////////////////////////////////////////////////////////
-ActionStop::ActionStop(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionStop::ActionStop(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
}
bool ActionStop::execute() {
- _engine->getScriptManager()->stopSideFx(_key);
+ _scriptManager->stopSideFx(_key);
return true;
}
@@ -955,8 +940,8 @@ bool ActionStop::execute() {
// ActionStreamVideo
//////////////////////////////////////////////////////////////////////////////
-ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_x1 = 0;
_x2 = 0;
_y1 = 0;
@@ -966,42 +951,69 @@ ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Commo
char fileName[25];
uint skipline = 0; //skipline - render video with skip every second line, not skippable.
- sscanf(line.c_str(), "%25s %u %u %u %u %u %u", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skipline);
+ sscanf(line.c_str(), "%24s %u %u %u %u %u %u", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skipline);
_fileName = Common::String(fileName);
_skippable = true;
}
bool ActionStreamVideo::execute() {
- ZorkAVIDecoder decoder;
- Common::File *_file = _engine->getSearchManager()->openFile(_fileName);
-
- if (_file) {
- if (!decoder.loadStream(_file)) {
+ Video::VideoDecoder *decoder;
+ Common::Rect destRect = Common::Rect(_x1, _y1, _x2 + 1, _y2 + 1);
+ Common::String subname = _fileName;
+ subname.setChar('s', subname.size() - 3);
+ subname.setChar('u', subname.size() - 2);
+ subname.setChar('b', subname.size() - 1);
+ bool subtitleExists = _engine->getSearchManager()->hasFile(subname);
+ bool switchToHires = false;
+
+// NOTE: We only show the hires MPEG2 videos when libmpeg2 is compiled in,
+// otherwise we fall back to the lowres ones
+#ifdef USE_MPEG2
+ Common::String hiresFileName = _fileName;
+ hiresFileName.setChar('d', hiresFileName.size() - 8);
+ hiresFileName.setChar('v', hiresFileName.size() - 3);
+ hiresFileName.setChar('o', hiresFileName.size() - 2);
+ hiresFileName.setChar('b', hiresFileName.size() - 1);
+
+ if (_scriptManager->getStateValue(StateKey_MPEGMovies) == 1 &&_engine->getSearchManager()->hasFile(hiresFileName)) {
+ // TODO: Enable once AC3 support is implemented
+ if (!_engine->getSearchManager()->hasFile(_fileName)) // Check for the regular video
return true;
- }
-
- _engine->getCursorManager()->showMouse(false);
+ warning("The hires videos of the DVD version of ZGI aren't supported yet, using lowres");
+ //_fileName = hiresFileName;
+ //switchToHires = true;
+ } else if (!_engine->getSearchManager()->hasFile(_fileName))
+ return true;
+#else
+ if (!_engine->getSearchManager()->hasFile(_fileName))
+ return true;
+#endif
- Common::Rect destRect = Common::Rect(_x1, _y1, _x2 + 1, _y2 + 1);
+ decoder = _engine->loadAnimation(_fileName);
+ Subtitle *sub = (subtitleExists) ? new Subtitle(_engine, subname, switchToHires) : NULL;
- Common::String subname = _fileName;
- subname.setChar('s', subname.size() - 3);
- subname.setChar('u', subname.size() - 2);
- subname.setChar('b', subname.size() - 1);
+ _engine->getCursorManager()->showMouse(false);
- Subtitle *sub = NULL;
+ if (switchToHires) {
+ _engine->initHiresScreen();
+ destRect = Common::Rect(40, -40, 760, 440);
+ Common::Rect workingWindow = _engine->_workingWindow;
+ workingWindow.translate(0, -40);
+ _engine->getRenderManager()->initSubArea(HIRES_WINDOW_WIDTH, HIRES_WINDOW_HEIGHT, workingWindow);
+ }
- if (_engine->getSearchManager()->hasFile(subname))
- sub = new Subtitle(_engine, subname);
+ _engine->playVideo(*decoder, destRect, _skippable, sub);
- _engine->playVideo(decoder, destRect, _skippable, sub);
+ if (switchToHires) {
+ _engine->initScreen();
+ _engine->getRenderManager()->initSubArea(WINDOW_WIDTH, WINDOW_HEIGHT, _engine->_workingWindow);
+ }
- _engine->getCursorManager()->showMouse(true);
+ _engine->getCursorManager()->showMouse(true);
- if (sub)
- delete sub;
- }
+ delete decoder;
+ delete sub;
return true;
}
@@ -1010,31 +1022,27 @@ bool ActionStreamVideo::execute() {
// ActionSyncSound
//////////////////////////////////////////////////////////////////////////////
-ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_syncto = 0;
char fileName[25];
int notUsed = 0;
- sscanf(line.c_str(), "%d %d %25s", &_syncto, &notUsed, fileName);
+ sscanf(line.c_str(), "%d %d %24s", &_syncto, &notUsed, fileName);
_fileName = Common::String(fileName);
}
bool ActionSyncSound::execute() {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_syncto);
+ ScriptingEffect *fx = _scriptManager->getSideFX(_syncto);
if (!fx)
return true;
- if (!(fx->getType() & SideFX::SIDEFX_ANIM))
+ if (!(fx->getType() & ScriptingEffect::SCRIPTING_EFFECT_ANIM))
return true;
- AnimationNode *animnode = (AnimationNode *)fx;
- if (animnode->getFrameDelay() > 200) // Hack for fix incorrect framedelay in some animpreload
- animnode->setNewFrameDelay(66); // ~15fps
-
- _engine->getScriptManager()->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto));
+ _scriptManager->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto));
return true;
}
@@ -1042,24 +1050,23 @@ bool ActionSyncSound::execute() {
// ActionTimer
//////////////////////////////////////////////////////////////////////////////
-ActionTimer::ActionTimer(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionTimer::ActionTimer(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char timeBuffer[64];
memset(timeBuffer, 0, 64);
sscanf(line.c_str(), "%s", timeBuffer);
- _time = new ValueSlot(_engine->getScriptManager(), timeBuffer);
+ _time = new ValueSlot(_scriptManager, timeBuffer);
}
ActionTimer::~ActionTimer() {
- if (_time)
- delete _time;
- _engine->getScriptManager()->killSideFx(_slotKey);
+ delete _time;
+ _scriptManager->killSideFx(_slotKey);
}
bool ActionTimer::execute() {
- if (_engine->getScriptManager()->getSideFX(_slotKey))
+ if (_scriptManager->getSideFX(_slotKey))
return true;
- _engine->getScriptManager()->addSideFX(new TimerNode(_engine, _slotKey, _time->getValue()));
+ _scriptManager->addSideFX(new TimerNode(_engine, _slotKey, _time->getValue()));
return true;
}
@@ -1067,25 +1074,25 @@ bool ActionTimer::execute() {
// ActionTtyText
//////////////////////////////////////////////////////////////////////////////
-ActionTtyText::ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionTtyText::ActionTtyText(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_delay = 0;
char filename[64];
int32 x1 = 0, y1 = 0, x2 = 0, y2 = 0;
- sscanf(line.c_str(), "%d %d %d %d %64s %u", &x1, &y1, &x2, &y2, filename, &_delay);
+ sscanf(line.c_str(), "%d %d %d %d %63s %u", &x1, &y1, &x2, &y2, filename, &_delay);
_r = Common::Rect(x1, y1, x2, y2);
_filename = Common::String(filename);
}
ActionTtyText::~ActionTtyText() {
- _engine->getScriptManager()->killSideFx(_slotKey);
+ _scriptManager->killSideFx(_slotKey);
}
bool ActionTtyText::execute() {
- if (_engine->getScriptManager()->getSideFX(_slotKey))
+ if (_scriptManager->getSideFX(_slotKey))
return true;
- _engine->getScriptManager()->addSideFX(new ttyTextNode(_engine, _slotKey, _filename, _r, _delay));
+ _scriptManager->addSideFX(new ttyTextNode(_engine, _slotKey, _filename, _r, _delay));
return true;
}
diff --git a/engines/zvision/scripting/actions.h b/engines/zvision/scripting/actions.h
index 292e25e19c..bde1baa291 100644
--- a/engines/zvision/scripting/actions.h
+++ b/engines/zvision/scripting/actions.h
@@ -32,6 +32,7 @@ namespace ZVision {
// Forward declaration of ZVision. This file is included before ZVision is declared
class ZVision;
+class ScriptManager;
class ValueSlot;
/**
@@ -40,7 +41,7 @@ class ValueSlot;
*/
class ResultAction {
public:
- ResultAction(ZVision *engine, int32 slotkey) : _engine(engine), _slotKey(slotkey) {}
+ ResultAction(ZVision *engine, int32 slotkey);
virtual ~ResultAction() {}
/**
* This is called by the script system whenever a Puzzle's criteria are found to be true.
@@ -53,6 +54,7 @@ public:
virtual bool execute() = 0;
protected:
ZVision *_engine;
+ ScriptManager *_scriptManager;
int32 _slotKey;
};
@@ -124,14 +126,6 @@ private:
uint8 _action;
};
-class ActionDebug : public ResultAction {
-public:
- ActionDebug(ZVision *engine, int32 slotkey, const Common::String &line);
- bool execute();
-
-private:
-};
-
class ActionDelayRender : public ResultAction {
public:
ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line);
@@ -150,15 +144,6 @@ private:
uint32 _key;
};
-class ActionDisableVenus : public ResultAction {
-public:
- ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line);
- bool execute();
-
-private:
- int32 _key;
-};
-
class ActionDisplayMessage : public ResultAction {
public:
ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line);
@@ -241,7 +226,7 @@ public:
private:
Common::String _fileName;
bool _loop;
- byte _volume;
+ ValueSlot *_volume;
bool _universe;
bool _midi;
int8 _note;
@@ -284,7 +269,6 @@ public:
bool execute();
private:
- uint32 _animationKey;
uint32 _controlKey;
uint32 _x1;
uint32 _y1;
@@ -338,7 +322,7 @@ private:
uint16 _unk2;
};
-// TODO: See if this exists in ZGI. It doesn't in ZNem
+// Only used by ZGI (locations cd6e, cd6k, dg2f, dg4e, dv1j)
class ActionUnloadAnimation : public ResultAction {
public:
ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line);
@@ -397,15 +381,6 @@ private:
Common::String _fileName;
};
-class ActionSetVenus : public ResultAction {
-public:
- ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line);
- bool execute();
-
-private:
- int32 _key;
-};
-
class ActionStop : public ResultAction {
public:
ActionStop(ZVision *engine, int32 slotkey, const Common::String &line);
diff --git a/engines/zvision/scripting/control.cpp b/engines/zvision/scripting/control.cpp
index 127f35ef12..81123eb99b 100644
--- a/engines/zvision/scripting/control.cpp
+++ b/engines/zvision/scripting/control.cpp
@@ -72,6 +72,7 @@ void Control::parsePanoramaControl(ZVision *engine, Common::SeekableReadStream &
renderTable->generateRenderTable();
}
+// Only used in Zork Nemesis, handles tilt controls (ZGI doesn't have a tilt view)
void Control::parseTiltControl(ZVision *engine, Common::SeekableReadStream &stream) {
RenderTable *renderTable = engine->getRenderManager()->getRenderTable();
renderTable->setRenderState(RenderTable::TILT);
diff --git a/engines/zvision/scripting/control.h b/engines/zvision/scripting/control.h
index 803d0cf1ce..108b83fd00 100644
--- a/engines/zvision/scripting/control.h
+++ b/engines/zvision/scripting/control.h
@@ -36,6 +36,11 @@ namespace ZVision {
class ZVision;
+/**
+ * The base class for all Controls.
+ *
+ * Controls are the things that the user interacts with. Ex: A lever on the door
+ */
class Control {
public:
diff --git a/engines/zvision/scripting/controls/fist_control.cpp b/engines/zvision/scripting/controls/fist_control.cpp
index 34a64b4298..f79c82dc79 100644
--- a/engines/zvision/scripting/controls/fist_control.cpp
+++ b/engines/zvision/scripting/controls/fist_control.cpp
@@ -46,10 +46,6 @@ FistControl::FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream
_order = 0;
_fistnum = 0;
- _frameCur = -1;
- _frameEnd = -1;
- _frameTime = 0;
- _lastRenderedFrame = -1;
_animationId = 0;
clearFistArray(_fistsUp);
@@ -95,41 +91,28 @@ FistControl::~FistControl() {
_entries.clear();
}
-void FistControl::renderFrame(uint frameNumber) {
- if ((int32)frameNumber == _lastRenderedFrame)
- return;
-
- _lastRenderedFrame = frameNumber;
-
- const Graphics::Surface *frameData;
-
- if (_animation) {
- _animation->seekToFrame(frameNumber);
- frameData = _animation->decodeNextFrame();
- if (frameData)
- _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _anmRect);
- }
-}
-
bool FistControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
- if (_frameCur >= 0 && _frameEnd >= 0)
- if (_frameCur <= _frameEnd) {
- _frameTime -= deltaTimeInMillis;
-
- if (_frameTime <= 0) {
- _frameTime = 1000.0 / _animation->getDuration().framerate();
-
- renderFrame(_frameCur);
-
- _frameCur++;
+ if (_animation && _animation->isPlaying()) {
+ if (_animation->endOfVideo()) {
+ _animation->stop();
+ _engine->getScriptManager()->setStateValue(_animationId, 2);
+ return false;
+ }
- if (_frameCur > _frameEnd)
- _engine->getScriptManager()->setStateValue(_animationId, 2);
- }
+ if (_animation->needsUpdate()) {
+ const Graphics::Surface *frameData = _animation->decodeNextFrame();
+ if (frameData)
+ // WORKAROUND: Ignore the target frame dimensions for the finger animations.
+ // The target dimensions specify an area smaller than expected, thus if we
+ // scale the finger videos to fit these dimensions, they are not aligned
+ // correctly. Not scaling these videos yields a result identical to the
+ // original. Fixes bug #6784.
+ _engine->getRenderManager()->blitSurfaceToBkg(*frameData, _anmRect.left, _anmRect.top);
}
+ }
return false;
}
@@ -160,9 +143,12 @@ bool FistControl::onMouseUp(const Common::Point &screenSpacePos, const Common::P
for (int i = 0; i < _numEntries; i++)
if (_entries[i]._bitsStrt == oldStatus && _entries[i]._bitsEnd == _fiststatus) {
- _frameCur = _entries[i]._anmStrt;
- _frameEnd = _entries[i]._anmEnd;
- _frameTime = 0;
+ if (_animation) {
+ _animation->stop();
+ _animation->seekToFrame(_entries[i]._anmStrt);
+ _animation->setEndFrame(_entries[i]._anmEnd);
+ _animation->start();
+ }
_engine->getScriptManager()->setStateValue(_animationId, 1);
_engine->getScriptManager()->setStateValue(_soundKey, _entries[i]._sound);
diff --git a/engines/zvision/scripting/controls/fist_control.h b/engines/zvision/scripting/controls/fist_control.h
index 0a6b977ead..d7cbcb1f71 100644
--- a/engines/zvision/scripting/controls/fist_control.h
+++ b/engines/zvision/scripting/controls/fist_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles the door lock puzzle with the skeletal fingers (td9e)
class FistControl : public Control {
public:
FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
@@ -63,10 +64,6 @@ private:
Video::VideoDecoder *_animation;
Common::Rect _anmRect;
int32 _soundKey;
- int32 _frameCur;
- int32 _frameEnd;
- int32 _frameTime;
- int32 _lastRenderedFrame;
int32 _animationId;
public:
@@ -75,7 +72,6 @@ public:
bool process(uint32 deltaTimeInMillis);
private:
- void renderFrame(uint frameNumber);
void readDescFile(const Common::String &fileName);
void clearFistArray(Common::Array< Common::Array<Common::Rect> > &arr);
uint32 readBits(const char *str);
diff --git a/engines/zvision/scripting/controls/hotmov_control.cpp b/engines/zvision/scripting/controls/hotmov_control.cpp
index e77272ec73..182447a990 100644
--- a/engines/zvision/scripting/controls/hotmov_control.cpp
+++ b/engines/zvision/scripting/controls/hotmov_control.cpp
@@ -41,10 +41,7 @@ HotMovControl::HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadSt
: Control(engine, key, CONTROL_HOTMOV) {
_animation = NULL;
_cycle = 0;
- _curFrame = -1;
- _lastRenderedFrame = -1;
_frames.clear();
- _frameTime = 0;
_cyclesCount = 0;
_framesCount = 0;
@@ -78,6 +75,7 @@ HotMovControl::HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadSt
sscanf(values.c_str(), "%s", filename);
values = Common::String(filename);
_animation = _engine->loadAnimation(values);
+ _animation->start();
} else if (param.matchString("venus_id", true)) {
_venusId = atoi(values.c_str());
}
@@ -95,41 +93,26 @@ HotMovControl::~HotMovControl() {
_frames.clear();
}
-void HotMovControl::renderFrame(uint frameNumber) {
- if ((int)frameNumber == _lastRenderedFrame)
- return;
-
- _lastRenderedFrame = frameNumber;
-
- const Graphics::Surface *frameData;
-
- if (_animation) {
- _animation->seekToFrame(frameNumber);
- frameData = _animation->decodeNextFrame();
- if (frameData)
- _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _rectangle);
- }
-}
-
bool HotMovControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
if (_cycle < _cyclesCount) {
- _frameTime -= deltaTimeInMillis;
+ if (_animation && _animation->endOfVideo()) {
+ _cycle++;
- if (_frameTime <= 0) {
- _curFrame++;
- if (_curFrame >= _framesCount) {
- _curFrame = 0;
- _cycle++;
- }
- if (_cycle != _cyclesCount)
- renderFrame(_curFrame);
- else
+ if (_cycle == _cyclesCount) {
_engine->getScriptManager()->setStateValue(_key, 2);
+ return false;
+ }
+
+ _animation->rewind();
+ }
- _frameTime = 1000.0 / _animation->getDuration().framerate();
+ if (_animation && _animation->needsUpdate()) {
+ const Graphics::Surface *frameData = _animation->decodeNextFrame();
+ if (frameData)
+ _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _rectangle);
}
}
@@ -140,8 +123,11 @@ bool HotMovControl::onMouseMove(const Common::Point &screenSpacePos, const Commo
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
+ if (!_animation)
+ return false;
+
if (_cycle < _cyclesCount) {
- if (_frames[_curFrame].contains(backgroundImageSpacePos)) {
+ if (_frames[_animation->getCurFrame()].contains(backgroundImageSpacePos)) {
_engine->getCursorManager()->changeCursor(CursorIndex_Active);
return true;
}
@@ -154,8 +140,11 @@ bool HotMovControl::onMouseUp(const Common::Point &screenSpacePos, const Common:
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
+ if (!_animation)
+ return false;
+
if (_cycle < _cyclesCount) {
- if (_frames[_curFrame].contains(backgroundImageSpacePos)) {
+ if (_frames[_animation->getCurFrame()].contains(backgroundImageSpacePos)) {
setVenus();
_engine->getScriptManager()->setStateValue(_key, 1);
return true;
diff --git a/engines/zvision/scripting/controls/hotmov_control.h b/engines/zvision/scripting/controls/hotmov_control.h
index b18d44c7a6..99d1fd0979 100644
--- a/engines/zvision/scripting/controls/hotmov_control.h
+++ b/engines/zvision/scripting/controls/hotmov_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles movies where the player needs to click on something (mj7g, vw3g)
class HotMovControl : public Control {
public:
HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
@@ -41,9 +42,6 @@ public:
private:
int32 _framesCount;
- int32 _frameTime;
- int32 _curFrame;
- int32 _lastRenderedFrame;
int32 _cycle;
int32 _cyclesCount;
Video::VideoDecoder *_animation;
@@ -55,7 +53,6 @@ public:
bool process(uint32 deltaTimeInMillis);
private:
- void renderFrame(uint frameNumber);
void readHsFile(const Common::String &fileName);
};
diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp
index e75cc15743..9525333ef0 100644
--- a/engines/zvision/scripting/controls/input_control.cpp
+++ b/engines/zvision/scripting/controls/input_control.cpp
@@ -39,16 +39,14 @@ namespace ZVision {
InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream)
: Control(engine, key, CONTROL_INPUT),
+ _background(0),
_nextTabstop(0),
_focused(false),
_textChanged(false),
- _cursorOffset(0),
_enterPressed(false),
_readOnly(false),
_txtWidth(0),
- _animation(NULL),
- _frameDelay(0),
- _frame(-1) {
+ _animation(NULL) {
// Loop until we find the closing brace
Common::String line = stream.readLine();
_engine->getScriptManager()->trimCommentsAndWhiteSpace(&line);
@@ -80,13 +78,13 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
sscanf(values.c_str(), "%u", &fontFormatNumber);
- _stringInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber));
+ _stringInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber));
} else if (param.matchString("chooser_init_string", true)) {
uint fontFormatNumber;
sscanf(values.c_str(), "%u", &fontFormatNumber);
- _stringChooserInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber));
+ _stringChooserInit.readAllStyles(_engine->getStringManager()->getTextLine(fontFormatNumber));
} else if (param.matchString("next_tabstop", true)) {
sscanf(values.c_str(), "%u", &_nextTabstop);
} else if (param.matchString("cursor_dimensions", true)) {
@@ -96,11 +94,10 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
} else if (param.matchString("cursor_animation", true)) {
char fileName[25];
- sscanf(values.c_str(), "%25s %*u", fileName);
+ sscanf(values.c_str(), "%24s %*u", fileName);
_animation = _engine->loadAnimation(fileName);
- _frame = -1;
- _frameDelay = 0;
+ _animation->start();
} else if (param.matchString("focus", true)) {
_focused = true;
_engine->getScriptManager()->setFocusControlKey(_key);
@@ -112,6 +109,15 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
_engine->getScriptManager()->trimCommentsAndWhiteSpace(&line);
getParams(line, param, values);
}
+
+ _maxTxtWidth = _textRectangle.width();
+ if (_animation)
+ _maxTxtWidth -= _animation->getWidth();
+}
+
+InputControl::~InputControl() {
+ _background->free();
+ delete _background;
}
bool InputControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
@@ -194,36 +200,42 @@ bool InputControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
+ if (!_background) {
+ _background = _engine->getRenderManager()->getBkgRect(_textRectangle);
+ }
+
// First see if we need to render the text
if (_textChanged) {
// Blit the text using the RenderManager
Graphics::Surface txt;
- txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_pixelFormat);
+ txt.copyFrom(*_background);
+
+ int32 oldTxtWidth = _txtWidth;
if (!_readOnly || !_focused)
- _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt);
+ _txtWidth = _engine->getTextRenderer()->drawText(_currentInputText, _stringInit, txt);
else
- _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringChooserInit, txt);
+ _txtWidth = _engine->getTextRenderer()->drawText(_currentInputText, _stringChooserInit, txt);
- _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top);
+ if (_readOnly || _txtWidth <= _maxTxtWidth)
+ _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top);
+ else {
+ // Assume the last character caused the overflow.
+ _currentInputText.deleteLastChar();
+ _txtWidth = oldTxtWidth;
+ }
txt.free();
}
if (_animation && !_readOnly && _focused) {
- bool needDraw = true;// = _textChanged;
- _frameDelay -= deltaTimeInMillis;
- if (_frameDelay <= 0) {
- _frame = (_frame + 1) % _animation->getFrameCount();
- _frameDelay = 1000.0 / _animation->getDuration().framerate();
- needDraw = true;
- }
+ if (_animation->endOfVideo())
+ _animation->rewind();
- if (needDraw) {
- _animation->seekToFrame(_frame);
+ if (_animation->needsUpdate()) {
const Graphics::Surface *srf = _animation->decodeNextFrame();
- uint32 xx = _textRectangle.left + _txtWidth;
+ int16 xx = _textRectangle.left + _txtWidth;
if (xx >= _textRectangle.left + (_textRectangle.width() - (int16)_animation->getWidth()))
xx = _textRectangle.left + _textRectangle.width() - (int16)_animation->getWidth();
_engine->getRenderManager()->blitSurfaceToBkg(*srf, xx, _textRectangle.top);
diff --git a/engines/zvision/scripting/controls/input_control.h b/engines/zvision/scripting/controls/input_control.h
index 99f7f5287d..6abdb3c692 100644
--- a/engines/zvision/scripting/controls/input_control.h
+++ b/engines/zvision/scripting/controls/input_control.h
@@ -38,25 +38,25 @@ namespace ZVision {
class InputControl : public Control {
public:
InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
+ ~InputControl();
private:
+ Graphics::Surface *_background;
Common::Rect _textRectangle;
Common::Rect _headerRectangle;
- cTxtStyle _stringInit;
- cTxtStyle _stringChooserInit;
+ TextStyleState _stringInit;
+ TextStyleState _stringChooserInit;
uint32 _nextTabstop;
bool _focused;
Common::String _currentInputText;
bool _textChanged;
- uint _cursorOffset;
bool _enterPressed;
bool _readOnly;
int16 _txtWidth;
+ int16 _maxTxtWidth;
Video::VideoDecoder *_animation;
- int32 _frameDelay;
- int16 _frame;
public:
void focus() {
diff --git a/engines/zvision/scripting/controls/lever_control.cpp b/engines/zvision/scripting/controls/lever_control.cpp
index 8faa18357c..0f105b424c 100644
--- a/engines/zvision/scripting/controls/lever_control.cpp
+++ b/engines/zvision/scripting/controls/lever_control.cpp
@@ -64,12 +64,12 @@ LeverControl::LeverControl(ZVision *engine, uint32 key, Common::SeekableReadStre
while (!stream.eos() && !line.contains('}')) {
if (param.matchString("descfile", true)) {
char levFileName[25];
- sscanf(values.c_str(), "%25s", levFileName);
+ sscanf(values.c_str(), "%24s", levFileName);
parseLevFile(levFileName);
} else if (param.matchString("cursor", true)) {
char cursorName[25];
- sscanf(values.c_str(), "%25s", cursorName);
+ sscanf(values.c_str(), "%24s", cursorName);
_cursor = _engine->getCursorManager()->getCursorId(Common::String(cursorName));
}
@@ -232,10 +232,13 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common
if (angle >= (int)iter->angle - ANGLE_DELTA && angle <= (int)iter->angle + ANGLE_DELTA) {
_currentFrame = iter->toFrame;
renderFrame(_currentFrame);
+ _engine->getScriptManager()->setStateValue(_key, _currentFrame);
break;
}
}
}
+ _engine->getCursorManager()->changeCursor(_cursor);
+ cursorWasChanged = true;
} else if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) {
_engine->getCursorManager()->changeCursor(_cursor);
cursorWasChanged = true;
diff --git a/engines/zvision/scripting/controls/lever_control.h b/engines/zvision/scripting/controls/lever_control.h
index fdf4a649dc..8787234c51 100644
--- a/engines/zvision/scripting/controls/lever_control.h
+++ b/engines/zvision/scripting/controls/lever_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles draggable levers (te2e, tm7e, tp2e, tt2e, tz2e)
class LeverControl : public Control {
public:
LeverControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
diff --git a/engines/zvision/scripting/controls/paint_control.cpp b/engines/zvision/scripting/controls/paint_control.cpp
index df06bb814e..62dde3d170 100644
--- a/engines/zvision/scripting/controls/paint_control.cpp
+++ b/engines/zvision/scripting/controls/paint_control.cpp
@@ -114,12 +114,18 @@ PaintControl::PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStre
PaintControl::~PaintControl() {
// Clear the state value back to 0
//_engine->getScriptManager()->setStateValue(_key, 0);
- if (_paint)
+ if (_paint) {
+ _paint->free();
delete _paint;
- if (_brush)
+ }
+ if (_brush) {
+ _brush->free();
delete _brush;
- if (_bkg)
+ }
+ if (_bkg) {
+ _bkg->free();
delete _bkg;
+ }
}
bool PaintControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
diff --git a/engines/zvision/scripting/controls/paint_control.h b/engines/zvision/scripting/controls/paint_control.h
index 8097290ac2..8c01f0e68a 100644
--- a/engines/zvision/scripting/controls/paint_control.h
+++ b/engines/zvision/scripting/controls/paint_control.h
@@ -32,6 +32,7 @@
namespace ZVision {
+// Only used in Zork Nemesis, handles the painting puzzle screen in Lucien's room in Irondune (ch4g)
class PaintControl : public Control {
public:
PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
diff --git a/engines/zvision/scripting/controls/safe_control.cpp b/engines/zvision/scripting/controls/safe_control.cpp
index 71be692431..4d2a91a1ad 100644
--- a/engines/zvision/scripting/controls/safe_control.cpp
+++ b/engines/zvision/scripting/controls/safe_control.cpp
@@ -49,10 +49,7 @@ SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream
_outerRadiusSqr = 0;
_zeroPointer = 0;
_startPointer = 0;
- _curFrame = -1;
_targetFrame = 0;
- _frameTime = 0;
- _lastRenderedFrame = -1;
// Loop until we find the closing brace
Common::String line = stream.readLine();
@@ -64,6 +61,7 @@ SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream
while (!stream.eos() && !line.contains('}')) {
if (param.matchString("animation", true)) {
_animation = _engine->loadAnimation(values);
+ _animation->start();
} else if (param.matchString("rectangle", true)) {
int x;
int y;
@@ -104,7 +102,9 @@ SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream
_engine->getScriptManager()->trimCommentsAndWhiteSpace(&line);
getParams(line, param, values);
}
- renderFrame(_curState);
+
+ if (_animation)
+ _animation->seekToFrame(_curState);
}
SafeControl::~SafeControl() {
@@ -113,44 +113,22 @@ SafeControl::~SafeControl() {
}
-void SafeControl::renderFrame(uint frameNumber) {
- if (frameNumber == 0) {
- _lastRenderedFrame = frameNumber;
- } else if ((int16)frameNumber < _lastRenderedFrame) {
- _lastRenderedFrame = frameNumber;
- frameNumber = (_statesCount * 2) - frameNumber;
- } else {
- _lastRenderedFrame = frameNumber;
- }
-
- const Graphics::Surface *frameData;
- int x = _rectangle.left;
- int y = _rectangle.top;
-
- _animation->seekToFrame(frameNumber);
- frameData = _animation->decodeNextFrame();
- if (frameData)
- _engine->getRenderManager()->blitSurfaceToBkg(*frameData, x, y);
-}
-
bool SafeControl::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED)
return false;
- if (_curFrame != _targetFrame) {
- _frameTime -= deltaTimeInMillis;
-
- if (_frameTime <= 0) {
- if (_curFrame < _targetFrame) {
- _curFrame++;
- renderFrame(_curFrame);
- } else if (_curFrame > _targetFrame) {
- _curFrame--;
- renderFrame(_curFrame);
- }
- _frameTime = 1000.0 / _animation->getDuration().framerate();
- }
+ if (_animation && _animation->getCurFrame() != _targetFrame && _animation->needsUpdate()) {
+ // If we're past the target frame, move back one
+ if (_animation->getCurFrame() > _targetFrame)
+ _animation->seekToFrame(_animation->getCurFrame() - 1);
+
+ const Graphics::Surface *frameData = _animation->decodeNextFrame();
+ if (_animation->getCurFrame() == _targetFrame)
+ _engine->getScriptManager()->setStateValue(_key, _curState);
+ if (frameData)
+ _engine->getRenderManager()->blitSurfaceToBkg(*frameData, _rectangle.left, _rectangle.top);
}
+
return false;
}
@@ -187,13 +165,12 @@ bool SafeControl::onMouseUp(const Common::Point &screenSpacePos, const Common::P
int16 tmp2 = (m_state + _curState - _zeroPointer + _statesCount - 1) % _statesCount;
- _curFrame = (_curState + _statesCount - _startPointer) % _statesCount;
+ if (_animation)
+ _animation->seekToFrame((_curState + _statesCount - _startPointer) % _statesCount);
_curState = (_statesCount * 2 + tmp2) % _statesCount;
_targetFrame = (_curState + _statesCount - _startPointer) % _statesCount;
-
- _engine->getScriptManager()->setStateValue(_key, _curState);
return true;
}
}
diff --git a/engines/zvision/scripting/controls/safe_control.h b/engines/zvision/scripting/controls/safe_control.h
index 6e1095e304..3e8c17635c 100644
--- a/engines/zvision/scripting/controls/safe_control.h
+++ b/engines/zvision/scripting/controls/safe_control.h
@@ -34,6 +34,7 @@ namespace Video {
namespace ZVision {
+// Only used in Zork Nemesis, handles the safe in the Asylum (ac4g)
class SafeControl : public Control {
public:
SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
@@ -51,19 +52,12 @@ private:
int32 _outerRadiusSqr;
int16 _zeroPointer;
int16 _startPointer;
- int16 _curFrame;
int16 _targetFrame;
- int32 _frameTime;
-
- int16 _lastRenderedFrame;
public:
bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos);
bool process(uint32 deltaTimeInMillis);
-
-private:
- void renderFrame(uint frameNumber);
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/controls/save_control.cpp b/engines/zvision/scripting/controls/save_control.cpp
index b35611feca..2ac77c4776 100644
--- a/engines/zvision/scripting/controls/save_control.cpp
+++ b/engines/zvision/scripting/controls/save_control.cpp
@@ -29,7 +29,8 @@
#include "zvision/scripting/script_manager.h"
#include "zvision/text/string_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
+#include "zvision/graphics/render_manager.h"
#include "common/str.h"
#include "common/stream.h"
@@ -97,18 +98,16 @@ bool SaveControl::process(uint32 deltaTimeInMillis) {
if (inp->getText().size() > 0) {
bool toSave = true;
if (iter->exist)
- if (!_engine->askQuestion(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEXIST)))
+ if (!_engine->getRenderManager()->askQuestion(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEXIST)))
toSave = false;
if (toSave) {
- // FIXME: At this point, the screen shows the save control, so the save game thumbnails will always
- // show the save control
- _engine->getSaveManager()->saveGameBuffered(iter->saveId, inp->getText());
- _engine->delayedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVED), 2000);
+ _engine->getSaveManager()->saveGame(iter->saveId, inp->getText(), true);
+ _engine->getRenderManager()->delayedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVED), 2000);
_engine->getScriptManager()->changeLocation(_engine->getScriptManager()->getLastMenuLocation());
}
} else {
- _engine->timedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEMPTY), 2000);
+ _engine->getRenderManager()->timedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEMPTY), 2000);
}
} else {
_engine->getSaveManager()->loadGame(iter->saveId);
diff --git a/engines/zvision/scripting/controls/titler_control.cpp b/engines/zvision/scripting/controls/titler_control.cpp
index 10ba0af655..683d6660af 100644
--- a/engines/zvision/scripting/controls/titler_control.cpp
+++ b/engines/zvision/scripting/controls/titler_control.cpp
@@ -67,20 +67,22 @@ TitlerControl::TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadSt
if (!_rectangle.isEmpty()) {
_surface = new Graphics::Surface;
- _surface->create(_rectangle.width(), _rectangle.height(), _engine->_pixelFormat);
+ _surface->create(_rectangle.width(), _rectangle.height(), _engine->_resourcePixelFormat);
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
}
}
TitlerControl::~TitlerControl() {
- if (_surface)
+ if (_surface) {
+ _surface->free();
delete _surface;
+ }
}
void TitlerControl::setString(int strLine) {
if (strLine != _curString && strLine >= 0 && strLine < (int)_strings.size()) {
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
- _engine->getTextRenderer()->drawTxtInOneLine(_strings[strLine], *_surface);
+ _engine->getTextRenderer()->drawTextWithWordWrapping(_strings[strLine], *_surface);
_engine->getRenderManager()->blitSurfaceToBkg(*_surface, _rectangle.left, _rectangle.top);
_curString = strLine;
}
diff --git a/engines/zvision/scripting/controls/titler_control.h b/engines/zvision/scripting/controls/titler_control.h
index 075e47c9e9..dd96e4a846 100644
--- a/engines/zvision/scripting/controls/titler_control.h
+++ b/engines/zvision/scripting/controls/titler_control.h
@@ -32,6 +32,7 @@
namespace ZVision {
+// Only used in Zork Nemesis, handles the death screen with the Restore/Exit buttons
class TitlerControl : public Control {
public:
TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream);
diff --git a/engines/zvision/scripting/sidefx/animation_node.cpp b/engines/zvision/scripting/effects/animation_effect.cpp
index 3a21227d1a..511a0db353 100644
--- a/engines/zvision/scripting/sidefx/animation_node.cpp
+++ b/engines/zvision/scripting/effects/animation_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/animation_node.h"
+#include "zvision/scripting/effects/animation_effect.h"
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
@@ -33,20 +33,27 @@
namespace ZVision {
-AnimationNode::AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse)
- : SideFX(engine, controlKey, SIDEFX_ANIM),
- _DisposeAfterUse(DisposeAfterUse),
+AnimationEffect::AnimationEffect(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool disposeAfterUse)
+ : ScriptingEffect(engine, controlKey, SCRIPTING_EFFECT_ANIM),
+ _disposeAfterUse(disposeAfterUse),
_mask(mask),
_animation(NULL) {
_animation = engine->loadAnimation(fileName);
- _frmDelay = 1000.0 / _animation->getDuration().framerate();
- if (frate > 0)
- _frmDelay = 1000.0 / frate;
+ if (frate > 0) {
+ _frmDelayOverride = (int32)(1000.0 / frate);
+
+ // WORKAROUND: We do not allow the engine to delay more than 66 msec
+ // per frame (15fps max)
+ if (_frmDelayOverride > 66)
+ _frmDelayOverride = 66;
+ } else {
+ _frmDelayOverride = 0;
+ }
}
-AnimationNode::~AnimationNode() {
+AnimationEffect::~AnimationEffect() {
if (_animation)
delete _animation;
@@ -56,60 +63,83 @@ AnimationNode::~AnimationNode() {
if (it != _playList.end()) {
_engine->getScriptManager()->setStateValue((*it).slot, 2);
- if ((*it)._scaled)
+ if ((*it)._scaled) {
+ (*it)._scaled->free();
delete(*it)._scaled;
+ }
}
_playList.clear();
}
-bool AnimationNode::process(uint32 deltaTimeInMillis) {
+bool AnimationEffect::process(uint32 deltaTimeInMillis) {
+ ScriptManager *scriptManager = _engine->getScriptManager();
+ RenderManager *renderManager = _engine->getRenderManager();
+ RenderTable::RenderState renderState = renderManager->getRenderTable()->getRenderState();
+ bool isPanorama = (renderState == RenderTable::PANORAMA);
+ int16 velocity = _engine->getMouseVelocity() + _engine->getKeyboardVelocity();
+
+ // Do not update animation nodes in panoramic mode while turning, if the user
+ // has set this option
+ if (scriptManager->getStateValue(StateKey_NoTurnAnim) == 1 && isPanorama && velocity)
+ return false;
+
PlayNodes::iterator it = _playList.begin();
if (it != _playList.end()) {
playnode *nod = &(*it);
- nod->_delay -= deltaTimeInMillis;
- if (nod->_delay <= 0) {
- nod->_delay += _frmDelay;
-
- const Graphics::Surface *frame = NULL;
-
- if (nod->_curFrame == -1) { // Start of new playlist node
- nod->_curFrame = nod->start;
-
- _animation->seekToFrame(nod->_curFrame);
- frame = _animation->decodeNextFrame();
-
- nod->_delay = _frmDelay;
- if (nod->slot)
- _engine->getScriptManager()->setStateValue(nod->slot, 1);
- } else {
- nod->_curFrame++;
-
- if (nod->_curFrame > nod->stop) {
- nod->loop--;
-
- if (nod->loop == 0) {
- if (nod->slot >= 0)
- _engine->getScriptManager()->setStateValue(nod->slot, 2);
- if (nod->_scaled)
- delete nod->_scaled;
- _playList.erase(it);
- return _DisposeAfterUse;
- }
-
- nod->_curFrame = nod->start;
- _animation->seekToFrame(nod->_curFrame);
+ if (nod->_curFrame == -1) {
+ // The node is just beginning playback
+ nod->_curFrame = nod->start;
+
+ _animation->start();
+ _animation->seekToFrame(nod->start);
+ _animation->setEndFrame(nod->stop);
+
+ nod->_delay = deltaTimeInMillis; // Force the frame to draw
+ if (nod->slot)
+ scriptManager->setStateValue(nod->slot, 1);
+ } else if (_animation->endOfVideo()) {
+ // The node has reached the end; check if we need to loop
+ nod->loop--;
+
+ if (nod->loop == 0) {
+ if (nod->slot >= 0)
+ scriptManager->setStateValue(nod->slot, 2);
+ if (nod->_scaled) {
+ nod->_scaled->free();
+ delete nod->_scaled;
}
+ _playList.erase(it);
+ return _disposeAfterUse;
+ }
- frame = _animation->decodeNextFrame();
+ nod->_curFrame = nod->start;
+ _animation->seekToFrame(nod->start);
+ }
+
+ // Check if we need to draw a frame
+ bool needsUpdate = false;
+ if (_frmDelayOverride == 0) {
+ // If not overridden, use the VideoDecoder's check
+ needsUpdate = _animation->needsUpdate();
+ } else {
+ // Otherwise, implement our own timing
+ nod->_delay -= deltaTimeInMillis;
+
+ if (nod->_delay <= 0) {
+ nod->_delay += _frmDelayOverride;
+ needsUpdate = true;
}
+ }
- if (frame) {
+ if (needsUpdate) {
+ const Graphics::Surface *frame = _animation->decodeNextFrame();
+ if (frame) {
uint32 dstw;
uint32 dsth;
- if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) {
+ if (isPanorama) {
dstw = nod->pos.height();
dsth = nod->pos.width();
} else {
@@ -126,6 +156,7 @@ bool AnimationNode::process(uint32 deltaTimeInMillis) {
if (frame->w > dstw || frame->h > dsth || (frame->w == dstw / 2 && frame->h == dsth / 2)) {
if (nod->_scaled)
if (nod->_scaled->w != dstw || nod->_scaled->h != dsth) {
+ nod->_scaled->free();
delete nod->_scaled;
nod->_scaled = NULL;
}
@@ -135,22 +166,17 @@ bool AnimationNode::process(uint32 deltaTimeInMillis) {
nod->_scaled->create(dstw, dsth, frame->format);
}
- _engine->getRenderManager()->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth);
+ renderManager->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth);
frame = nod->_scaled;
}
- if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) {
+ if (isPanorama) {
Graphics::Surface *transposed = RenderManager::tranposeSurface(frame);
- if (_mask > 0)
- _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask);
- else
- _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top);
+ renderManager->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask);
+ transposed->free();
delete transposed;
} else {
- if (_mask > 0)
- _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask);
- else
- _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top);
+ renderManager->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask);
}
}
}
@@ -159,16 +185,12 @@ bool AnimationNode::process(uint32 deltaTimeInMillis) {
return false;
}
-void AnimationNode::addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops) {
+void AnimationEffect::addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops) {
playnode nod;
nod.loop = loops;
nod.pos = Common::Rect(x, y, x2 + 1, y2 + 1);
nod.start = startFrame;
- nod.stop = endFrame;
-
- if (nod.stop >= (int)_animation->getFrameCount())
- nod.stop = _animation->getFrameCount() - 1;
-
+ nod.stop = CLIP<int>(endFrame, 0, _animation->getFrameCount() - 1);
nod.slot = slot;
nod._curFrame = -1;
nod._delay = 0;
@@ -176,12 +198,14 @@ void AnimationNode::addPlayNode(int32 slot, int x, int y, int x2, int y2, int st
_playList.push_back(nod);
}
-bool AnimationNode::stop() {
+bool AnimationEffect::stop() {
PlayNodes::iterator it = _playList.begin();
if (it != _playList.end()) {
_engine->getScriptManager()->setStateValue((*it).slot, 2);
- if ((*it)._scaled)
+ if ((*it)._scaled) {
+ (*it)._scaled->free();
delete(*it)._scaled;
+ }
}
_playList.clear();
@@ -190,21 +214,4 @@ bool AnimationNode::stop() {
return false;
}
-void AnimationNode::setNewFrameDelay(int32 newDelay) {
- if (newDelay > 0) {
- PlayNodes::iterator it = _playList.begin();
- if (it != _playList.end()) {
- playnode *nod = &(*it);
- float percent = (float)nod->_delay / (float)_frmDelay;
- nod->_delay = percent * newDelay; // Scale to new max
- }
-
- _frmDelay = newDelay;
- }
-}
-
-int32 AnimationNode::getFrameDelay() {
- return _frmDelay;
-}
-
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/animation_node.h b/engines/zvision/scripting/effects/animation_effect.h
index 3adfd91f32..fd6e24ab8b 100644
--- a/engines/zvision/scripting/sidefx/animation_node.h
+++ b/engines/zvision/scripting/effects/animation_effect.h
@@ -23,7 +23,7 @@
#ifndef ZVISION_ANIMATION_NODE_H
#define ZVISION_ANIMATION_NODE_H
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
#include "common/rect.h"
#include "common/list.h"
@@ -39,10 +39,10 @@ namespace ZVision {
class ZVision;
-class AnimationNode : public SideFX {
+class AnimationEffect : public ScriptingEffect {
public:
- AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse = true);
- ~AnimationNode();
+ AnimationEffect(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool disposeAfterUse = true);
+ ~AnimationEffect();
struct playnode {
Common::Rect pos;
@@ -61,10 +61,10 @@ private:
PlayNodes _playList;
int32 _mask;
- bool _DisposeAfterUse;
+ bool _disposeAfterUse;
Video::VideoDecoder *_animation;
- int32 _frmDelay;
+ int32 _frmDelayOverride;
public:
bool process(uint32 deltaTimeInMillis);
@@ -72,9 +72,6 @@ public:
void addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops = 1);
bool stop();
-
- void setNewFrameDelay(int32 newDelay);
- int32 getFrameDelay();
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/distort_node.cpp b/engines/zvision/scripting/effects/distort_effect.cpp
index 0d5c8b1ed5..113b5d048d 100644
--- a/engines/zvision/scripting/sidefx/distort_node.cpp
+++ b/engines/zvision/scripting/effects/distort_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/distort_node.h"
+#include "zvision/scripting/effects/distort_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -34,7 +34,7 @@
namespace ZVision {
DistortNode::DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale)
- : SideFX(engine, key, SIDEFX_DISTORT) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_DISTORT) {
_angle = _engine->getRenderManager()->getRenderTable()->getAngle();
_linScale = _engine->getRenderManager()->getRenderTable()->getLinscale();
@@ -52,7 +52,7 @@ DistortNode::DistortNode(ZVision *engine, uint32 key, int16 speed, float startAn
_diffLinScale = endLineScale - startLineScale;
_frmSpeed = (float)speed / 15.0;
- _frames = ceil((5.0 - _frmSpeed * 2.0) / _frmSpeed);
+ _frames = (int)ceil((5.0 - _frmSpeed * 2.0) / _frmSpeed);
if (_frames <= 0)
_frames = 1;
@@ -65,7 +65,6 @@ DistortNode::~DistortNode() {
}
bool DistortNode::process(uint32 deltaTimeInMillis) {
-
float updTime = deltaTimeInMillis / (1000.0 / 60.0);
if (_incr)
diff --git a/engines/zvision/scripting/sidefx/distort_node.h b/engines/zvision/scripting/effects/distort_effect.h
index 787a69bdde..c64f10e6ff 100644
--- a/engines/zvision/scripting/sidefx/distort_node.h
+++ b/engines/zvision/scripting/effects/distort_effect.h
@@ -23,13 +23,13 @@
#ifndef ZVISION_DISTORT_NODE_H
#define ZVISION_DISTORT_NODE_H
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
namespace ZVision {
class ZVision;
-class DistortNode : public SideFX {
+class DistortNode : public ScriptingEffect {
public:
DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale);
~DistortNode();
diff --git a/engines/zvision/scripting/sidefx/music_node.cpp b/engines/zvision/scripting/effects/music_effect.cpp
index 56598189f6..e3fdc96dba 100644
--- a/engines/zvision/scripting/sidefx/music_node.cpp
+++ b/engines/zvision/scripting/effects/music_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/music_node.h"
+#include "zvision/scripting/effects/music_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -36,16 +36,33 @@
namespace ZVision {
-MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, int8 volume)
- : MusicNodeBASE(engine, key, SIDEFX_AUDIO) {
+static const uint8 dbMapLinear[256] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
+2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14,
+14, 15, 15, 16, 16, 17, 18, 18, 19, 20, 21, 21, 22, 23, 24, 25,
+26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 40, 41, 43, 45,
+46, 48, 50, 52, 53, 55, 57, 60, 62, 64, 67, 69, 72, 74, 77, 80,
+83, 86, 89, 92, 96, 99, 103, 107, 111, 115, 119, 123, 128, 133, 137, 143,
+148, 153, 159, 165, 171, 177, 184, 191, 198, 205, 212, 220, 228, 237, 245, 255};
+
+MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, uint8 volume)
+ : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) {
_loop = loop;
_volume = volume;
+ _deltaVolume = 0;
+ _balance = 0;
_crossfade = false;
_crossfadeTarget = 0;
_crossfadeTime = 0;
- _attenuate = 0;
- _pantrack = false;
- _pantrackPosition = 0;
_sub = NULL;
_stereo = false;
_loaded = false;
@@ -66,9 +83,9 @@ MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool
if (_loop) {
Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES);
- _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, _volume);
+ _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, dbMapLinear[_volume]);
} else {
- _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, _volume);
+ _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, dbMapLinear[_volume]);
}
if (_key != StateKey_NotSet)
@@ -88,26 +105,23 @@ MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool
}
MusicNode::~MusicNode() {
- if (!_loaded)
+ if (_loaded)
_engine->_mixer->stopHandle(_handle);
if (_key != StateKey_NotSet)
_engine->getScriptManager()->setStateValue(_key, 2);
if (_sub)
delete _sub;
- debug(1, "MusicNode: %d destroyed\n", _key);
+ debug(1, "MusicNode: %d destroyed", _key);
}
-void MusicNode::setPanTrack(int16 pos) {
- if (!_stereo) {
- _pantrack = true;
- _pantrackPosition = pos;
- setVolume(_volume);
- }
+void MusicNode::setDeltaVolume(uint8 volume) {
+ _deltaVolume = volume;
+ setVolume(_volume);
}
-void MusicNode::unsetPanTrack() {
- _pantrack = false;
- setVolume(_volume);
+void MusicNode::setBalance(int8 balance) {
+ _balance = balance;
+ _engine->_mixer->setChannelBalance(_handle, _balance);
}
void MusicNode::setFade(int32 time, uint8 target) {
@@ -126,7 +140,7 @@ bool MusicNode::process(uint32 deltaTimeInMillis) {
if (_crossfadeTime > 0) {
if ((int32)deltaTimeInMillis > _crossfadeTime)
deltaTimeInMillis = _crossfadeTime;
- _newvol += floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis;
+ _newvol += (int)(floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis);
_crossfadeTime -= deltaTimeInMillis;
} else {
_crossfade = false;
@@ -134,10 +148,10 @@ bool MusicNode::process(uint32 deltaTimeInMillis) {
}
}
- if (_pantrack || _volume != _newvol)
+ if (_volume != _newvol)
setVolume(_newvol);
- if (_sub)
+ if (_sub && _engine->getScriptManager()->getStateValue(StateKey_Subtitles) == 1)
_sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100);
}
return false;
@@ -146,59 +160,89 @@ bool MusicNode::process(uint32 deltaTimeInMillis) {
void MusicNode::setVolume(uint8 newVolume) {
if (!_loaded)
return;
- if (_pantrack) {
- int curX = _engine->getScriptManager()->getStateValue(StateKey_ViewPos);
- curX -= _pantrackPosition;
- int32 _width = _engine->getRenderManager()->getBkgSize().x;
- if (curX < (-_width) / 2)
- curX += _width;
- else if (curX >= _width / 2)
- curX -= _width;
-
- float norm = (float)curX / ((float)_width / 2.0);
- float lvl = fabs(norm);
- if (lvl > 0.5)
- lvl = (lvl - 0.5) * 1.7;
- else
- lvl = 1.0;
- float bal = sin(-norm * 3.1415926) * 127.0;
+ _volume = newVolume;
- if (_engine->_mixer->isSoundHandleActive(_handle)) {
- _engine->_mixer->setChannelBalance(_handle, bal);
- _engine->_mixer->setChannelVolume(_handle, newVolume * lvl);
- }
- } else {
- if (_engine->_mixer->isSoundHandleActive(_handle)) {
- _engine->_mixer->setChannelBalance(_handle, 0);
- _engine->_mixer->setChannelVolume(_handle, newVolume);
- }
- }
+ if (_deltaVolume >= _volume)
+ _engine->_mixer->setChannelVolume(_handle, 0);
+ else
+ _engine->_mixer->setChannelVolume(_handle, dbMapLinear[_volume - _deltaVolume]);
+}
- _volume = newVolume;
+uint8 MusicNode::getVolume() {
+ return _volume;
}
PanTrackNode::PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos)
- : SideFX(engine, key, SIDEFX_PANTRACK) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_PANTRACK) {
_slot = slot;
+ _position = pos;
- SideFX *fx = _engine->getScriptManager()->getSideFX(slot);
- if (fx && fx->getType() == SIDEFX_AUDIO) {
- MusicNodeBASE *mus = (MusicNodeBASE *)fx;
- mus->setPanTrack(pos);
- }
+ // Try to set pan value for music node immediately
+ process(0);
}
PanTrackNode::~PanTrackNode() {
- SideFX *fx = _engine->getScriptManager()->getSideFX(_slot);
- if (fx && fx->getType() == SIDEFX_AUDIO) {
+}
+
+bool PanTrackNode::process(uint32 deltaTimeInMillis) {
+ ScriptManager * scriptManager = _engine->getScriptManager();
+ ScriptingEffect *fx = scriptManager->getSideFX(_slot);
+ if (fx && fx->getType() == SCRIPTING_EFFECT_AUDIO) {
MusicNodeBASE *mus = (MusicNodeBASE *)fx;
- mus->unsetPanTrack();
+
+ int curPos = scriptManager->getStateValue(StateKey_ViewPos);
+ int16 _width = _engine->getRenderManager()->getBkgSize().x;
+ int16 _halfWidth = _width / 2;
+ int16 _quarterWidth = _width / 4;
+
+ int tmp = 0;
+ if (curPos <= _position)
+ tmp = _position - curPos;
+ else
+ tmp = _position - curPos + _width;
+
+ int balance = 0;
+
+ if (tmp > _halfWidth)
+ tmp -= _width;
+
+ if (tmp > _quarterWidth) {
+ balance = 1;
+ tmp = _halfWidth - tmp;
+ } else if (tmp < -_quarterWidth) {
+ balance = -1;
+ tmp = -_halfWidth - tmp;
+ }
+
+ // Originally it's value -90...90 but we use -127...127 and therefore 360 replaced by 508
+ mus->setBalance( (508 * tmp) / _width );
+
+ tmp = (360 * tmp) / _width;
+
+ int deltaVol = balance;
+
+ // This value sets how fast volume goes off than sound source back of you
+ // By this value we can hack some "bugs" have place in originall game engine like beat sound in ZGI-dc10
+ int volumeCorrection = 2;
+
+ if (_engine->getGameId() == GID_GRANDINQUISITOR) {
+ if (scriptManager->getCurrentLocation() == "dc10")
+ volumeCorrection = 5;
+ }
+
+ if (deltaVol != 0)
+ deltaVol = (mus->getVolume() * volumeCorrection) * (90 - tmp * balance) / 90;
+ if (deltaVol > 255)
+ deltaVol = 255;
+
+ mus->setDeltaVolume(deltaVol);
}
+ return false;
}
MusicMidiNode::MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume)
- : MusicNodeBASE(engine, key, SIDEFX_AUDIO) {
+ : MusicNodeBASE(engine, key, SCRIPTING_EFFECT_AUDIO) {
_volume = volume;
_prog = program;
_noteNumber = note;
@@ -225,10 +269,10 @@ MusicMidiNode::~MusicMidiNode() {
_engine->getScriptManager()->setStateValue(_key, 2);
}
-void MusicMidiNode::setPanTrack(int16 pos) {
+void MusicMidiNode::setDeltaVolume(uint8 volume) {
}
-void MusicMidiNode::unsetPanTrack() {
+void MusicMidiNode::setBalance(int8 balance) {
}
void MusicMidiNode::setFade(int32 time, uint8 target) {
@@ -245,4 +289,8 @@ void MusicMidiNode::setVolume(uint8 newVolume) {
_volume = newVolume;
}
+uint8 MusicMidiNode::getVolume() {
+ return _volume;
+}
+
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/music_node.h b/engines/zvision/scripting/effects/music_effect.h
index 09bdc3707e..7657be8e09 100644
--- a/engines/zvision/scripting/sidefx/music_node.h
+++ b/engines/zvision/scripting/effects/music_effect.h
@@ -24,8 +24,8 @@
#define ZVISION_MUSIC_NODE_H
#include "audio/mixer.h"
-#include "zvision/scripting/sidefx.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/scripting/scripting_effect.h"
+#include "zvision/text/subtitles.h"
namespace Common {
class String;
@@ -33,9 +33,9 @@ class String;
namespace ZVision {
-class MusicNodeBASE : public SideFX {
+class MusicNodeBASE : public ScriptingEffect {
public:
- MusicNodeBASE(ZVision *engine, uint32 key, SideFXType type) : SideFX(engine, key, type) {}
+ MusicNodeBASE(ZVision *engine, uint32 key, ScriptingEffectType type) : ScriptingEffect(engine, key, type) {}
~MusicNodeBASE() {}
/**
@@ -48,16 +48,16 @@ public:
virtual bool process(uint32 deltaTimeInMillis) = 0;
virtual void setVolume(uint8 volume) = 0;
-
- virtual void setPanTrack(int16 pos) = 0;
- virtual void unsetPanTrack() = 0;
+ virtual uint8 getVolume() = 0;
+ virtual void setDeltaVolume(uint8 volume) = 0;
+ virtual void setBalance(int8 balance) = 0;
virtual void setFade(int32 time, uint8 target) = 0;
};
class MusicNode : public MusicNodeBASE {
public:
- MusicNode(ZVision *engine, uint32 key, Common::String &file, bool loop, int8 volume);
+ MusicNode(ZVision *engine, uint32 key, Common::String &file, bool loop, uint8 volume);
~MusicNode();
/**
@@ -70,17 +70,16 @@ public:
bool process(uint32 deltaTimeInMillis);
void setVolume(uint8 volume);
-
- void setPanTrack(int16 pos);
- void unsetPanTrack();
+ uint8 getVolume();
+ void setDeltaVolume(uint8 volume);
+ void setBalance(int8 balance);
void setFade(int32 time, uint8 target);
private:
- bool _pantrack;
- int32 _pantrackPosition;
- int32 _attenuate;
uint8 _volume;
+ uint8 _deltaVolume;
+ int8 _balance;
bool _loop;
bool _crossfade;
uint8 _crossfadeTarget;
@@ -91,6 +90,7 @@ private:
bool _loaded;
};
+// Only used by Zork: Nemesis, for the flute and piano puzzles (tj4e and ve6f, as well as vr)
class MusicMidiNode : public MusicNodeBASE {
public:
MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume);
@@ -106,9 +106,9 @@ public:
bool process(uint32 deltaTimeInMillis);
void setVolume(uint8 volume);
-
- void setPanTrack(int16 pos);
- void unsetPanTrack();
+ uint8 getVolume();
+ void setDeltaVolume(uint8 volume);
+ void setBalance(int8 balance);
void setFade(int32 time, uint8 target);
@@ -120,13 +120,16 @@ private:
int8 _prog;
};
-class PanTrackNode : public SideFX {
+class PanTrackNode : public ScriptingEffect {
public:
PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos);
~PanTrackNode();
+ bool process(uint32 deltaTimeInMillis);
+
private:
uint32 _slot;
+ int16 _position;
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/region_node.cpp b/engines/zvision/scripting/effects/region_effect.cpp
index de613d8af2..78061cf4de 100644
--- a/engines/zvision/scripting/sidefx/region_node.cpp
+++ b/engines/zvision/scripting/effects/region_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/region_node.h"
+#include "zvision/scripting/effects/region_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -30,8 +30,8 @@
namespace ZVision {
-RegionNode::RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay)
- : SideFX(engine, key, SIDEFX_REGION) {
+RegionNode::RegionNode(ZVision *engine, uint32 key, GraphicsEffect *effect, uint32 delay)
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_REGION) {
_effect = effect;
_delay = delay;
_timeLeft = 0;
diff --git a/engines/zvision/scripting/sidefx/region_node.h b/engines/zvision/scripting/effects/region_effect.h
index ec716b6e3e..4fc16224ff 100644
--- a/engines/zvision/scripting/sidefx/region_node.h
+++ b/engines/zvision/scripting/effects/region_effect.h
@@ -25,16 +25,16 @@
#include "graphics/surface.h"
-#include "zvision/scripting/sidefx.h"
-#include "zvision/graphics/effect.h"
+#include "zvision/scripting/scripting_effect.h"
+#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
-class RegionNode : public SideFX {
+class RegionNode : public ScriptingEffect {
public:
- RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay);
+ RegionNode(ZVision *engine, uint32 key, GraphicsEffect *effect, uint32 delay);
~RegionNode();
/**
@@ -49,7 +49,7 @@ public:
private:
int32 _timeLeft;
uint32 _delay;
- Effect *_effect;
+ GraphicsEffect *_effect;
};
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/sidefx/syncsound_node.cpp b/engines/zvision/scripting/effects/syncsound_effect.cpp
index c1f139694b..70ba97deb8 100644
--- a/engines/zvision/scripting/sidefx/syncsound_node.cpp
+++ b/engines/zvision/scripting/effects/syncsound_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/syncsound_node.h"
+#include "zvision/scripting/effects/syncsound_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -36,7 +36,7 @@
namespace ZVision {
SyncSoundNode::SyncSoundNode(ZVision *engine, uint32 key, Common::String &filename, int32 syncto)
- : SideFX(engine, key, SIDEFX_AUDIO) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_AUDIO) {
_syncto = syncto;
_sub = NULL;
@@ -76,7 +76,7 @@ bool SyncSoundNode::process(uint32 deltaTimeInMillis) {
if (_engine->getScriptManager()->getSideFX(_syncto) == NULL)
return stop();
- if (_sub)
+ if (_sub && _engine->getScriptManager()->getStateValue(StateKey_Subtitles) == 1)
_sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100);
}
return false;
diff --git a/engines/zvision/scripting/sidefx/syncsound_node.h b/engines/zvision/scripting/effects/syncsound_effect.h
index 7cd02a8aef..0eabff77a3 100644
--- a/engines/zvision/scripting/sidefx/syncsound_node.h
+++ b/engines/zvision/scripting/effects/syncsound_effect.h
@@ -24,15 +24,15 @@
#define ZVISION_SYNCSOUND_NODE_H
#include "audio/mixer.h"
-#include "zvision/scripting/sidefx.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/scripting/scripting_effect.h"
+#include "zvision/text/subtitles.h"
namespace Common {
class String;
}
namespace ZVision {
-class SyncSoundNode : public SideFX {
+class SyncSoundNode : public ScriptingEffect {
public:
SyncSoundNode(ZVision *engine, uint32 key, Common::String &file, int32 syncto);
~SyncSoundNode();
diff --git a/engines/zvision/scripting/sidefx/timer_node.cpp b/engines/zvision/scripting/effects/timer_effect.cpp
index 170f6e7472..778f9dec6c 100644
--- a/engines/zvision/scripting/sidefx/timer_node.cpp
+++ b/engines/zvision/scripting/effects/timer_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/timer_node.h"
+#include "zvision/scripting/effects/timer_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -32,7 +32,7 @@
namespace ZVision {
TimerNode::TimerNode(ZVision *engine, uint32 key, uint timeInSeconds)
- : SideFX(engine, key, SIDEFX_TIMER) {
+ : ScriptingEffect(engine, key, SCRIPTING_EFFECT_TIMER) {
_timeLeft = 0;
if (_engine->getGameId() == GID_NEMESIS)
diff --git a/engines/zvision/scripting/sidefx/timer_node.h b/engines/zvision/scripting/effects/timer_effect.h
index 7a26aff251..5e45d54d7d 100644
--- a/engines/zvision/scripting/sidefx/timer_node.h
+++ b/engines/zvision/scripting/effects/timer_effect.h
@@ -23,13 +23,13 @@
#ifndef ZVISION_TIMER_NODE_H
#define ZVISION_TIMER_NODE_H
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
namespace ZVision {
class ZVision;
-class TimerNode : public SideFX {
+class TimerNode : public ScriptingEffect {
public:
TimerNode(ZVision *engine, uint32 key, uint timeInSeconds);
~TimerNode();
diff --git a/engines/zvision/scripting/sidefx/ttytext_node.cpp b/engines/zvision/scripting/effects/ttytext_effect.cpp
index 9a7fa01649..8d340dae39 100644
--- a/engines/zvision/scripting/sidefx/ttytext_node.cpp
+++ b/engines/zvision/scripting/effects/ttytext_effect.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#include "zvision/scripting/sidefx/ttytext_node.h"
+#include "zvision/scripting/effects/ttytext_effect.h"
#include "zvision/zvision.h"
#include "zvision/scripting/script_manager.h"
@@ -35,7 +35,7 @@
namespace ZVision {
ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay) :
- SideFX(engine, key, SIDEFX_TTYTXT),
+ ScriptingEffect(engine, key, SCRIPTING_EFFECT_TTYTXT),
_fnt(engine) {
_delay = delay;
_r = r;
@@ -56,10 +56,10 @@ ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file
delete infile;
}
- _img.create(_r.width(), _r.height(), _engine->_pixelFormat);
- _style.sharp = true;
- _style.readAllStyle(_txtbuf);
- _style.setFont(_fnt);
+ _img.create(_r.width(), _r.height(), _engine->_resourcePixelFormat);
+ _state._sharp = true;
+ _state.readAllStyles(_txtbuf);
+ _state.updateFontWithTextState(_fnt);
_engine->getScriptManager()->setStateValue(_key, 1);
}
@@ -74,29 +74,27 @@ bool ttyTextNode::process(uint32 deltaTimeInMillis) {
if (_nexttime < 0) {
if (_txtpos < _txtbuf.size()) {
if (_txtbuf[_txtpos] == '<') {
- int32 strt = _txtpos;
- int32 endt = 0;
+ int32 start = _txtpos;
+ int32 end = 0;
int16 ret = 0;
while (_txtbuf[_txtpos] != '>' && _txtpos < _txtbuf.size())
_txtpos++;
- endt = _txtpos;
- if (strt != -1)
- if ((endt - strt - 1) > 0)
- ret = _style.parseStyle(_txtbuf.c_str() + strt + 1, endt - strt - 1);
-
- if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) {
- if (ret & TXT_RET_FNTCHG)
- _style.setFont(_fnt);
- if (ret & TXT_RET_FNTSTL)
- _style.setFontStyle(_fnt);
-
- if (ret & TXT_RET_NEWLN)
- newline();
+ end = _txtpos;
+ if (start != -1) {
+ if ((end - start - 1) > 0) {
+ ret = _state.parseStyle(_txtbuf.c_str() + start + 1, end - start - 1);
+ }
+ }
+
+ if (ret & (TEXT_CHANGE_FONT_TYPE | TEXT_CHANGE_FONT_STYLE)) {
+ _state.updateFontWithTextState(_fnt);
+ } else if (ret & TEXT_CHANGE_NEWLINE) {
+ newline();
}
- if (ret & TXT_RET_HASSTBOX) {
+ if (ret & TEXT_CHANGE_HAS_STATE_BOX) {
Common::String buf;
- buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_style.statebox));
+ buf = Common::String::format("%d", _engine->getScriptManager()->getStateValue(_state._statebox));
for (uint8 j = 0; j < buf.size(); j++)
outchar(buf[j]);
@@ -158,7 +156,7 @@ void ttyTextNode::newline() {
}
void ttyTextNode::outchar(uint16 chr) {
- uint32 clr = _engine->_pixelFormat.RGBToColor(_style.red, _style.green, _style.blue);
+ uint32 clr = _engine->_resourcePixelFormat.RGBToColor(_state._red, _state._green, _state._blue);
if (_dx + _fnt.getCharWidth(chr) > _r.width())
newline();
diff --git a/engines/zvision/scripting/sidefx/ttytext_node.h b/engines/zvision/scripting/effects/ttytext_effect.h
index b6cbed3e34..18cbbbaee3 100644
--- a/engines/zvision/scripting/sidefx/ttytext_node.h
+++ b/engines/zvision/scripting/effects/ttytext_effect.h
@@ -26,16 +26,16 @@
#include "common/rect.h"
#include "graphics/surface.h"
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
#include "zvision/text/text.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
namespace Common {
class String;
}
namespace ZVision {
-class ttyTextNode : public SideFX {
+class ttyTextNode : public ScriptingEffect {
public:
ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay);
~ttyTextNode();
@@ -51,7 +51,7 @@ public:
private:
Common::Rect _r;
- cTxtStyle _style;
+ TextStyleState _state;
StyledTTFont _fnt;
Common::String _txtbuf;
uint32 _txtpos;
diff --git a/engines/zvision/core/menu.cpp b/engines/zvision/scripting/menu.cpp
index 31e0d71370..064bd1b57d 100644
--- a/engines/zvision/core/menu.cpp
+++ b/engines/zvision/scripting/menu.cpp
@@ -20,26 +20,22 @@
*
*/
-#include "common/scummsys.h"
-
-#include "zvision/core/menu.h"
-
#include "zvision/graphics/render_manager.h"
+#include "zvision/scripting/menu.h"
namespace ZVision {
enum {
- SLOT_START_SLOT = 151,
- SLOT_SPELL_1 = 191,
- SLOT_USER_CHOSE_THIS_SPELL = 205,
- SLOT_REVERSED_SPELLBOOK = 206
+ kMainMenuSave = 0,
+ kMainMenuLoad = 1,
+ kMainMenuPrefs = 2,
+ kMainMenuExit = 3
};
enum {
- menu_MAIN_SAVE = 0,
- menu_MAIN_REST = 1,
- menu_MAIN_PREF = 2,
- menu_MAIN_EXIT = 3
+ kMenuItem = 0,
+ kMenuMagic = 1,
+ kMenuMain = 2
};
MenuHandler::MenuHandler(ZVision *engine) {
@@ -50,13 +46,13 @@ MenuHandler::MenuHandler(ZVision *engine) {
MenuZGI::MenuZGI(ZVision *engine) :
MenuHandler(engine) {
menuMouseFocus = -1;
- inmenu = false;
+ inMenu = false;
scrolled[0] = false;
scrolled[1] = false;
scrolled[2] = false;
- scrollPos[0] = 0.0;
- scrollPos[1] = 0.0;
- scrollPos[2] = 0.0;
+ scrollPos[0] = 0;
+ scrollPos[1] = 0;
+ scrollPos[2] = 0;
mouseOnItem = -1;
redraw = false;
clean = false;
@@ -64,15 +60,15 @@ MenuZGI::MenuZGI(ZVision *engine) :
char buf[24];
for (int i = 1; i < 4; i++) {
sprintf(buf, "gmzau%2.2x1.tga", i);
- _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][0], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBack[i - 1][0], false);
sprintf(buf, "gmzau%2.2x1.tga", i + 0x10);
- _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][1], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBack[i - 1][1], false);
}
for (int i = 0; i < 4; i++) {
sprintf(buf, "gmzmu%2.2x1.tga", i);
- _engine->getRenderManager()->readImageToSurface(buf, menubar[i][0], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBar[i][0], false);
sprintf(buf, "gmznu%2.2x1.tga", i);
- _engine->getRenderManager()->readImageToSurface(buf, menubar[i][1], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBar[i][1], false);
}
for (int i = 0; i < 50; i++) {
@@ -90,12 +86,12 @@ MenuZGI::MenuZGI(ZVision *engine) :
MenuZGI::~MenuZGI() {
for (int i = 0; i < 3; i++) {
- menuback[i][0].free();
- menuback[i][1].free();
+ menuBack[i][0].free();
+ menuBack[i][1].free();
}
for (int i = 0; i < 4; i++) {
- menubar[i][0].free();
- menubar[i][1].free();
+ menuBar[i][0].free();
+ menuBar[i][1].free();
}
for (int i = 0; i < 50; i++) {
if (items[i][0]) {
@@ -122,8 +118,8 @@ MenuZGI::~MenuZGI() {
void MenuZGI::onMouseUp(const Common::Point &Pos) {
if (Pos.y < 40) {
switch (menuMouseFocus) {
- case menu_ITEM:
- if (menuBarFlag & menuBar_Items) {
+ case kMenuItem:
+ if (menuBarFlag & kMenubarItems) {
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
itemCount = 20;
@@ -131,13 +127,13 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) {
for (int i = 0; i < itemCount; i++) {
int itemspace = (600 - 28) / itemCount;
- if (Common::Rect(scrollPos[menu_ITEM] + itemspace * i, 0,
- scrollPos[menu_ITEM] + itemspace * i + 28, 32).contains(Pos)) {
+ if (Common::Rect(scrollPos[kMenuItem] + itemspace * i, 0,
+ scrollPos[kMenuItem] + itemspace * i + 28, 32).contains(Pos)) {
int32 mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem);
if (mouseItem >= 0 && mouseItem < 0xE0) {
_engine->getScriptManager()->inventoryDrop(mouseItem);
- _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(SLOT_START_SLOT + i));
- _engine->getScriptManager()->setStateValue(SLOT_START_SLOT + i, mouseItem);
+ _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + i));
+ _engine->getScriptManager()->setStateValue(StateKey_Inv_StartSlot + i, mouseItem);
redraw = true;
}
@@ -146,62 +142,62 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) {
}
break;
- case menu_MAGIC:
- if (menuBarFlag & menuBar_Magic) {
+ case kMenuMagic:
+ if (menuBarFlag & kMenubarMagic) {
for (int i = 0; i < 12; i++) {
- uint itemnum = _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + i);
+ uint itemnum = _engine->getScriptManager()->getStateValue(StateKey_Spell_1 + i);
if (itemnum != 0) {
- if (_engine->getScriptManager()->getStateValue(SLOT_REVERSED_SPELLBOOK) == 1)
+ if (_engine->getScriptManager()->getStateValue(StateKey_Reversed_Spellbooc) == 1)
itemnum = 0xEE + i;
else
itemnum = 0xE0 + i;
}
if (itemnum)
if (_engine->getScriptManager()->getStateValue(StateKey_InventoryItem) == 0 || _engine->getScriptManager()->getStateValue(StateKey_InventoryItem) >= 0xE0)
- if (Common::Rect(668 + 47 * i - scrollPos[menu_MAGIC], 0,
- 668 + 47 * i - scrollPos[menu_MAGIC] + 28, 32).contains(Pos))
- _engine->getScriptManager()->setStateValue(SLOT_USER_CHOSE_THIS_SPELL, itemnum);
+ if (Common::Rect(668 + 47 * i - scrollPos[kMenuMagic], 0,
+ 668 + 47 * i - scrollPos[kMenuMagic] + 28, 32).contains(Pos))
+ _engine->getScriptManager()->setStateValue(StateKey_Active_Spell, itemnum);
}
}
break;
- case menu_MAIN:
+ case kMenuMain:
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(320 + 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->ifQuit();
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(320 ,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->getScriptManager()->changeLocation('g', 'j', 'p', 'e', 0);
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(320 - 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->getScriptManager()->changeLocation('g', 'j', 'r', 'e', 0);
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(320 - 135 * 2,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 - 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
_engine->getScriptManager()->changeLocation('g', 'j', 's', 'e', 0);
}
break;
@@ -212,12 +208,12 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) {
void MenuZGI::onMouseMove(const Common::Point &Pos) {
if (Pos.y < 40) {
- if (!inmenu)
+ if (!inMenu)
redraw = true;
- inmenu = true;
+ inMenu = true;
switch (menuMouseFocus) {
- case menu_ITEM:
- if (menuBarFlag & menuBar_Items) {
+ case kMenuItem:
+ if (menuBarFlag & kMenubarItems) {
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
itemCount = 20;
@@ -231,78 +227,78 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
for (int i = 0; i < itemCount; i++) {
int itemspace = (600 - 28) / itemCount;
- if (Common::Rect(scrollPos[menu_ITEM] + itemspace * i, 0,
- scrollPos[menu_ITEM] + itemspace * i + 28, 32).contains(Pos)) {
+ if (Common::Rect(scrollPos[kMenuItem] + itemspace * i, 0,
+ scrollPos[kMenuItem] + itemspace * i + 28, 32).contains(Pos)) {
mouseOnItem = i;
break;
}
}
if (lastItem != mouseOnItem)
- if (_engine->getScriptManager()->getStateValue(SLOT_START_SLOT + mouseOnItem) ||
- _engine->getScriptManager()->getStateValue(SLOT_START_SLOT + lastItem))
+ if (_engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + mouseOnItem) ||
+ _engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + lastItem))
redraw = true;
}
break;
- case menu_MAGIC:
- if (menuBarFlag & menuBar_Magic) {
+ case kMenuMagic:
+ if (menuBarFlag & kMenubarMagic) {
int lastItem = mouseOnItem;
mouseOnItem = -1;
for (int i = 0; i < 12; i++) {
- if (Common::Rect(668 + 47 * i - scrollPos[menu_MAGIC], 0,
- 668 + 47 * i - scrollPos[menu_MAGIC] + 28, 32).contains(Pos)) {
+ if (Common::Rect(668 + 47 * i - scrollPos[kMenuMagic], 0,
+ 668 + 47 * i - scrollPos[kMenuMagic] + 28, 32).contains(Pos)) {
mouseOnItem = i;
break;
}
}
if (lastItem != mouseOnItem)
- if (_engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + mouseOnItem) ||
- _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + lastItem))
+ if (_engine->getScriptManager()->getStateValue(StateKey_Spell_1 + mouseOnItem) ||
+ _engine->getScriptManager()->getStateValue(StateKey_Spell_1 + lastItem))
redraw = true;
}
break;
- case menu_MAIN: {
+ case kMenuMain: {
int lastItem = mouseOnItem;
mouseOnItem = -1;
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(320 + 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_EXIT;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuExit;
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(320 ,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 + 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_PREF;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuPrefs;
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(320 - 135,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_REST;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuLoad;
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(320 - 135 * 2,
- scrollPos[menu_MAIN],
+ scrollPos[kMenuMain],
320 - 135,
- scrollPos[menu_MAIN] + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_SAVE;
+ scrollPos[kMenuMain] + 32).contains(Pos)) {
+ mouseOnItem = kMainMenuSave;
}
if (lastItem != mouseOnItem)
@@ -313,25 +309,25 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
default:
int cur_menu = menuMouseFocus;
if (Common::Rect(64, 0, 64 + 512, 8).contains(Pos)) { // Main
- menuMouseFocus = menu_MAIN;
- scrolled[menu_MAIN] = false;
- scrollPos[menu_MAIN] = menuback[menu_MAIN][1].h - menuback[menu_MAIN][0].h;
+ menuMouseFocus = kMenuMain;
+ scrolled[kMenuMain] = false;
+ scrollPos[kMenuMain] = menuBack[kMenuMain][1].h - menuBack[kMenuMain][0].h;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 2);
}
- if (menuBarFlag & menuBar_Magic)
+ if (menuBarFlag & kMenubarMagic)
if (Common::Rect(640 - 28, 0, 640, 32).contains(Pos)) { // Magic
- menuMouseFocus = menu_MAGIC;
- scrolled[menu_MAGIC] = false;
- scrollPos[menu_MAGIC] = 28;
+ menuMouseFocus = kMenuMagic;
+ scrolled[kMenuMagic] = false;
+ scrollPos[kMenuMagic] = 28;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 3);
}
- if (menuBarFlag & menuBar_Items)
+ if (menuBarFlag & kMenubarItems)
if (Common::Rect(0, 0, 28, 32).contains(Pos)) { // Items
- menuMouseFocus = menu_ITEM;
- scrolled[menu_ITEM] = false;
- scrollPos[menu_ITEM] = 28 - 600;
+ menuMouseFocus = kMenuItem;
+ scrolled[kMenuItem] = false;
+ scrollPos[kMenuItem] = 28 - 600;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 1);
}
@@ -341,9 +337,9 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
break;
}
} else {
- if (inmenu)
+ if (inMenu)
clean = true;
- inmenu = false;
+ inMenu = false;
if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0)
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 0);
menuMouseFocus = -1;
@@ -356,24 +352,24 @@ void MenuZGI::process(uint32 deltatime) {
clean = false;
}
switch (menuMouseFocus) {
- case menu_ITEM:
- if (menuBarFlag & menuBar_Items)
- if (!scrolled[menu_ITEM]) {
+ case kMenuItem:
+ if (menuBarFlag & kMenubarItems)
+ if (!scrolled[kMenuItem]) {
redraw = true;
float scrl = 600.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos [menu_ITEM] += scrl;
+ scrollPos[kMenuItem] += (int)scrl;
- if (scrollPos[menu_ITEM] >= 0) {
- scrolled[menu_ITEM] = true;
- scrollPos [menu_ITEM] = 0;
+ if (scrollPos[kMenuItem] >= 0) {
+ scrolled[kMenuItem] = true;
+ scrollPos[kMenuItem] = 0;
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_ITEM][0], scrollPos[menu_ITEM], 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuItem][0], scrollPos[kMenuItem], 0);
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
@@ -389,7 +385,7 @@ void MenuZGI::process(uint32 deltatime) {
if (mouseOnItem == i)
inrect = true;
- uint curItemId = _engine->getScriptManager()->getStateValue(SLOT_START_SLOT + i);
+ uint curItemId = _engine->getScriptManager()->getStateValue(StateKey_Inv_StartSlot + i);
if (curItemId != 0) {
if (itemId[i] != curItemId) {
@@ -402,9 +398,9 @@ void MenuZGI::process(uint32 deltatime) {
}
if (inrect)
- _engine->getRenderManager()->blitSurfaceToMenu(*items[i][1], scrollPos[menu_ITEM] + itemspace * i, 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*items[i][1], scrollPos[kMenuItem] + itemspace * i, 0, 0);
else
- _engine->getRenderManager()->blitSurfaceToMenu(*items[i][0], scrollPos[menu_ITEM] + itemspace * i, 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*items[i][0], scrollPos[kMenuItem] + itemspace * i, 0, 0);
} else {
if (items[i][0]) {
@@ -425,24 +421,24 @@ void MenuZGI::process(uint32 deltatime) {
}
break;
- case menu_MAGIC:
- if (menuBarFlag & menuBar_Magic)
- if (!scrolled[menu_MAGIC]) {
+ case kMenuMagic:
+ if (menuBarFlag & kMenubarMagic)
+ if (!scrolled[kMenuMagic]) {
redraw = true;
float scrl = 600.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos [menu_MAGIC] += scrl;
+ scrollPos[kMenuMagic] += (int)scrl;
- if (scrollPos[menu_MAGIC] >= 600) {
- scrolled[menu_MAGIC] = true;
- scrollPos [menu_MAGIC] = 600;
+ if (scrollPos[kMenuMagic] >= 600) {
+ scrolled[kMenuMagic] = true;
+ scrollPos[kMenuMagic] = 600;
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAGIC][0], 640 - scrollPos[menu_MAGIC], 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMagic][0], 640 - scrollPos[kMenuMagic], 0);
for (int i = 0; i < 12; i++) {
bool inrect = false;
@@ -450,9 +446,9 @@ void MenuZGI::process(uint32 deltatime) {
if (mouseOnItem == i)
inrect = true;
- uint curItemId = _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + i);
+ uint curItemId = _engine->getScriptManager()->getStateValue(StateKey_Spell_1 + i);
if (curItemId) {
- if (_engine->getScriptManager()->getStateValue(SLOT_REVERSED_SPELLBOOK) == 1)
+ if (_engine->getScriptManager()->getStateValue(StateKey_Reversed_Spellbooc) == 1)
curItemId = 0xEE + i;
else
curItemId = 0xE0 + i;
@@ -469,9 +465,9 @@ void MenuZGI::process(uint32 deltatime) {
}
if (inrect)
- _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][1], 668 + 47 * i - scrollPos[menu_MAGIC], 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][1], 668 + 47 * i - scrollPos[kMenuMagic], 0, 0);
else
- _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][0], 668 + 47 * i - scrollPos[menu_MAGIC], 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][0], 668 + 47 * i - scrollPos[kMenuMagic], 0, 0);
} else {
if (magic[i][0]) {
@@ -491,61 +487,61 @@ void MenuZGI::process(uint32 deltatime) {
}
break;
- case menu_MAIN:
- if (!scrolled[menu_MAIN]) {
+ case kMenuMain:
+ if (!scrolled[kMenuMain]) {
redraw = true;
float scrl = 32.0 * 2.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos [menu_MAIN] += scrl;
+ scrollPos[kMenuMain] += (int)scrl;
- if (scrollPos[menu_MAIN] >= 0) {
- scrolled[menu_MAIN] = true;
- scrollPos [menu_MAIN] = 0;
+ if (scrollPos[kMenuMain] >= 0) {
+ scrolled[kMenuMain] = true;
+ scrollPos[kMenuMain] = 0;
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAIN][0], 30, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMain][0], 30, scrollPos[kMenuMain]);
- if (menuBarFlag & menuBar_Exit) {
- if (mouseOnItem == menu_MAIN_EXIT)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_EXIT][1], 320 + 135, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarExit) {
+ if (mouseOnItem == kMainMenuExit)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuExit][1], 320 + 135, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_EXIT][0], 320 + 135, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuExit][0], 320 + 135, scrollPos[kMenuMain]);
}
- if (menuBarFlag & menuBar_Settings) {
- if (mouseOnItem == menu_MAIN_PREF)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_PREF][1], 320, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarSettings) {
+ if (mouseOnItem == kMainMenuPrefs)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuPrefs][1], 320, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_PREF][0], 320, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuPrefs][0], 320, scrollPos[kMenuMain]);
}
- if (menuBarFlag & menuBar_Restore) {
- if (mouseOnItem == menu_MAIN_REST)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_REST][1], 320 - 135, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarRestore) {
+ if (mouseOnItem == kMainMenuLoad)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuLoad][1], 320 - 135, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_REST][0], 320 - 135, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuLoad][0], 320 - 135, scrollPos[kMenuMain]);
}
- if (menuBarFlag & menuBar_Save) {
- if (mouseOnItem == menu_MAIN_SAVE)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_SAVE][1], 320 - 135 * 2, scrollPos[menu_MAIN]);
+ if (menuBarFlag & kMenubarSave) {
+ if (mouseOnItem == kMainMenuSave)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuSave][1], 320 - 135 * 2, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_SAVE][0], 320 - 135 * 2, scrollPos[menu_MAIN]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuSave][0], 320 - 135 * 2, scrollPos[kMenuMain]);
}
redraw = false;
}
break;
default:
if (redraw) {
- if (inmenu) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAIN][1], 30, 0);
+ if (inMenu) {
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMain][1], 30, 0);
- if (menuBarFlag & menuBar_Items)
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_ITEM][1], 0, 0);
+ if (menuBarFlag & kMenubarItems)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuItem][1], 0, 0);
- if (menuBarFlag & menuBar_Magic)
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAGIC][1], 640 - 28, 0);
+ if (menuBarFlag & kMenubarMagic)
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMagic][1], 640 - 28, 0);
}
redraw = false;
}
@@ -555,9 +551,9 @@ void MenuZGI::process(uint32 deltatime) {
MenuNemesis::MenuNemesis(ZVision *engine) :
MenuHandler(engine) {
- inmenu = false;
+ inMenu = false;
scrolled = false;
- scrollPos = 0.0;
+ scrollPos = 0;
mouseOnItem = -1;
redraw = false;
delay = 0;
@@ -569,7 +565,7 @@ MenuNemesis::MenuNemesis(ZVision *engine) :
_engine->getRenderManager()->readImageToSurface(buf, but[i][j], false);
}
- _engine->getRenderManager()->readImageToSurface("bar.tga", menubar, false);
+ _engine->getRenderManager()->readImageToSurface("bar.tga", menuBar, false);
frm = 0;
}
@@ -579,7 +575,7 @@ MenuNemesis::~MenuNemesis() {
for (int j = 0; j < 6; j++)
but[i][j].free();
- menubar.free();
+ menuBar.free();
}
static const int16 buts[4][2] = { {120 , 64}, {144, 184}, {128, 328}, {120, 456} };
@@ -587,7 +583,7 @@ static const int16 buts[4][2] = { {120 , 64}, {144, 184}, {128, 328}, {120, 456}
void MenuNemesis::onMouseUp(const Common::Point &Pos) {
if (Pos.y < 40) {
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(buts[3][1],
scrollPos,
buts[3][0] + buts[3][1],
@@ -598,7 +594,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(buts[2][1],
scrollPos,
buts[2][0] + buts[2][1],
@@ -609,7 +605,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(buts[1][1],
scrollPos,
buts[1][0] + buts[1][1],
@@ -620,7 +616,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(buts[0][1],
scrollPos,
buts[0][0] + buts[0][1],
@@ -635,7 +631,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
void MenuNemesis::onMouseMove(const Common::Point &Pos) {
if (Pos.y < 40) {
- inmenu = true;
+ inMenu = true;
if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 2)
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 2);
@@ -644,39 +640,39 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) {
mouseOnItem = -1;
// Exit
- if (menuBarFlag & menuBar_Exit)
+ if (menuBarFlag & kMenubarExit)
if (Common::Rect(buts[3][1],
scrollPos,
buts[3][0] + buts[3][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_EXIT;
+ mouseOnItem = kMainMenuExit;
}
// Settings
- if (menuBarFlag & menuBar_Settings)
+ if (menuBarFlag & kMenubarSettings)
if (Common::Rect(buts[2][1],
scrollPos,
buts[2][0] + buts[2][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_PREF;
+ mouseOnItem = kMainMenuPrefs;
}
// Load
- if (menuBarFlag & menuBar_Restore)
+ if (menuBarFlag & kMenubarRestore)
if (Common::Rect(buts[1][1],
scrollPos,
buts[1][0] + buts[1][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_REST;
+ mouseOnItem = kMainMenuLoad;
}
// Save
- if (menuBarFlag & menuBar_Save)
+ if (menuBarFlag & kMenubarSave)
if (Common::Rect(buts[0][1],
scrollPos,
buts[0][0] + buts[0][1],
scrollPos + 32).contains(Pos)) {
- mouseOnItem = menu_MAIN_SAVE;
+ mouseOnItem = kMainMenuSave;
}
if (lastItem != mouseOnItem) {
@@ -685,7 +681,7 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) {
delay = 200;
}
} else {
- inmenu = false;
+ inMenu = false;
if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0)
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 0);
mouseOnItem = -1;
@@ -693,14 +689,14 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) {
}
void MenuNemesis::process(uint32 deltatime) {
- if (inmenu) {
+ if (inMenu) {
if (!scrolled) {
float scrl = 32.0 * 2.0 * (deltatime / 1000.0);
if (scrl == 0)
scrl = 1.0;
- scrollPos += scrl;
+ scrollPos += (int)scrl;
redraw = true;
}
@@ -719,22 +715,22 @@ void MenuNemesis::process(uint32 deltatime) {
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar, 64, scrollPos);
- if (menuBarFlag & menuBar_Exit)
- if (mouseOnItem == menu_MAIN_EXIT)
+ if (menuBarFlag & kMenubarExit)
+ if (mouseOnItem == kMainMenuExit)
_engine->getRenderManager()->blitSurfaceToMenu(but[3][frm], buts[3][1], scrollPos);
- if (menuBarFlag & menuBar_Settings)
- if (mouseOnItem == menu_MAIN_PREF)
+ if (menuBarFlag & kMenubarSettings)
+ if (mouseOnItem == kMainMenuPrefs)
_engine->getRenderManager()->blitSurfaceToMenu(but[2][frm], buts[2][1], scrollPos);
- if (menuBarFlag & menuBar_Restore)
- if (mouseOnItem == menu_MAIN_REST)
+ if (menuBarFlag & kMenubarRestore)
+ if (mouseOnItem == kMainMenuLoad)
_engine->getRenderManager()->blitSurfaceToMenu(but[1][frm], buts[1][1], scrollPos);
- if (menuBarFlag & menuBar_Save)
- if (mouseOnItem == menu_MAIN_SAVE)
+ if (menuBarFlag & kMenubarSave)
+ if (mouseOnItem == kMainMenuSave)
_engine->getRenderManager()->blitSurfaceToMenu(but[0][frm], buts[0][1], scrollPos);
redraw = false;
@@ -747,16 +743,16 @@ void MenuNemesis::process(uint32 deltatime) {
if (scrl == 0)
scrl = 1.0;
- Common::Rect cl(64, 32 + scrollPos - scrl, 64 + 512, 32 + scrollPos + 1);
+ Common::Rect cl(64, (int16)(32 + scrollPos - scrl), 64 + 512, 32 + scrollPos + 1);
_engine->getRenderManager()->clearMenuSurface(cl);
- scrollPos -= scrl;
+ scrollPos -= (int)scrl;
redraw = true;
} else
scrollPos = -32;
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar, 64, scrollPos);
redraw = false;
}
}
diff --git a/engines/zvision/core/menu.h b/engines/zvision/scripting/menu.h
index ebe0bb50ac..f6b21b9c97 100644
--- a/engines/zvision/core/menu.h
+++ b/engines/zvision/scripting/menu.h
@@ -32,12 +32,12 @@
namespace ZVision {
enum menuBar {
- menuBar_Exit = 0x1,
- menuBar_Settings = 0x2,
- menuBar_Restore = 0x4,
- menuBar_Save = 0x8,
- menuBar_Items = 0x100,
- menuBar_Magic = 0x200
+ kMenubarExit = 0x1,
+ kMenubarSettings = 0x2,
+ kMenubarRestore = 0x4,
+ kMenubarSave = 0x8,
+ kMenubarItems = 0x100,
+ kMenubarMagic = 0x200
};
class MenuHandler {
@@ -68,8 +68,8 @@ public:
void onMouseUp(const Common::Point &Pos);
void process(uint32 deltaTimeInMillis);
private:
- Graphics::Surface menuback[3][2];
- Graphics::Surface menubar[4][2];
+ Graphics::Surface menuBack[3][2];
+ Graphics::Surface menuBar[4][2];
Graphics::Surface *items[50][2];
uint itemId[50];
@@ -77,19 +77,13 @@ private:
uint magicId[12];
int menuMouseFocus;
- bool inmenu;
+ bool inMenu;
int mouseOnItem;
- bool scrolled[3];
+ bool scrolled[3];
int16 scrollPos[3];
- enum {
- menu_ITEM = 0,
- menu_MAGIC = 1,
- menu_MAIN = 2
- };
-
bool clean;
bool redraw;
@@ -104,13 +98,13 @@ public:
void process(uint32 deltaTimeInMillis);
private:
Graphics::Surface but[4][6];
- Graphics::Surface menubar;
+ Graphics::Surface menuBar;
- bool inmenu;
+ bool inMenu;
int mouseOnItem;
- bool scrolled;
+ bool scrolled;
int16 scrollPos;
bool redraw;
@@ -120,6 +114,6 @@ private:
};
-}
+} // End of namespace ZVision
#endif
diff --git a/engines/zvision/scripting/scr_file_handling.cpp b/engines/zvision/scripting/scr_file_handling.cpp
index c117da5ec2..edc1b8622c 100644
--- a/engines/zvision/scripting/scr_file_handling.cpp
+++ b/engines/zvision/scripting/scr_file_handling.cpp
@@ -47,15 +47,13 @@ namespace ZVision {
void ScriptManager::parseScrFile(const Common::String &fileName, ScriptScope &scope) {
Common::File file;
if (!_engine->getSearchManager()->openFile(file, fileName)) {
- warning("Script file not found: %s", fileName.c_str());
- return;
+ error("Script file not found: %s", fileName.c_str());
}
while (!file.eos()) {
Common::String line = file.readLine();
if (file.err()) {
- warning("Error parsing scr file: %s", fileName.c_str());
- return;
+ error("Error parsing scr file: %s", fileName.c_str());
}
trimCommentsAndWhiteSpace(&line);
@@ -85,9 +83,18 @@ void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stre
while (!stream.eos() && !line.contains('}')) {
if (line.matchString("criteria {", true)) {
- parseCriteria(stream, puzzle->criteriaList);
+ parseCriteria(stream, puzzle->criteriaList, puzzle->key);
} else if (line.matchString("results {", true)) {
parseResults(stream, puzzle->resultActions);
+
+ // WORKAROUND for a script bug in Zork Nemesis, room ve5e (tuning
+ // fork box closeup). If the player leaves the screen while the
+ // box is open, puzzle 19398 shows the animation where the box
+ // closes, but the box state (state variable 19397) is not updated.
+ // We insert the missing assignment for the box state here.
+ // Fixes bug #6803.
+ if (_engine->getGameId() == GID_NEMESIS && puzzle->key == 19398)
+ puzzle->resultActions.push_back(new ActionAssign(_engine, 11, "19397, 0"));
} else if (line.matchString("flags {", true)) {
setStateFlag(puzzle->key, parseFlags(stream));
}
@@ -99,11 +106,18 @@ void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stre
puzzle->addedBySetState = false;
}
-bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const {
+bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList, uint32 key) const {
// Loop until we find the closing brace
Common::String line = stream.readLine();
trimCommentsAndWhiteSpace(&line);
+ // Skip any commented out criteria. If all the criteria are commented out,
+ // we might end up with an invalid criteria list (bug #6776).
+ while (line.empty()) {
+ line = stream.readLine();
+ trimCommentsAndWhiteSpace(&line);
+ }
+
// Criteria can be empty
if (line.contains('}')) {
return false;
@@ -112,6 +126,21 @@ bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::Li
// Create a new List to hold the CriteriaEntries
criteriaList.push_back(Common::List<Puzzle::CriteriaEntry>());
+ // WORKAROUND for a script bug in Zork: Nemesis, room td9e (fist puzzle)
+ // Since we patch the script that triggers when manipulating the left fist
+ // (below), we add an additional check for the left fist sound, so that it
+ // doesn't get killed immediately when the left fist animation starts.
+ // Together with the workaround below, it fixes bug #6783.
+ if (_engine->getGameId() == GID_NEMESIS && key == 3594) {
+ Puzzle::CriteriaEntry entry;
+ entry.key = 567;
+ entry.criteriaOperator = Puzzle::NOT_EQUAL_TO;
+ entry.argumentIsAKey = false;
+ entry.argument = 1;
+
+ criteriaList.back().push_back(entry);
+ }
+
while (!stream.eos() && !line.contains('}')) {
Puzzle::CriteriaEntry entry;
@@ -123,6 +152,13 @@ bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::Li
token = tokenizer.nextToken();
sscanf(token.c_str(), "[%u]", &(entry.key));
+ // WORKAROUND for a script bug in Zork: Nemesis, room td9e (fist puzzle)
+ // Check for the state of animation 567 (left fist) when manipulating
+ // the fingers of the left fist (puzzle slots 3582, 3583).
+ // Together with the workaround above, it fixes bug #6783.
+ if (_engine->getGameId() == GID_NEMESIS && (key == 3582 || key == 3583) && entry.key == 568)
+ entry.key = 567;
+
// Parse the operator out of the second token
token = tokenizer.nextToken();
if (token.c_str()[0] == '=')
@@ -134,9 +170,17 @@ bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::Li
else if (token.c_str()[0] == '<')
entry.criteriaOperator = Puzzle::LESS_THAN;
+ // There are supposed to be three tokens, but there is no
+ // guarantee that there will be a space between the second and
+ // the third one (bug #6774)
+ if (token.size() == 1) {
+ token = tokenizer.nextToken();
+ } else {
+ token.deleteChar(0);
+ }
+
// First determine if the last token is an id or a value
// Then parse it into 'argument'
- token = tokenizer.nextToken();
if (token.contains('[')) {
sscanf(token.c_str(), "[%u]", &(entry.argument));
entry.argumentIsAKey = true;
@@ -216,6 +260,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("animpreload", true)) {
actionList.push_back(new ActionPreloadAnimation(_engine, slot, args));
} else if (act.matchString("animunload", true)) {
+ // Only used by ZGI (locations cd6e, cd6k, dg2f, dg4e, dv1j)
actionList.push_back(new ActionUnloadAnimation(_engine, slot, args));
} else if (act.matchString("attenuate", true)) {
actionList.push_back(new ActionAttenuate(_engine, slot, args));
@@ -234,12 +279,13 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("disable_control", true)) {
actionList.push_back(new ActionDisableControl(_engine, slot, args));
} else if (act.matchString("disable_venus", true)) {
- actionList.push_back(new ActionDisableVenus(_engine, slot, args));
+ // Not used. Purposely left empty
} else if (act.matchString("display_message", true)) {
actionList.push_back(new ActionDisplayMessage(_engine, slot, args));
} else if (act.matchString("dissolve", true)) {
actionList.push_back(new ActionDissolve(_engine));
} else if (act.matchString("distort", true)) {
+ // Only used by Zork: Nemesis for the "treatment" puzzle in the Sanitarium (aj30)
actionList.push_back(new ActionDistort(_engine, slot, args));
} else if (act.matchString("enable_control", true)) {
actionList.push_back(new ActionEnableControl(_engine, slot, args));
@@ -248,6 +294,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("inventory", true)) {
actionList.push_back(new ActionInventory(_engine, slot, args));
} else if (act.matchString("kill", true)) {
+ // Only used by ZGI
actionList.push_back(new ActionKill(_engine, slot, args));
} else if (act.matchString("menu_bar_enable", true)) {
actionList.push_back(new ActionMenuBarEnable(_engine, slot, args));
@@ -264,8 +311,11 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("random", true)) {
actionList.push_back(new ActionRandom(_engine, slot, args));
} else if (act.matchString("region", true)) {
+ // Only used by Zork: Nemesis
actionList.push_back(new ActionRegion(_engine, slot, args));
} else if (act.matchString("restore_game", true)) {
+ // Only used by ZGI to load the restart game slot, r.svr.
+ // Used by the credits screen.
actionList.push_back(new ActionRestoreGame(_engine, slot, args));
} else if (act.matchString("rotate_to", true)) {
actionList.push_back(new ActionRotateTo(_engine, slot, args));
@@ -276,7 +326,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (act.matchString("set_screen", true)) {
actionList.push_back(new ActionSetScreen(_engine, slot, args));
} else if (act.matchString("set_venus", true)) {
- actionList.push_back(new ActionSetVenus(_engine, slot, args));
+ // Not used. Purposely left empty
} else if (act.matchString("stop", true)) {
actionList.push_back(new ActionStop(_engine, slot, args));
} else if (act.matchString("streamvideo", true)) {
@@ -337,6 +387,16 @@ Control *ScriptManager::parseControl(Common::String &line, Common::SeekableReadS
Common::String controlType(controlTypeBuffer);
if (controlType.equalsIgnoreCase("push_toggle")) {
+ // WORKAROUND for a script bug in ZGI: There is an invalid hotspot
+ // at scene em1h (bottom of tower), which points to a missing
+ // script em1n. This is a hotspot at the right of the screen.
+ // In the original, this hotspot doesn't lead anywhere anyway,
+ // so instead of moving to a missing scene, we just remove the
+ // hotspot altogether. The alternative would be to just process
+ // and ignore invalid scenes, but I don't think it's worth the
+ // effort. Fixes bug #6780.
+ if (_engine->getGameId() == GID_GRANDINQUISITOR && key == 5653)
+ return NULL;
return new PushToggleControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("flat")) {
Control::parseFlatControl(_engine);
@@ -345,25 +405,32 @@ Control *ScriptManager::parseControl(Common::String &line, Common::SeekableReadS
Control::parsePanoramaControl(_engine, stream);
return NULL;
} else if (controlType.equalsIgnoreCase("tilt")) {
+ // Only used in Zork Nemesis, handles tilt controls (ZGI doesn't have a tilt view)
Control::parseTiltControl(_engine, stream);
return NULL;
- } else if (controlType.equalsIgnoreCase("lever")) {
- return new LeverControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("slot")) {
return new SlotControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("input")) {
return new InputControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("save")) {
return new SaveControl(_engine, key, stream);
+ } else if (controlType.equalsIgnoreCase("lever")) {
+ // Only used in Zork Nemesis, handles draggable levers (te2e, tm7e, tp2e, tt2e, tz2e)
+ return new LeverControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("safe")) {
+ // Only used in Zork Nemesis, handles the safe in the Asylum (ac4g)
return new SafeControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("hotmovie")) {
+ // Only used in Zork Nemesis, handles movies where the player needs to click on something (mj7g, vw3g)
return new HotMovControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("fist")) {
+ // Only used in Zork Nemesis, handles the door lock puzzle with the skeletal fingers (td9e)
return new FistControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("paint")) {
+ // Only used in Zork Nemesis, handles the painting puzzle screen in Lucien's room in Irondune (ch4g)
return new PaintControl(_engine, key, stream);
} else if (controlType.equalsIgnoreCase("titler")) {
+ // Only used in Zork Nemesis, handles the death screen with the Restore/Exit buttons (cjde)
return new TitlerControl(_engine, key, stream);
}
return NULL;
diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp
index 4c1e69072d..70eaab2a0a 100644
--- a/engines/zvision/scripting/script_manager.cpp
+++ b/engines/zvision/scripting/script_manager.cpp
@@ -27,9 +27,10 @@
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/actions.h"
-#include "zvision/scripting/sidefx/timer_node.h"
+#include "zvision/scripting/menu.h"
+#include "zvision/scripting/effects/timer_effect.h"
#include "common/algorithm.h"
#include "common/hashmap.h"
@@ -71,21 +72,23 @@ void ScriptManager::initialize() {
}
void ScriptManager::update(uint deltaTimeMillis) {
- if (_currentLocation.node != _nextLocation.node ||
- _currentLocation.room != _nextLocation.room ||
- _currentLocation.view != _nextLocation.view ||
- _currentLocation.world != _nextLocation.world)
- ChangeLocationReal();
+ if (_currentLocation != _nextLocation) {
+ ChangeLocationReal(false);
+ }
updateNodes(deltaTimeMillis);
- if (! execScope(nodeview))
+ if (!execScope(nodeview)) {
return;
- if (! execScope(room))
+ }
+ if (!execScope(room)) {
return;
- if (! execScope(world))
+ }
+ if (!execScope(world)) {
return;
- if (! execScope(universe))
+ }
+ if (!execScope(universe)) {
return;
+ }
updateControls(deltaTimeMillis);
}
@@ -96,17 +99,22 @@ bool ScriptManager::execScope(ScriptScope &scope) {
scope.scopeQueue = tmp;
scope.scopeQueue->clear();
- for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter)
+ for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) {
(*PuzzleIter)->addedBySetState = false;
+ }
if (scope.procCount < 2 || getStateValue(StateKey_ExecScopeStyle)) {
- for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter)
- if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount))
+ for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) {
+ if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) {
return false;
+ }
+ }
} else {
- for (PuzzleList::iterator PuzzleIter = scope.execQueue->begin(); PuzzleIter != scope.execQueue->end(); ++PuzzleIter)
- if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount))
+ for (PuzzleList::iterator PuzzleIter = scope.execQueue->begin(); PuzzleIter != scope.execQueue->end(); ++PuzzleIter) {
+ if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) {
return false;
+ }
+ }
}
if (scope.procCount < 2) {
@@ -118,9 +126,11 @@ bool ScriptManager::execScope(ScriptScope &scope) {
void ScriptManager::referenceTableAddPuzzle(uint32 key, PuzzleRef ref) {
if (_referenceTable.contains(key)) {
Common::Array<PuzzleRef> *arr = &_referenceTable[key];
- for (uint32 i = 0; i < arr->size(); i++)
- if ((*arr)[i].puz == ref.puz)
+ for (uint32 i = 0; i < arr->size(); i++) {
+ if ((*arr)[i].puz == ref.puz) {
return;
+ }
+ }
}
_referenceTable[key].push_back(ref);
@@ -138,9 +148,11 @@ void ScriptManager::addPuzzlesToReferenceTable(ScriptScope &scope) {
referenceTableAddPuzzle(puzzlePtr->key, ref);
// Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle
- for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*PuzzleIter)->criteriaList.begin(); criteriaIter != (*PuzzleIter)->criteriaList.end(); ++criteriaIter)
- for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter)
+ for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*PuzzleIter)->criteriaList.begin(); criteriaIter != (*PuzzleIter)->criteriaList.end(); ++criteriaIter) {
+ for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) {
referenceTableAddPuzzle(entryIter->key, ref);
+ }
+ }
}
}
@@ -158,8 +170,9 @@ void ScriptManager::updateNodes(uint deltaTimeMillis) {
}
void ScriptManager::updateControls(uint deltaTimeMillis) {
- if (!_activeControls)
+ if (!_activeControls) {
return;
+ }
// Process only one event
if (!_controlEvents.empty()) {
@@ -186,21 +199,24 @@ void ScriptManager::updateControls(uint deltaTimeMillis) {
_controlEvents.pop_front();
}
- for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++)
- if ((*iter)->process(deltaTimeMillis))
+ for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++) {
+ if ((*iter)->process(deltaTimeMillis)) {
break;
+ }
+ }
}
bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) {
// Check if the puzzle is already finished
// Also check that the puzzle isn't disabled
- if (getStateValue(puzzle->key) == 1 || (getStateFlag(puzzle->key) & Puzzle::DISABLED) == Puzzle::DISABLED) {
+ if (getStateValue(puzzle->key) == 1 || (getStateFlag(puzzle->key) & Puzzle::DISABLED)) {
return true;
}
// Check each Criteria
- if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0)
+ if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0) {
return true;
+ }
bool criteriaMet = false;
for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) {
@@ -209,10 +225,11 @@ bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) {
for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) {
// Get the value to compare against
int argumentValue;
- if (entryIter->argumentIsAKey)
+ if (entryIter->argumentIsAKey) {
argumentValue = getStateValue(entryIter->argument);
- else
+ } else {
argumentValue = entryIter->argument;
+ }
// Do the comparison
switch (entryIter->criteriaOperator) {
@@ -250,8 +267,9 @@ bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) {
setStateValue(puzzle->key, 1);
for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) {
- if (!(*resultIter)->execute())
+ if (!(*resultIter)->execute()) {
return false;
+ }
}
}
@@ -274,13 +292,15 @@ void ScriptManager::cleanScriptScope(ScriptScope &scope) {
scope.privQueueTwo.clear();
scope.scopeQueue = &scope.privQueueOne;
scope.execQueue = &scope.privQueueTwo;
- for (PuzzleList::iterator iter = scope.puzzles.begin(); iter != scope.puzzles.end(); ++iter)
+ for (PuzzleList::iterator iter = scope.puzzles.begin(); iter != scope.puzzles.end(); ++iter) {
delete(*iter);
+ }
scope.puzzles.clear();
- for (ControlList::iterator iter = scope.controls.begin(); iter != scope.controls.end(); ++iter)
+ for (ControlList::iterator iter = scope.controls.begin(); iter != scope.controls.end(); ++iter) {
delete(*iter);
+ }
scope.controls.clear();
@@ -288,44 +308,49 @@ void ScriptManager::cleanScriptScope(ScriptScope &scope) {
}
int ScriptManager::getStateValue(uint32 key) {
- if (_globalState.contains(key))
+ if (_globalState.contains(key)) {
return _globalState[key];
- else
+ } else {
return 0;
+ }
}
void ScriptManager::queuePuzzles(uint32 key) {
if (_referenceTable.contains(key)) {
Common::Array<PuzzleRef> *arr = &_referenceTable[key];
- for (int32 i = arr->size() - 1; i >= 0; i--)
+ for (int32 i = arr->size() - 1; i >= 0; i--) {
if (!(*arr)[i].puz->addedBySetState) {
(*arr)[i].scope->scopeQueue->push_back((*arr)[i].puz);
(*arr)[i].puz->addedBySetState = true;
}
+ }
}
}
void ScriptManager::setStateValue(uint32 key, int value) {
- if (value == 0)
+ if (value == 0) {
_globalState.erase(key);
- else
+ } else {
_globalState[key] = value;
+ }
queuePuzzles(key);
}
void ScriptManager::setStateValueSilent(uint32 key, int value) {
- if (value == 0)
+ if (value == 0) {
_globalState.erase(key);
- else
+ } else {
_globalState[key] = value;
+ }
}
uint ScriptManager::getStateFlag(uint32 key) {
- if (_globalStateFlags.contains(key))
+ if (_globalStateFlags.contains(key)) {
return _globalStateFlags[key];
- else
+ } else {
return 0;
+ }
}
void ScriptManager::setStateFlag(uint32 key, uint value) {
@@ -335,10 +360,11 @@ void ScriptManager::setStateFlag(uint32 key, uint value) {
}
void ScriptManager::setStateFlagSilent(uint32 key, uint value) {
- if (value == 0)
+ if (value == 0) {
_globalStateFlags.erase(key);
- else
+ } else {
_globalStateFlags[key] = value;
+ }
}
void ScriptManager::unsetStateFlag(uint32 key, uint value) {
@@ -347,23 +373,29 @@ void ScriptManager::unsetStateFlag(uint32 key, uint value) {
if (_globalStateFlags.contains(key)) {
_globalStateFlags[key] &= ~value;
- if (_globalStateFlags[key] == 0)
+ if (_globalStateFlags[key] == 0) {
_globalStateFlags.erase(key);
+ }
}
}
Control *ScriptManager::getControl(uint32 key) {
- for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter)
- if ((*iter)->getKey() == key)
+ for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
+ if ((*iter)->getKey() == key) {
return *iter;
+ }
+ }
+
return nullptr;
}
void ScriptManager::focusControl(uint32 key) {
- if (!_activeControls)
+ if (!_activeControls) {
return;
- if (_currentlyFocusedControl == key)
+ }
+ if (_currentlyFocusedControl == key) {
return;
+ }
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
uint32 controlKey = (*iter)->getKey();
@@ -381,11 +413,11 @@ void ScriptManager::setFocusControlKey(uint32 key) {
_currentlyFocusedControl = key;
}
-void ScriptManager::addSideFX(SideFX *fx) {
+void ScriptManager::addSideFX(ScriptingEffect *fx) {
_activeSideFx.push_back(fx);
}
-SideFX *ScriptManager::getSideFX(uint32 key) {
+ScriptingEffect *ScriptManager::getSideFX(uint32 key) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
if ((*iter)->getKey() == key) {
return (*iter);
@@ -429,7 +461,7 @@ void ScriptManager::killSideFx(uint32 key) {
}
}
-void ScriptManager::killSideFxType(SideFX::SideFXType type) {
+void ScriptManager::killSideFxType(ScriptingEffect::ScriptingEffectType type) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) {
if ((*iter)->getType() & type) {
(*iter)->kill();
@@ -442,50 +474,60 @@ void ScriptManager::killSideFxType(SideFX::SideFXType type) {
}
void ScriptManager::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
- if (!_activeControls)
+ if (!_activeControls) {
return;
+ }
for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) {
- if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos))
+ if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos)) {
return;
+ }
}
}
void ScriptManager::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
- if (!_activeControls)
+ if (!_activeControls) {
return;
+ }
for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) {
- if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos))
+ if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos)) {
return;
+ }
}
}
bool ScriptManager::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
- if (!_activeControls)
+ if (!_activeControls) {
return false;
+ }
for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) {
- if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos))
+ if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos)) {
return true;
+ }
}
return false;
}
void ScriptManager::onKeyDown(Common::KeyState keyState) {
- if (!_activeControls)
+ if (!_activeControls) {
return;
+ }
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
- if ((*iter)->onKeyDown(keyState))
+ if ((*iter)->onKeyDown(keyState)) {
return;
+ }
}
}
void ScriptManager::onKeyUp(Common::KeyState keyState) {
- if (!_activeControls)
+ if (!_activeControls) {
return;
+ }
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
- if ((*iter)->onKeyUp(keyState))
+ if ((*iter)->onKeyUp(keyState)) {
return;
+ }
}
}
@@ -499,8 +541,8 @@ void ScriptManager::changeLocation(char _world, char _room, char _node, char _vi
_nextLocation.node = _node;
_nextLocation.view = _view;
_nextLocation.offset = offset;
- // If next location 0000 - it's indicate to go to previous location.
- if (_nextLocation.world == '0' && _nextLocation.room == '0' && _nextLocation.node == '0' && _nextLocation.view == '0') {
+ // If next location is 0000, return to the previous location.
+ if (_nextLocation == "0000") {
if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') {
_nextLocation.world = getStateValue(StateKey_LastWorld);
_nextLocation.room = getStateValue(StateKey_LastRoom);
@@ -517,36 +559,42 @@ void ScriptManager::changeLocation(char _world, char _room, char _node, char _vi
}
}
-void ScriptManager::ChangeLocationReal() {
+void ScriptManager::ChangeLocationReal(bool isLoading) {
assert(_nextLocation.world != 0);
debug(1, "Changing location to: %c %c %c %c %u", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view, _nextLocation.offset);
- if (_nextLocation.world == 'g' && _nextLocation.room == 'j' && !ConfMan.getBool("originalsaveload")) {
- if ((_nextLocation.node == 's' || _nextLocation.node == 'r') && _nextLocation.view == 'e') {
+ const bool enteringMenu = (_nextLocation.world == 'g' && _nextLocation.room == 'j');
+ const bool leavingMenu = (_currentLocation.world == 'g' && _currentLocation.room == 'j');
+ const bool isSaveScreen = (enteringMenu && _nextLocation.node == 's' && _nextLocation.view == 'e');
+ const bool isRestoreScreen = (enteringMenu && _nextLocation.node == 'r' && _nextLocation.view == 'e');
+
+ if (enteringMenu && !ConfMan.getBool("originalsaveload")) {
+ if (isSaveScreen || isRestoreScreen) {
// Hook up the ScummVM save/restore dialog
- bool isSave = (_nextLocation.node == 's');
- bool gameSavedOrLoaded = _engine->getSaveManager()->scummVMSaveLoadDialog(isSave);
- if (!gameSavedOrLoaded || isSave) {
+ bool gameSavedOrLoaded = _engine->getSaveManager()->scummVMSaveLoadDialog(isSaveScreen);
+ if (!gameSavedOrLoaded || isSaveScreen) {
// Reload the current room
_nextLocation.world = _currentLocation.world;
_nextLocation.room = _currentLocation.room;
_nextLocation.node = _currentLocation.node;
_nextLocation.view = _currentLocation.view;
_nextLocation.offset = _currentLocation.offset;
- _currentLocation.world = '0';
+
+ return;
+ } else {
+ _currentLocation.world = 'g';
_currentLocation.room = '0';
_currentLocation.node = '0';
_currentLocation.view = '0';
_currentLocation.offset = 0;
- } else
- return;
+ }
}
}
_engine->setRenderDelay(2);
- if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') {
- if (_nextLocation.world != 'g' || _nextLocation.room != 'j') {
+ if (!leavingMenu) {
+ if (!isLoading && !enteringMenu) {
setStateValue(StateKey_LastWorld, getStateValue(StateKey_World));
setStateValue(StateKey_LastRoom, getStateValue(StateKey_Room));
setStateValue(StateKey_LastNode, getStateValue(StateKey_Node));
@@ -561,16 +609,13 @@ void ScriptManager::ChangeLocationReal() {
}
}
- if (_nextLocation.world == 'g' && _nextLocation.room == 'j') {
- if (_nextLocation.node == 's' && _nextLocation.view == 'e' &&
- _currentLocation.world != 'g' && _currentLocation.room != 'j')
+ if (enteringMenu) {
+ if (isSaveScreen && !leavingMenu) {
_engine->getSaveManager()->prepareSaveBuffer();
+ }
} else {
- if (_currentLocation.world == 'g' && _currentLocation.room == 'j')
+ if (leavingMenu) {
_engine->getSaveManager()->flushSaveBuffer();
- else {
- // Auto save
- //_engine->getSaveManager()->autoSave();
}
}
@@ -583,7 +628,7 @@ void ScriptManager::ChangeLocationReal() {
_referenceTable.clear();
addPuzzlesToReferenceTable(universe);
- _engine->menuBarEnable(0xFFFF);
+ _engine->getMenuHandler()->setEnable(0xFFFF);
if (_nextLocation.world != _currentLocation.world) {
cleanScriptScope(nodeview);
@@ -634,7 +679,7 @@ void ScriptManager::ChangeLocationReal() {
// Change the background position
_engine->getRenderManager()->setBackgroundPosition(_nextLocation.offset);
- if (_currentLocation.world == 0 && _currentLocation.room == 0 && _currentLocation.node == 0 && _currentLocation.view == 0) {
+ if (_currentLocation == "0000") {
_currentLocation = _nextLocation;
execScope(world);
execScope(room);
@@ -652,7 +697,7 @@ void ScriptManager::ChangeLocationReal() {
execScope(nodeview);
}
- _engine->checkBorders();
+ _engine->getRenderManager()->checkBorders();
}
void ScriptManager::serialize(Common::WriteStream *stream) {
@@ -667,26 +712,30 @@ void ScriptManager::serialize(Common::WriteStream *stream) {
stream->writeByte(getStateValue(StateKey_View));
stream->writeUint32LE(getStateValue(StateKey_ViewPos));
- for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter)
+ for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
(*iter)->serialize(stream);
+ }
stream->writeUint32BE(MKTAG('F', 'L', 'A', 'G'));
int32 slots = 20000;
- if (_engine->getGameId() == GID_NEMESIS)
+ if (_engine->getGameId() == GID_NEMESIS) {
slots = 30000;
+ }
stream->writeUint32LE(slots * 2);
- for (int32 i = 0; i < slots; i++)
+ for (int32 i = 0; i < slots; i++) {
stream->writeUint16LE(getStateFlag(i));
+ }
stream->writeUint32BE(MKTAG('P', 'U', 'Z', 'Z'));
stream->writeUint32LE(slots * 2);
- for (int32 i = 0; i < slots; i++)
+ for (int32 i = 0; i < slots; i++) {
stream->writeSint16LE(getStateValue(i));
+ }
}
void ScriptManager::deserialize(Common::SeekableReadStream *stream) {
@@ -703,8 +752,9 @@ void ScriptManager::deserialize(Common::SeekableReadStream *stream) {
_currentLocation.room = 0;
_currentLocation.view = 0;
- for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++)
+ for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++) {
delete(*iter);
+ }
_activeSideFx.clear();
@@ -737,20 +787,23 @@ void ScriptManager::deserialize(Common::SeekableReadStream *stream) {
case MKTAG('T', 'I', 'M', 'R'): {
uint32 key = stream->readUint32LE();
uint32 time = stream->readUint32LE();
- if (_engine->getGameId() == GID_GRANDINQUISITOR)
+ if (_engine->getGameId() == GID_GRANDINQUISITOR) {
time /= 100;
- else if (_engine->getGameId() == GID_NEMESIS)
+ } else if (_engine->getGameId() == GID_NEMESIS) {
time /= 1000;
+ }
addSideFX(new TimerNode(_engine, key, time));
}
break;
case MKTAG('F', 'L', 'A', 'G'):
- for (uint32 i = 0; i < tagSize / 2; i++)
+ for (uint32 i = 0; i < tagSize / 2; i++) {
setStateFlagSilent(i, stream->readUint16LE());
+ }
break;
case MKTAG('P', 'U', 'Z', 'Z'):
- for (uint32 i = 0; i < tagSize / 2; i++)
+ for (uint32 i = 0; i < tagSize / 2; i++) {
setStateValueSilent(i, stream->readUint16LE());
+ }
break;
default:
stream->seek(tagSize, SEEK_CUR);
@@ -759,7 +812,7 @@ void ScriptManager::deserialize(Common::SeekableReadStream *stream) {
_nextLocation = nextLocation;
- ChangeLocationReal();
+ ChangeLocationReal(true);
_engine->setRenderDelay(10);
setStateValue(StateKey_RestoreFlag, 1);
@@ -804,10 +857,11 @@ void ScriptManager::flushEvent(Common::EventType type) {
EventList::iterator it = _controlEvents.begin();
while (it != _controlEvents.end()) {
- if ((*it).type == type)
+ if ((*it).type == type) {
it = _controlEvents.erase(it);
- else
+ } else {
it++;
+ }
}
}
@@ -836,12 +890,15 @@ ValueSlot::ValueSlot(ScriptManager *scriptManager, const char *slotValue):
}
int16 ValueSlot::getValue() {
if (slot) {
- if (value >= 0)
+ if (value >= 0) {
return _scriptManager->getStateValue(value);
- else
+ }
+ else {
return 0;
- } else
+ }
+ } else {
return value;
+ }
}
} // End of namespace ZVision
diff --git a/engines/zvision/scripting/script_manager.h b/engines/zvision/scripting/script_manager.h
index 1e308faf0d..7c276bf917 100644
--- a/engines/zvision/scripting/script_manager.h
+++ b/engines/zvision/scripting/script_manager.h
@@ -25,7 +25,7 @@
#include "zvision/scripting/puzzle.h"
#include "zvision/scripting/control.h"
-#include "zvision/scripting/sidefx.h"
+#include "zvision/scripting/scripting_effect.h"
#include "common/hashmap.h"
#include "common/queue.h"
@@ -87,6 +87,7 @@ enum StateKey {
StateKey_JapanFonts = 75,
StateKey_ExecScopeStyle = 76,
StateKey_Brightness = 77,
+ StateKey_MPEGMovies = 78,
StateKey_EF9_R = 91,
StateKey_EF9_G = 92,
StateKey_EF9_B = 93,
@@ -94,7 +95,12 @@ enum StateKey {
StateKey_Inv_Cnt_Slot = 100,
StateKey_Inv_1_Slot = 101,
StateKey_Inv_49_Slot = 149,
- StateKey_Inv_TotalSlots = 150
+ // ZGI only
+ StateKey_Inv_TotalSlots = 150,
+ StateKey_Inv_StartSlot = 151,
+ StateKey_Spell_1 = 191,
+ StateKey_Active_Spell = 205,
+ StateKey_Reversed_Spellbooc = 206
};
struct Location {
@@ -107,11 +113,33 @@ struct Location {
uint32 offset;
};
+inline bool operator==(const Location& lhs, const Location& rhs) {
+ return (
+ lhs.world == rhs.world &&
+ lhs.room == rhs.room &&
+ lhs.node == rhs.node &&
+ lhs.view == rhs.view
+ );
+}
+
+inline bool operator==(const Location& lhs, const char* rhs) {
+ Common::String lhsStr = Common::String::format("%c%c%c%c", lhs.world, lhs.room, lhs.node, lhs.view);
+ return lhsStr == rhs;
+}
+
+inline bool operator!=(const Location& lhs, const Location& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const Location& lhs, const char* rhs) {
+ return !(lhs == rhs);
+}
+
typedef Common::List<Puzzle *> PuzzleList;
typedef Common::Queue<Puzzle *> PuzzleQueue;
typedef Common::List<Control *> ControlList;
typedef Common::HashMap<uint32, int32> StateMap;
-typedef Common::List<SideFX *> SideFXList;
+typedef Common::List<ScriptingEffect *> SideFXList;
typedef Common::List<Common::Event> EventList;
class ScriptManager {
@@ -191,12 +219,12 @@ public:
// Only change focus control without call focus/unfocus.
void setFocusControlKey(uint32 key);
- void addSideFX(SideFX *fx);
- SideFX *getSideFX(uint32 key);
+ void addSideFX(ScriptingEffect *fx);
+ ScriptingEffect *getSideFX(uint32 key);
void deleteSideFx(uint32 key);
void stopSideFx(uint32 key);
void killSideFx(uint32 key);
- void killSideFxType(SideFX::SideFXType type);
+ void killSideFxType(ScriptingEffect::ScriptingEffectType type);
void addEvent(Common::Event);
void flushEvent(Common::EventType type);
@@ -267,7 +295,7 @@ private:
bool execScope(ScriptScope &scope);
/** Perform change location */
- void ChangeLocationReal();
+ void ChangeLocationReal(bool isLoading);
int8 inventoryGetCount();
void inventorySetCount(int8 cnt);
@@ -282,7 +310,7 @@ public:
void inventoryDrop(int16 item);
void inventoryCycle();
- // TODO: Make this private. It was only made public so Console::cmdParseAllScrFiles() could use it
+private:
/**
* Parses a script file into triggers and events
*
@@ -291,7 +319,6 @@ public:
*/
void parseScrFile(const Common::String &fileName, ScriptScope &scope);
-private:
/**
* Parses the stream into a Puzzle object
* Helper method for parseScrFile.
@@ -307,9 +334,10 @@ private:
*
* @param criteria Pointer to the Criteria object to fill
* @param stream Scr file stream
+ * @param key Puzzle key (for workarounds)
* @return Whether any criteria were read
*/
- bool parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const;
+ bool parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList, uint32 key) const;
/**
* Parses the stream into a ResultAction objects
diff --git a/engines/zvision/scripting/sidefx.h b/engines/zvision/scripting/scripting_effect.h
index 5bb14f0cdd..2a2153204f 100644
--- a/engines/zvision/scripting/sidefx.h
+++ b/engines/zvision/scripting/scripting_effect.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SIDEFX_H_INCLUDED
-#define SIDEFX_H_INCLUDED
+#ifndef SCRIPTING_EFFECT_H_INCLUDED
+#define SCRIPTING_EFFECT_H_INCLUDED
namespace Common {
class SeekableReadStream;
@@ -33,29 +33,39 @@ namespace ZVision {
class ZVision;
-class SideFX {
+/**
+ * The base class that represents effects created from Actions.
+ * This class is virtual.
+ *
+ * Detailed Description:
+ * A scene has Controls. By interacting with the controls, the user
+ * causes Actions to execute. Certain Actions create 'effects', for
+ * example, a sound or an animation. This is the base class for
+ * those effects.
+ */
+class ScriptingEffect {
public:
- enum SideFXType {
- SIDEFX_ANIM = 1,
- SIDEFX_AUDIO = 2,
- SIDEFX_DISTORT = 4,
- SIDEFX_PANTRACK = 8,
- SIDEFX_REGION = 16,
- SIDEFX_TIMER = 32,
- SIDEFX_TTYTXT = 64,
- SIDEFX_UNK = 128,
- SIDEFX_ALL = 255
+ enum ScriptingEffectType {
+ SCRIPTING_EFFECT_ANIM = 1,
+ SCRIPTING_EFFECT_AUDIO = 2,
+ SCRIPTING_EFFECT_DISTORT = 4,
+ SCRIPTING_EFFECT_PANTRACK = 8,
+ SCRIPTING_EFFECT_REGION = 16,
+ SCRIPTING_EFFECT_TIMER = 32,
+ SCRIPTING_EFFECT_TTYTXT = 64,
+ SCRIPTING_EFFECT_UNKNOWN = 128,
+ SCRIPTING_EFFECT_ALL = 255
};
- SideFX() : _engine(0), _key(0), _type(SIDEFX_UNK) {}
- SideFX(ZVision *engine, uint32 key, SideFXType type) : _engine(engine), _key(key), _type(type) {}
- virtual ~SideFX() {}
+ ScriptingEffect() : _engine(0), _key(0), _type(SCRIPTING_EFFECT_UNKNOWN) {}
+ ScriptingEffect(ZVision *engine, uint32 key, ScriptingEffectType type) : _engine(engine), _key(key), _type(type) {}
+ virtual ~ScriptingEffect() {}
uint32 getKey() {
return _key;
}
- SideFXType getType() {
+ ScriptingEffectType getType() {
return _type;
}
@@ -103,7 +113,7 @@ public:
protected:
ZVision *_engine;
uint32 _key;
- SideFXType _type;
+ ScriptingEffectType _type;
// Static member functions
public:
@@ -111,4 +121,4 @@ public:
};
} // End of namespace ZVision
-#endif // SIDEFX_H_INCLUDED
+#endif // SCRIPTING_EFFECT_H_INCLUDED
diff --git a/engines/zvision/sound/zork_raw.cpp b/engines/zvision/sound/zork_raw.cpp
index 8688039325..124235e0e0 100644
--- a/engines/zvision/sound/zork_raw.cpp
+++ b/engines/zvision/sound/zork_raw.cpp
@@ -33,7 +33,6 @@
#include "zvision/sound/zork_raw.h"
#include "zvision/zvision.h"
-#include "zvision/detection.h"
namespace ZVision {
@@ -73,10 +72,7 @@ RawChunkStream::RawChunk RawChunkStream::readNextChunk(Common::SeekableReadStrea
tmp.size = 0;
tmp.data = NULL;
- if (!stream)
- return tmp;
-
- if (stream && (stream->size() == 0 || stream->eos()))
+ if (!stream || stream->size() == 0 || stream->eos())
return tmp;
tmp.size = (stream->size() - stream->pos()) * 2;
@@ -139,7 +135,8 @@ int RawChunkStream::readBuffer(int16 *buffer, Common::SeekableReadStream *stream
return bytesRead;
}
-const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {{'0', 0x1F40, false, false, false},
+const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {
+ {'0', 0x1F40, false, false, false},
{'1', 0x1F40, true, false, false},
{'2', 0x1F40, false, false, true},
{'3', 0x1F40, true, false, true},
@@ -173,7 +170,8 @@ const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {{'0', 0x1F40,
{'x', 0xAC44, true, true, true}
};
-const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {{'4', 0x2B11, false, false, false},
+const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {
+ {'4', 0x2B11, false, false, false},
{'5', 0x2B11, true, false, false},
{'6', 0x2B11, false, false, true},
{'7', 0x2B11, true, false, true},
@@ -216,7 +214,6 @@ RawZorkStream::RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag dis
}
int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) {
-
int32 bytesRead = _streamReader.readBuffer(buffer, _stream.get(), numSamples);
if (_stream->eos())
@@ -244,19 +241,29 @@ Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stre
return new RawZorkStream(rate, stereo, disposeAfterUse, stream);
}
-Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size,
- int rate,
- bool stereo,
- DisposeAfterUse::Flag disposeAfterUse) {
- return makeRawZorkStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, stereo, DisposeAfterUse::YES);
-}
-
Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine) {
Common::File *file = new Common::File();
- assert(engine->getSearchManager()->openFile(*file, filePath));
+ Common::String actualName = filePath;
+ bool found = engine->getSearchManager()->openFile(*file, actualName);
+ bool isRaw = actualName.hasSuffix(".raw");
+
+ if ((!found && isRaw) || (found && isRaw && file->size() < 10)) {
+ if (found)
+ file->close();
+
+ // Check for an audio patch (.src)
+ actualName.setChar('s', actualName.size() - 3);
+ actualName.setChar('r', actualName.size() - 2);
+ actualName.setChar('c', actualName.size() - 1);
+
+ if (!engine->getSearchManager()->openFile(*file, actualName))
+ return NULL;
+ } else if (!found && !isRaw) {
+ return NULL;
+ }
// Get the file name
- Common::StringTokenizer tokenizer(filePath, "/\\");
+ Common::StringTokenizer tokenizer(actualName, "/\\");
Common::String fileName;
while (!tokenizer.empty()) {
fileName = tokenizer.nextToken();
diff --git a/engines/zvision/sound/zork_raw.h b/engines/zvision/sound/zork_raw.h
index 0b408d818c..892bad4d5f 100644
--- a/engines/zvision/sound/zork_raw.h
+++ b/engines/zvision/sound/zork_raw.h
@@ -123,20 +123,6 @@ public:
};
/**
- * Creates an audio stream, which plays from the given buffer.
- *
- * @param buffer Buffer to play from.
- * @param size Size of the buffer in bytes.
- * @param rate Rate of the sound data.
- * @param dispose AfterUse Whether to free the buffer after use (with free!).
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size,
- int rate,
- bool stereo,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
-
-/**
* Creates an audio stream, which plays from the given stream.
*
* @param stream Stream object to play from.
diff --git a/engines/zvision/text/string_manager.cpp b/engines/zvision/text/string_manager.cpp
index ec10b6220c..c62e18f4b0 100644
--- a/engines/zvision/text/string_manager.cpp
+++ b/engines/zvision/text/string_manager.cpp
@@ -43,21 +43,17 @@ StringManager::~StringManager() {
}
void StringManager::initialize(ZVisionGameId gameId) {
- if (gameId == GID_NEMESIS) {
- // TODO: Check this hardcoded filename against all versions of Nemesis
+ if (gameId == GID_NEMESIS)
loadStrFile("nemesis.str");
- } else if (gameId == GID_GRANDINQUISITOR) {
- // TODO: Check this hardcoded filename against all versions of Grand Inquisitor
+ else if (gameId == GID_GRANDINQUISITOR)
loadStrFile("inquis.str");
- }
}
void StringManager::loadStrFile(const Common::String &fileName) {
Common::File file;
- if (!_engine->getSearchManager()->openFile(file, fileName)) {
- warning("%s does not exist. String parsing failed", fileName.c_str());
- return;
- }
+ if (!_engine->getSearchManager()->openFile(file, fileName))
+ error("%s does not exist. String parsing failed", fileName.c_str());
+
uint lineNumber = 0;
while (!file.eos()) {
_lines[lineNumber] = readWideLine(file);
diff --git a/engines/zvision/text/string_manager.h b/engines/zvision/text/string_manager.h
index b77ad65040..2c31cf7afe 100644
--- a/engines/zvision/text/string_manager.h
+++ b/engines/zvision/text/string_manager.h
@@ -23,8 +23,7 @@
#ifndef ZVISION_STRING_MANAGER_H
#define ZVISION_STRING_MANAGER_H
-#include "zvision/detection.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
namespace Graphics {
class FontManager;
diff --git a/engines/zvision/graphics/subtitles.cpp b/engines/zvision/text/subtitles.cpp
index d2c56f0991..ffc9e2b808 100644
--- a/engines/zvision/graphics/subtitles.cpp
+++ b/engines/zvision/text/subtitles.cpp
@@ -21,13 +21,13 @@
*/
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/text/subtitles.h"
#include "zvision/file/search_manager.h"
#include "zvision/text/text.h"
namespace ZVision {
-Subtitle::Subtitle(ZVision *engine, const Common::String &subname) :
+Subtitle::Subtitle(ZVision *engine, const Common::String &subname, bool upscaleToHires) :
_engine(engine),
_areaId(-1),
_subId(-1) {
@@ -44,6 +44,8 @@ Subtitle::Subtitle(ZVision *engine, const Common::String &subname) :
int32 x1, y1, x2, y2;
sscanf(str.c_str(), "%*[^:]:%d %d %d %d", &x1, &y1, &x2, &y2);
Common::Rect rct = Common::Rect(x1, y1, x2, y2);
+ if (upscaleToHires)
+ _engine->getRenderManager()->upscaleRect(rct);
_areaId = _engine->getRenderManager()->createSubArea(rct);
} else if (str.matchString("*TextFile*", true)) {
char filename[64];
@@ -67,6 +69,11 @@ Subtitle::Subtitle(ZVision *engine, const Common::String &subname) :
int32 sb;
if (sscanf(str.c_str(), "%*[^:]:(%d,%d)=%d", &st, &en, &sb) == 3) {
if (sb <= (int32)_subs.size()) {
+ if (upscaleToHires) {
+ // Convert from 15FPS (AVI) to 29.97FPS (VOB)
+ st = st * 2997 / 1500;
+ en = en * 2997 / 1500;
+ }
_subs[sb].start = st;
_subs[sb].stop = en;
}
diff --git a/engines/zvision/graphics/subtitles.h b/engines/zvision/text/subtitles.h
index c3da6583a4..329339be55 100644
--- a/engines/zvision/graphics/subtitles.h
+++ b/engines/zvision/text/subtitles.h
@@ -31,7 +31,7 @@ class ZVision;
class Subtitle {
public:
- Subtitle(ZVision *engine, const Common::String &subname);
+ Subtitle(ZVision *engine, const Common::String &subname, bool upscaleToHires = false);
~Subtitle();
void process(int32 time);
diff --git a/engines/zvision/text/text.cpp b/engines/zvision/text/text.cpp
index 406c36e5b0..868ee4f1ae 100644
--- a/engines/zvision/text/text.cpp
+++ b/engines/zvision/text/text.cpp
@@ -33,33 +33,37 @@
#include "zvision/text/text.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "zvision/scripting/script_manager.h"
namespace ZVision {
-cTxtStyle::cTxtStyle() {
- fontname = "Arial";
- blue = 255;
- green = 255;
- red = 255;
- bold = false;
- escapement = 0;
- italic = false;
- justify = TXT_JUSTIFY_LEFT;
- newline = false;
- size = 12;
- skipcolor = false;
- strikeout = false;
- underline = false;
- statebox = 0;
- sharp = false;
+TextStyleState::TextStyleState() {
+ _fontname = "Arial";
+ _blue = 255;
+ _green = 255;
+ _red = 255;
+ _bold = false;
+#if 0
+ _newline = false;
+ _escapement = 0;
+#endif
+ _italic = false;
+ _justification = TEXT_JUSTIFY_LEFT;
+ _size = 12;
+#if 0
+ _skipcolor = false;
+#endif
+ _strikeout = false;
+ _underline = false;
+ _statebox = 0;
+ _sharp = false;
}
-txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
- Common::String buf = Common::String(strin.c_str(), ln);
+TextChange TextStyleState::parseStyle(const Common::String &str, int16 len) {
+ Common::String buf = Common::String(str.c_str(), len);
- int8 retval = TXT_RET_NOTHING;
+ uint retval = TEXT_CHANGE_NONE;
Common::StringTokenizer tokenizer(buf, " ");
Common::String token;
@@ -80,73 +84,77 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (_tmp.lastChar() == '"')
_tmp.deleteLastChar();
- fontname = _tmp;
+ _fontname = _tmp;
} else {
if (!tokenizer.empty())
- fontname = token;
+ _fontname = token;
}
- retval |= TXT_RET_FNTCHG;
+ retval |= TEXT_CHANGE_FONT_TYPE;
} else if (token.matchString("blue", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (blue != tmp) {
- blue = tmp;
- retval |= TXT_RET_FNTSTL;
+ if (_blue != tmp) {
+ _blue = tmp;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
} else if (token.matchString("red", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (red != tmp) {
- red = tmp;
- retval |= TXT_RET_FNTSTL;
+ if (_red != tmp) {
+ _red = tmp;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
} else if (token.matchString("green", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (green != tmp) {
- green = tmp;
- retval |= TXT_RET_FNTSTL;
+ if (_green != tmp) {
+ _green = tmp;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
} else if (token.matchString("newline", true)) {
+#if 0
if ((retval & TXT_RET_NEWLN) == 0)
- newline = 0;
+ _newline = 0;
- newline++;
- retval |= TXT_RET_NEWLN;
+ _newline++;
+#endif
+ retval |= TEXT_CHANGE_NEWLINE;
} else if (token.matchString("point", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
int32 tmp = atoi(token.c_str());
- if (size != tmp) {
- size = tmp;
- retval |= TXT_RET_FNTCHG;
+ if (_size != tmp) {
+ _size = tmp;
+ retval |= TEXT_CHANGE_FONT_TYPE;
}
}
} else if (token.matchString("escapement", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
+#if 0
int32 tmp = atoi(token.c_str());
- escapement = tmp;
+ _escapement = tmp;
+#endif
}
} else if (token.matchString("italic", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (italic != true) {
- italic = true;
- retval |= TXT_RET_FNTSTL;
+ if (_italic != true) {
+ _italic = true;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
- if (italic != false) {
- italic = false;
- retval |= TXT_RET_FNTSTL;
+ if (_italic != false) {
+ _italic = false;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -154,14 +162,14 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (underline != true) {
- underline = true;
- retval |= TXT_RET_FNTSTL;
+ if (_underline != true) {
+ _underline = true;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
- if (underline != false) {
- underline = false;
- retval |= TXT_RET_FNTSTL;
+ if (_underline != false) {
+ _underline = false;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -169,14 +177,14 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (strikeout != true) {
- strikeout = true;
- retval |= TXT_RET_FNTSTL;
+ if (_strikeout != true) {
+ _strikeout = true;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
- if (strikeout != false) {
- strikeout = false;
- retval |= TXT_RET_FNTSTL;
+ if (_strikeout != false) {
+ _strikeout = false;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
@@ -184,50 +192,52 @@ txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("on", true)) {
- if (bold != true) {
- bold = true;
- retval |= TXT_RET_FNTSTL;
+ if (_bold != true) {
+ _bold = true;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
} else if (token.matchString("off", true)) {
- if (bold != false) {
- bold = false;
- retval |= TXT_RET_FNTSTL;
+ if (_bold != false) {
+ _bold = false;
+ retval |= TEXT_CHANGE_FONT_STYLE;
}
}
}
} else if (token.matchString("skipcolor", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
+#if 0
if (token.matchString("on", true)) {
- skipcolor = true;
+ _skipcolor = true;
} else if (token.matchString("off", true)) {
- skipcolor = false;
+ _skipcolor = false;
}
+#endif
}
} else if (token.matchString("image", true)) {
// Not used
} else if (token.matchString("statebox", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
- statebox = atoi(token.c_str());
- retval |= TXT_RET_HASSTBOX;
+ _statebox = atoi(token.c_str());
+ retval |= TEXT_CHANGE_HAS_STATE_BOX;
}
} else if (token.matchString("justify", true)) {
if (!tokenizer.empty()) {
token = tokenizer.nextToken();
if (token.matchString("center", true))
- justify = TXT_JUSTIFY_CENTER;
+ _justification = TEXT_JUSTIFY_CENTER;
else if (token.matchString("left", true))
- justify = TXT_JUSTIFY_LEFT;
+ _justification = TEXT_JUSTIFY_LEFT;
else if (token.matchString("right", true))
- justify = TXT_JUSTIFY_RIGHT;
+ _justification = TEXT_JUSTIFY_RIGHT;
}
}
}
- return (txtReturn)retval;
+ return (TextChange)retval;
}
-void cTxtStyle::readAllStyle(const Common::String &txt) {
+void TextStyleState::readAllStyles(const Common::String &txt) {
int16 startTextPosition = -1;
int16 endTextPosition = -1;
@@ -236,251 +246,273 @@ void cTxtStyle::readAllStyle(const Common::String &txt) {
startTextPosition = i;
else if (txt[i] == '>') {
endTextPosition = i;
- if (startTextPosition != -1)
- if ((endTextPosition - startTextPosition - 1) > 0)
+ if (startTextPosition != -1) {
+ if ((endTextPosition - startTextPosition - 1) > 0) {
parseStyle(Common::String(txt.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1);
+ }
+ }
}
}
}
-void cTxtStyle::setFontStyle(StyledTTFont &font) {
+void TextStyleState::updateFontWithTextState(StyledTTFont &font) {
uint tempStyle = 0;
- if (bold)
- tempStyle |= StyledTTFont::STTF_BOLD;
-
- if (italic)
- tempStyle |= StyledTTFont::STTF_ITALIC;
-
- if (underline)
- tempStyle |= StyledTTFont::STTF_UNDERLINE;
-
- if (strikeout)
- tempStyle |= StyledTTFont::STTF_STRIKEOUT;
-
- if (sharp)
- tempStyle |= StyledTTFont::STTF_SHARP;
+ if (_bold) {
+ tempStyle |= StyledTTFont::TTF_STYLE_BOLD;
+ }
+ if (_italic) {
+ tempStyle |= StyledTTFont::TTF_STYLE_ITALIC;
+ }
+ if (_underline) {
+ tempStyle |= StyledTTFont::TTF_STYLE_UNDERLINE;
+ }
+ if (_strikeout) {
+ tempStyle |= StyledTTFont::TTF_STYLE_STRIKETHROUGH;
+ }
+ if (_sharp) {
+ tempStyle |= StyledTTFont::TTF_STYLE_SHARP;
+ }
- font.setStyle(tempStyle);
+ font.loadFont(_fontname, _size, tempStyle);
}
-void cTxtStyle::setFont(StyledTTFont &font) {
- uint tempStyle = 0;
-
- if (bold)
- tempStyle |= StyledTTFont::STTF_BOLD;
+void TextRenderer::drawTextWithJustification(const Common::String &text, StyledTTFont &font, uint32 color, Graphics::Surface &dest, int lineY, TextJustification justify) {
+ if (justify == TEXT_JUSTIFY_LEFT)
+ font.drawString(&dest, text, 0, lineY, dest.w, color, Graphics::kTextAlignLeft);
+ else if (justify == TEXT_JUSTIFY_CENTER)
+ font.drawString(&dest, text, 0, lineY, dest.w, color, Graphics::kTextAlignCenter);
+ else if (justify == TEXT_JUSTIFY_RIGHT)
+ font.drawString(&dest, text, 0, lineY, dest.w, color, Graphics::kTextAlignRight);
+}
- if (italic)
- tempStyle |= StyledTTFont::STTF_ITALIC;
+int32 TextRenderer::drawText(const Common::String &text, TextStyleState &state, Graphics::Surface &dest) {
+ StyledTTFont font(_engine);
+ state.updateFontWithTextState(font);
- if (underline)
- tempStyle |= StyledTTFont::STTF_UNDERLINE;
+ uint32 color = _engine->_resourcePixelFormat.RGBToColor(state._red, state._green, state._blue);
+ drawTextWithJustification(text, font, color, dest, 0, state._justification);
- if (strikeout)
- tempStyle |= StyledTTFont::STTF_STRIKEOUT;
+ return font.getStringWidth(text);
+}
- if (sharp)
- tempStyle |= StyledTTFont::STTF_SHARP;
+struct TextSurface {
+ TextSurface(Graphics::Surface *surface, Common::Point surfaceOffset, uint lineNumber)
+ : _surface(surface),
+ _surfaceOffset(surfaceOffset),
+ _lineNumber(lineNumber) {
+ }
- font.loadFont(fontname, size, tempStyle);
-}
+ Graphics::Surface *_surface;
+ Common::Point _surfaceOffset;
+ uint _lineNumber;
+};
-Graphics::Surface *TextRenderer::render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style) {
- style.setFontStyle(fnt);
- uint32 clr = _engine->_pixelFormat.RGBToColor(style.red, style.green, style.blue);
- return fnt.renderSolidText(txt, clr);
-}
+void TextRenderer::drawTextWithWordWrapping(const Common::String &text, Graphics::Surface &dest) {
+ Common::Array<TextSurface> textSurfaces;
+ Common::Array<uint> lineWidths;
+ Common::Array<TextJustification> lineJustifications;
-void TextRenderer::drawTxtWithJustify(const Common::String &txt, StyledTTFont &fnt, uint32 color, Graphics::Surface &dst, int lineY, txtJustify justify) {
- if (justify == TXT_JUSTIFY_LEFT)
- fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignLeft);
- else if (justify == TXT_JUSTIFY_CENTER)
- fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignCenter);
- else if (justify == TXT_JUSTIFY_RIGHT)
- fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignRight);
-}
+ // Create the initial text state
+ TextStyleState currentState;
-int32 TextRenderer::drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Graphics::Surface &dst) {
+ // Create an empty font and bind it to the state
StyledTTFont font(_engine);
- fontStyle.setFont(font);
+ currentState.updateFontWithTextState(font);
- dst.fillRect(Common::Rect(dst.w, dst.h), 0);
+ Common::String currentSentence; // Not a true 'grammatical' sentence. Rather, it's just a collection of words
+ Common::String currentWord;
+ int sentenceWidth = 0;
+ int wordWidth = 0;
+ int lineWidth = 0;
+ int lineHeight = font.getFontHeight();
- uint32 clr = _engine->_pixelFormat.RGBToColor(fontStyle.red, fontStyle.green, fontStyle.blue);
+ uint currentLineNumber = 0u;
- int16 w;
+ uint numSpaces = 0u;
+ int spaceWidth = 0;
- w = font.getStringWidth(txt);
+ // The pixel offset to the currentSentence
+ Common::Point sentencePixelOffset;
- drawTxtWithJustify(txt, font, clr, dst, 0, fontStyle.justify);
+ uint i = 0u;
+ uint stringlen = text.size();
- return w;
-}
+ while (i < stringlen) {
+ if (text[i] == '<') {
+ // Flush the currentWord to the currentSentence
+ currentSentence += currentWord;
+ sentenceWidth += wordWidth;
+
+ // Reset the word variables
+ currentWord.clear();
+ wordWidth = 0;
+
+ // Parse the style tag
+ uint startTextPosition = i;
+ while (i < stringlen && text[i] != '>') {
+ ++i;
+ }
+ uint endTextPosition = i;
-void TextRenderer::drawTxtInOneLine(const Common::String &text, Graphics::Surface &dst) {
- const int16 TXT_CFG_TEXTURES_LINES = 256; // For now I don't want remake it
- const int TXT_CFG_TEXTURES_PER_LINE = 6;
- cTxtStyle style, style2;
- int16 startTextPosition = -1;
- int16 endTextPosition = -1;
- int16 i = 0;
- int16 dx = 0, dy = 0;
- int16 textPixelWidth;
- int16 textPosition = 0;
- Common::String buf;
- Common::String buf2;
-
- Graphics::Surface *TxtSurfaces[TXT_CFG_TEXTURES_LINES][TXT_CFG_TEXTURES_PER_LINE];
- int16 currentline = 0, currentlineitm = 0;
-
- int TxtJustify[TXT_CFG_TEXTURES_LINES];
- int TxtPoint[TXT_CFG_TEXTURES_LINES];
-
- for (int16 k = 0; k < TXT_CFG_TEXTURES_LINES; k++) {
- TxtPoint[k] = 0;
- for (int j = 0; j < TXT_CFG_TEXTURES_PER_LINE; j++)
- TxtSurfaces[k][j] = NULL;
- }
+ uint32 textColor = currentState.getTextColor(_engine);
- int16 stringlen = text.size();
+ uint stateChanges = 0u;
+ if ((endTextPosition - startTextPosition - 1) > 0) {
+ stateChanges = currentState.parseStyle(Common::String(text.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1);
+ }
- StyledTTFont font(_engine);
+ if (stateChanges & (TEXT_CHANGE_FONT_TYPE | TEXT_CHANGE_FONT_STYLE)) {
+ // Use the last state to render out the current sentence
+ // Styles apply to the text 'after' them
+ if (!currentSentence.empty()) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, textColor), sentencePixelOffset, currentLineNumber));
- style.setFont(font);
+ lineWidth += sentenceWidth;
+ sentencePixelOffset.x += sentenceWidth;
- int16 prevbufspace = 0, prevtxtspace = 0;
+ // Reset the sentence variables
+ currentSentence.clear();
+ sentenceWidth = 0;
+ }
- while (i < stringlen) {
- TxtJustify[currentline] = style.justify;
- if (text[i] == '<') {
- int16 ret = 0;
+ // Update the current state with the style information
+ currentState.updateFontWithTextState(font);
- startTextPosition = i;
- while (i < stringlen && text[i] != '>')
- i++;
- endTextPosition = i;
- if (startTextPosition != -1)
- if ((endTextPosition - startTextPosition - 1) > 0) {
- style2 = style;
- ret = style.parseStyle(Common::String(text.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1);
+ lineHeight = MAX(lineHeight, font.getFontHeight());
+ spaceWidth = font.getCharWidth(' ');
+ }
+ if (stateChanges & TEXT_CHANGE_NEWLINE) {
+ // If the current sentence has content, render it out
+ if (!currentSentence.empty()) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, textColor), sentencePixelOffset, currentLineNumber));
}
+
+ // Set line width
+ lineWidths.push_back(lineWidth + sentenceWidth - (numSpaces * spaceWidth));
+
+ currentSentence.clear();
+ sentenceWidth = 0;
+
+ // Update the offsets
+ sentencePixelOffset.x = 0u;
+ sentencePixelOffset.y += lineHeight;
+
+ // Reset the line variables
+ lineHeight = font.getFontHeight();
+ lineWidth = 0;
+ ++currentLineNumber;
+ lineJustifications.push_back(currentState._justification);
+ }
+ if (stateChanges & TEXT_CHANGE_HAS_STATE_BOX) {
+ Common::String temp = Common::String::format("%d", _engine->getScriptManager()->getStateValue(currentState._statebox));
+ wordWidth += font.getStringWidth(temp);
- if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) {
- if (buf.size() > 0) {
- textPixelWidth = font.getStringWidth(buf);
-
- TxtSurfaces[currentline][currentlineitm] = render(font, buf, style2);
- TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]);
+ // If the word causes the line to overflow, render the sentence and start a new line
+ if (lineWidth + sentenceWidth + wordWidth > dest.w) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, textColor), sentencePixelOffset, currentLineNumber));
- currentlineitm++;
+ // Set line width
+ lineWidths.push_back(lineWidth + sentenceWidth - (numSpaces * spaceWidth));
- buf.clear();
- prevbufspace = 0;
- textPosition = 0;
- dx += textPixelWidth;
+ currentSentence.clear();
+ sentenceWidth = 0;
- }
- if (ret & TXT_RET_FNTCHG) {
- style.setFont(font);
- }
- if (ret & TXT_RET_FNTSTL)
- style.setFontStyle(font);
+ // Update the offsets
+ sentencePixelOffset.x = 0u;
+ sentencePixelOffset.y += lineHeight;
- if (ret & TXT_RET_NEWLN) {
- currentline++;
- currentlineitm = 0;
- dx = 0;
+ // Reset the line variables
+ lineHeight = font.getFontHeight();
+ lineWidth = 0;
+ ++currentLineNumber;
+ lineJustifications.push_back(currentState._justification);
}
}
-
- if (ret & TXT_RET_HASSTBOX) {
- Common::String buf3;
- buf3 = Common::String::format("%d", _engine->getScriptManager()->getStateValue(style.statebox));
- buf += buf3;
- textPosition += buf3.size();
- }
-
} else {
-
- buf += text[i];
- textPosition++;
+ currentWord += text[i];
+ wordWidth += font.getCharWidth(text[i]);
if (text[i] == ' ') {
- prevbufspace = textPosition - 1;
- prevtxtspace = i;
- }
+ // When we hit the first space, flush the current word to the sentence
+ if (!currentWord.empty()) {
+ currentSentence += currentWord;
+ sentenceWidth += wordWidth;
- if (font.isLoaded()) {
- textPixelWidth = font.getStringWidth(buf);
- if (textPixelWidth + dx > dst.w) {
- if (prevbufspace == 0) {
- prevtxtspace = i;
- prevbufspace = textPosition - 1;
- }
- buf2 = Common::String(buf.c_str(), prevbufspace + 1);
+ currentWord.clear();
+ wordWidth = 0;
+ }
- if (buf2.size() > 0) {
- TxtSurfaces[currentline][currentlineitm] = render(font, buf2, style);
- TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]);
+ // We track the number of spaces so we can disregard their width in lineWidth calculations
+ ++numSpaces;
+ } else {
+ // If the word causes the line to overflow, render the sentence and start a new line
+ if (lineWidth + sentenceWidth + wordWidth > dest.w) {
+ // Only render out content
+ if (!currentSentence.empty()) {
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, currentState.getTextColor(_engine)), sentencePixelOffset, currentLineNumber));
}
- buf.clear();
- i = prevtxtspace;
- prevbufspace = 0;
- textPosition = 0;
- currentline++;
- currentlineitm = 0;
- dx = 0;
+ // Set line width
+ lineWidths.push_back(lineWidth + sentenceWidth - (numSpaces * spaceWidth));
+
+ currentSentence.clear();
+ sentenceWidth = 0;
+
+ // Update the offsets
+ sentencePixelOffset.x = 0u;
+ sentencePixelOffset.y += lineHeight;
+
+ // Reset the line variables
+ lineHeight = font.getFontHeight();
+ lineWidth = 0;
+ ++currentLineNumber;
+ lineJustifications.push_back(currentState._justification);
}
+
+ numSpaces = 0u;
}
}
+
i++;
}
- if (buf.size() > 0) {
- TxtSurfaces[currentline][currentlineitm] = render(font, buf, style);
- TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]);
+ // Render out any remaining words/sentences
+ if (!currentWord.empty() || !currentSentence.empty()) {
+ currentSentence += currentWord;
+ sentenceWidth += wordWidth;
+
+ textSurfaces.push_back(TextSurface(font.renderSolidText(currentSentence, currentState.getTextColor(_engine)), sentencePixelOffset, currentLineNumber));
}
- dy = 0;
- for (i = 0; i <= currentline; i++) {
- int16 j = 0;
- int16 width = 0;
- while (TxtSurfaces[i][j] != NULL) {
- width += TxtSurfaces[i][j]->w;
- j++;
- }
- dx = 0;
- for (int32 jj = 0; jj < j; jj++) {
- if (TxtJustify[i] == TXT_JUSTIFY_LEFT)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
-
- else if (TxtJustify[i] == TXT_JUSTIFY_CENTER)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, ((dst.w - width) / 2) + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ lineWidths.push_back(lineWidth + sentenceWidth);
+ lineJustifications.push_back(currentState._justification);
- else if (TxtJustify[i] == TXT_JUSTIFY_RIGHT)
- _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, dst.w - width + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0);
+ for (Common::Array<TextSurface>::iterator iter = textSurfaces.begin(); iter != textSurfaces.end(); ++iter) {
+ Common::Rect empty;
- dx += TxtSurfaces[i][jj]->w;
+ if (lineJustifications[iter->_lineNumber] == TEXT_JUSTIFY_LEFT) {
+ _engine->getRenderManager()->blitSurfaceToSurface(*iter->_surface, empty, dest, iter->_surfaceOffset.x, iter->_surfaceOffset.y, 0);
+ } else if (lineJustifications[iter->_lineNumber] == TEXT_JUSTIFY_CENTER) {
+ _engine->getRenderManager()->blitSurfaceToSurface(*iter->_surface, empty, dest, ((dest.w - lineWidths[iter->_lineNumber]) / 2) + iter->_surfaceOffset.x, iter->_surfaceOffset.y, 0);
+ } else if (lineJustifications[iter->_lineNumber] == TEXT_JUSTIFY_RIGHT) {
+ _engine->getRenderManager()->blitSurfaceToSurface(*iter->_surface, empty, dest, dest.w - lineWidths[iter->_lineNumber] + iter->_surfaceOffset.x, iter->_surfaceOffset.y, 0);
}
- dy += TxtPoint[i];
+ // Release memory
+ iter->_surface->free();
+ delete iter->_surface;
}
-
- for (i = 0; i < TXT_CFG_TEXTURES_LINES; i++)
- for (int32 j = 0; j < TXT_CFG_TEXTURES_PER_LINE; j++)
- if (TxtSurfaces[i][j] != NULL) {
- TxtSurfaces[i][j]->free();
- delete TxtSurfaces[i][j];
- }
}
Common::String readWideLine(Common::SeekableReadStream &stream) {
Common::String asciiString;
- while (!stream.eos()) {
+ while (true) {
uint32 value = stream.readUint16LE();
+ if (stream.eos())
+ break;
// Check for CRLF
if (value == 0x0A0D) {
// Read in the extra NULL char
@@ -495,10 +527,12 @@ Common::String readWideLine(Common::SeekableReadStream &stream) {
} else if (value >= 0x80 && value < 0x800) {
asciiString += (char)(0xC0 | ((value >> 6) & 0x1F));
asciiString += (char)(0x80 | (value & 0x3F));
- } else if (value >= 0x800 && value < 0x10000) {
+ } else if (value >= 0x800 && value < 0x10000 && value != 0xCCCC) {
asciiString += (char)(0xE0 | ((value >> 12) & 0xF));
asciiString += (char)(0x80 | ((value >> 6) & 0x3F));
asciiString += (char)(0x80 | (value & 0x3F));
+ } else if (value == 0xCCCC) {
+ // Ignore, this character is used as newline sometimes
} else if (value >= 0x10000 && value < 0x200000) {
asciiString += (char)(0xF0);
asciiString += (char)(0x80 | ((value >> 12) & 0x3F));
diff --git a/engines/zvision/text/text.h b/engines/zvision/text/text.h
index ecec3ccde6..5dd872a440 100644
--- a/engines/zvision/text/text.h
+++ b/engines/zvision/text/text.h
@@ -24,63 +24,60 @@
#ifndef ZVISION_TEXT_H
#define ZVISION_TEXT_H
-#include "zvision/detection.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "zvision/zvision.h"
namespace ZVision {
class ZVision;
-enum txtJustify {
- TXT_JUSTIFY_CENTER = 0,
- TXT_JUSTIFY_LEFT = 1,
- TXT_JUSTIFY_RIGHT = 2
+enum TextJustification {
+ TEXT_JUSTIFY_CENTER = 0,
+ TEXT_JUSTIFY_LEFT = 1,
+ TEXT_JUSTIFY_RIGHT = 2
};
-enum txtReturn {
- TXT_RET_NOTHING = 0x0,
- TXT_RET_FNTCHG = 0x1,
- TXT_RET_FNTSTL = 0x2,
- TXT_RET_NEWLN = 0x4,
- TXT_RET_HASSTBOX = 0x8
+enum TextChange {
+ TEXT_CHANGE_NONE = 0x0,
+ TEXT_CHANGE_FONT_TYPE = 0x1,
+ TEXT_CHANGE_FONT_STYLE = 0x2,
+ TEXT_CHANGE_NEWLINE = 0x4,
+ TEXT_CHANGE_HAS_STATE_BOX = 0x8
};
-class cTxtStyle {
+class TextStyleState {
public:
- cTxtStyle();
- txtReturn parseStyle(const Common::String &strin, int16 len);
- void readAllStyle(const Common::String &txt);
- void setFontStyle(StyledTTFont &font);
- void setFont(StyledTTFont &font);
+ TextStyleState();
+ TextChange parseStyle(const Common::String &str, int16 len);
+ void readAllStyles(const Common::String &txt);
+ void updateFontWithTextState(StyledTTFont &font);
+
+ uint32 getTextColor(ZVision *engine) {
+ return engine->_resourcePixelFormat.RGBToColor(_red, _green, _blue);
+ }
public:
- Common::String fontname;
- txtJustify justify; // 0 - center, 1-left, 2-right
- int16 size;
- uint8 red; // 0-255
- uint8 green; // 0-255
- uint8 blue; // 0-255
- int8 newline;
- int8 escapement;
- bool italic;
- bool bold;
- bool underline;
- bool strikeout;
- bool skipcolor;
- int32 statebox;
- bool sharp;
- // char image ??
+ Common::String _fontname;
+ TextJustification _justification;
+ int16 _size;
+ uint8 _red; // 0-255
+ uint8 _green; // 0-255
+ uint8 _blue; // 0-255
+ bool _italic;
+ bool _bold;
+ bool _underline;
+ bool _strikeout;
+ int32 _statebox;
+ bool _sharp;
};
class TextRenderer {
public:
TextRenderer(ZVision *engine): _engine(engine) {};
- void drawTxtWithJustify(const Common::String &txt, StyledTTFont &fnt, uint32 color, Graphics::Surface &dst, int lineY, txtJustify justify);
- int32 drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Graphics::Surface &dst);
- Graphics::Surface *render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style);
- void drawTxtInOneLine(const Common::String &txt, Graphics::Surface &dst);
+ void drawTextWithJustification(const Common::String &text, StyledTTFont &font, uint32 color, Graphics::Surface &dest, int lineY, TextJustification jusification);
+ int32 drawText(const Common::String &text, TextStyleState &state, Graphics::Surface &dest);
+ void drawTextWithWordWrapping(const Common::String &text, Graphics::Surface &dest);
private:
ZVision *_engine;
diff --git a/engines/zvision/text/truetype_font.cpp b/engines/zvision/text/truetype_font.cpp
new file mode 100644
index 0000000000..acb053ea8d
--- /dev/null
+++ b/engines/zvision/text/truetype_font.cpp
@@ -0,0 +1,265 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/system.h"
+#include "common/unzip.h"
+#include "common/ustr.h"
+#include "graphics/font.h"
+#include "graphics/fonts/ttf.h"
+#include "graphics/surface.h"
+
+#include "zvision/zvision.h"
+#include "zvision/graphics/render_manager.h"
+#include "zvision/text/truetype_font.h"
+
+namespace ZVision {
+
+const FontStyle systemFonts[] = {
+ { "*times new roman*", "times", "FreeSerif", "Italic", "LiberationSerif" },
+ { "*times*", "times", "FreeSerif", "Italic", "LiberationSerif" },
+ { "*century schoolbook*", "censcbk", "FreeSerif", "Italic", "LiberationSerif" },
+ { "*garamond*", "gara", "FreeSerif", "Italic", "LiberationSerif" },
+ { "*courier new*", "cour", "FreeMono", "Oblique", "LiberationMono" },
+ { "*courier*", "cour", "FreeMono", "Oblique", "LiberationMono" },
+ { "*ZorkDeath*", "cour", "FreeMono", "Oblique", "LiberationMono" },
+ { "*arial*", "arial", "FreeSans", "Oblique", "LiberationSans" },
+ { "*ZorkNormal*", "arial", "FreeSans", "Oblique", "LiberationSans" }
+};
+
+const FontStyle getSystemFont(int fontIndex) {
+ return systemFonts[fontIndex];
+}
+
+StyledTTFont::StyledTTFont(ZVision *engine) {
+ _engine = engine;
+ _style = 0;
+ _font = nullptr;
+ _lineHeight = 0;
+}
+
+StyledTTFont::~StyledTTFont() {
+ delete _font;
+}
+
+bool StyledTTFont::loadFont(const Common::String &fontName, int32 point, uint style) {
+ // Don't re-load the font if we've already loaded it
+ // We have to check for empty so we can default to Arial
+ if (!fontName.empty() && _fontName.equalsIgnoreCase(fontName) && _lineHeight == point && _style == style) {
+ return true;
+ }
+
+ _style = style;
+
+ Common::String newFontName;
+ Common::String freeFontName;
+ Common::String liberationFontName;
+
+ for (int i = 0; i < FONT_COUNT; i++) {
+ FontStyle curFont = getSystemFont(i);
+ if (fontName.matchString(curFont.zorkFont, true)) {
+ newFontName = curFont.fontBase;
+ freeFontName = curFont.freeFontBase;
+ liberationFontName = curFont.liberationFontBase;
+
+ if ((_style & TTF_STYLE_BOLD) && (_style & TTF_STYLE_ITALIC)) {
+ newFontName += "bi";
+ freeFontName += "Bold";
+ freeFontName += curFont.freeFontItalicName;
+ liberationFontName += "-BoldItalic";
+ } else if (_style & TTF_STYLE_BOLD) {
+ newFontName += "bd";
+ freeFontName += "Bold";
+ liberationFontName += "-Bold";
+ } else if (_style & TTF_STYLE_ITALIC) {
+ newFontName += "i";
+ freeFontName += curFont.freeFontItalicName;
+ liberationFontName += "-Italic";
+ } else {
+ liberationFontName += "-Regular";
+ }
+
+ newFontName += ".ttf";
+ freeFontName += ".ttf";
+ liberationFontName += ".ttf";
+ break;
+ }
+ }
+
+ if (newFontName.empty()) {
+ debug("Could not identify font: %s. Reverting to Arial", fontName.c_str());
+ newFontName = "arial.ttf";
+ freeFontName = "FreeSans.ttf";
+ liberationFontName = "LiberationSans-Regular.ttf";
+ }
+
+ bool sharp = (_style & TTF_STYLE_SHARP) == TTF_STYLE_SHARP;
+
+ Common::File file;
+ if (!file.open(newFontName) && !_engine->getSearchManager()->openFile(file, newFontName) &&
+ !file.open(liberationFontName) && !_engine->getSearchManager()->openFile(file, liberationFontName) &&
+ !file.open(freeFontName) && !_engine->getSearchManager()->openFile(file, freeFontName))
+ error("Unable to open font file %s (Liberation Font alternative: %s, FreeFont alternative: %s)", newFontName.c_str(), liberationFontName.c_str(), freeFontName.c_str());
+
+ Graphics::Font *newFont = Graphics::loadTTFFont(file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display
+ if (newFont == nullptr) {
+ return false;
+ }
+
+ delete _font;
+ _font = newFont;
+
+ _fontName = fontName;
+ _lineHeight = point;
+
+ return true;
+}
+
+int StyledTTFont::getFontHeight() {
+ if (_font)
+ return _font->getFontHeight();
+
+ return 0;
+}
+
+int StyledTTFont::getMaxCharWidth() {
+ if (_font)
+ return _font->getMaxCharWidth();
+
+ return 0;
+}
+
+int StyledTTFont::getCharWidth(byte chr) {
+ if (_font)
+ return _font->getCharWidth(chr);
+
+ return 0;
+}
+
+int StyledTTFont::getKerningOffset(byte left, byte right) {
+ if (_font)
+ return _font->getKerningOffset(left, right);
+
+ return 0;
+}
+
+Common::U32String StyledTTFont::convertUtf8ToUtf32(const Common::String &str) {
+ // The String class, and therefore the Font class as well, assume one
+ // character is one byte, but in this case it's actually an UTF-8
+ // string with up to 4 bytes per character. To work around this,
+ // convert it to an U32String before drawing it, because our Font class
+ // can handle that.
+ Common::U32String u32str;
+ uint i = 0;
+ while (i < str.size()) {
+ uint32 chr = 0;
+ if ((str[i] & 0xF8) == 0xF0) {
+ chr |= (str[i++] & 0x07) << 18;
+ chr |= (str[i++] & 0x3F) << 12;
+ chr |= (str[i++] & 0x3F) << 6;
+ chr |= (str[i++] & 0x3F);
+ } else if ((str[i] & 0xF0) == 0xE0) {
+ chr |= (str[i++] & 0x0F) << 12;
+ chr |= (str[i++] & 0x3F) << 6;
+ chr |= (str[i++] & 0x3F);
+ } else if ((str[i] & 0xE0) == 0xC0) {
+ chr |= (str[i++] & 0x1F) << 6;
+ chr |= (str[i++] & 0x3F);
+ } else {
+ chr = (str[i++] & 0x7F);
+ }
+ u32str += chr;
+ }
+ return u32str;
+}
+
+void StyledTTFont::drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color) {
+ if (_font) {
+ _font->drawChar(dst, chr, x, y, color);
+ if (_style & TTF_STYLE_UNDERLINE) {
+ int16 pos = (int16)floor(_font->getFontHeight() * 0.87);
+ int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
+ dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color);
+ }
+ if (_style & TTF_STYLE_STRIKETHROUGH) {
+ int16 pos = (int16)floor(_font->getFontHeight() * 0.60);
+ int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
+ dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color);
+ }
+ }
+}
+
+void StyledTTFont::drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, Graphics::TextAlign align) {
+ if (_font) {
+ Common::U32String u32str = convertUtf8ToUtf32(str);
+ _font->drawString(dst, u32str, x, y, w, color, align);
+ if (_style & TTF_STYLE_UNDERLINE) {
+ int16 pos = (int16)floor(_font->getFontHeight() * 0.87);
+ int16 wd = MIN(_font->getStringWidth(u32str), w);
+ int16 stX = x;
+ if (align == Graphics::kTextAlignCenter)
+ stX += (w - wd) / 2;
+ else if (align == Graphics::kTextAlignRight)
+ stX += (w - wd);
+
+ int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
+
+ dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color);
+ }
+ if (_style & TTF_STYLE_STRIKETHROUGH) {
+ int16 pos = (int16)floor(_font->getFontHeight() * 0.60);
+ int16 wd = MIN(_font->getStringWidth(u32str), w);
+ int16 stX = x;
+ if (align == Graphics::kTextAlignCenter)
+ stX += (w - wd) / 2;
+ else if (align == Graphics::kTextAlignRight)
+ stX += (w - wd);
+
+ int thk = MAX((int)(_font->getFontHeight() * 0.05), 1);
+
+ dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color);
+ }
+ }
+}
+
+int StyledTTFont::getStringWidth(const Common::String &str) {
+ if (_font)
+ return _font->getStringWidth(str);
+ return 0;
+}
+
+Graphics::Surface *StyledTTFont::renderSolidText(const Common::String &str, uint32 color) {
+ Graphics::Surface *tmp = new Graphics::Surface;
+ if (_font) {
+ int16 w = _font->getStringWidth(str);
+ if (w && w < 1024) {
+ tmp->create(w, _font->getFontHeight(), _engine->_resourcePixelFormat);
+ drawString(tmp, str, 0, 0, w, color);
+ }
+ }
+ return tmp;
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/graphics/truetype_font.h b/engines/zvision/text/truetype_font.h
index b5fac4af8a..6abe05cda6 100644
--- a/engines/zvision/graphics/truetype_font.h
+++ b/engines/zvision/text/truetype_font.h
@@ -34,6 +34,16 @@ struct Surface;
namespace ZVision {
+struct FontStyle {
+ const char *zorkFont;
+ const char *fontBase;
+ const char *freeFontBase;
+ const char *freeFontItalicName;
+ const char *liberationFontBase;
+};
+
+#define FONT_COUNT 9
+
class ZVision;
// Styled TTF
@@ -43,11 +53,11 @@ public:
~StyledTTFont();
enum {
- STTF_BOLD = 1,
- STTF_ITALIC = 2,
- STTF_UNDERLINE = 4,
- STTF_STRIKEOUT = 8,
- STTF_SHARP = 16
+ TTF_STYLE_BOLD = 0x01,
+ TTF_STYLE_ITALIC = 0x02,
+ TTF_STYLE_UNDERLINE = 0x04,
+ TTF_STYLE_STRIKETHROUGH = 0x08,
+ TTF_STYLE_SHARP = 0x10
};
private:
@@ -55,18 +65,18 @@ private:
Graphics::Font *_font;
int _lineHeight;
uint _style;
- Common::String _fntName;
+ Common::String _fontName;
public:
- bool loadFont(const Common::String &fontName, int32 point);
bool loadFont(const Common::String &fontName, int32 point, uint style);
- void setStyle(uint newStyle);
int getFontHeight();
int getMaxCharWidth();
int getCharWidth(byte chr);
int getKerningOffset(byte left, byte right);
+ Common::U32String convertUtf8ToUtf32(const Common::String &str);
+
void drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color);
void drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, Graphics::TextAlign align = Graphics::kTextAlignLeft);
diff --git a/engines/zvision/video/rlf_decoder.cpp b/engines/zvision/video/rlf_decoder.cpp
index bdb5dc18bc..3bbf22edff 100644
--- a/engines/zvision/video/rlf_decoder.cpp
+++ b/engines/zvision/video/rlf_decoder.cpp
@@ -30,8 +30,6 @@
#include "common/debug.h"
#include "common/endian.h"
-#include "graphics/colormasks.h"
-
namespace ZVision {
RLFDecoder::~RLFDecoder() {
@@ -41,9 +39,13 @@ RLFDecoder::~RLFDecoder() {
bool RLFDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
- addTrack(new RLFVideoTrack(stream));
-
- return true;
+ // Check if the stream is valid
+ if (stream && !stream->err() && stream->readUint32BE() == MKTAG('F', 'E', 'L', 'R')) {
+ addTrack(new RLFVideoTrack(stream));
+ return true;
+ } else {
+ return false;
+ }
}
RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
@@ -54,7 +56,7 @@ RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
_height(0),
_frameTime(0),
_frames(0),
- _curFrame(0),
+ _displayedFrame(-1),
_frameBufferByteSize(0) {
if (!readHeader()) {
@@ -62,7 +64,7 @@ RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
return;
}
- _currentFrameBuffer.create(_width, _height, Graphics::createPixelFormat<565>());
+ _currentFrameBuffer.create(_width, _height, getPixelFormat());
_frameBufferByteSize = _width * _height * sizeof(uint16);
_frames = new Frame[_frameCount];
@@ -83,10 +85,6 @@ RLFDecoder::RLFVideoTrack::~RLFVideoTrack() {
}
bool RLFDecoder::RLFVideoTrack::readHeader() {
- if (_readStream->readUint32BE() != MKTAG('F', 'E', 'L', 'R')) {
- return false;
- }
-
// Read the header
_readStream->readUint32LE(); // Size1
_readStream->readUint32LE(); // Unknown1
@@ -161,22 +159,17 @@ RLFDecoder::RLFVideoTrack::Frame RLFDecoder::RLFVideoTrack::readNextFrame() {
bool RLFDecoder::RLFVideoTrack::seek(const Audio::Timestamp &time) {
uint frame = getFrameAtTime(time);
- assert(frame < (int)_frameCount);
+ assert(frame < _frameCount);
- if ((uint)_curFrame == frame)
+ if ((uint)_displayedFrame == frame)
return true;
- if (frame < 0) {
- _curFrame = 0;
- return false;
- }
-
- int closestFrame = _curFrame;
- int distance = (int)frame - _curFrame;
+ int closestFrame = _displayedFrame;
+ int distance = (int)frame - closestFrame;
if (distance < 0) {
for (uint i = 0; i < _completeFrames.size(); ++i) {
- if ((int)_completeFrames[i] > frame)
+ if (_completeFrames[i] > frame)
break;
closestFrame = _completeFrames[i];
}
@@ -196,19 +189,18 @@ bool RLFDecoder::RLFVideoTrack::seek(const Audio::Timestamp &time) {
applyFrameToCurrent(i);
}
- _curFrame = frame;
+ _displayedFrame = frame - 1;
return true;
}
const Graphics::Surface *RLFDecoder::RLFVideoTrack::decodeNextFrame() {
- // When an animation ends, rewind
- if (_curFrame == (int)_frameCount)
- seek(Audio::Timestamp(0, getFrameRate().toInt()));
-
- applyFrameToCurrent(_curFrame);
+ if (_displayedFrame >= (int)_frameCount)
+ return NULL;
+
+ _displayedFrame++;
+ applyFrameToCurrent(_displayedFrame);
- _curFrame++;
return &_currentFrameBuffer;
}
@@ -242,10 +234,7 @@ void RLFDecoder::RLFVideoTrack::decodeMaskedRunLengthEncoding(int8 *source, int8
return;
}
- byte r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(READ_LE_UINT16(source + sourceOffset), r, g, b);
- uint16 destColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
- WRITE_UINT16(dest + destOffset, destColor);
+ WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset));
sourceOffset += 2;
destOffset += 2;
@@ -289,10 +278,7 @@ void RLFDecoder::RLFVideoTrack::decodeSimpleRunLengthEncoding(int8 *source, int8
return;
}
- byte r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(READ_LE_UINT16(source + sourceOffset), r, g, b);
- uint16 destColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
- WRITE_UINT16(dest + destOffset, destColor);
+ WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset));
sourceOffset += 2;
destOffset += 2;
@@ -306,9 +292,7 @@ void RLFDecoder::RLFVideoTrack::decodeSimpleRunLengthEncoding(int8 *source, int8
return;
}
- byte r, g, b;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(READ_LE_UINT16(source + sourceOffset), r, g, b);
- uint16 sampleColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
+ uint16 sampleColor = READ_LE_UINT16(source + sourceOffset);
sourceOffset += 2;
numberOfCopy = numberOfSamples + 2;
diff --git a/engines/zvision/video/rlf_decoder.h b/engines/zvision/video/rlf_decoder.h
index f0f31c2128..8b8cbaecd5 100644
--- a/engines/zvision/video/rlf_decoder.h
+++ b/engines/zvision/video/rlf_decoder.h
@@ -45,15 +45,15 @@ private:
uint16 getWidth() const { return _width; }
uint16 getHeight() const { return _height; }
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); /*RGB 565*/ }
- int getCurFrame() const { return _curFrame; }
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); /* RGB 555 */ }
+ int getCurFrame() const { return _displayedFrame; }
int getFrameCount() const { return _frameCount; }
const Graphics::Surface *decodeNextFrame();
bool isSeekable() const { return true; }
bool seek(const Audio::Timestamp &time);
protected:
- Common::Rational getFrameRate() const { return Common::Rational(60, _frameTime); }
+ Common::Rational getFrameRate() const { return Common::Rational(1000, _frameTime); }
private:
enum EncodingType {
@@ -121,7 +121,7 @@ private:
Frame *_frames;
Common::Array<uint> _completeFrames;
- int _curFrame;
+ int _displayedFrame;
Graphics::Surface _currentFrameBuffer;
uint32 _frameBufferByteSize;
diff --git a/engines/zvision/video/video.cpp b/engines/zvision/video/video.cpp
index 189fb22194..1cfd0f4197 100644
--- a/engines/zvision/video/video.cpp
+++ b/engines/zvision/video/video.cpp
@@ -23,13 +23,17 @@
#include "common/scummsys.h"
#include "common/system.h"
#include "video/video_decoder.h"
+#ifdef USE_MPEG2
+#include "video/mpegps_decoder.h"
+#endif
#include "engines/util.h"
#include "graphics/surface.h"
#include "zvision/zvision.h"
#include "zvision/core/clock.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/graphics/subtitles.h"
+#include "zvision/scripting/script_manager.h"
+#include "zvision/text/subtitles.h"
#include "zvision/video/rlf_decoder.h"
#include "zvision/video/zork_avi_decoder.h"
@@ -44,12 +48,21 @@ Video::VideoDecoder *ZVision::loadAnimation(const Common::String &fileName) {
animation = new RLFDecoder();
else if (tmpFileName.hasSuffix(".avi"))
animation = new ZorkAVIDecoder();
+#ifdef USE_MPEG2
+ else if (tmpFileName.hasSuffix(".vob"))
+ animation = new Video::MPEGPSDecoder();
+#endif
else
error("Unknown suffix for animation %s", fileName.c_str());
Common::File *_file = getSearchManager()->openFile(tmpFileName);
- animation->loadStream(_file);
-
+ if (!_file)
+ error("Error opening %s", tmpFileName.c_str());
+
+ bool loaded = animation->loadStream(_file);
+ if (!loaded)
+ error("Error loading animation %s", tmpFileName.c_str());
+
return animation;
}
@@ -70,6 +83,7 @@ void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect,
uint16 y = _workingWindow.top + dst.top;
uint16 finalWidth = dst.width() < _workingWindow.width() ? dst.width() : _workingWindow.width();
uint16 finalHeight = dst.height() < _workingWindow.height() ? dst.height() : _workingWindow.height();
+ bool showSubs = (_scriptManager->getStateValue(StateKey_Subtitles) == 1);
_clock.stop();
vid.start();
@@ -101,7 +115,7 @@ void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect,
if (vid.needsUpdate()) {
const Graphics::Surface *frame = vid.decodeNextFrame();
- if (sub)
+ if (sub && showSubs)
sub->process(vid.getCurFrame());
if (frame) {
@@ -109,7 +123,8 @@ void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect,
_renderManager->scaleBuffer(frame->getPixels(), scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, scaled->w, scaled->h);
frame = scaled;
}
- _system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, x, y, finalWidth, finalHeight);
+ Common::Rect rect = Common::Rect(x, y, x + finalWidth, y + finalHeight);
+ _renderManager->copyToScreen(*frame, rect, 0, 0);
_renderManager->processSubs(0);
}
}
diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp
index 67fab0a114..cf8505ec82 100644
--- a/engines/zvision/video/zork_avi_decoder.cpp
+++ b/engines/zvision/video/zork_avi_decoder.cpp
@@ -39,17 +39,34 @@ Video::AVIDecoder::AVIAudioTrack *ZorkAVIDecoder::createAudioTrack(Video::AVIDec
}
void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
+ bool updateCurChunk = true;
if (_audStream) {
if (_wvInfo.tag == kWaveFormatZorkPCM) {
assert(_wvInfo.size == 8);
RawChunkStream::RawChunk chunk = decoder->readNextChunk(stream);
delete stream;
- if (chunk.data)
- _audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO);
+ if (chunk.data) {
+ byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
+#ifdef SCUMM_LITTLE_ENDIAN
+ // RawChunkStream produces native endianness int16
+ flags |= Audio::FLAG_LITTLE_ENDIAN;
+#endif
+ _audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
+ }
} else {
+ updateCurChunk = false;
AVIAudioTrack::queueSound(stream);
}
+ } else {
+ delete stream;
+ }
+
+ // The superclass always updates _curChunk, whether or not audio has
+ // been queued, so we should do that too. Unless the superclass already
+ // has done it for us.
+ if (updateCurChunk) {
+ _curChunk++;
}
}
diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp
index 4e5307c182..779fdc4464 100644
--- a/engines/zvision/zvision.cpp
+++ b/engines/zvision/zvision.cpp
@@ -27,13 +27,12 @@
#include "zvision/scripting/script_manager.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/text/string_manager.h"
-#include "zvision/detection.h"
-#include "zvision/core/menu.h"
+#include "zvision/scripting/menu.h"
#include "zvision/file/search_manager.h"
#include "zvision/text/text.h"
-#include "zvision/graphics/truetype_font.h"
+#include "zvision/text/truetype_font.h"
#include "zvision/sound/midi.h"
#include "zvision/file/zfs_archive.h"
@@ -46,42 +45,42 @@
#include "common/system.h"
#include "common/file.h"
+#include "gui/message.h"
#include "engines/util.h"
-
#include "audio/mixer.h"
namespace ZVision {
-#define ZVISION_SETTINGS_KEYS_COUNT 17
+#define ZVISION_SETTINGS_KEYS_COUNT 12
struct zvisionIniSettings {
const char *name;
int16 slot;
- int16 deflt;
+ int16 defaultValue; // -1: use the bool value
+ bool defaultBoolValue;
+ bool allowEditing;
} settingsKeys[ZVISION_SETTINGS_KEYS_COUNT] = {
- {"ZVision_KeyboardTurnSpeed", StateKey_KbdRotateSpeed, 5},
- {"ZVision_PanaRotateSpeed", StateKey_RotateSpeed, 540},
- {"ZVision_QSoundEnabled", StateKey_Qsound, 1},
- {"ZVision_VenusEnabled", StateKey_VenusEnable, 1},
- {"ZVision_HighQuality", StateKey_HighQuality, 1},
- {"ZVision_Platform", StateKey_Platform, 0},
- {"ZVision_InstallLevel", StateKey_InstallLevel, 0},
- {"ZVision_CountryCode", StateKey_CountryCode, 0},
- {"ZVision_CPU", StateKey_CPU, 1},
- {"ZVision_MovieCursor", StateKey_MovieCursor, 1},
- {"ZVision_NoAnimWhileTurning", StateKey_NoTurnAnim, 0},
- {"ZVision_Win958", StateKey_WIN958, 0},
- {"ZVision_ShowErrorDialogs", StateKey_ShowErrorDlg, 0},
- {"ZVision_ShowSubtitles", StateKey_Subtitles, 1},
- {"ZVision_DebugCheats", StateKey_DebugCheats, 0},
- {"ZVision_JapaneseFonts", StateKey_JapanFonts, 0},
- {"ZVision_Brightness", StateKey_Brightness, 0}
+ // Hardcoded settings
+ {"countrycode", StateKey_CountryCode, 0, false, false}, // always 0 = US, subtitles are shown for codes 0 - 4, unused
+ {"lineskipvideo", StateKey_VideoLineSkip, 0, false, false}, // video line skip, 0 = default, 1 = always, 2 = pixel double when possible, unused
+ {"installlevel", StateKey_InstallLevel, 0, false, false}, // 0 = full, checked by universe.scr
+ {"highquality", StateKey_HighQuality, -1, true, false}, // high panorama quality, unused
+ {"qsoundenabled", StateKey_Qsound, -1, true, false}, // 1 = enable QSound - TODO: not supported yet
+ {"debugcheats", StateKey_DebugCheats, -1, true, false}, // always start with the GOxxxx cheat enabled
+ // Editable settings
+ {"keyboardturnspeed", StateKey_KbdRotateSpeed, 5, false, true},
+ {"panarotatespeed", StateKey_RotateSpeed, 540, false, true}, // checked by universe.scr
+ {"noanimwhileturning", StateKey_NoTurnAnim, -1, false, true}, // toggle playing animations during pana rotation
+ {"venusenabled", StateKey_VenusEnable, -1, true, true},
+ {"subtitles", StateKey_Subtitles, -1, true, true},
+ {"mpegmovies", StateKey_MPEGMovies, -1, true, true} // Zork: Grand Inquisitor DVD hi-res MPEG movies (0 = normal, 1 = hires, 2 = disable option)
};
ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc)
: Engine(syst),
_gameDescription(gameDesc),
- _pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), /*RGB 565*/
+ _resourcePixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), /* RGB 555 */
+ _screenPixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), /* RGB 565 */
_desiredFrameTime(33), /* ~30 fps */
_clock(_system),
_scriptManager(nullptr),
@@ -95,25 +94,18 @@ ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc)
_menu(nullptr),
_searchManager(nullptr),
_textRenderer(nullptr),
- _halveDelay(false),
+ _doubleFPS(false),
_audioId(0),
- _rendDelay(2),
- _kbdVelocity(0),
+ _frameRenderDelay(2),
+ _keyboardVelocity(0),
_mouseVelocity(0),
- _videoIsPlaying(false) {
+ _videoIsPlaying(false),
+ _renderedFrameCount(0),
+ _fps(0) {
debug(1, "ZVision::ZVision");
- uint16 workingWindowWidth = (gameDesc->gameId == GID_NEMESIS) ? ZNM_WORKING_WINDOW_WIDTH : ZGI_WORKING_WINDOW_WIDTH;
- uint16 workingWindowHeight = (gameDesc->gameId == GID_NEMESIS) ? ZNM_WORKING_WINDOW_HEIGHT : ZGI_WORKING_WINDOW_HEIGHT;
- _workingWindow = Common::Rect(
- (WINDOW_WIDTH - workingWindowWidth) / 2,
- (WINDOW_HEIGHT - workingWindowHeight) / 2,
- ((WINDOW_WIDTH - workingWindowWidth) / 2) + workingWindowWidth,
- ((WINDOW_HEIGHT - workingWindowHeight) / 2) + workingWindowHeight
- );
-
- memset(_cheatBuff, 0, sizeof(_cheatBuff));
+ memset(_cheatBuffer, 0, sizeof(_cheatBuffer));
}
ZVision::~ZVision() {
@@ -124,24 +116,45 @@ ZVision::~ZVision() {
delete _cursorManager;
delete _stringManager;
delete _saveManager;
- delete _renderManager;
delete _scriptManager;
+ delete _renderManager; // should be deleted after the script manager
delete _rnd;
delete _midiManager;
+ getTimerManager()->removeTimerProc(&fpsTimerCallback);
+
// Remove all of our debug levels
DebugMan.clearAllDebugChannels();
}
void ZVision::registerDefaultSettings() {
- for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++)
- ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].deflt);
+ for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) {
+ if (settingsKeys[i].allowEditing) {
+ if (settingsKeys[i].defaultValue >= 0)
+ ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].defaultValue);
+ else
+ ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].defaultBoolValue);
+ }
+ }
+
+ ConfMan.registerDefault("originalsaveload", false);
ConfMan.registerDefault("doublefps", false);
}
void ZVision::loadSettings() {
- for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++)
- _scriptManager->setStateValue(settingsKeys[i].slot, ConfMan.getInt(settingsKeys[i].name));
+ int16 value = 0;
+ bool boolValue = false;
+
+ for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) {
+ if (settingsKeys[i].defaultValue >= 0) {
+ value = (settingsKeys[i].allowEditing) ? ConfMan.getInt(settingsKeys[i].name) : settingsKeys[i].defaultValue;
+ } else {
+ boolValue = (settingsKeys[i].allowEditing) ? ConfMan.getBool(settingsKeys[i].name) : settingsKeys[i].defaultBoolValue;
+ value = (boolValue) ? 1 : 0;
+ }
+
+ _scriptManager->setStateValue(settingsKeys[i].slot, value);
+ }
if (getGameId() == GID_NEMESIS)
_scriptManager->setStateValue(StateKey_ExecScopeStyle, 1);
@@ -150,8 +163,15 @@ void ZVision::loadSettings() {
}
void ZVision::saveSettings() {
- for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++)
- ConfMan.setInt(settingsKeys[i].name, _scriptManager->getStateValue(settingsKeys[i].slot));
+ for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) {
+ if (settingsKeys[i].allowEditing) {
+ if (settingsKeys[i].defaultValue >= 0)
+ ConfMan.setInt(settingsKeys[i].name, _scriptManager->getStateValue(settingsKeys[i].slot));
+ else
+ ConfMan.setBool(settingsKeys[i].name, (_scriptManager->getStateValue(settingsKeys[i].slot) == 1));
+ }
+ }
+
ConfMan.flushToDisk();
}
@@ -163,40 +183,32 @@ void ZVision::initialize() {
_searchManager->addDir("FONTS");
_searchManager->addDir("addon");
- if (_gameDescription->gameId == GID_GRANDINQUISITOR) {
- _searchManager->loadZix("INQUIS.ZIX");
- _searchManager->addPatch("C000H01Q.RAW", "C000H01Q.SRC");
- _searchManager->addPatch("CM00H01Q.RAW", "CM00H01Q.SRC");
- _searchManager->addPatch("DM00H01Q.RAW", "DM00H01Q.SRC");
- _searchManager->addPatch("E000H01Q.RAW", "E000H01Q.SRC");
- _searchManager->addPatch("EM00H50Q.RAW", "EM00H50Q.SRC");
- _searchManager->addPatch("GJNPH65P.RAW", "GJNPH65P.SRC");
- _searchManager->addPatch("GJNPH72P.RAW", "GJNPH72P.SRC");
- _searchManager->addPatch("H000H01Q.RAW", "H000H01Q.SRC");
- _searchManager->addPatch("M000H01Q.RAW", "M000H01Q.SRC");
- _searchManager->addPatch("P000H01Q.RAW", "P000H01Q.SRC");
- _searchManager->addPatch("Q000H01Q.RAW", "Q000H01Q.SRC");
- _searchManager->addPatch("SW00H01Q.RAW", "SW00H01Q.SRC");
- _searchManager->addPatch("T000H01Q.RAW", "T000H01Q.SRC");
- _searchManager->addPatch("U000H01Q.RAW", "U000H01Q.SRC");
- } else if (_gameDescription->gameId == GID_NEMESIS)
- _searchManager->loadZix("NEMESIS.ZIX");
-
- initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_pixelFormat);
+ if (getGameId() == GID_GRANDINQUISITOR) {
+ if (!_searchManager->loadZix("INQUIS.ZIX"))
+ error("Unable to load file INQUIS.ZIX");
+ } else if (getGameId() == GID_NEMESIS) {
+ if (!_searchManager->loadZix("NEMESIS.ZIX")) {
+ // The game might not be installed, try MEDIUM.ZIX instead
+ if (!_searchManager->loadZix("ZNEMSCR/MEDIUM.ZIX"))
+ error("Unable to load the file ZNEMSCR/MEDIUM.ZIX");
+ }
+ }
+
+ initScreen();
// Register random source
_rnd = new Common::RandomSource("zvision");
// Create managers
_scriptManager = new ScriptManager(this);
- _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _pixelFormat);
+ _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _resourcePixelFormat, _doubleFPS);
_saveManager = new SaveManager(this);
_stringManager = new StringManager(this);
- _cursorManager = new CursorManager(this, &_pixelFormat);
+ _cursorManager = new CursorManager(this, _resourcePixelFormat);
_textRenderer = new TextRenderer(this);
_midiManager = new MidiManager();
- if (_gameDescription->gameId == GID_GRANDINQUISITOR)
+ if (getGameId() == GID_GRANDINQUISITOR)
_menu = new MenuZGI(this);
else
_menu = new MenuNemesis(this);
@@ -204,17 +216,27 @@ void ZVision::initialize() {
// Initialize the managers
_cursorManager->initialize();
_scriptManager->initialize();
- _stringManager->initialize(_gameDescription->gameId);
+ _stringManager->initialize(getGameId());
registerDefaultSettings();
loadSettings();
+#ifndef USE_MPEG2
+ // libmpeg2 not loaded, disable the MPEG2 movies option
+ _scriptManager->setStateValue(StateKey_MPEGMovies, 2);
+#endif
+
// Create debugger console. It requires GFX to be initialized
_console = new Console(this);
- _halveDelay = ConfMan.getBool("doublefps");
+ _doubleFPS = ConfMan.getBool("doublefps");
+
+ // Initialize FPS timer callback
+ getTimerManager()->installTimerProc(&fpsTimerCallback, 1000000, this, "zvisionFPS");
}
+extern const FontStyle getSystemFont(int fontIndex);
+
Common::Error ZVision::run() {
initialize();
@@ -222,6 +244,68 @@ Common::Error ZVision::run() {
if (ConfMan.hasKey("save_slot"))
_saveManager->loadGame(ConfMan.getInt("save_slot"));
+ bool foundAllFonts = true;
+
+ // Before starting, make absolutely sure that the user has copied the needed fonts
+ for (int i = 0; i < FONT_COUNT; i++) {
+ FontStyle curFont = getSystemFont(i);
+ Common::String freeFontBoldItalic = Common::String("Bold") + curFont.freeFontItalicName;
+
+ const char *fontSuffixes[4] = { "", "bd", "i", "bi" };
+ const char *freeFontSuffixes[4] = { "", "Bold", curFont.freeFontItalicName, freeFontBoldItalic.c_str() };
+ const char *liberationFontSuffixes[4] = { "-Regular", "-Bold", "-Italic", "-BoldItalic" };
+
+ for (int j = 0; j < 4; j++) {
+ Common::String fontName = curFont.fontBase;
+ if (fontName == "censcbk" && j > 0)
+ fontName = "schlbk";
+ fontName += fontSuffixes[j];
+ fontName += ".ttf";
+
+ if (fontName == "schlbkbd.ttf")
+ fontName = "schlbkb.ttf";
+ if (fontName == "garabi.ttf")
+ continue;
+ if (fontName == "garai.ttf")
+ fontName = "garait.ttf";
+
+ Common::String freeFontName = curFont.freeFontBase;
+ freeFontName += freeFontSuffixes[j];
+ freeFontName += ".ttf";
+
+ Common::String liberationFontName = curFont.liberationFontBase;
+ liberationFontName += liberationFontSuffixes[j];
+ liberationFontName += ".ttf";
+
+ if (!Common::File::exists(fontName) && !_searchManager->hasFile(fontName) &&
+ !Common::File::exists(liberationFontName) && !_searchManager->hasFile(liberationFontName) &&
+ !Common::File::exists(freeFontName) && !_searchManager->hasFile(freeFontName)) {
+ foundAllFonts = false;
+ break;
+ }
+ }
+
+ if (!foundAllFonts)
+ break;
+ }
+
+ if (!foundAllFonts) {
+ GUI::MessageDialog dialog(
+ "Before playing this game, you'll need to copy the required "
+ "fonts into ScummVM's extras directory, or into the game directory. "
+ "On Windows, you'll need the following font files from the Windows "
+ "font directory: Times New Roman, Century Schoolbook, Garamond, "
+ "Courier New and Arial. Alternatively, you can download the "
+ "Liberation Fonts or the GNU FreeFont package. You'll need all the "
+ "fonts from the font package you choose, i.e., LiberationMono, "
+ "LiberationSans and LiberationSerif, or FreeMono, FreeSans and "
+ "FreeSerif respectively."
+ );
+ dialog.runModal();
+ quitGame();
+ return Common::kUnknownError;
+ }
+
// Main loop
while (!shouldQuit()) {
_clock.update();
@@ -231,106 +315,42 @@ Common::Error ZVision::run() {
_cursorManager->setItemID(_scriptManager->getStateValue(StateKey_InventoryItem));
processEvents();
- updateRotation();
+ _renderManager->updateRotation();
- // Call _renderManager->update() first so the background renders
- // before anything that puzzles/controls will render
_scriptManager->update(deltaTime);
_menu->process(deltaTime);
// Render the backBuffer to the screen
- _renderManager->prepareBkg();
+ _renderManager->prepareBackground();
_renderManager->renderMenuToScreen();
_renderManager->processSubs(deltaTime);
- _renderManager->renderBackbufferToScreen();
+ _renderManager->renderSceneToScreen();
// Update the screen
- if (_rendDelay <= 0)
+ if (canRender()) {
_system->updateScreen();
- else
- _rendDelay--;
+ _renderedFrameCount++;
+ } else {
+ _frameRenderDelay--;
+ }
// Calculate the frame delay based off a desired frame time
int delay = _desiredFrameTime - int32(_system->getMillis() - currentTime);
// Ensure non-negative
delay = delay < 0 ? 0 : delay;
- if (_halveDelay)
- delay >>= 1;
- _system->delayMillis(delay);
- }
- return Common::kNoError;
-}
-
-bool ZVision::askQuestion(const Common::String &str) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, str);
- _renderManager->processSubs(0);
- _renderManager->renderBackbufferToScreen();
- _clock.stop();
-
- int result = 0;
-
- while (result == 0) {
- Common::Event evnt;
- while (_eventMan->pollEvent(evnt)) {
- if (evnt.type == Common::EVENT_KEYDOWN) {
- switch (evnt.kbd.keycode) {
- case Common::KEYCODE_y:
- result = 2;
- break;
- case Common::KEYCODE_n:
- result = 1;
- break;
- default:
- break;
- }
- }
+ if (_doubleFPS) {
+ delay >>= 1;
}
- _system->updateScreen();
- if (_halveDelay)
- _system->delayMillis(33);
- else
- _system->delayMillis(66);
- }
- _renderManager->deleteSubArea(msgid);
- _clock.start();
- return result == 2;
-}
-void ZVision::delayedMessage(const Common::String &str, uint16 milsecs) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, str);
- _renderManager->processSubs(0);
- _renderManager->renderBackbufferToScreen();
- _clock.stop();
-
- uint32 stopTime = _system->getMillis() + milsecs;
- while (_system->getMillis() < stopTime) {
- Common::Event evnt;
- while (_eventMan->pollEvent(evnt)) {
- if (evnt.type == Common::EVENT_KEYDOWN &&
- (evnt.kbd.keycode == Common::KEYCODE_SPACE ||
- evnt.kbd.keycode == Common::KEYCODE_RETURN ||
- evnt.kbd.keycode == Common::KEYCODE_ESCAPE))
- break;
+ if (canSaveGameStateCurrently() && shouldPerformAutoSave(_saveManager->getLastSaveTime())) {
+ _saveManager->autoSave();
}
- _system->updateScreen();
- if (_halveDelay)
- _system->delayMillis(33);
- else
- _system->delayMillis(66);
+
+ _system->delayMillis(delay);
}
- _renderManager->deleteSubArea(msgid);
- _clock.start();
-}
-void ZVision::timedMessage(const Common::String &str, uint16 milsecs) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, str);
- _renderManager->processSubs(0);
- _renderManager->renderBackbufferToScreen();
- _renderManager->deleteSubArea(msgid, milsecs);
+ return Common::kNoError;
}
void ZVision::pauseEngineIntern(bool pause) {
@@ -347,200 +367,50 @@ Common::String ZVision::generateSaveFileName(uint slot) {
return Common::String::format("%s.%03u", _targetName.c_str(), slot);
}
-Common::String ZVision::generateAutoSaveFileName() {
- return Common::String::format("%s.auto", _targetName.c_str());
-}
-
void ZVision::setRenderDelay(uint delay) {
- _rendDelay = delay;
+ _frameRenderDelay = delay;
}
bool ZVision::canRender() {
- return _rendDelay <= 0;
+ return _frameRenderDelay <= 0;
}
-void ZVision::updateRotation() {
- int16 _velocity = _mouseVelocity + _kbdVelocity;
-
- if (_halveDelay)
- _velocity /= 2;
-
- if (_velocity) {
- RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
- if (renderState == RenderTable::PANORAMA) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition + (_renderManager->getRenderTable()->getPanoramaReverse() ? -_velocity : _velocity);
-
- int16 zeroPoint = _renderManager->getRenderTable()->getPanoramaZeroPoint();
- if (startPosition >= zeroPoint && newPosition < zeroPoint)
- _scriptManager->setStateValue(StateKey_Rounds, _scriptManager->getStateValue(StateKey_Rounds) - 1);
- if (startPosition <= zeroPoint && newPosition > zeroPoint)
- _scriptManager->setStateValue(StateKey_Rounds, _scriptManager->getStateValue(StateKey_Rounds) + 1);
-
- int16 screenWidth = _renderManager->getBkgSize().x;
- if (screenWidth)
- newPosition %= screenWidth;
-
- if (newPosition < 0)
- newPosition += screenWidth;
-
- _renderManager->setBackgroundPosition(newPosition);
- } else if (renderState == RenderTable::TILT) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition + _velocity;
-
- int16 screenHeight = _renderManager->getBkgSize().y;
- int16 tiltGap = _renderManager->getRenderTable()->getTiltGap();
-
- if (newPosition >= (screenHeight - tiltGap))
- newPosition = screenHeight - tiltGap;
- if (newPosition <= tiltGap)
- newPosition = tiltGap;
-
- _renderManager->setBackgroundPosition(newPosition);
- }
- }
+GUI::Debugger *ZVision::getDebugger() {
+ return _console;
}
-void ZVision::checkBorders() {
- RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState();
- if (renderState == RenderTable::PANORAMA) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition;
-
- int16 screenWidth = _renderManager->getBkgSize().x;
-
- if (screenWidth)
- newPosition %= screenWidth;
-
- if (newPosition < 0)
- newPosition += screenWidth;
+void ZVision::syncSoundSettings() {
+ Engine::syncSoundSettings();
- if (startPosition != newPosition)
- _renderManager->setBackgroundPosition(newPosition);
- } else if (renderState == RenderTable::TILT) {
- int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos);
-
- int16 newPosition = startPosition;
-
- int16 screenHeight = _renderManager->getBkgSize().y;
- int16 tiltGap = _renderManager->getRenderTable()->getTiltGap();
-
- if (newPosition >= (screenHeight - tiltGap))
- newPosition = screenHeight - tiltGap;
- if (newPosition <= tiltGap)
- newPosition = tiltGap;
-
- if (startPosition != newPosition)
- _renderManager->setBackgroundPosition(newPosition);
- }
+ _scriptManager->setStateValue(StateKey_Subtitles, ConfMan.getBool("subtitles") ? 1 : 0);
}
-void ZVision::rotateTo(int16 _toPos, int16 _time) {
- if (_renderManager->getRenderTable()->getRenderState() != RenderTable::PANORAMA)
- return;
-
- if (_time == 0)
- _time = 1;
-
- int32 maxX = _renderManager->getBkgSize().x;
- int32 curX = _renderManager->getCurrentBackgroundOffset();
- int32 dx = 0;
-
- if (curX == _toPos)
- return;
-
- if (curX > _toPos) {
- if (curX - _toPos > maxX / 2)
- dx = (_toPos + (maxX - curX)) / _time;
- else
- dx = -(curX - _toPos) / _time;
- } else {
- if (_toPos - curX > maxX / 2)
- dx = -((maxX - _toPos) + curX) / _time;
- else
- dx = (_toPos - curX) / _time;
- }
-
- _clock.stop();
-
- for (int16 i = 0; i <= _time; i++) {
- if (i == _time)
- curX = _toPos;
- else
- curX += dx;
-
- if (curX < 0)
- curX = maxX - curX;
- else if (curX >= maxX)
- curX %= maxX;
-
- _renderManager->setBackgroundPosition(curX);
-
- _renderManager->prepareBkg();
- _renderManager->renderBackbufferToScreen();
-
- _system->updateScreen();
-
- _system->delayMillis(500 / _time);
- }
-
- _clock.start();
-}
-
-void ZVision::menuBarEnable(uint16 menus) {
- if (_menu)
- _menu->setEnable(menus);
-}
-
-uint16 ZVision::getMenuBarEnable() {
- if (_menu)
- return _menu->getEnable();
- return 0;
-}
-
-bool ZVision::ifQuit() {
- if (askQuestion(_stringManager->getTextLine(StringManager::ZVISION_STR_EXITPROMT))) {
- quitGame();
- return true;
- }
- return false;
+void ZVision::fpsTimerCallback(void *refCon) {
+ ((ZVision *)refCon)->fpsTimer();
}
-void ZVision::pushKeyToCheatBuf(uint8 key) {
- for (int i = 0; i < KEYBUF_SIZE - 1; i++)
- _cheatBuff[i] = _cheatBuff[i + 1];
-
- _cheatBuff[KEYBUF_SIZE - 1] = key;
+void ZVision::fpsTimer() {
+ _fps = _renderedFrameCount;
+ _renderedFrameCount = 0;
}
-bool ZVision::checkCode(const char *code) {
- int codeLen = strlen(code);
-
- if (codeLen > KEYBUF_SIZE)
- return false;
-
- for (int i = 0; i < codeLen; i++)
- if (code[i] != _cheatBuff[KEYBUF_SIZE - codeLen + i] && code[i] != '?')
- return false;
+void ZVision::initScreen() {
+ uint16 workingWindowWidth = (getGameId() == GID_NEMESIS) ? ZNM_WORKING_WINDOW_WIDTH : ZGI_WORKING_WINDOW_WIDTH;
+ uint16 workingWindowHeight = (getGameId() == GID_NEMESIS) ? ZNM_WORKING_WINDOW_HEIGHT : ZGI_WORKING_WINDOW_HEIGHT;
+ _workingWindow = Common::Rect(
+ (WINDOW_WIDTH - workingWindowWidth) / 2,
+ (WINDOW_HEIGHT - workingWindowHeight) / 2,
+ ((WINDOW_WIDTH - workingWindowWidth) / 2) + workingWindowWidth,
+ ((WINDOW_HEIGHT - workingWindowHeight) / 2) + workingWindowHeight
+ );
- return true;
+ initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_screenPixelFormat);
}
-uint8 ZVision::getBufferedKey(uint8 pos) {
- if (pos >= KEYBUF_SIZE)
- return 0;
- else
- return _cheatBuff[KEYBUF_SIZE - pos - 1];
-}
+void ZVision::initHiresScreen() {
+ _renderManager->upscaleRect(_workingWindow);
-void ZVision::showDebugMsg(const Common::String &msg, int16 delay) {
- uint16 msgid = _renderManager->createSubArea();
- _renderManager->updateSubArea(msgid, msg);
- _renderManager->deleteSubArea(msgid, delay);
+ initGraphics(HIRES_WINDOW_WIDTH, HIRES_WINDOW_HEIGHT, true, &_screenPixelFormat);
}
} // End of namespace ZVision
diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h
index 78c1c824a1..4c948faaa4 100644
--- a/engines/zvision/zvision.h
+++ b/engines/zvision/zvision.h
@@ -24,7 +24,6 @@
#ifndef ZVISION_ZVISION_H
#define ZVISION_ZVISION_H
-#include "zvision/detection.h"
#include "zvision/core/clock.h"
#include "zvision/file/search_manager.h"
@@ -41,6 +40,16 @@ namespace Video {
class VideoDecoder;
}
+/**
+ * This is the namespace of the ZVision engine.
+ *
+ * Status of this engine: complete
+ *
+ * Games using this engine:
+ * - Zork Nemesis: The Forbidden Lands
+ * - Zork: Grand Inquisitor
+ *
+ */
namespace ZVision {
struct ZVisionGameDescription;
@@ -56,6 +65,33 @@ class TextRenderer;
class Subtitle;
class MidiManager;
+enum {
+ WINDOW_WIDTH = 640,
+ WINDOW_HEIGHT = 480,
+
+ HIRES_WINDOW_WIDTH = 800,
+ HIRES_WINDOW_HEIGHT = 600,
+
+ // Zork Nemesis working window sizes
+ ZNM_WORKING_WINDOW_WIDTH = 512,
+ ZNM_WORKING_WINDOW_HEIGHT = 320,
+
+ // ZGI working window sizes
+ ZGI_WORKING_WINDOW_WIDTH = 640,
+ ZGI_WORKING_WINDOW_HEIGHT = 344,
+
+ ROTATION_SCREEN_EDGE_OFFSET = 60,
+ MAX_ROTATION_SPEED = 400, // Pixels per second
+
+ KEYBUF_SIZE = 20
+};
+
+enum ZVisionGameId {
+ GID_NONE = 0,
+ GID_NEMESIS = 1,
+ GID_GRANDINQUISITOR = 2
+};
+
class ZVision : public Engine {
public:
ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc);
@@ -68,27 +104,10 @@ public:
* edges of this Rectangle
*/
Common::Rect _workingWindow;
- const Graphics::PixelFormat _pixelFormat;
+ const Graphics::PixelFormat _resourcePixelFormat;
+ const Graphics::PixelFormat _screenPixelFormat;
private:
- enum {
- WINDOW_WIDTH = 640,
- WINDOW_HEIGHT = 480,
-
- // Zork nemesis working window sizes
- ZNM_WORKING_WINDOW_WIDTH = 512,
- ZNM_WORKING_WINDOW_HEIGHT = 320,
-
- // ZGI working window sizes
- ZGI_WORKING_WINDOW_WIDTH = 640,
- ZGI_WORKING_WINDOW_HEIGHT = 344,
-
- ROTATION_SCREEN_EDGE_OFFSET = 60,
- MAX_ROTATION_SPEED = 400, // Pixels per second
-
- KEYBUF_SIZE = 20
- };
-
Console *_console;
const ZVisionGameDescription *_gameDescription;
@@ -101,12 +120,12 @@ private:
ScriptManager *_scriptManager;
RenderManager *_renderManager;
CursorManager *_cursorManager;
- SaveManager *_saveManager;
StringManager *_stringManager;
- MenuHandler *_menu;
SearchManager *_searchManager;
TextRenderer *_textRenderer;
MidiManager *_midiManager;
+ SaveManager *_saveManager;
+ MenuHandler *_menu;
// Clock
Clock _clock;
@@ -117,19 +136,24 @@ private:
// To prevent allocation every time we process events
Common::Event _event;
- int _rendDelay;
+ int _frameRenderDelay;
+ int _renderedFrameCount;
+ int _fps;
int16 _mouseVelocity;
- int16 _kbdVelocity;
- bool _halveDelay;
+ int16 _keyboardVelocity;
+ bool _doubleFPS;
bool _videoIsPlaying;
- uint8 _cheatBuff[KEYBUF_SIZE];
+ uint8 _cheatBuffer[KEYBUF_SIZE];
+
public:
- uint32 getFeatures() const;
- Common::Language getLanguage() const;
Common::Error run();
void pauseEngineIntern(bool pause);
+ ZVisionGameId getGameId() const;
+ Common::Language getLanguage() const;
+ uint32 getFeatures() const;
+
ScriptManager *getScriptManager() const {
return _scriptManager;
}
@@ -154,15 +178,33 @@ public:
MidiManager *getMidiManager() const {
return _midiManager;
}
+ MenuHandler *getMenuHandler() const {
+ return _menu;
+ }
+
Common::RandomSource *getRandomSource() const {
return _rnd;
}
- ZVisionGameId getGameId() const {
- return _gameDescription->gameId;
+ int16 getKeyboardVelocity() const {
+ return _keyboardVelocity;
+ }
+ int16 getMouseVelocity() const {
+ return _mouseVelocity;
}
uint8 getZvisionKey(Common::KeyCode scummKeyCode);
+ void startClock() {
+ _clock.start();
+ }
+
+ void stopClock() {
+ _clock.stop();
+ }
+
+ void initScreen();
+ void initHiresScreen();
+
/**
* Play a video until it is finished. This is a blocking call. It will call
* _clock.stop() when the video starts and _clock.start() when the video finishes.
@@ -175,35 +217,31 @@ public:
void playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect = Common::Rect(0, 0, 0, 0), bool skippable = true, Subtitle *sub = NULL);
Video::VideoDecoder *loadAnimation(const Common::String &fileName);
- void rotateTo(int16 to, int16 time);
-
Common::String generateSaveFileName(uint slot);
- Common::String generateAutoSaveFileName();
-
- bool askQuestion(const Common::String &str);
- void delayedMessage(const Common::String &str, uint16 milsecs);
- void timedMessage(const Common::String &str, uint16 milsecs);
void setRenderDelay(uint);
bool canRender();
+ static void fpsTimerCallback(void *refCon);
+ void fpsTimer();
+ int getFPS() const {
+ return _fps;
+ }
+
+ GUI::Debugger *getDebugger();
+ void syncSoundSettings();
void loadSettings();
void saveSettings();
- void menuBarEnable(uint16 menus);
- uint16 getMenuBarEnable();
-
bool ifQuit();
- void checkBorders();
- void showDebugMsg(const Common::String &msg, int16 delay = 3000);
-
// Engine features
bool hasFeature(EngineFeature f) const;
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
Common::Error loadGameState(int slot);
Common::Error saveGameState(int slot, const Common::String &desc);
+
private:
void initialize();
void initFonts();
@@ -214,7 +252,6 @@ private:
void processEvents();
void onMouseMove(const Common::Point &pos);
- void updateRotation();
void registerDefaultSettings();
void shortKeys(Common::Event);