[Scummvm-git-logs] scummvm master -> a80ea4c5257cb440fe43f77238faeed5e3445c90
bluegr
noreply at scummvm.org
Sun Jun 30 19:50:43 UTC 2024
This automated email contains information about 200 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
3845931407 DGDS: Initial import
348c6aca5a DGDS: Update and rebase engine
b813fbd719 DGDS: Refactors and cleanups to remove globals.
ed1062d63e DGDS: Implement full SDS (Scene data) parsing
7a0c5f4dd2 DGDS: Add parsing for GDS style SDS data
797b2d4a74 DGDS: Fix shadowed variable
9383f1f827 DGDS: Added a wrapper to read resource streams
4b3aeaa022 DGDS: Re-enable the Dragon intro credit scenes
230e1c5d11 DGDS: Fix path for dump files
2d922448fb DGDS: Encapsulate compression logic inside the Decompressor class
888be0a6e3 DGDS: Split RST chunk parsing into a separate function
79e6981671 DGDS: Split Amiga chunk handling into a separate function
9648702c51 DGDS: Fix spacing
fd4d31db04 DGDS: Remove debug variable scount
0e863e7640 DGDS: Start splitting the sound code into a separate class
6d1af43454 DGDS: Remove unused functions
826630d88a DGDS: Cleanup
bff77cfe47 DGDS: Move music player out of DgdsEngine
2556312d63 DGDS: Move sound resource loading inside the Sound class
53386d6d54 DGDS: Moved Amiga SFX handling into Sound::playAmigaSfx()
596de66e98 DGDS: Move Mac music handling inside the Sound class
85c41b0c93 DGDS: Silene some MSVC warnings
b13a34d7a0 DGDS: Add REQ file parsing and refactor parsing a bit overall
4c4d8b9c3d DGDS: Fix some clang warnings
6f1df860d9 DGDS: Fix decompressor usage
527c5037b9 DGDS: move bmpId and drawWin to script state
9f72cad6e7 DGDS: Refactor the TTM and ADS player and remove external data and state
98b8305a52 DGDS: Play intro credits and scenes from their respective ADS files
1c281ed585 DGDS: Fix Request and Gadget object parsing
ba280b159f DGDS: Remove incorrect check. Fixes the intros of Beamish and HoC
98d1c40995 DGDS: Remove dead code
fc77e76228 DGDS: Move font loading logic in the Font class
fea0a4ac92 DGDS: Remove superfluous variables and fix Mac music resource ID
a4e33facc8 DGDS: Mark SDS file versions for HoC and Willy
12db5e1224 DGDS: Load font for Beamish
da940c29ae DGDS: Refactored the last parts of the file parser
af8e6da0b2 DGDS: Add detection for beamish FDD data
a97a50f4cf DGDS: Better handling of scene skipping
379ef4c67d DGDS: Whitespace and variable initialization fixes
bda43200f5 DGDS: Read page count for ttm scripts
bf9f08824a DGDS: Add SCN format image parsing
67ca71b91c DGDS: Add a debug function to dump REQ contents after parsing
6132d44e42 DGDS: Give request struct a better name
3d54a567cf DGDS: Enhance filedump console command
d2186d863d DGDS: Correct request parsing and test on more games
d68d7348dc DGDS: Give gadget types meaningful names
dab391f442 DGDS: Cleaner font loading and eliminate memory leak
41dba27e0f DGDS: Add font manager to keep multiple fonts
d17930218a DGDS: Fix font data deallocation
7923cac2ee DGDS: Start adding gadget drawing code
a70d15bd6c DGDS: Hook up VCR (main menu) drawing code to F5
0ea519cf4b DGDS: Some renames and small changes to script parsing
dab1edd234 DGDS: Add drawing code for more gadgets
10debcef1e DGDS: Implement most of menu drawing
9ee2315420 DGDS: Start to implement dialogue rendering
006a38b338 DGDS: Dialogue is a class - fix forward declaration
09529edb05 DGDS: Start implementing menus
7576860102 DGDS: Add debug command to dump bitmap frames
8523a24e4b DGDS: Add loading of game icons (mouse cursors etc)
78f23ed1c8 DGDS: Use default mouse cursor from icons file
086f896a43 DGDS: Name mouse cursor struct correctly
bec24c36db DGDS: Fix background buffer handling
423dd1f267 DGDS: Fix shadowed variables
25bbabb6b2 DGDS: Start moving menu-related functionality in a separate class
fa18dd02b8 DGDS: Draw menu text - WIP
abcc5c8104 DGDS: Add menu button click animations
650062dcc7 DGDS: Fix some compile warnings
0c629728b1 DGDS: Add dump code for SDS and GDS scene data
c2c9e0e040 DGDS: Name some structures and members of scene data
481c286597 DGDS: Rename scene trigger type now I understand it a bit
a0355e18b5 DGDS: Implement some scene operations
d12688f156 DGDS: Implement thought-bubble style dialogues and text alignment
064585c48c DGDS: Add more script ops and unsupported items
8a6bb5e031 DGDS: Check magic on scene load like original
c2d3651782 DGDS: Add some more menu button IDs used in HoC
925290ff9e DGDS: Silence some noisy debug console output
f437ad7e84 DGDS: Implement some more TTM opcodes
67547e0ed1 DGDS: Refactor TTM opcode handling
afede5326f DGDS: Refactor the ADS script parser, and add stubs for some opcodes
b3e7422bc0 DGDS: Implement multi-palette management and fades
8ea13cb86c DGDS: Fix fades a bit - still not quite right.
7f0a1aad5a DGDS: Control dialogues more like the original.
6112d70c1b DGDS: Add handling for game globals
0d3d6caa30 DGDS: Rename some op lists to better names, call some on scene change
94a3aa994c DGDS: Work out more scene opcodes
c72cca34e3 DGDS: ADS and TTM implementation
7bd0be7a71 DGDS: More work on ADS and TTM
1aca7ded40 DGDS: More work to move ADS and TTM execution closer to original
1c9ea68069 DGDS: More ADS fixes, now mostly working
aadb9ecbc1 DGDS: Fix TTM initialization
66800f48dc DGDS: Properly implement some ADS if conditions
247b1750f7 DGDS: More ADS improvements
bbe68b84d7 DGDS: Fix ADS and TTM interpreters even more
be29343c7c DGDS: Add sfx as a separate thing from music
f7770582fd DGDS: Add more debugging for frame progression
65fc35e32b DGDS: Better struct names
f273055d2b DGDS: Slight script execution improvements
24b306ac9a DGDS: Fix one-shot ttm opcodes
a3c5458985 DGDS: More ADS execution improvements
ea049fe010 DGDS: Fix ADS branch handling to match original
c29b9d8260 DGDS: Improve comments and debug
f7b92ccafe DGDS: Improve dialogues - better names, more code
f9179c2bbc DGDS: Rename dialog class for shorter name
470e01f0ca DGDS: Mostly implement original dialog behavior
4db0782221 DGDS: More small improvements to dialogs
6051f5f365 DGDS: Split dialog functions into their own file
af5fbb6f32 DGDS: More work on dialogs and scenes
302331f071 DGDS: Implement some more ADS and TTM opcodes
734c67ee8c DGDS: Fix build on some platforms
f0a45e2bd2 DGDS: Implement even more TT3 and ADS opcodes
0381ea72dd DGDS: Implement ADS logic OR and AND opcodes
7164439ff2 DGDS: Make globals signed ints
24ff433799 DGDS: Small tweaks to drawing ops
dc4b2bce3f DGDS: Load all frames of an image at once
617c364469 DGDS: Fix more scene op running
0be203599e DGDS: Small fixes to dialog rendering. Still broken.
9b7f8d9bf3 DGDS: Fix scene rendering a bit
01525c55b5 DGDS: Add code to draw game clock
72535a9c61 DGDS: Add inventory button
a84fa4f998 DGDS: Start to implement inventory and item stuff
2f44f3f1a2 DGDS: Start to implement Inventory screen
7032295828 DGDS: More inventory implementation
f3b7165fd6 DGDS: Incrementally implement inventory interactions
87fa1a8482 DGDS: Improve clock and scene condition evaluation
1030ef3224 DGDS: Implement more inventory stuff
c219ffd53e DGDS: Add object-object interactions
98185eb48b DGDS: Hack in some dialog stuff
272827e9d4 DGDS: support for multi-ads, inventory now sorta works
a3097b4628 DGDS: Implement minimal ops to make HoC boot
3c091686ed DGDS: Fix more rendering and execution issues
3b41518ecc DGDS: Fix some implicit scene change crashes for inventory
6abe2cd0b3 DGDS: Fix mouse on inv drop
c0d78c7ded DGDS: Rename buffers to make it more understandable
33057f412e DGDS: Improve debug, fix store opcode.
487586681f DGDS: Fix compile with new palette
affe5bf0b8 DGDS: Add initial load/save code
e79b60a4d2 DGDS: Add save/load dialogs. Fix skipping dialog
6f94da020a DGDS: Fix dialog item selection
c028ebf8ce DGDS: Fix dragging out of inventory
0516a3e3ac DGDS: Mostly fix save/load of games
1a714adcd8 DGDS: Fix dialog selection
48ce6e938b DGDS: Fix some drag-drop, dialog, and resource loading issues
9c06c52e4f DGDS: Load/save background image name
b6406e7611 DGDS: Clear stored and foreground buffer on load
c263922adf DGDS: Load active script on save/load
fcf43ac0f7 DGDS: Stop processing drag ops if scene changed
faa70e545f DGDS: Load game from launcher if set
c79b6d8982 DGDS: Fix dragging in inventory a bit
ccdfdb683d DGDS: Implement opening menu from script
2b9f38ede1 DGDS: Fix script timing values to match original
46b90500b5 DGDS: Add minutes on various events
b593f026f7 DGDS: Fix small things to make china not crash
723761ec2f DGDS: Fix some inventory interactions
8339a8de2a DGDS: Don't run scripts during mini inventory
62b886874d DGDS: Go back to just clearing foreground
7e27347b55 DGDS: More tweaking to rendering to match originals
45cc070eb8 DGDS: Fix wrapping with space padding
38185598b6 DGDS: Remove foreground buffer
dddb5097cf DGDS: Add sq5 demo detection
1cef88c99e DGDS: Hook up save/load menu items
a15c1cb1e1 DGDS: Various fixes to font and dialog handling
87666a29ed DGDS: Add debug command to dump all frames of bmp
cd1aba710a DGDS: Fix ADS while handling and improve debug messages
2e408a73c3 DGDS: Fix msvc build
bbfd955b0e DGDS: Fix dropping wire clips on electrical board
42481c5684 DGDS: Mark most detection entries as unstable
15f8a90b31 DGDS: Refactor to split into smaller files
11c3480ffe DGDS: Fix a few small game interaction bugs
e9815f1413 DGDS: Fix more small engine bugs
25f1fa5604 DGDS: Fix some msvc errors
c3b0b32df5 DGDS: Implement RST (reset state) loading
3abd356fea DGDS: Enforce clip window on drawline
50522d6567 DGDS: Fix rendering on game load
009e430bde DGDS: Add passcode opcode for Dragon.
9a0ebf8f0a DGDS: Fix use of scene num global
7fec7d4848 DGDS: Implement various wipe-copy operations
80becfc075 DGDS: Add 'coming soon' non-interactive demo detection
04f97efdcd DGDS: Avoid crashing on Dragon EGA
7582100484 DGDS: Fix inventory right-click zoom
57e272d9b6 DGDS: Clean up sound and music a bit
822aa3db8e DGDS: Reset palette list on game load
fc14318df3 DGDS: Fix game events happening at wrong times
b1a67aa263 DGDS: Refactor globals as some are common between games
7d0631ee87 DGDS: Add slidget gadget support
30363ff492 DGDS: Skip arcade sequences automatically
fec21fa8f3 DGDS: Small cleanups to run non-interactive demos
f2941d6777 DGDS: Fix final scenes of dragon
bed15d2533 DGDS: Whitespace fixes
a16c8955cd DGDS: Update includes
f7baf88cf2 DGDS: Cleanups, remove excessive casts
dd0bacd947 DGDS: Improvements for China
caacea6904 DGDS: Change menus to open by ID instead of offset
9fb6e47cd6 DGDS: Add keymapper support
b874625c90 DGDS: Small fixes for non-interactive demos
ffef4790f4 DGDS: Fix font, music, and rendering slightly in SQ5 demo
7dd64b3d35 DGDS: Fix crash in sq5 demo
5531ae485a DGDS: Fix large font rendering
5f63c5b1af DGDS: Fix parsing for Willy Beamish
21c133656c DGDS: Fixes for "coming attractions" demo
a80ea4c525 DGDS: Implement more required features for Willy Beamish
Commit: 3845931407308a0b630f712efec40ae688c903d7
https://github.com/scummvm/scummvm/commit/3845931407308a0b630f712efec40ae688c903d7
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Initial import
This is the initial import of the sources from vcosta's implementation.
Work has progressed on that base, so that it forms into an actual engine.
There has been heavy refactoring into classes, but there's still loads of
work to be done.
The status is almost the same the original vcosta's engine: it's possible
to play the intro Rise of the Dragon, and parts of the intro of Heart of
China and Willy Beamish. The DOS VQT images are still not decoded, so only
the Mac versions work for now - or the DOS versions with the Mac images
as patches
Changed paths:
A engines/dgds/configure.engine
A engines/dgds/console.cpp
A engines/dgds/console.h
A engines/dgds/decompress.cpp
A engines/dgds/decompress.h
A engines/dgds/detection.cpp
A engines/dgds/detection_tables.h
A engines/dgds/dgds.cpp
A engines/dgds/dgds.h
A engines/dgds/font.cpp
A engines/dgds/font.h
A engines/dgds/image.cpp
A engines/dgds/image.h
A engines/dgds/includes.h
A engines/dgds/metaengine.cpp
A engines/dgds/module.mk
A engines/dgds/movies.cpp
A engines/dgds/movies.h
A engines/dgds/music.cpp
A engines/dgds/music.h
A engines/dgds/parser.cpp
A engines/dgds/parser.h
A engines/dgds/resource.cpp
A engines/dgds/resource.h
A engines/dgds/sound.cpp
A engines/dgds/sound.h
diff --git a/engines/dgds/configure.engine b/engines/dgds/configure.engine
new file mode 100644
index 00000000000..ad2a46a9208
--- /dev/null
+++ b/engines/dgds/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine dgds "DGDS" yes
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
new file mode 100644
index 00000000000..308b69cfc7b
--- /dev/null
+++ b/engines/dgds/console.cpp
@@ -0,0 +1,130 @@
+/* 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/memstream.h"
+#include "dgds/console.h"
+#include "dgds/decompress.h"
+#include "dgds/dgds.h"
+#include "dgds/includes.h"
+#include "dgds/parser.h"
+#include "dgds/resource.h"
+#include "gui/debugger.h"
+
+namespace Dgds {
+
+Console::Console(DgdsEngine *vm) : _vm(vm) {
+ registerCmd("fileinfo", WRAP_METHOD(Console, cmdFileInfo));
+ registerCmd("filesearch", WRAP_METHOD(Console, cmdFileSearch));
+ registerCmd("filedump", WRAP_METHOD(Console, cmdFileDump));
+}
+
+bool Console::cmdFileInfo(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <file>\n", argv[0]);
+ return true;
+ }
+
+ Resource res = _vm->_resource->getResourceInfo(argv[1]);
+ debugPrintf("Resource volume: %d, position: %d, size: %d, checksum: %d\n", res.volume, res.pos, res.size, res.checksum);
+
+ return true;
+}
+
+bool Console::cmdFileSearch(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <file to search>\n", argv[0]);
+ return true;
+ }
+
+ ResourceList resources = _vm->_resource->_resources;
+ for (ResourceList::const_iterator i = resources.begin(), end = resources.end(); i != end; ++i) {
+ if (i->_key.contains(argv[1])) {
+ Resource res = i->_value;
+ debugPrintf("Resource: %s, volume: %d, position: %d, size: %d, checksum: %d\n", i->_key.c_str(), res.volume, res.pos, res.size, res.checksum);
+ }
+ }
+
+ return true;
+}
+
+bool Console::cmdFileDump(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: %s <file> <ignore patches> <unpack>\n", argv[0]);
+ return true;
+ }
+
+ Common::String fileName = argv[1];
+ bool ignorePatches = (argc > 2) && (!scumm_stricmp(argv[2], "true") || !strcmp(argv[2], "1"));
+ bool unpack = (argc > 3) && (!scumm_stricmp(argv[3], "true") || !strcmp(argv[3], "1"));
+ Common::SeekableReadStream *res = _vm->_resource->getResource(fileName, ignorePatches);
+ if (res == nullptr) {
+ debugPrintf("Resource not found\n");
+ return true;
+ }
+ int32 size = res->size();
+ byte *data;
+
+ if (!unpack) {
+ data = new byte[size];
+ res->read(data, size);
+ } else {
+ data = new byte[2000000]; // about 2MB, but maximum container size is around 1.5MB
+ byte *ptr = data;
+ const char *dot;
+ DGDS_EX ex = 0;
+ size = 0;
+
+ if ((dot = strrchr(fileName.c_str(), '.'))) {
+ ex = MKTAG24(dot[1], dot[2], dot[3]);
+ }
+
+ Decompressor *decompressor = new Decompressor();
+ DgdsParser ctx(*res, fileName.c_str());
+ DgdsChunk chunk;
+ while (chunk.readHeader(ctx)) {
+ Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, decompressor) : chunk.readStream(ctx);
+
+ memcpy(ptr, chunk._idStr, 4);
+ ptr += 4;
+
+ stream->read(ptr, stream->size());
+ ptr += stream->size();
+
+ size += 4 + stream->size();
+ }
+
+ delete decompressor;
+ }
+
+ delete res;
+
+ Common::DumpFile out;
+ out.open(fileName);
+ out.write(data, size);
+ out.flush();
+ out.close();
+ delete[] data;
+
+ return true;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/console.h b/engines/dgds/console.h
new file mode 100644
index 00000000000..f96c53ecc03
--- /dev/null
+++ b/engines/dgds/console.h
@@ -0,0 +1,46 @@
+/* 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 DGDS_CONSOLE_H
+#define DGDS_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Dgds {
+
+class DgdsEngine;
+
+class Console : public GUI::Debugger {
+public:
+ Console(DgdsEngine *vm);
+ ~Console() override {}
+
+private:
+ bool cmdFileInfo(int argc, const char **argv);
+ bool cmdFileSearch(int argc, const char **argv);
+ bool cmdFileDump(int argc, const char **argv);
+ DgdsEngine *_vm;
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_DGDS_H
diff --git a/engines/dgds/decompress.cpp b/engines/dgds/decompress.cpp
new file mode 100644
index 00000000000..e2582e264c3
--- /dev/null
+++ b/engines/dgds/decompress.cpp
@@ -0,0 +1,217 @@
+/* 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/debug.h"
+#include "common/util.h"
+#include "common/stream.h"
+
+#include "dgds/decompress.h"
+
+namespace Dgds {
+
+uint32 RleDecompressor::decompress(byte *dest, uint32 sz, Common::SeekableReadStream &input) {
+ uint32 left = sz;
+
+ uint32 lenR = 0, lenW = 0;
+ while (left > 0 && !input.eos()) {
+ lenR = input.readByte();
+
+ if (lenR == 128) {
+ lenW = 0;
+ } else if (lenR <= 127) {
+ lenW = MIN(lenR, left);
+ for (uint32 j = 0; j < lenW; j++) {
+ *dest++ = input.readByte();
+ }
+ for (; lenR > lenW; lenR--) {
+ input.readByte();
+ }
+ } else {
+ lenW = MIN(lenR & 0x7F, left);
+ byte val = input.readByte();
+ memset(dest, val, lenW);
+ dest += lenW;
+ }
+
+ left -= lenW;
+ }
+
+ return sz - left;
+}
+
+void LzwDecompressor::reset() {
+ memset(&_codeTable, 0, sizeof(_codeTable));
+
+ for (uint32 code = 0; code < 256; code++) {
+ _codeTable[code].len = 1;
+ _codeTable[code].str[0] = code;
+ }
+
+ _tableSize = 0x101;
+ _tableMax = 0x200;
+ _tableFull = false;
+
+ _codeSize = 9;
+ _codeLen = 0;
+
+ _cacheBits = 0;
+}
+
+uint32 LzwDecompressor::decompress(byte *dest, uint32 sz, Common::SeekableReadStream &input) {
+ _bitsData = 0;
+ _bitsSize = 0;
+
+ reset();
+
+ uint32 idx;
+ idx = 0;
+ _cacheBits = 0;
+
+ do {
+ uint32 code;
+
+ code = getCode(_codeSize, input);
+ if (code == 0xFFFFFFFF) break;
+
+ _cacheBits += _codeSize;
+ if (_cacheBits >= _codeSize * 8) {
+ _cacheBits -= _codeSize * 8;
+ }
+
+ if (code == 0x100) {
+ if (_cacheBits > 0)
+ getCode(_codeSize * 8 - _cacheBits, input);
+ reset();
+ } else {
+ if (code >= _tableSize && !_tableFull) {
+ _codeCur[_codeLen++] = _codeCur[0];
+
+ for (uint32 i = 0; i < _codeLen; i++) {
+ if (idx >= sz)
+ break;
+ dest[idx++] = _codeCur[i];
+ }
+ } else {
+ for (uint32 i = 0; i < _codeTable[code].len; i++) {
+ if (idx >= sz)
+ break;
+ dest[idx++] = _codeTable[code].str[i];
+ }
+
+ _codeCur[_codeLen++] = _codeTable[code].str[0];
+ }
+
+ if (_codeLen >= 2) {
+ if (!_tableFull) {
+ uint32 i;
+
+ if (_tableSize == _tableMax && _codeSize == 12) {
+ _tableFull = true;
+ i = _tableSize;
+ } else {
+ i = _tableSize++;
+ _cacheBits = 0;
+ }
+
+ if (_tableSize == _tableMax && _codeSize < 12) {
+ _codeSize++;
+ _tableMax <<= 1;
+ }
+
+ for (uint32 j=0; j<_codeLen; j++) {
+ _codeTable[i].str[j] = _codeCur[j];
+ _codeTable[i].len++;
+ }
+ }
+
+ for (uint32 i=0; i<_codeTable[code].len; i++)
+ _codeCur[i] = _codeTable[code].str[i];
+
+ _codeLen = _codeTable[code].len;
+ }
+ }
+ } while (idx < sz);
+
+ return idx;
+}
+
+uint32 LzwDecompressor::getCode(uint32 totalBits, Common::SeekableReadStream &input) {
+ uint32 result, numBits;
+ const byte bitMasks[9] = {
+ 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
+ };
+
+ numBits = totalBits;
+ result = 0;
+ while (numBits > 0) {
+ uint32 useBits;
+
+ if (input.pos() >= input.size()) return 0xFFFFFFFF;
+
+ if (_bitsSize == 0) {
+ _bitsSize = 8;
+ _bitsData = input.readByte();
+ }
+
+ useBits = numBits;
+ if (useBits > 8) useBits = 8;
+ if (useBits > _bitsSize) useBits = _bitsSize;
+
+ result |= (_bitsData & bitMasks[useBits]) << (totalBits - numBits);
+
+ numBits -= useBits;
+ _bitsSize -= useBits;
+ _bitsData >>= useBits;
+ }
+ return result;
+}
+
+Decompressor::Decompressor() {
+ _rleDecompressor = new RleDecompressor();
+ _lzwDecompressor = new LzwDecompressor();
+}
+
+Decompressor::~Decompressor() {
+ delete _rleDecompressor;
+ delete _lzwDecompressor;
+}
+
+void Decompressor::decompress(byte compression, byte *data, int uncompressedSize, Common::SeekableReadStream *input, int size) {
+ switch (compression) {
+ case 0x00:
+ input->read(data, size);
+ break;
+ case 0x01:
+ _rleDecompressor->decompress(data, uncompressedSize, *input);
+ break;
+ case 0x02:
+ _lzwDecompressor->decompress(data, uncompressedSize, *input);
+ break;
+ default:
+ input->skip(size);
+ debug("Unknown chunk compression: 0x%x", compression);
+ break;
+ }
+}
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/decompress.h b/engines/dgds/decompress.h
new file mode 100644
index 00000000000..76d1f0acf72
--- /dev/null
+++ b/engines/dgds/decompress.h
@@ -0,0 +1,80 @@
+/* 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 DGDS_DECOMPRESS_H
+#define DGDS_DECOMPRESS_H
+
+#include "common/scummsys.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Dgds {
+
+class RleDecompressor {
+public:
+ uint32 decompress(byte *dest, uint32 sz, Common::SeekableReadStream &input);
+};
+
+class LzwDecompressor {
+public:
+ uint32 decompress(byte *dest, uint32 sz, Common::SeekableReadStream &input);
+
+protected:
+ void reset();
+ uint32 getCode(uint32 totalBits, Common::SeekableReadStream &input);
+
+private:
+ struct {
+ byte str[256];
+ uint8 len;
+ } _codeTable[0x4000];
+
+ byte _codeCur[256];
+
+ uint32 _bitsData, _bitsSize;
+
+ uint32 _codeSize, _codeLen, _cacheBits;
+
+ uint32 _tableSize, _tableMax;
+ bool _tableFull;
+};
+
+class Decompressor {
+public:
+ Decompressor();
+ virtual ~Decompressor();
+
+ void decompress(byte compression, byte *data, int uncompressedSize, Common::SeekableReadStream *input, int size);
+
+private:
+ RleDecompressor *_rleDecompressor;
+ LzwDecompressor *_lzwDecompressor;
+
+ const char *_compressionDescr[3] = {"None", "RLE", "LZW"};
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_DECOMPRESS_H
+
diff --git a/engines/dgds/detection.cpp b/engines/dgds/detection.cpp
new file mode 100644
index 00000000000..10d6db058b5
--- /dev/null
+++ b/engines/dgds/detection.cpp
@@ -0,0 +1,59 @@
+/* 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 "base/plugins.h"
+#include "engines/advancedDetector.h"
+//#include "common/translation.h"
+
+static const PlainGameDescriptor dgdsGames[] = {
+ {"dgds", "Dynamix DGDS game"},
+ {"rise", "Rise of the Dragon"},
+ {"china", "Heart of China"},
+ {"beamish", "The Adventures of Willy Beamish"},
+
+ {0, 0}
+};
+
+#include "dgds/detection_tables.h"
+
+class DgdsMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
+public:
+ DgdsMetaEngineDetection() :
+ AdvancedMetaEngineDetection(Dgds::gameDescriptions, dgdsGames) {
+ _guiOptions = GUIO1(GUIO_NONE);
+ }
+
+ const char* getEngineId() const override {
+ return "dgds";
+ }
+
+ const char *getName() const override {
+ return "DGDS";
+ }
+
+ const char *getOriginalCopyright() const override {
+ return "Dynamix Game Development System (C) Dynamix";
+ }
+
+};
+
+REGISTER_PLUGIN_STATIC(DGDS_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, DgdsMetaEngineDetection);
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
new file mode 100644
index 00000000000..e74c6645776
--- /dev/null
+++ b/engines/dgds/detection_tables.h
@@ -0,0 +1,165 @@
+/* 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.
+ *
+ */
+
+namespace Dgds {
+
+static const ADGameDescription gameDescriptions[] = {
+ // Rise of the Dragon (PC) : GOG
+ {
+ "rise",
+ 0,
+ {
+ {"volume.vga", 0, "2d08870dbfeff4f5e06061dd277d666d", 8992},
+ {"volume.001", 0, "5210b0a77f89bfa2544970d56b23f9e4", 1153936},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Rise of the Dragon (PC)
+ {
+ "rise",
+ 0,
+ {
+ {"volume.vga", 0, "b0583c199614ed1c161a25398c5c7fba", 7823},
+ {"volume.001", 0, "3483f61b9bf0023c00a7fc1b568a54fa", 769811},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Rise of the Dragon (Amiga)
+ {
+ "rise",
+ 0,
+ {
+ {"volume.rmf", 0, "44cd1ffdfeb385dcfcd60563e1036167", 8972},
+ {"volume.001", 0, "71b0b4a623166dc4aeba9bd19d71697f", 519385},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Rise of the Dragon (Macintosh)
+ {
+ "rise",
+ 0,
+ {
+ {"volume.rmf", 0, "fe8d0b0f68bb4068793f2ea438d28d97", 7079},
+ {"volume.001", 0, "90b30eb275d468e21d308ca836a3d3b8", 1403672},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Adventures of Willy Beamish (PC)
+ {
+ "beamish",
+ 0,
+ {
+ {"volume.rmf", 0, "c2be5cd4693dfcdbe45dd0e74dd5306d", 9896},
+ {"volume.001", 0, "7e9f3b0b7a5ec9989d3149f5e1f011a9", 1263007},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Adventures of Willy Beamish (Macintosh)
+ {
+ "beamish",
+ 0,
+ {
+ {"volume.rmf", 0, "a8cd2d95b9c972fd33bf22b6de0b50c8", 9832},
+ {"volume.001", 0, "0849203c8da5f2b7868e11a77a537ee5", 1359359},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Heart of China (PC) : GOG
+ {
+ "china",
+ 0,
+ {
+ {"volume.rmf", 0, "94402b65f07606a2fb5591f9dc514c19", 10008},
+ {"volume.001", 0, "26354d54b9f2e220620b0c1d31ed5a83", 1096322},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Heart of China (PC)
+ {
+ "china",
+ 0,
+ {
+ {"volume.rmf", 0, "677b91bc6961824f1997c187292f174e", 9791},
+ {"volume.001", 0, "3efe89a72940e85d2137162609b8b883", 851843},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Heart of China (Macintosh)
+ {
+ "china",
+ 0,
+ {
+ {"volume.rmf", 0, "6bc1730f371c7330333bed4c66fe7511", 9918},
+ {"volume.001", 0, "bca16136f0fd36d25b1b1ba1870aa97f", 1240128},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
new file mode 100644
index 00000000000..7ee29118244
--- /dev/null
+++ b/engines/dgds/dgds.cpp
@@ -0,0 +1,1028 @@
+/* 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/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/debug.h"
+#include "common/endian.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/platform.h"
+#include "common/str-array.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/system.h"
+
+#include "common/iff_container.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/aiff.h"
+#include "audio/decoders/raw.h"
+#include "audio/mixer.h"
+
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+#include "engines/advancedDetector.h"
+#include "engines/util.h"
+
+#include "dgds/console.h"
+#include "dgds/decompress.h"
+#include "dgds/detection_tables.h"
+#include "dgds/dgds.h"
+#include "dgds/font.h"
+#include "dgds/image.h"
+#include "dgds/includes.h"
+#include "dgds/movies.h"
+#include "dgds/music.h"
+#include "dgds/parser.h"
+#include "dgds/resource.h"
+#include "dgds/sound.h"
+
+namespace Dgds {
+
+Graphics::ManagedSurface resData;
+Graphics::Surface bottomBuffer;
+Graphics::Surface topBuffer;
+
+Common::MemoryReadStream *soundData;
+byte *musicData;
+uint32 musicSize;
+
+Common::StringArray _bubbles;
+Common::StringArray BMPs;
+
+PFont *_fntP;
+FFont *_fntF;
+
+#define DGDS_FILENAME_MAX 12
+
+Common::SeekableReadStream *ttm;
+char ttmName[DGDS_FILENAME_MAX + 1];
+
+Common::SeekableReadStream *ads;
+char adsName[DGDS_FILENAME_MAX + 1];
+
+DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
+ : Engine(syst) {
+ syncSoundSettings();
+
+ _platform = gameDesc->platform;
+
+ if (!strcmp(gameDesc->gameId, "rise"))
+ _gameId = GID_DRAGON;
+ else if (!strcmp(gameDesc->gameId, "china"))
+ _gameId = GID_CHINA;
+ else if (!strcmp(gameDesc->gameId, "beamish"))
+ _gameId = GID_BEAMISH;
+
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "patches");
+}
+
+DgdsEngine::~DgdsEngine() {
+ DebugMan.clearAllDebugChannels();
+
+ delete _image;
+ delete _decompressor;
+ delete _resource;
+}
+
+void readStrings(Common::SeekableReadStream *stream) {
+ uint16 count = stream->readUint16LE();
+ debug(" %u:", count);
+
+ for (uint16 k = 0; k < count; k++) {
+ byte ch;
+ uint16 idx;
+ idx = stream->readUint16LE();
+
+ Common::String str;
+ while ((ch = stream->readByte()))
+ str += ch;
+ debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
+ }
+}
+
+struct Tag {
+ uint16 id;
+ Common::String tag;
+};
+
+Common::HashMap<uint16, Common::String> *readTags(Common::SeekableReadStream *stream) {
+ Common::HashMap<uint16, Common::String> *tags = new Common::HashMap<uint16, Common::String>;
+ uint16 count = stream->readUint16LE();
+ debug(" %u:", count);
+
+ for (uint16 i = 0; i < count; i++) {
+ Common::String string;
+ byte c = 0;
+ uint16 idx = stream->readUint16LE();
+ while (c = stream->readByte())
+ string += c;
+ debug(" %2u: %2u, \"%s\"", i, idx, string.c_str());
+
+ (*tags)[idx] = string;
+ }
+
+ return tags;
+}
+
+void readSDS(Common::SeekableReadStream *stream) {
+ uint32 mark;
+
+ // Debug
+ /*uint32 pos = stream->pos();
+ byte *tmp = new byte[stream->size()];
+ stream->read(tmp, stream->size());
+ Common::hexdump(tmp, stream->size());
+ stream->seek(pos, SEEK_SET);*/
+
+ mark = stream->readUint32LE();
+ debug(" 0x%X", mark);
+
+ char version[7];
+ stream->read(version, sizeof(version));
+ debug(" %s", version);
+
+ uint16 idx;
+ idx = stream->readUint16LE();
+ debug(" S%d.SDS", idx);
+
+ // gross hack to grep the strings.
+ _bubbles.clear();
+
+ bool inside = false;
+ Common::String txt;
+ while (1) {
+ char buf[4];
+ stream->read(buf, sizeof(buf));
+ if (stream->pos() >= stream->size())
+ break;
+ if (Common::isPrint(buf[0]) && Common::isPrint(buf[1]) && Common::isPrint(buf[2]) && Common::isPrint(buf[3])) {
+ inside = true;
+ }
+ stream->seek(-3, SEEK_CUR);
+
+ if (inside) {
+ if (buf[0] == '\0') {
+ // here's where we do a clever thing. we want Pascal like strings.
+ uint16 pos = txt.size() + 1;
+ stream->seek(-pos - 2, SEEK_CUR);
+ uint16 len = stream->readUint16LE();
+ stream->seek(pos, SEEK_CUR);
+
+ // gotcha!
+ if (len == pos) {
+ //if (resource == 0)
+ _bubbles.push_back(txt);
+ debug(" \"%s\"", txt.c_str());
+ }
+ // let's hope the string wasn't shorter than 4 chars...
+ txt.clear();
+ inside = false;
+ } else {
+ txt += buf[0];
+ }
+ }
+ }
+#if 0
+ idx = stream->readUint16LE();
+ debug(" %d", idx);
+
+ idx = stream->readUint16LE();
+ debug(" %d", idx);
+
+ uint16 count;
+ while (1) {
+ uint16 code;
+ code = stream->readUint16LE();
+ count = stream->readUint16LE();
+ idx = stream->readUint16LE();
+
+ debugN("\tOP: 0x%8.8x %2u %2u\n", code, count, idx);
+
+ uint16 pitch = (count+1)&(~1); // align to word.
+ if ((stream->pos()+pitch) >= stream->size()) break;
+
+ if (code == 0 && count == 0) break;
+
+ stream->skip(pitch);
+ }
+
+ Common::String sval;
+ byte ch;
+
+ do {
+ ch = stream->readByte();
+ sval += ch;
+ } while (ch != 0);
+
+ debug("\"%s\"", sval.c_str());
+#endif
+#if 0
+ // probe for the .ADS name. are these shorts?
+ uint count;
+ count = 0;
+ while (1) {
+ uint16 x;
+ x = stream->readUint16LE();
+ if ((x & 0xFF00) != 0)
+ break;
+ debug(" %u: %u|0x%4.4X", count++, x, x);
+ }
+ stream->seek(-2, SEEK_CUR);
+
+ // .ADS name.
+ Common::String ads;
+ byte ch;
+ while ((ch = stream->readByte()))
+ ads += ch;
+ debug(" %s", ads.c_str());
+
+ stream->hexdump(6);
+ stream->skip(6);
+
+ int w, h;
+
+ w = stream->readSint16LE();
+ h = stream->readSint16LE();
+ debug(" %dx%d", w, h);
+
+ // probe for the strings. are these shorts?
+ count = 0;
+ while (1) {
+ uint16 x;
+ x = stream->readUint16LE();
+ if ((x & 0xFF00) != 0)
+ break;
+ if (stream->pos() >= stream->size()) break;
+ debug(" %u: %u|0x%4.4X", count++, x, x);
+ }
+ stream->seek(-4, SEEK_CUR);
+ // here we are.
+
+ uint16 len;
+ len = stream->readSint16LE();
+ Common::String txt;
+ for (uint16 j=0; j<len; j++) {
+ ch = stream->readByte();
+ txt += ch;
+ debug(" \"%s\"", txt.c_str());
+ }
+#endif
+}
+
+void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor) {
+ const char *dot;
+ DGDS_EX ex = 0;
+
+ if ((dot = strrchr(name, '.'))) {
+ ex = MKTAG24(dot[1], dot[2], dot[3]);
+ }
+
+ uint parent = 0;
+
+ DgdsParser ctx(file, name);
+ if (isFlatfile(platform, ex)) {
+ uint16 tcount;
+ uint16 *tw, *th;
+ uint32 *toffset;
+ Common::String line;
+
+ switch (ex) {
+ case EX_RST: {
+ uint32 mark;
+
+ mark = file.readUint32LE();
+ debug(" 0x%X", mark);
+
+ // elaborate guesswork. who knows it might be true.
+ while (!file.eos()) {
+ uint16 idx;
+ uint16 vals[7];
+
+ idx = file.readUint16LE();
+ debugN(" #%u:\t", idx);
+ if (idx == 0)
+ break;
+ for (int i = 0; i < ARRAYSIZE(vals); i++) {
+ vals[i] = file.readUint16LE();
+ if (i != 0)
+ debugN(", ");
+ debugN("%u", vals[i]);
+ }
+ debug(".");
+ }
+ debug("-");
+
+ while (!file.eos()) {
+ uint16 idx;
+ uint16 vals[2];
+ idx = file.readUint16LE();
+ debugN(" #%u:\t", idx);
+ for (int i = 0; i < ARRAYSIZE(vals); i++) {
+ vals[i] = file.readUint16LE();
+ if (i != 0)
+ debugN(", ");
+ debugN("%u", vals[i]);
+ }
+ debug(".");
+ if (idx == 0)
+ break;
+ }
+ debug("-");
+ } break;
+ case EX_SCR: {
+ /* Unknown image format (Amiga). */
+ byte tag[5];
+ file.read(tag, 4); /* maybe */
+ tag[4] = '\0';
+
+ uint16 pitch, planes;
+ pitch = file.readUint16BE(); /* always 200 (320x200 screen). */
+ planes = file.readUint16BE(); /* always 5 (32 color). */
+
+ debug(" \"%s\" pitch:%u bpp:%u size: %u bytes",
+ tag, pitch, planes,
+ SCREEN_WIDTH * planes * SCREEN_HEIGHT / 8);
+ } break;
+ case EX_BMP: {
+ /* Unknown image format (Amiga). */
+ tcount = file.readUint16BE();
+ tw = new uint16[tcount];
+ th = new uint16[tcount];
+
+ uint32 packedSize, unpackedSize;
+ unpackedSize = file.readUint32BE();
+ debug(" [%u] %u =", tcount, unpackedSize);
+
+ uint32 sz = 0;
+ toffset = new uint32[tcount];
+ for (uint16 k = 0; k < tcount; k++) {
+ tw[k] = file.readUint16BE();
+ th[k] = file.readUint16BE();
+ debug(" %ux%u ~@%u", tw[k], th[k], sz);
+
+ toffset[k] = sz;
+ sz += uint(tw[k] + 15) / 16 * th[k] * 5;
+ }
+ debug(" ~= [%u]", sz);
+
+ /* this is a wild guess. */
+ byte version[13];
+ file.read(version, 12);
+ version[12] = '\0';
+ debug(" %s", version);
+
+ unpackedSize = file.readUint32BE();
+ packedSize = file.readUint32BE();
+ debug(" %u -> %u",
+ packedSize, unpackedSize);
+ } break;
+ case EX_INS: {
+ /* AIFF sound sample (Amiga). */
+ byte *dest = new byte[file.size()];
+ file.read(dest, file.size());
+ soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
+ } break;
+ case EX_SNG:
+ /* IFF-SMUS music (Amiga). */
+ break;
+ case EX_AMG:
+ /* (Amiga). */
+ line = file.readLine();
+ while (!file.eos() && !line.empty()) {
+ debug(" \"%s\"", line.c_str());
+ line = file.readLine();
+ }
+ break;
+ case EX_VIN:
+ line = file.readLine();
+ while (!file.eos()) {
+ if (!line.empty())
+ debug(" \"%s\"", line.c_str());
+ line = file.readLine();
+ }
+ break;
+ default:
+ break;
+ }
+ int leftover = file.size() - file.pos();
+ file.hexdump(leftover);
+ file.skip(leftover);
+ } else {
+ uint16 tcount;
+ uint16 scount;
+ uint16 *tw = 0, *th = 0;
+ uint32 *toffset = 0;
+
+ uint16 *mtx;
+ uint16 mw, mh;
+
+ scount = 0;
+
+ DgdsChunk chunk;
+ while (chunk.readHeader(ctx)) {
+ if (chunk.container) {
+ parent = chunk._id;
+ continue;
+ }
+
+ Common::SeekableReadStream *stream;
+
+ bool packed = chunk.isPacked(ex);
+ stream = packed ? chunk.decodeStream(ctx, decompressor) : chunk.readStream(ctx);
+
+ switch (ex) {
+ case EX_TDS:
+ /* Heart of China. */
+ if (chunk.isSection(ID_THD)) {
+ uint32 mark;
+
+ mark = stream->readUint32LE();
+ debug(" 0x%X", mark);
+
+ char version[7];
+ stream->read(version, sizeof(version));
+ debug(" \"%s\"", version);
+
+ byte ch;
+ Common::String bmpName;
+ while ((ch = stream->readByte()))
+ bmpName += ch;
+ debug(" \"%s\"", bmpName.c_str());
+
+ Common::String personName;
+ while ((ch = stream->readByte()))
+ personName += ch;
+ debug(" \"%s\"", personName.c_str());
+ }
+ break;
+ case EX_DDS:
+ /* Heart of China. */
+ if (chunk.isSection(ID_DDS)) {
+ uint32 mark;
+
+ mark = stream->readUint32LE();
+ debug(" 0x%X", mark);
+
+ char version[7];
+ stream->read(version, sizeof(version));
+ debug(" \"%s\"", version);
+
+ byte ch;
+ Common::String tag;
+ while ((ch = stream->readByte()))
+ tag += ch;
+ debug(" \"%s\"", tag.c_str());
+ }
+ break;
+ case EX_SDS:
+ if (chunk.isSection(ID_SDS)) {
+ readSDS(stream);
+ }
+ break;
+ case EX_TTM:
+ if (chunk.isSection(ID_VER)) {
+ char version[5];
+
+ stream->read(version, sizeof(version));
+ debug(" %s", version);
+ } else if (chunk.isSection(ID_PAG)) {
+ uint16 pages;
+ pages = stream->readUint16LE();
+ debug(" %u", pages);
+ } else if (chunk.isSection(ID_TT3)) {
+ if (resource == 0) {
+ uint32 size = stream->size();
+ byte *dest = new byte[size];
+ stream->read(dest, size);
+ ttm = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
+ Common::strlcpy(ttmName, name, sizeof(ttmName));
+ } else {
+ while (!stream->eos()) {
+ uint16 code;
+ byte count;
+ uint op;
+
+ code = stream->readUint16LE();
+ count = code & 0x000F;
+ op = code & 0xFFF0;
+
+ debugN("\tOP: 0x%4.4x %2u ", op, count);
+ if (count == 0x0F) {
+ Common::String sval;
+ byte ch[2];
+
+ do {
+ ch[0] = stream->readByte();
+ ch[1] = stream->readByte();
+ sval += ch[0];
+ sval += ch[1];
+ } while (ch[0] != 0 && ch[1] != 0);
+
+ debugN("\"%s\"", sval.c_str());
+ } else {
+ int ival;
+
+ for (byte k = 0; k < count; k++) {
+ ival = stream->readSint16LE();
+
+ if (k == 0)
+ debugN("%d", ival);
+ else
+ debugN(", %d", ival);
+ }
+ }
+ debug(" ");
+ }
+ }
+ } else if (chunk.isSection(ID_TAG)) {
+ uint16 count;
+
+ count = stream->readUint16LE();
+ debug(" %u", count);
+ // something fishy here. the first two entries sometimes are an empty string or non-text junk.
+ // most of the time entries have text (sometimes with garbled characters).
+ // this parser is likely not ok. but the NUL count seems to be ok.
+ for (uint16 k = 0; k < count; k++) {
+ byte ch;
+ uint16 idx;
+ Common::String str;
+
+ idx = stream->readUint16LE();
+ while ((ch = stream->readByte()))
+ str += ch;
+ debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
+ }
+ }
+ break;
+ case EX_GDS:
+ if (chunk.isSection(ID_INF)) {
+ //stream->hexdump(stream->size());
+ uint32 mark;
+ char version[7];
+
+ mark = stream->readUint32LE();
+ debug(" 0x%X", mark);
+
+ stream->read(version, sizeof(version));
+ debug(" \"%s\"", version);
+
+ } else if (chunk.isSection(ID_SDS)) {
+ //stream->hexdump(stream->size());
+
+ uint32 x;
+ x = stream->readUint32LE();
+ debug(" %u", x);
+
+ while (!stream->eos()) {
+ uint16 x2;
+ do {
+ do {
+ x2 = stream->readUint16LE();
+ debugN(" %u: %u|%u, ", x2, (x2 & 0xF), (x2 >> 4));
+ if (stream->pos() >= stream->size())
+ break;
+ } while ((x2 & 0x80) != 0x80);
+ debug("-");
+ if (stream->pos() >= stream->size())
+ break;
+ } while ((x2 & 0xF0) != 0xF0);
+ }
+ }
+ break;
+ case EX_ADS:
+ case EX_ADL:
+ case EX_ADH:
+ if (chunk.isSection(ID_VER)) {
+ char version[5];
+
+ stream->read(version, sizeof(version));
+ debug(" %s", version);
+ } else if (chunk.isSection(ID_RES)) {
+ debug("res0");
+ if (resource == 0) {
+ readTags(stream);
+ } else {
+ readStrings(stream);
+ }
+ } else if (chunk.isSection(ID_SCR)) {
+ if (resource == 0) {
+ uint32 size = stream->size();
+ byte *dest = new byte[size];
+ stream->read(dest, size);
+ ads = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
+ Common::strlcpy(adsName, name, sizeof(adsName));
+ } else {
+ /* this is either a script, or a property sheet, i can't decide. */
+ while (!stream->eos()) {
+ uint16 code;
+ code = stream->readUint16LE();
+ if ((code & 0xFF00) == 0) {
+ uint16 tag = (code & 0xFF);
+ debug(" PUSH %d (0x%4.4X)", tag, tag); // ADS:TAG or TTM:TAG id.
+ } else {
+ const char *desc = "";
+ switch (code) {
+ case 0xF010:
+ case 0xF200:
+ case 0xFDA8:
+ case 0xFE98:
+ case 0xFF88:
+ case 0xFF10:
+ debug(" INT 0x%4.4X\t;", code);
+ continue;
+
+ case 0xFFFF:
+ debug(" INT 0x%4.4X\t; return", code);
+ debug("-");
+ continue;
+
+ case 0x0190:
+ case 0x1070:
+ case 0x1340:
+ case 0x1360:
+ case 0x1370:
+ case 0x1420:
+ case 0x1430:
+ case 0x1500:
+ case 0x1520:
+ case 0x2000:
+ case 0x2010:
+ case 0x2020:
+ case 0x3010:
+ case 0x3020:
+ case 0x30FF:
+ case 0x4000:
+ case 0x4010:
+ desc = "?";
+ break;
+
+ case 0x1330:
+ break;
+ case 0x1350:
+ desc = "? (res,rtag)";
+ break;
+
+ case 0x1510:
+ desc = "? ()";
+ break;
+ case 0x2005:
+ desc = "? (res,rtag,?,?)";
+ break;
+
+ default:
+ break;
+ }
+ debug(" OP 0x%4.4X\t;%s", code, desc);
+ }
+ }
+ assert(stream->size() == stream->pos());
+ //stream->hexdump(stream->size());
+ }
+ } else if (chunk.isSection(ID_TAG)) {
+ readStrings(stream);
+ }
+ break;
+ case EX_REQ:
+ if (parent == ID_TAG) {
+ if (chunk.isSection(ID_REQ)) {
+ readStrings(stream);
+ } else if (chunk.isSection(ID_GAD)) {
+ readStrings(stream);
+ }
+ } else if (parent == ID_REQ) {
+ if (chunk.isSection(ID_REQ)) {
+ } else if (chunk.isSection(ID_GAD)) {
+ }
+ }
+ break;
+ case EX_SNG:
+ /* DOS. */
+ if (chunk.isSection(ID_SNG)) {
+ musicSize = stream->size();
+
+ debug(" %2u: %u bytes", scount, musicSize);
+
+ musicData = (uint8 *)malloc(musicSize);
+ stream->read(musicData, musicSize);
+ scount++;
+ } else if (chunk.isSection(ID_INF)) {
+ uint32 count;
+ count = stream->size() / 2;
+ debug(" [%u]", count);
+ for (uint32 k = 0; k < count; k++) {
+ uint16 idx;
+ idx = stream->readUint16LE();
+ debug(" %2u: %u", k, idx);
+ }
+ }
+ break;
+ case EX_SX:
+ /* Macintosh. */
+ if (chunk.isSection(ID_INF)) {
+ uint16 type, count;
+
+ type = stream->readUint16LE();
+ count = stream->readUint16LE();
+
+ debug(" %u [%u]:", type, count);
+ for (uint16 k = 0; k < count; k++) {
+ uint16 idx;
+ idx = stream->readUint16LE();
+ debug(" %2u: %u", k, idx);
+ }
+ } else if (chunk.isSection(ID_TAG)) {
+ readStrings(stream);
+ } else if (chunk.isSection(ID_FNM)) {
+ readStrings(stream);
+ } else if (chunk.isSection(ID_DAT)) {
+ uint16 idx, type;
+ byte compression;
+ uint32 unpackSize;
+ idx = stream->readUint16LE();
+ type = stream->readUint16LE();
+ compression = stream->readByte();
+ unpackSize = stream->readUint32LE();
+ //debug(" #%2u: (0x%X?) %s %u", idx, type, compressionDescr[compression], unpackSize);
+
+ musicSize = unpackSize;
+ debug(" %2u: %u bytes", scount, musicSize);
+
+ musicData = (uint8 *)malloc(musicSize);
+ decompressor->decompress(compression, musicData, musicSize, stream, stream->size() - stream->pos());
+
+ scount++;
+ }
+ break;
+ case EX_PAL:
+ /* DOS & Macintosh. */
+ // Handled in Image::setPalette
+ error("Should not be here");
+ break;
+ case EX_FNT:
+ if (resource == 0) {
+ if (chunk.isSection(ID_FNT)) {
+ byte magic = stream->readByte();
+ stream->seek(-1, SEEK_CUR);
+ debug(" magic: %u", magic);
+
+ if (magic != 0xFF)
+ _fntF = FFont::load(*stream);
+ else
+ _fntP = PFont::load(*stream, decompressor);
+ }
+ }
+ break;
+ case EX_SCR:
+ // Handled in Image::loadScreen
+ error("Should not be here");
+ break;
+ case EX_BMP:
+ // Handled in Image::loadBitmap
+ error("Should not be here");
+ break;
+ default:
+ break;
+ }
+ int leftover = stream->size() - stream->pos();
+ //stream->hexdump(leftover);
+ stream->skip(leftover);
+
+ delete stream;
+ }
+ }
+
+ if (ex == EX_BMP) {
+ BMPs.push_back(Common::String(name));
+ debug("BMPs: %s", name);
+ }
+
+ debug(" [%u:%u] --", file.pos(), ctx.bytesRead);
+}
+
+void DgdsEngine::parseFile(Common::String filename, int resource) {
+ //filename.toLowercase();
+
+ if (filename.hasSuffix(".SNG") || filename.hasSuffix(".sng")) // TODO: Mac sound
+ return;
+
+ Common::SeekableReadStream *stream = _resource->getResource(filename);
+ parseFileInner(_platform, *stream, filename.c_str(), resource, _decompressor);
+ delete stream;
+}
+
+int delay = 0;
+
+struct Channel {
+ Audio::AudioStream *stream;
+ Audio::SoundHandle handle;
+ byte volume;
+};
+
+struct Channel _channels[2];
+
+void DgdsEngine::playSfx(const char *fileName, byte channel, byte volume) {
+ parseFile(fileName);
+ if (soundData) {
+ Channel *ch = &_channels[channel];
+ Audio::AudioStream *input = Audio::makeAIFFStream(soundData, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
+ soundData = 0;
+ }
+}
+
+void DgdsEngine::stopSfx(byte channel) {
+ if (_mixer->isSoundHandleActive(_channels[channel].handle)) {
+ _mixer->stopHandle(_channels[channel].handle);
+ _channels[channel].stream = 0;
+ }
+}
+
+bool DgdsEngine::playPCM(byte *data, uint32 size) {
+ _mixer->stopAll();
+
+ if (!data)
+ return false;
+
+ byte numParts;
+ byte *trackPtr[0xFF];
+ uint16 trackSiz[0xFF];
+ numParts = loadSndTrack(DIGITAL_PCM, trackPtr, trackSiz, data, size);
+ if (numParts == 0)
+ return false;
+
+ for (byte part = 0; part < numParts; part++) {
+ byte *ptr = trackPtr[part];
+
+ bool digital_pcm = false;
+ if (READ_LE_UINT16(ptr) == 0x00FE) {
+ digital_pcm = true;
+ }
+ ptr += 2;
+
+ if (!digital_pcm)
+ continue;
+
+ uint16 rate, length, first, last;
+ rate = READ_LE_UINT16(ptr);
+
+ length = READ_LE_UINT16(ptr + 2);
+ first = READ_LE_UINT16(ptr + 4);
+ last = READ_LE_UINT16(ptr + 6);
+ ptr += 8;
+
+ ptr += first;
+ debug(" - Digital PCM: %u Hz, [%u]=%u:%u",
+ rate, length, first, last);
+ trackPtr[part] = ptr;
+ trackSiz[part] = length;
+
+ Channel *ch = &_channels[part];
+ byte volume = 255;
+ Audio::AudioStream *input = Audio::makeRawStream(trackPtr[part], trackSiz[part],
+ rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
+ }
+ return true;
+}
+
+void DgdsEngine::playMusic(const char *fileName) {
+ //stopMusic();
+
+ parseFile(fileName);
+ if (musicData) {
+ uint32 tracks;
+ tracks = availableSndTracks(musicData, musicSize);
+ if ((tracks & TRACK_MT32))
+ _midiPlayer->play(musicData, musicSize);
+ if ((tracks & DIGITAL_PCM))
+ playPCM(musicData, musicSize);
+ }
+}
+
+Common::Error DgdsEngine::run() {
+ initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ soundData = 0;
+ musicData = 0;
+
+ _console = new Console(this);
+ _resource = new ResourceManager();
+ _decompressor = new Decompressor();
+ _image = new Image(_resource, _decompressor);
+ _midiPlayer = new DgdsMidiPlayer();
+ assert(_midiPlayer);
+
+ setDebugger(_console);
+
+ bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+
+ debug("DgdsEngine::init");
+
+ g_system->fillScreen(0);
+
+ Common::EventManager *eventMan = g_system->getEventManager();
+ Common::Event ev;
+
+ ADSInterpreter interpADS(this);
+ TTMInterpreter interpTTM(this);
+
+ TTMState title1State, title2State;
+ ADSState introState;
+
+ if (getGameId() == GID_DRAGON) {
+ TTMData title1Data, title2Data;
+ ADSData introData;
+ interpTTM.load("TITLE1.TTM", &title1Data);
+ interpTTM.load("TITLE2.TTM", &title2Data);
+ interpADS.load("INTRO.ADS", &introData);
+
+ interpTTM.init(&title1State, &title1Data);
+ interpTTM.init(&title2State, &title2Data);
+ interpADS.init(&introState, &introData);
+
+ parseFile("DRAGON.FNT");
+ parseFile("S55.SDS");
+ } else if (getGameId() == GID_CHINA) {
+ ADSData introData;
+ interpADS.load("TITLE.ADS", &introData);
+
+ interpADS.init(&introState, &introData);
+
+ parseFile("HOC.FNT");
+ } else if (getGameId() == GID_BEAMISH) {
+ ADSData introData;
+ interpADS.load("TITLE.ADS", &introData);
+
+ interpADS.init(&introState, &introData);
+
+ //parseFile("HOC.FNT");
+ }
+
+ _console->attach();
+
+ while (!shouldQuit()) {
+ if (eventMan->pollEvent(ev)) {
+ if (ev.type == Common::EVENT_KEYDOWN) {
+ switch (ev.kbd.keycode) {
+ /*
+ case Common::KEYCODE_TAB: sid++; break;
+ case Common::KEYCODE_UP: if (id > 0) id--; bk=0; break;
+ case Common::KEYCODE_DOWN: if (id < BMPs.size()) id++; bk=0; break;
+ case Common::KEYCODE_LEFT: if (bk > 0) bk--; break;
+ case Common::KEYCODE_RIGHT: if (bk < (_tcount-1)) bk++; break;
+ */
+ case Common::KEYCODE_ESCAPE:
+ return Common::kNoError;
+ default:
+ break;
+ }
+ }
+ }
+
+ // browse(_platform, _rmfName, this);
+
+ if (getGameId() == GID_DRAGON) {
+ if (!interpTTM.run(&title1State))
+ if (!interpTTM.run(&title2State))
+ if (!interpADS.run(&introState))
+ return Common::kNoError;
+ } else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
+ if (!interpADS.run(&introState))
+ return Common::kNoError;
+ }
+
+ g_system->delayMillis(40);
+ }
+ return Common::kNoError;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
new file mode 100644
index 00000000000..1ae925bd0c7
--- /dev/null
+++ b/engines/dgds/dgds.h
@@ -0,0 +1,86 @@
+/* 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 DGDS_DGDS_H
+#define DGDS_DGDS_H
+
+#include "common/error.h"
+#include "common/platform.h"
+
+#include "engines/advancedDetector.h"
+#include "engines/engine.h"
+
+#include "gui/debugger.h"
+
+namespace Dgds {
+
+class Console;
+class ResourceManager;
+class Decompressor;
+class Image;
+
+class DgdsMidiPlayer;
+struct DgdsADS;
+
+enum DgdsGameId {
+ GID_DRAGON,
+ GID_CHINA,
+ GID_BEAMISH
+};
+
+class DgdsEngine : public Engine {
+public:
+ Common::Platform _platform;
+
+private:
+ Console *_console;
+ DgdsMidiPlayer *_midiPlayer;
+
+protected:
+ virtual Common::Error run();
+
+public:
+ DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ virtual ~DgdsEngine();
+
+ DgdsGameId getGameId() { return _gameId; }
+
+ void playSfx(const char* fileName, byte channel, byte volume);
+ void stopSfx(byte channel);
+
+ bool playPCM(byte *data, uint32 size);
+ void playMusic(const char* fileName);
+
+ void parseFile(Common::String filename, int resource = 0);
+
+ ResourceManager *_resource;
+ Decompressor *_decompressor;
+ Image *_image;
+
+ DgdsGameId _gameId;
+};
+
+//void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource);
+
+} // End of namespace Dgds
+
+#endif // DGDS_DGDS_H
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
new file mode 100644
index 00000000000..f8295c4960c
--- /dev/null
+++ b/engines/dgds/font.cpp
@@ -0,0 +1,152 @@
+/* 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 "graphics/font.h"
+#include "graphics/surface.h"
+#include "common/stream.h"
+
+#include "dgds/decompress.h"
+#include "dgds/font.h"
+
+namespace Dgds {
+
+bool Font::hasChar(byte chr) const {
+ return (chr >= _start && chr <= (_start+_count));
+}
+
+static inline uint isSet(byte *set, uint bit) {
+ return (set[(bit >> 3)] & (1 << (bit & 7)));
+}
+
+void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const {
+ const Common::Rect destRect(x, y, x+_w, y+_h);
+ Common::Rect clippedDestRect(0, 0, dst->w, dst->h);
+ clippedDestRect.clip(destRect);
+
+ const Common::Point croppedBy(clippedDestRect.left-destRect.left, clippedDestRect.top-destRect.top);
+
+ const int rows = clippedDestRect.height();
+ const int columns = clippedDestRect.width();
+
+ int idx = bit + croppedBy.x;
+ byte *src = _data + pos + croppedBy.y;
+ byte *ptr = (byte *)dst->getBasePtr(clippedDestRect.left, clippedDestRect.top);
+ for (int i=0; i<rows; ++i) {
+ for (int j=0; j<columns; ++j) {
+ if (isSet(src, idx+_w-1-j))
+ ptr[j] = color;
+ }
+ ptr += dst->pitch;
+ src++;
+ }
+}
+
+void FFont::mapChar(byte chr, int& pos, int& bit) const {
+ pos = (chr-_start)*_h;
+ bit = 8-_w;
+}
+
+void FFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const {
+ if (!hasChar(chr)) return;
+
+ int pos, bit;
+ mapChar(chr, pos, bit);
+ Font::drawChar(dst, pos, bit, x, y, color);
+}
+
+FFont *FFont::load(Common::SeekableReadStream &input) {
+ byte w, h, start, count;
+ w = input.readByte();
+ h = input.readByte();
+ start = input.readByte();
+ count = input.readByte();
+
+ int size = h*count;
+ debug(" w: %u, h: %u, start: 0x%x, count: %u", w, h, start, count);
+ assert((4+size) == input.size());
+
+ FFont* fnt = new FFont;
+ fnt->_w = w;
+ fnt->_h = h;
+ fnt->_start = start;
+ fnt->_count = count;
+ fnt->_data = new byte[size];
+ input.read(fnt->_data, size);
+ return fnt;
+}
+
+void PFont::mapChar(byte chr, int& pos, int& bit) const {
+ pos = READ_LE_UINT16(&_offsets[chr-_start]);
+ bit = 0;
+}
+
+void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const {
+ if (!hasChar(chr)) return;
+
+ int pos, bit;
+ mapChar(chr, pos, bit);
+ Font::drawChar(dst, pos, bit, x, y, color);
+}
+
+PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor) {
+ byte magic;
+
+ magic = input.readByte();
+ assert(magic == 0xFF);
+
+ byte w, h;
+ byte unknown, start, count, compression;
+ int size;
+ int uncompressedSize;
+
+ w = input.readByte();
+ h = input.readByte();
+ unknown = input.readByte();
+ start = input.readByte();
+ count = input.readByte();
+ size = input.readUint16LE();
+ compression = input.readByte();
+ uncompressedSize = input.readUint32LE();
+ debug(" magic: 0x%x, w: %u, h: %u, unknown: %u, start: 0x%x, count: %u\n"
+ " size: %u, compression: 0x%x, uncompressedSize: %u",
+ magic, w, h, unknown, start, count,
+ size, compression, uncompressedSize);
+ assert(uncompressedSize == size);
+
+ size = input.size()-input.pos();
+
+ byte *data = new byte[uncompressedSize];
+ decompressor->decompress(compression, data, uncompressedSize, &input, size);
+
+ PFont* fnt = new PFont;
+ fnt->_w = w;
+ fnt->_h = h;
+ fnt->_start = start;
+ fnt->_count = count;
+
+ fnt->_offsets = (uint16*)data;
+ fnt->_widths = data+2*count;
+ fnt->_data = data+3*count;
+ return fnt;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
new file mode 100644
index 00000000000..7874345b7d2
--- /dev/null
+++ b/engines/dgds/font.h
@@ -0,0 +1,84 @@
+/* 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 DGDS_FONT_H
+#define DGDS_FONT_H
+
+#include "common/scummsys.h"
+#include "graphics/font.h"
+
+namespace Graphics {
+class Font;
+struct Surface;
+}
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Dgds {
+
+class Decompressor;
+
+class Font : public Graphics::Font {
+public:
+ int getFontHeight() const { return _h; }
+ int getMaxCharWidth() const { return _w; }
+ virtual int getCharWidth(uint32 chr) const = 0;
+ void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const;
+
+protected:
+ byte _w;
+ byte _h;
+ byte _start;
+ byte _count;
+ byte *_data;
+
+ bool hasChar(byte chr) const;
+};
+
+class PFont : public Font {
+public:
+ int getCharWidth(uint32 chr) const { return _widths[chr - _start]; }
+ void drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const;
+ static PFont *load(Common::SeekableReadStream &input, Decompressor *decompressor);
+
+protected:
+ uint16 *_offsets;
+ byte *_widths;
+
+ void mapChar(byte chr, int &pos, int &bit) const;
+};
+
+class FFont : public Font {
+public:
+ int getCharWidth(uint32 chr) const { return _w; }
+ void drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const;
+ static FFont *load(Common::SeekableReadStream &input);
+
+protected:
+ void mapChar(byte chr, int &pos, int &bit) const;
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_FONT_H
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
new file mode 100644
index 00000000000..eee4ccc5b9e
--- /dev/null
+++ b/engines/dgds/image.cpp
@@ -0,0 +1,283 @@
+/* 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/debug.h"
+#include "common/rect.h"
+#include "common/textconsole.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "common/platform.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "dgds/dgds.h"
+#include "dgds/font.h"
+#include "dgds/includes.h"
+#include "dgds/image.h"
+#include "dgds/resource.h"
+#include "dgds/parser.h"
+
+namespace Dgds {
+
+Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor), _tileWidth(0), _tileHeight(0), _tileOffset(0) {
+ memset(_palette, 0, 256 * 3);
+ memset(_blacks, 0, 256 * 3);
+}
+
+Image::~Image() {
+ _bmpData.free();
+}
+
+void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
+ const char *dot;
+ DGDS_EX ex;
+ Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ DgdsParser ctx(*fileStream, filename.c_str());
+
+ DgdsChunk chunk;
+
+ if ((dot = strrchr(filename.c_str(), '.'))) {
+ ex = MKTAG24(dot[1], dot[2], dot[3]);
+ } else {
+ ex = 0;
+ }
+
+ if (ex != EX_SCR) {
+ warning("Unknown screen tag: %d", ex);
+ delete fileStream;
+ return;
+ }
+
+ surface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+
+ // Currently does not handle the VQT: and OFF: chunks
+ // for the compressed pics in the DOS port.
+ while (chunk.readHeader(ctx)) {
+ Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
+ if (chunk.isSection(ID_BIN)) {
+ loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, false);
+ } else if (chunk.isSection(ID_VGA)) {
+ loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, true);
+ } else if (chunk.isSection(ID_MA8)) {
+ loadBitmap8(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream);
+ } else if (chunk.isSection(ID_VQT)) {
+ loadVQT(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream);
+ }
+ }
+
+ delete fileStream;
+}
+
+void Image::loadBitmap(Common::String filename, int number) {
+ const char *dot;
+ DGDS_EX ex;
+ uint16 *mtx;
+ uint16 mw, mh;
+ Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ DgdsParser ctx(*fileStream, filename.c_str());
+ DgdsChunk chunk;
+
+ _tileOffset = 0;
+ _bmpData.free();
+
+ if ((dot = strrchr(filename.c_str(), '.'))) {
+ ex = MKTAG24(dot[1], dot[2], dot[3]);
+ } else {
+ ex = 0;
+ }
+
+ if (ex != EX_BMP) {
+ warning("Unknown bitmap tag: %d", ex);
+ delete fileStream;
+ return;
+ }
+
+ // Currently does not handle the VQT: and OFF: chunks
+ // for the compressed pics in the DOS port.
+ while (chunk.readHeader(ctx)) {
+ Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
+ if (chunk.isSection(ID_INF)) {
+ uint16 tileCount = stream->readUint16LE();
+ uint16 *tileWidths = new uint16[tileCount];
+ uint16 *tileHeights = new uint16[tileCount];
+
+ for (uint16 k = 0; k < tileCount; k++) {
+ tileWidths[k] = stream->readUint16LE();
+ if (k == number)
+ _tileWidth = tileWidths[k];
+ }
+
+ for (uint16 k = 0; k < tileCount; k++) {
+ tileHeights[k] = stream->readUint16LE();
+ if (k == number)
+ _tileHeight = tileHeights[k];
+
+ if (k < number)
+ _tileOffset += tileWidths[k] * tileHeights[k];
+ }
+
+ delete[] tileWidths;
+ delete[] tileHeights;
+ } else if (chunk.isSection(ID_MTX)) {
+ // Scroll offset
+ mw = stream->readUint16LE();
+ mh = stream->readUint16LE();
+ uint32 mcount = uint32(mw) * mh;
+ debug(" %ux%u: %u bytes", mw, mh, mcount * 2);
+
+ mtx = new uint16[mcount];
+ for (uint32 k = 0; k < mcount; k++) {
+ uint16 tile;
+ tile = stream->readUint16LE();
+ mtx[k] = tile;
+ }
+ // TODO: Use these
+ delete mtx;
+ } else if (chunk.isSection(ID_BIN)) {
+ loadBitmap4(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream, false);
+ } else if (chunk.isSection(ID_VGA)) {
+ loadBitmap4(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream, true);
+ } else if (chunk.isSection(ID_VQT)) {
+ loadVQT(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream);
+ }
+ }
+
+ delete fileStream;
+}
+
+void Image::drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &surface) {
+ const Common::Rect destRect(x, y, x + _tileWidth, y + _tileHeight);
+ Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ clippedDestRect.clip(destRect);
+ clippedDestRect.clip(drawWin);
+
+ const Common::Point croppedBy(clippedDestRect.left - destRect.left, clippedDestRect.top - destRect.top);
+ const int rows = clippedDestRect.height();
+ const int columns = clippedDestRect.width();
+
+ byte *src = (byte *)_bmpData.getPixels() + croppedBy.y * _tileWidth + croppedBy.x;
+ byte *ptr = (byte *)surface.getBasePtr(clippedDestRect.left, clippedDestRect.top);
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j) {
+ if (src[j])
+ ptr[j] = src[j];
+ }
+ ptr += surface.pitch;
+ src += _tileWidth;
+ }
+}
+
+void Image::loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte) {
+ uint16 outPitch = tw;
+ if (surf.h == 0)
+ surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
+ byte *data = (byte *)surf.getPixels();
+ byte buf;
+
+ stream->skip(toffset >> 1);
+
+ if (highByte) {
+ for (int i = 0; i < tw * th; i += 2) {
+ buf = stream->readByte();
+ data[i + 0] |= buf & 0xF0;
+ data[i + 1] |= (buf & 0x0F) << 4;
+ }
+ } else {
+ for (int i = 0; i < tw * th; i += 2) {
+ buf = stream->readByte();
+ data[i + 0] |= (buf & 0xF0) >> 4;
+ data[i + 1] |= buf & 0x0F;
+ }
+ }
+}
+
+void Image::loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream) {
+ uint16 outPitch = tw;
+ surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
+ byte *data = (byte *)surf.getPixels();
+
+ stream->skip(toffset);
+ stream->read(data, uint32(outPitch) * th);
+}
+
+void Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream) {
+ uint16 outPitch = tw;
+ surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
+ byte *data = (byte *)surf.getPixels();
+
+ // HACK
+ stream->skip(toffset);
+ stream->read(data, uint32(outPitch) * th);
+}
+
+void Image::loadPalette(Common::String filename) {
+ const char *dot;
+ DGDS_EX ex;
+ Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ DgdsParser ctx(*fileStream, filename.c_str());
+
+ DgdsChunk chunk;
+
+ while (chunk.readHeader(ctx)) {
+ Common::SeekableReadStream *stream = chunk.readStream(ctx);
+ if (chunk.isSection(ID_VGA)) {
+ stream->read(_palette, 256 * 3);
+
+ for (uint k = 0; k < 256 * 3; k += 3) {
+ _palette[k + 0] <<= 2;
+ _palette[k + 1] <<= 2;
+ _palette[k + 2] <<= 2;
+ }
+ }
+ }
+
+ delete fileStream;
+}
+
+void Image::setPalette() {
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void Image::clearPalette() {
+ g_system->getPaletteManager()->setPalette(_blacks, 0, 256);
+}
+
+ // grayscale palette.
+/*
+ for (uint i=0; i<256; i++) {
+ palette[i*3+0] = 255-i;
+ palette[i*3+1] = 255-i;
+ palette[i*3+2] = 255-i;
+ }
+ */
+/*
+ // Amiga grayscale palette.
+ for (uint i=0; i<32; i++) {
+ palette[i*3+0] = 255-i*8;
+ palette[i*3+1] = 255-i*8;
+ palette[i*3+2] = 255-i*8;
+ }
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ */
+
+} // End of namespace Dgds
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
new file mode 100644
index 00000000000..a4528387a90
--- /dev/null
+++ b/engines/dgds/image.h
@@ -0,0 +1,70 @@
+/* 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 DGDS_IMAGE_H
+#define DGDS_IMAGE_H
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace Dgds {
+
+class Decompressor;
+class DgdsChunk;
+class ResourceManager;
+
+class Image {
+public:
+ Image(ResourceManager *resourceMan, Decompressor *decompressor);
+ virtual ~Image();
+
+ void drawScreen(Common::String filename, Graphics::Surface &surface);
+ void loadBitmap(Common::String filename, int number);
+ void drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &surface);
+
+ void loadPalette(Common::String filename);
+ void setPalette();
+ void clearPalette();
+
+private:
+ void loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
+ void loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
+ void loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
+
+ Graphics::Surface _bmpData;
+ ResourceManager *_resourceMan;
+ Decompressor *_decompressor;
+ uint16 _tileWidth, _tileHeight;
+ uint32 _tileOffset;
+
+ byte _palette[256 * 3];
+ byte _blacks[256 * 3];
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_IMAGE_H
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
new file mode 100644
index 00000000000..c3b7cf05312
--- /dev/null
+++ b/engines/dgds/includes.h
@@ -0,0 +1,87 @@
+/* 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 DGDS_INCLUDES_H
+#define DGDS_INCLUDES_H
+
+namespace Dgds {
+
+// TODO: Remove
+#define MKTAG24(a0, a1, a2) ((uint32)((a2) | (a1) << 8 | ((a0) << 16)))
+
+#define ID_BIN MKTAG24('B', 'I', 'N')
+#define ID_DAT MKTAG24('D', 'A', 'T')
+#define ID_FNM MKTAG24('F', 'N', 'M')
+#define ID_FNT MKTAG24('F', 'N', 'T')
+#define ID_GAD MKTAG24('G', 'A', 'D')
+#define ID_INF MKTAG24('I', 'N', 'F')
+#define ID_MTX MKTAG24('M', 'T', 'X')
+#define ID_PAG MKTAG24('P', 'A', 'G')
+#define ID_REQ MKTAG24('R', 'E', 'Q')
+#define ID_RES MKTAG24('R', 'E', 'S')
+#define ID_SCR MKTAG24('S', 'C', 'R')
+#define ID_SDS MKTAG24('S', 'D', 'S')
+#define ID_SNG MKTAG24('S', 'N', 'G')
+#define ID_TAG MKTAG24('T', 'A', 'G')
+#define ID_TT3 MKTAG24('T', 'T', '3')
+#define ID_VER MKTAG24('V', 'E', 'R')
+#define ID_VGA MKTAG24('V', 'G', 'A')
+#define ID_VQT MKTAG24('V', 'Q', 'T')
+
+/* Heart of China */
+#define ID_MA8 MKTAG24('M', 'A', '8')
+#define ID_DDS MKTAG24('D', 'D', 'S')
+#define ID_THD MKTAG24('T', 'H', 'D')
+
+#define EX_ADH MKTAG24('A', 'D', 'H')
+#define EX_ADL MKTAG24('A', 'D', 'L')
+#define EX_ADS MKTAG24('A', 'D', 'S')
+#define EX_AMG MKTAG24('A', 'M', 'G')
+#define EX_BMP MKTAG24('B', 'M', 'P')
+#define EX_GDS MKTAG24('G', 'D', 'S')
+#define EX_INS MKTAG24('I', 'N', 'S')
+#define EX_PAL MKTAG24('P', 'A', 'L')
+#define EX_FNT MKTAG24('F', 'N', 'T')
+#define EX_REQ MKTAG24('R', 'E', 'Q')
+#define EX_RST MKTAG24('R', 'S', 'T')
+#define EX_SCR MKTAG24('S', 'C', 'R')
+#define EX_SDS MKTAG24('S', 'D', 'S')
+#define EX_SNG MKTAG24('S', 'N', 'G')
+#define EX_SX MKTAG24('S', 'X', 0)
+#define EX_TTM MKTAG24('T', 'T', 'M')
+#define EX_VIN MKTAG24('V', 'I', 'N')
+
+/* Heart of China */
+#define EX_DAT MKTAG24('D', 'A', 'T')
+#define EX_DDS MKTAG24('D', 'D', 'S')
+#define EX_TDS MKTAG24('T', 'D', 'S')
+
+#define EX_OVL MKTAG24('O', 'V', 'L')
+
+#define SCREEN_WIDTH 320
+#define SCREEN_HEIGHT 200
+
+#define FILENAME_LENGTH 12
+
+} // End of namespace Dgds
+
+#endif // DGDS_MOVIES_H
diff --git a/engines/dgds/metaengine.cpp b/engines/dgds/metaengine.cpp
new file mode 100644
index 00000000000..fa95c05dae4
--- /dev/null
+++ b/engines/dgds/metaengine.cpp
@@ -0,0 +1,59 @@
+/* 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 "base/plugins.h"
+
+#include "engines/advancedDetector.h"
+
+#include "dgds/dgds.h"
+
+class DgdsMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
+public:
+ const char *getName() const override {
+ return "DGDS";
+ }
+
+ bool hasFeature(MetaEngineFeature f) const override;
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+};
+
+bool DgdsMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSimpleSavesNames);
+}
+
+bool DgdsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc)
+ *engine = new Dgds::DgdsEngine(syst, desc);
+
+ return desc != nullptr;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(DGDS)
+ REGISTER_PLUGIN_DYNAMIC(DGDS, PLUGIN_TYPE_ENGINE, DgdsMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(DGDS, PLUGIN_TYPE_ENGINE, DgdsMetaEngine);
+#endif
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
new file mode 100644
index 00000000000..3e88f7ed45f
--- /dev/null
+++ b/engines/dgds/module.mk
@@ -0,0 +1,25 @@
+MODULE := engines/dgds
+
+MODULE_OBJS := \
+ console.o \
+ decompress.o \
+ dgds.o \
+ font.o \
+ image.o \
+ metaengine.o \
+ movies.o \
+ music.o \
+ parser.o \
+ resource.o \
+ sound.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_DGDS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
+
+# Detection objects
+DETECT_OBJS += $(MODULE)/detection.o
diff --git a/engines/dgds/movies.cpp b/engines/dgds/movies.cpp
new file mode 100644
index 00000000000..31e8c72ebeb
--- /dev/null
+++ b/engines/dgds/movies.cpp
@@ -0,0 +1,515 @@
+/* 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/debug.h"
+#include "common/rect.h"
+#include "common/textconsole.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "common/platform.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "dgds/dgds.h"
+#include "dgds/font.h"
+#include "dgds/image.h"
+#include "dgds/includes.h"
+#include "dgds/movies.h"
+#include "dgds/resource.h"
+#include "dgds/parser.h"
+
+namespace Dgds {
+
+// TODO: Move
+extern Graphics::ManagedSurface resData;
+extern Graphics::Surface bottomBuffer;
+extern Graphics::Surface topBuffer;
+extern Common::StringArray _bubbles;
+
+const Common::Rect rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+int bk = -1;
+int id = 0, sid = 0;
+Common::String text;
+extern PFont *_fntP;
+Common::Rect drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+Common::String _bmpNames[16];
+
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(0), _filename(0) {}
+
+bool TTMInterpreter::load(const char *filename, TTMData *scriptData) {
+ Common::SeekableReadStream *stream = _vm->_resource->getResource(filename);
+
+ if (!stream) {
+ error("Couldn't open script file '%s'", filename);
+ return false;
+ }
+
+ memset(scriptData, 0, sizeof(*scriptData));
+ _scriptData = scriptData;
+ _filename = filename;
+
+ TTMParser dgds(*stream, _filename);
+ dgds.parse(scriptData, _vm->_decompressor);
+
+ delete stream;
+
+ Common::strlcpy(_scriptData->filename, filename, sizeof(_scriptData->filename));
+ _scriptData = 0;
+ _filename = 0;
+ return true;
+}
+
+void TTMInterpreter::unload(TTMData *data) {
+ if (!data)
+ return;
+ delete data->scr;
+
+ data->scr = 0;
+}
+
+void TTMInterpreter::init(TTMState *state, const TTMData *data) {
+ state->dataPtr = data;
+ state->delay = 0;
+ state->scene = 0;
+ data->scr->seek(0);
+}
+
+bool TTMInterpreter::run(TTMState *script) {
+ if (!script)
+ return false;
+
+ Common::SeekableReadStream *scr = script->dataPtr->scr;
+ if (!scr)
+ return false;
+ if (scr->pos() >= scr->size())
+ return false;
+
+ script->delay = 0;
+ do {
+ uint16 code;
+ byte count;
+ uint op;
+ int16 ivals[8];
+
+ Common::String sval;
+
+ code = scr->readUint16LE();
+ count = code & 0x000F;
+ op = code & 0xFFF0;
+
+ debugN("\tOP: 0x%4.4x %2u ", op, count);
+ if (count == 0x0F) {
+ byte ch[2];
+
+ do {
+ ch[0] = scr->readByte();
+ ch[1] = scr->readByte();
+ sval += ch[0];
+ sval += ch[1];
+ } while (ch[0] != 0 && ch[1] != 0);
+
+ debugN("\"%s\"", sval.c_str());
+ } else {
+ for (byte i = 0; i < count; i++) {
+ ivals[i] = scr->readSint16LE();
+ if (i > 0)
+ debugN(", ");
+ debugN("%d", ivals[i]);
+ }
+ }
+ debug(" ");
+
+ Common::Rect bmpWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ switch (op) {
+ case 0x0000:
+ // FINISH: void
+ break;
+ case 0xf010:
+ // LOAD SCR: filename:str
+ _vm->_image->drawScreen(sval, bottomBuffer);
+ continue;
+ case 0xf020:
+ // LOAD BMP: filename:str
+ _bmpNames[id] = Common::String(sval);
+ continue;
+ case 0xf050:
+ // LOAD PAL: filename:str
+ _vm->_image->loadPalette(sval);
+ continue;
+ case 0xf060:
+ // LOAD SONG: filename:str
+ if (_vm->_platform == Common::kPlatformAmiga) {
+ byte volume = 255;
+ byte channel = 0;
+ _vm->stopSfx(channel);
+ _vm->playSfx("DYNAMIX.INS", channel, volume);
+ } else {
+ _vm->playMusic(sval.c_str());
+ }
+ continue;
+
+ case 0x1030:
+ // SET BMP: id:int [-1:n]
+ bk = ivals[0];
+
+ if (bk != -1) {
+ _vm->_image->loadBitmap(_bmpNames[id], bk);
+ }
+ continue;
+ case 0x1050:
+ // SELECT BMP: id:int [0:n]
+ id = ivals[0];
+ continue;
+ case 0x1060:
+ // SELECT SCR|PAL: id:int [0]
+ sid = ivals[0];
+ continue;
+ case 0x1090:
+ // SELECT SONG: id:int [0]
+ continue;
+
+ case 0x4120:
+ // FADE IN: ?,?,?,?:byte
+ _vm->_image->setPalette();
+ continue;
+
+ case 0x4110:
+ // FADE OUT: ?,?,?,?:byte
+ g_system->delayMillis(script->delay);
+ _vm->_image->clearPalette();
+ bottomBuffer.fillRect(rect, 0);
+ continue;
+
+ // these 3 ops do interaction between the topBuffer (imgData) and the bottomBuffer (scrData) but... it might turn out this uses z values!
+ case 0xa050: { //GFX? i,j,k,l:int [i<k,j<l] // HAPPENS IN INTRO.TTM:INTRO9
+ // it works like a bitblit, but it doesn't write if there's something already at the destination?
+ resData.blitFrom(bottomBuffer);
+ resData.transBlitFrom(topBuffer);
+ topBuffer.copyFrom(resData);
+ continue;
+ }
+ case 0x0020: //SAVE BG?: void // OR PERHAPS SWAPBUFFERS ; it makes bmpData persist in the next frames.
+ bottomBuffer.copyFrom(topBuffer);
+ continue;
+
+ case 0x4200: {
+ // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
+ const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ resData.blitFrom(bottomBuffer);
+ resData.transBlitFrom(topBuffer);
+ bottomBuffer.copyRectToSurface(resData, destRect.left, destRect.top, destRect);
+ }
+ continue;
+
+ case 0x0ff0: {
+ // REFRESH: void
+ resData.blitFrom(bottomBuffer);
+ Graphics::Surface bmpSub = topBuffer.getSubArea(bmpWin);
+ resData.transBlitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
+ topBuffer.fillRect(bmpWin, 0);
+
+ if (!text.empty()) {
+ Common::StringArray lines;
+ const int h = _fntP->getFontHeight();
+
+ _fntP->wordWrapText(text, SCREEN_HEIGHT, lines);
+ Common::Rect r(0, 7, SCREEN_WIDTH, h * lines.size() + 13);
+ resData.fillRect(r, 15);
+ for (uint i = 0; i < lines.size(); i++) {
+ const int w = _fntP->getStringWidth(lines[i]);
+ _fntP->drawString(&resData, lines[i], 10, 10 + 1 + i * h, w, 0);
+ }
+ }
+ } break;
+
+ case 0xa520:
+ //DRAW BMP: x,y:int ; happens once in INTRO.TTM
+ case 0xa500:
+ debug("DRAW \"%s\"", _bmpNames[id].c_str());
+
+ // DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // This is kind of file system intensive, will likely have to change to store all the BMPs.
+ if (count == 4) {
+ bk = ivals[2];
+ id = ivals[3];
+ if (bk != -1) {
+ _vm->_image->loadBitmap(_bmpNames[id], bk);
+ }
+ }
+
+ // DRAW BMP: x,y:int [-n,+n] (RISE)
+ _vm->_image->drawBitmap(ivals[0], ivals[1], drawWin, topBuffer);
+ continue;
+
+ case 0x1110: { //SET SCENE?: i:int [1..n]
+ // DESCRIPTION IN TTM TAGS.
+ debug("SET SCENE: %u", ivals[0]);
+ script->scene = ivals[0];
+
+ if (!_bubbles.empty()) {
+ // TODO: Are these hardcoded?
+ if (!scumm_stricmp(script->dataPtr->filename, "INTRO.TTM")) {
+ switch (ivals[0]) {
+ case 15:
+ text = _bubbles[3];
+ break;
+ case 16:
+ text = _bubbles[4];
+ break;
+ case 17:
+ text = _bubbles[5];
+ break;
+ case 19:
+ text = _bubbles[6];
+ break;
+ case 20:
+ text = _bubbles[7];
+ break;
+ case 22:
+ text = _bubbles[8];
+ break;
+ case 23:
+ text = _bubbles[9];
+ break;
+ case 25:
+ text = _bubbles[10];
+ break;
+ case 26:
+ text = _bubbles[11];
+ break;
+ default:
+ text.clear();
+ break;
+ }
+ } else if (!scumm_stricmp(script->dataPtr->filename, "BIGTV.TTM")) {
+ switch (ivals[0]) {
+ case 1:
+ text = _bubbles[0];
+ break;
+ case 2:
+ text = _bubbles[1];
+ break;
+ case 3:
+ text = _bubbles[2];
+ break;
+ }
+ }
+ if (!text.empty())
+ script->delay += 1500;
+ } else {
+ text.clear();
+ }
+ }
+ continue;
+
+ case 0x4000:
+ //SET WINDOW? x,y,w,h:int [0..320,0..200]
+ drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ continue;
+
+ case 0xa100:
+ //SET WINDOW? x,y,w,h:int [0..320,0..200]
+ bmpWin = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ continue;
+
+ case 0x1020: //DELAY?: i:int [0..n]
+ script->delay += ivals[0] * 10;
+ continue;
+
+ case 0x10a0:
+ // SET SCR|PAL: id:int [0]
+ case 0x2000: //SET FRAME1?: i,j:int [0..255]
+
+ case 0xa530: // CHINA
+ // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
+ case 0x0110: //PURGE IMGS? void
+ case 0x0080: //DRAW BG: void
+ case 0x1100: //? i:int [9]
+ case 0x1300: //? i:int [72,98,99,100,107]
+
+ case 0x1310: //? i:int [107]
+
+ default:
+ warning("Unimplemented TTM opcode: 0x%04X", op);
+ continue;
+ }
+ break;
+ } while (scr->pos() < scr->size());
+
+ Graphics::Surface *dst;
+ dst = g_system->lockScreen();
+ dst->copyRectToSurface(resData, 0, 0, rect);
+ g_system->unlockScreen();
+ g_system->updateScreen();
+ g_system->delayMillis(script->delay);
+ return true;
+}
+
+ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(0), _filename(0) {}
+
+bool ADSInterpreter::load(const char *filename, ADSData *scriptData) {
+ Common::SeekableReadStream *stream = _vm->_resource->getResource(filename);
+
+ if (!stream) {
+ error("Couldn't open script file '%s'", filename);
+ return false;
+ }
+
+ memset(scriptData, 0, sizeof(*scriptData));
+ _scriptData = scriptData;
+ _filename = filename;
+
+ ADSParser dgds(*stream, _filename);
+ dgds.parse(scriptData, _vm->_decompressor);
+
+ delete stream;
+
+ TTMInterpreter interp(_vm);
+
+ TTMData *scriptDatas;
+ scriptDatas = new TTMData[_scriptData->count];
+ assert(scriptDatas);
+ _scriptData->scriptDatas = scriptDatas;
+
+ for (uint16 i = _scriptData->count; i--;)
+ interp.load(_scriptData->names[i], &_scriptData->scriptDatas[i]);
+
+ Common::strlcpy(_scriptData->filename, filename, sizeof(_scriptData->filename));
+ _scriptData = 0;
+ _filename = 0;
+ return true;
+}
+
+void ADSInterpreter::unload(ADSData *data) {
+ if (!data)
+ return;
+ for (uint16 i = data->count; i--;)
+ delete data->names[i];
+ delete data->names;
+ delete data->scriptDatas;
+ delete data->scr;
+
+ data->count = 0;
+ data->names = 0;
+ data->scriptDatas = 0;
+ data->scr = 0;
+}
+
+void ADSInterpreter::init(ADSState *state, const ADSData *data) {
+ state->dataPtr = data;
+ state->scene = 0;
+ state->subIdx = 0;
+ state->subMax = 0;
+ data->scr->seek(0);
+
+ TTMInterpreter interp(_vm);
+
+ TTMState *scriptStates;
+ scriptStates = new TTMState[data->count];
+ assert(scriptStates);
+ state->scriptStates = scriptStates;
+
+ for (uint16 i = data->count; i--;)
+ interp.init(&state->scriptStates[i], &data->scriptDatas[i]);
+}
+
+bool ADSInterpreter::run(ADSState *script) {
+ TTMInterpreter interp(_vm);
+
+ if (script->subMax != 0) {
+ TTMState *state = &script->scriptStates[script->subIdx - 1];
+ if (!interp.run(state) || state->scene >= script->subMax)
+ script->subMax = 0;
+ return true;
+ }
+
+ if (!script)
+ return false;
+ Common::SeekableReadStream *scr = script->dataPtr->scr;
+ if (!scr)
+ return false;
+ if (scr->pos() >= scr->size())
+ return false;
+
+ do {
+ uint16 code;
+ byte count;
+ uint op;
+ code = scr->readUint16LE();
+ count = code & 0x000F;
+ op = code & 0xFFF0;
+
+ if ((code & 0xFF00) == 0) {
+ continue;
+ }
+
+ switch (code) {
+ case 0x2005: {
+ // play scene.
+ script->subIdx = scr->readUint16LE();
+ script->subMax = scr->readUint16LE();
+ uint16 unk1 = scr->readUint16LE();
+ uint16 unk2 = scr->readUint16LE();
+ debug("ADSInterpreter play scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", script->subIdx, script->subMax, unk1, unk2);
+ }
+ return true;
+ case 0xF010:
+ case 0xF200:
+ case 0xFDA8:
+ case 0xFE98:
+ case 0xFF88:
+ case 0xFF10:
+ case 0xFFFF:
+ case 0x0190:
+ case 0x1070:
+ case 0x1340:
+ case 0x1360:
+ case 0x1370:
+ case 0x1420:
+ case 0x1430:
+ case 0x1500:
+ case 0x1520:
+ case 0x2000:
+ case 0x2010:
+ case 0x2020:
+ case 0x3010:
+ case 0x3020:
+ case 0x30FF:
+ case 0x4000:
+ case 0x4010:
+ case 0x1510:
+ case 0x1330:
+ case 0x1350:
+ default:
+ warning("Unimplemented ADS opcode: 0x%04X", code);
+ continue;
+ }
+ break;
+ } while (scr->pos() < scr->size());
+ return false;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/movies.h b/engines/dgds/movies.h
new file mode 100644
index 00000000000..be9d0a54c2f
--- /dev/null
+++ b/engines/dgds/movies.h
@@ -0,0 +1,102 @@
+/* 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 DGDS_MOVIES_H
+#define DGDS_MOVIES_H
+
+namespace Dgds {
+
+class DgdsEngine;
+class DgdsChunk;
+
+struct TTMData {
+ char filename[13];
+ Common::SeekableReadStream *scr;
+};
+
+struct TTMState {
+ const TTMData *dataPtr;
+ uint16 scene;
+ int delay;
+};
+
+struct ADSData {
+ char filename[13];
+
+ uint16 count;
+ char **names;
+ TTMData *scriptDatas;
+
+ Common::SeekableReadStream *scr;
+};
+
+struct ADSState {
+ const ADSData *dataPtr;
+ uint16 scene;
+ uint16 subIdx, subMax;
+
+ TTMState *scriptStates;
+};
+
+class ADSInterpreter {
+public:
+ ADSInterpreter(DgdsEngine *vm);
+
+ bool load(const char *filename, ADSData *data);
+ void unload(ADSData *data);
+
+ bool callback(DgdsChunk &chunk);
+
+ void init(ADSState *scriptState, const ADSData *scriptData);
+ bool run(ADSState *script);
+
+protected:
+ DgdsEngine *_vm;
+
+ const char *_filename;
+ ADSData *_scriptData;
+};
+
+class TTMInterpreter {
+public:
+ TTMInterpreter(DgdsEngine *vm);
+
+ bool load(const char *filename, TTMData *data);
+ void unload(TTMData *data);
+
+ bool callback(DgdsChunk &chunk);
+
+ void init(TTMState *scriptState, const TTMData *scriptData);
+ bool run(TTMState *script);
+
+protected:
+ DgdsEngine *_vm;
+
+ const char *_filename;
+ TTMData *_scriptData;
+
+ //Common::String _bmpNames[16];
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_MOVIES_H
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
new file mode 100644
index 00000000000..46053ff06ee
--- /dev/null
+++ b/engines/dgds/music.cpp
@@ -0,0 +1,369 @@
+/* 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/debug.h"
+#include "audio/midiparser.h"
+
+#include "dgds/sound.h"
+#include "dgds/music.h"
+
+namespace Dgds {
+
+/**
+ * The Standard MIDI File version of MidiParser.
+ */
+class MidiParser_DGDS : public MidiParser {
+protected:
+ byte *_init;
+ byte *_last;
+
+ byte numParts;
+ byte *trackPtr[0xFF];
+ uint16 trackSiz[0xFF];
+
+protected:
+ void parseNextEvent(EventInfo &info);
+
+public:
+ MidiParser_DGDS();
+ ~MidiParser_DGDS();
+
+ void sendInitCommands();
+
+ bool loadMusic(byte *data, uint32 size);
+
+ bool validateNextRead(uint i, uint16 *_curPos);
+ byte midiGetNextChannel(uint16 *_curPos, uint32 *_time, long ticker);
+ void mixChannels();
+};
+
+MidiParser_DGDS::MidiParser_DGDS() : _init(0), _last(0) {
+ numParts = 0;
+ memset(trackSiz, 0, sizeof(trackSiz));
+}
+
+void MidiParser_DGDS::sendInitCommands() {
+}
+
+MidiParser_DGDS::~MidiParser_DGDS() {
+ free(_init);
+}
+
+void MidiParser_DGDS::parseNextEvent(EventInfo &info) {
+ if (_position._playPos >= _last) {
+ // fake an end-of-track meta event
+ info.delta = 0;
+ info.event = 0xFF;
+ info.ext.type = 0x2F;
+ info.length = 0;
+ return;
+ }
+
+ info.start = _position._playPos;
+ info.delta = 0;
+ while (*_position._playPos == 0xF8) {
+ info.delta += 240;
+ _position._playPos++;
+ }
+ info.delta += *_position._playPos++;
+
+ // Process the next info.
+ if ((_position._playPos[0] & 0xF0) >= 0x80)
+ info.event = *_position._playPos++;
+ else
+ info.event = _position._runningStatus;
+ if (info.event < 0x80)
+ return;
+
+ _position._runningStatus = info.event;
+ switch (info.command()) {
+ case 0x9:
+ info.basic.param1 = *_position._playPos++;
+ info.basic.param2 = *_position._playPos++;
+ if (info.basic.param2 == 0) {
+ // NoteOn with param2==0 is a NoteOff
+ info.event = info.channel() | 0x80;
+ }
+ info.length = 0;
+ break;
+
+ case 0xC:
+ case 0xD:
+ info.basic.param1 = *_position._playPos++;
+ info.basic.param2 = 0;
+ break;
+
+ case 0x8:
+ case 0xA:
+ case 0xB:
+ case 0xE:
+ info.basic.param1 = *_position._playPos++;
+ info.basic.param2 = *_position._playPos++;
+ info.length = 0;
+ break;
+
+ case 0xF: // System Common, Meta or SysEx event
+ switch (info.event & 0x0F) {
+ case 0x2: // Song Position Pointer
+ info.basic.param1 = *_position._playPos++;
+ info.basic.param2 = *_position._playPos++;
+ break;
+
+ case 0x3: // Song Select
+ info.basic.param1 = *_position._playPos++;
+ info.basic.param2 = 0;
+ break;
+
+ case 0x6:
+ case 0x8:
+ case 0xA:
+ case 0xB:
+ case 0xC:
+ case 0xE:
+ info.basic.param1 = info.basic.param2 = 0;
+ break;
+
+ case 0x0: // SysEx
+ info.length = readVLQ(_position._playPos);
+ info.ext.data = _position._playPos;
+ _position._playPos += info.length;
+ break;
+
+ case 0xF: // META event
+ info.ext.type = *_position._playPos++;
+ info.length = readVLQ(_position._playPos);
+ info.ext.data = _position._playPos;
+ _position._playPos += info.length;
+ break;
+
+ default:
+ warning("Unexpected midi event 0x%02X in midi data", info.event);
+ }
+ }
+}
+
+byte MidiParser_DGDS::midiGetNextChannel(uint16 *trackPos, uint32 *trackTimer, long ticker) {
+ byte curr = 0xFF;
+ uint32 closest = ticker + 1000000, next = 0;
+
+ for (byte i = 0; i < numParts; i++) {
+ if (trackTimer[i] == 0xFFFFFFFF) // channel ended
+ continue;
+ if (trackPos[i] >= trackSiz[i])
+ continue;
+ next = trackPtr[i][trackPos[i]]; // when the next event should occur
+ if (next == 0xF8) // 0xF8 means 240 ticks delay
+ next = 240;
+ next += trackTimer[i];
+ if (next < closest) {
+ curr = i;
+ closest = next;
+ }
+ }
+
+ return curr;
+}
+
+inline bool MidiParser_DGDS::validateNextRead(uint i, uint16 *trackPos) {
+ if (trackSiz[i] <= trackPos[i]) {
+ warning("Unexpected end. Music may sound wrong due to game resource corruption");
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static const byte commandLengths[] = { 2, 2, 2, 2, 1, 1, 2, 0 };
+
+void MidiParser_DGDS::mixChannels() {
+ int totalSize = 0;
+
+ uint16 trackPos[0xFF];
+ uint32 trackTimer[0xFF];
+ byte _prev[0xFF];
+ for (byte i = 0; i < numParts; i++) {
+ trackTimer[i] = 0;
+ _prev[i] = 0;
+ trackPos[i] = 0;
+ totalSize += trackSiz[i];
+ }
+
+ byte *output = (byte*)malloc(totalSize * 2);
+ _tracks[0] = output;
+
+ uint32 ticker = 0;
+ byte channel, curDelta;
+ byte midiCommand = 0, midiParam, globalPrev = 0;
+ uint32 newDelta;
+
+ while ((channel = midiGetNextChannel(trackPos, trackTimer, ticker)) != 0xFF) { // there is still an active channel
+ if (!validateNextRead(channel, trackPos))
+ goto end;
+ curDelta = trackPtr[channel][trackPos[channel]++];
+ trackTimer[channel] += (curDelta == 0xF8 ? 240 : curDelta); // when the command is supposed to occur
+ if (curDelta == 0xF8)
+ continue;
+ newDelta = trackTimer[channel] - ticker;
+ ticker += newDelta;
+
+ if (!validateNextRead(channel, trackPos))
+ goto end;
+ midiCommand = trackPtr[channel][trackPos[channel]++];
+ if (midiCommand != 0xFC) {
+ // Write delta
+ while (newDelta > 240) {
+ *output++ = 0xF8;
+ newDelta -= 240;
+ }
+ *output++ = (byte)newDelta;
+ }
+ // Write command
+ switch (midiCommand) {
+ case 0xF0: // sysEx
+ *output++ = midiCommand;
+ do {
+ if (!validateNextRead(channel, trackPos))
+ goto end;
+ midiParam = trackPtr[channel][trackPos[channel]++];
+ *output++ = midiParam;
+ } while (midiParam != 0xF7);
+ break;
+ case 0xFC: // end of channel
+ trackTimer[channel] = 0xFFFFFFFF;
+ break;
+ default: // MIDI command
+ if (midiCommand & 0x80) {
+ if (!validateNextRead(channel, trackPos))
+ goto end;
+ midiParam = trackPtr[channel][trackPos[channel]++];
+ } else {// running status
+ midiParam = midiCommand;
+ midiCommand = _prev[channel];
+ }
+
+ // remember which channel got used for channel remapping
+ byte midiChannel = midiCommand & 0xF;
+ //_channelUsed[midiChannel] = true;
+
+ if (midiCommand != globalPrev)
+ *output++ = midiCommand;
+ *output++ = midiParam;
+ if (commandLengths[(midiCommand >> 4) - 8] == 2) {
+ if (!validateNextRead(channel, trackPos))
+ goto end;
+ *output++ = trackPtr[channel][trackPos[channel]++];
+ }
+ _prev[channel] = midiCommand;
+ globalPrev = midiCommand;
+ break;
+ }
+ }
+
+end:
+ _last = output;
+}
+
+bool MidiParser_DGDS::loadMusic(byte *data, uint32 size) {
+ unloadMusic();
+
+ if (!data) return false;
+
+ numParts = loadSndTrack(TRACK_MT32, trackPtr, trackSiz, data, size);
+ if (numParts == 0) return false;
+
+ for (byte part = 0; part < numParts; part++) {
+ byte *ptr = trackPtr[part];
+
+ byte number, voices;
+ number = (*ptr++);
+ voices = (*ptr++) & 0x0F;
+ debug(" - #%u: voices: %u", number, voices);
+
+ trackPtr[part] += 2;
+ trackSiz[part] -= 2;
+ }
+
+ mixChannels();
+
+ _init = _tracks[0];
+ _numTracks = 1;
+
+ _ppqn = 1;
+ setTempo(16667);
+
+ // Note that we assume the original data passed in
+ // will persist beyond this call, i.e. we do NOT
+ // copy the data to our own buffer. Take warning....
+ resetTracking();
+ setTrack(0);
+ return true;
+}
+
+MidiParser_DGDS *createParser_DGDS() { return new MidiParser_DGDS; }
+
+
+DgdsMidiPlayer::DgdsMidiPlayer() {
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+ debug("MidiPlayer()");
+}
+
+void DgdsMidiPlayer::play(byte *data, uint32 size) {
+ Common::StackLock lock(_mutex);
+
+ stop();
+ if (!data) return;
+
+ MidiParser_DGDS *parser = createParser_DGDS();
+ if (parser->loadMusic(data, size)) {
+ parser->setMidiDriver(this);
+ parser->sendInitCommands();
+ parser->setTimerRate(_driver->getBaseTempo());/*
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+ parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);*/
+ _parser = parser;
+ syncVolume();
+
+ _isLooping = true;
+ _isPlaying = true;
+ debug("Playing music track");
+ } else {
+ debug("Cannot play music track");
+ delete parser;
+ }
+}
+
+void DgdsMidiPlayer::stop() {
+ Audio::MidiPlayer::stop();
+ debug("Stopping track");
+}
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/music.h b/engines/dgds/music.h
new file mode 100644
index 00000000000..6fae6225e55
--- /dev/null
+++ b/engines/dgds/music.h
@@ -0,0 +1,41 @@
+/* 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 DGDS_MUSIC_H
+#define DGDS_MUSIC_H
+
+#include "audio/midiplayer.h"
+
+namespace Dgds {
+
+class DgdsMidiPlayer : public Audio::MidiPlayer {
+public:
+ DgdsMidiPlayer();
+
+ void play(byte *data, uint32 size);
+ void stop();
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_MUSIC_H
+
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
new file mode 100644
index 00000000000..c48565ef5a2
--- /dev/null
+++ b/engines/dgds/parser.cpp
@@ -0,0 +1,132 @@
+/* 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/debug.h"
+#include "common/textconsole.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/platform.h"
+#include "dgds/includes.h"
+#include "dgds/movies.h"
+#include "dgds/resource.h"
+#include "dgds/parser.h"
+
+namespace Dgds {
+
+DgdsParser::DgdsParser(Common::SeekableReadStream &file, const char *filename) : _file(file) {
+ Common::strlcpy(_filename, filename, sizeof(_filename));
+ bytesRead = 0;
+}
+
+void DgdsParser::parse(void *data, Decompressor *decompressor) {
+ const char *dot;
+ DGDS_EX _ex;
+
+ if ((dot = strrchr(_filename, '.'))) {
+ _ex = MKTAG24(toupper(dot[1]), toupper(dot[2]), toupper(dot[3]));
+ } else {
+ _ex = 0;
+ }
+
+ DgdsChunk chunk;
+ while (chunk.readHeader(*this)) {
+ bool stop;
+
+ //chunk._stream = 0;
+ if (chunk.container) {
+ chunk._stream = &_file;
+ stop = callback(chunk, data);
+ } else {
+ chunk._stream = chunk.isPacked(_ex) ? chunk.decodeStream(*this, decompressor) : chunk.readStream(*this);
+
+ stop = callback(chunk, data);
+
+ int leftover = chunk._stream->size() - chunk._stream->pos();
+ chunk._stream->skip(leftover);
+ delete chunk._stream;
+ }
+ if (stop)
+ break;
+ }
+}
+
+bool TTMParser::callback(DgdsChunk &chunk, void *data) {
+ TTMData *scriptData = (TTMData *)data;
+
+ switch (chunk._id) {
+ case ID_TT3:
+ scriptData->scr = chunk._stream->readStream(chunk._stream->size());
+ break;
+ case ID_VER:
+ chunk._stream->skip(chunk._size);
+ break;
+ default:
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename);
+ chunk._stream->skip(chunk._size);
+ break;
+ }
+ return false;
+}
+
+bool ADSParser::callback(DgdsChunk &chunk, void *data) {
+ ADSData *scriptData = (ADSData *)data;
+ switch (chunk._id) {
+ case EX_ADS:
+ break;
+ case ID_RES: {
+ uint16 count = chunk._stream->readUint16LE();
+ char **strs = new char *[count];
+ assert(strs);
+
+ scriptData->count = count;
+ for (uint16 i = 0; i < count; i++) {
+ Common::String string;
+ byte c = 0;
+ uint16 idx;
+
+ idx = chunk._stream->readUint16LE();
+ assert(idx == (i + 1));
+
+ while ((c = chunk._stream->readByte()))
+ string += c;
+
+ strs[i] = new char[string.size() + 1];
+ strcpy(strs[i], string.c_str());
+ }
+ scriptData->names = strs;
+ } break;
+ case ID_SCR:
+ scriptData->scr = chunk._stream->readStream(chunk._stream->size());
+ break;
+ case ID_VER:
+ // These exist in Willy Beamish
+ chunk._stream->skip(chunk._size);
+ break;
+ default:
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename);
+ chunk._stream->skip(chunk._size);
+ break;
+ }
+ return false;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/parser.h b/engines/dgds/parser.h
new file mode 100644
index 00000000000..43f1144a92f
--- /dev/null
+++ b/engines/dgds/parser.h
@@ -0,0 +1,60 @@
+/* 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 DGDS_PARSER_H
+#define DGDS_PARSER_H
+
+namespace Dgds {
+
+class DgdsChunk;
+class Decompressor;
+
+class DgdsParser {
+public:
+ char _filename[13];
+ Common::SeekableReadStream &_file;
+ uint32 bytesRead;
+
+ DgdsParser(Common::SeekableReadStream &file, const char *filename);
+ void parse(void *data, Decompressor *decompressor);
+ virtual bool callback(DgdsChunk &chunk, void *data) { return false; }
+};
+
+class TTMParser : public DgdsParser {
+public:
+ TTMParser(Common::SeekableReadStream &file, const char *filename) : DgdsParser(file, filename) {}
+
+private:
+ bool callback(DgdsChunk &chunk, void *data);
+};
+
+class ADSParser : public DgdsParser {
+public:
+ ADSParser(Common::SeekableReadStream &file, const char *filename) : DgdsParser(file, filename) {}
+
+private:
+ bool callback(DgdsChunk &chunk, void *data);
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_RESOURCE_H
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
new file mode 100644
index 00000000000..1ef137e2dee
--- /dev/null
+++ b/engines/dgds/resource.cpp
@@ -0,0 +1,598 @@
+/* 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 "dgds/resource.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/platform.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "dgds/decompress.h"
+#include "dgds/includes.h"
+#include "dgds/parser.h"
+
+namespace Dgds {
+
+ResourceManager::ResourceManager() {
+ const char *indexFiles[] = {
+ "volume.vga", // early Dragon versions
+ "volume.rmf", // Beamish / HoC
+ "volume.map" // Beamish CD
+ };
+
+ Common::File indexFile;
+ for (int i = 0; i < ARRAYSIZE(indexFiles); i++) {
+ if (Common::File::exists(indexFiles[i])) {
+ indexFile.open(indexFiles[i]);
+ break;
+ }
+ }
+
+ indexFile.skip(4); // salt for file hash, TODO
+ int volumes = indexFile.readUint16LE();
+
+ for (int i = 0; i < volumes; i++) {
+ Common::String volumeName;
+ for (int j = 0; j < FILENAME_LENGTH; j++)
+ volumeName += indexFile.readByte();
+ volumeName.toLowercase();
+
+ _volumes[i].open(volumeName);
+
+ indexFile.skip(1); // unknown
+ int entries = indexFile.readUint16LE();
+ //debug("File %s has %d entries", volumeName.c_str(), entries);
+
+ for (int j = 0; j < entries; j++) {
+ Resource res;
+ res.volume = i;
+ res.checksum = indexFile.readUint32LE();
+ res.pos = indexFile.readUint32LE();
+
+ _volumes[i].seek(res.pos, SEEK_SET);
+ res.pos += FILENAME_LENGTH + 1 + 4;
+
+ Common::String fileName;
+ for (int k = 0; k < FILENAME_LENGTH; k++)
+ fileName += _volumes[i].readByte();
+ fileName.toLowercase();
+
+ _volumes[i].skip(1); // unknown
+ res.size = _volumes[i].readUint32LE();
+ _resources[fileName] = res;
+
+ if (fileName == "" || res.size == 0)
+ continue;
+
+ //debug(" - %s at %d, size: %d", fileName.c_str(), res.pos, res.size);
+ }
+ }
+
+ indexFile.close();
+}
+
+ResourceManager::~ResourceManager() {
+ for (int i = 0; i < MAX_VOLUMES; i++)
+ _volumes[i].close();
+}
+
+Common::SeekableReadStream *ResourceManager::getResource(Common::String name, bool ignorePatches) {
+ name.toLowercase();
+
+ // Load external patches
+ if (!ignorePatches && Common::File::exists(name)) {
+ Common::File *patch = new Common::File();
+ patch->open(name);
+ return patch;
+ }
+
+ if (!_resources.contains(name))
+ return nullptr;
+
+ Resource res = _resources[name];
+ return new Common::SeekableSubReadStream(&_volumes[res.volume], res.pos, res.pos + res.size);
+}
+
+Resource ResourceManager::getResourceInfo(Common::String name) {
+ name.toLowercase();
+
+ if (!_resources.contains(name))
+ return Resource();
+
+ return _resources[name];
+}
+
+bool DgdsChunk::isSection(const Common::String §ion) {
+ return section.equals(_idStr);
+}
+
+bool DgdsChunk::isSection(DGDS_ID section) {
+ return (section == _id);
+}
+
+bool DgdsChunk::isPacked(DGDS_EX ex) {
+ bool packed = false;
+
+ switch (ex) {
+ case EX_ADS:
+ case EX_ADL:
+ case EX_ADH:
+ packed = (_id == ID_SCR);
+ break;
+ case EX_BMP:
+ packed = (_id == ID_BIN || _id == ID_VGA);
+ break;
+ case EX_GDS:
+ case EX_SDS:
+ packed = (_id == ID_SDS);
+ break;
+ case EX_SCR:
+ packed = (_id == ID_BIN || _id == ID_VGA || _id == ID_MA8);
+ break;
+ case EX_SNG:
+ packed = (_id == ID_SNG);
+ break;
+ case EX_TTM:
+ packed = (_id == ID_TT3);
+ break;
+ case EX_TDS:
+ packed = (_id == ID_THD);
+ break;
+ default:
+ break;
+ }
+
+ switch (ex) {
+ case EX_DDS:
+ packed = !strcmp(_idStr, "DDS:");
+ break;
+ case EX_OVL:
+ if (0) {
+ } else if (strcmp(_idStr, "ADL:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "ADS:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "APA:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "ASB:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "GMD:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "M32:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "NLD:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "PRO:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "PS1:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "SBL:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "SBP:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "STD:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "TAN:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "T3V:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "001:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "003:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "004:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "101:") == 0)
+ packed = true;
+ else if (strcmp(_idStr, "VGA:") == 0)
+ packed = true;
+ break;
+ case EX_TDS:
+ if (0) {
+ } else if (strcmp(_idStr, "TDS:") == 0)
+ packed = true; /* ? */
+ break;
+ default:
+ break;
+ }
+ return packed;
+}
+
+bool DgdsChunk::readHeader(DgdsParser &ctx) {
+ memset(_idStr, 0, sizeof(_idStr));
+ _id = 0;
+
+ if (ctx._file.pos() >= ctx._file.size()) {
+ return false;
+ }
+
+ ctx._file.read(_idStr, DGDS_TYPENAME_MAX);
+
+ if (_idStr[DGDS_TYPENAME_MAX - 1] != ':') {
+ debug("bad header in: %s", ctx._filename);
+ return false;
+ }
+ _idStr[DGDS_TYPENAME_MAX] = '\0';
+ _id = MKTAG24(uint32(_idStr[0]), uint32(_idStr[1]), uint32(_idStr[2]));
+
+ _size = ctx._file.readUint32LE();
+ //ctx._file.skip(2);
+ if (_size & 0x80000000) {
+ _size &= ~0x80000000;
+ container = true;
+ } else {
+ container = false;
+ }
+ return true;
+}
+
+Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompressor *decompressor) {
+ byte compression;
+ uint32 unpackSize;
+ Common::SeekableReadStream *output = 0;
+
+ compression = ctx._file.readByte();
+ unpackSize = ctx._file.readUint32LE();
+ _size -= (1 + 4);
+
+ if (!container) {
+ byte *dest = new byte[unpackSize];
+ decompressor->decompress(compression, dest, unpackSize, &ctx._file, _size);
+ output = new Common::MemoryReadStream(dest, unpackSize, DisposeAfterUse::YES);
+ ctx.bytesRead += unpackSize;
+ }
+
+ /*debug(" %s %u %s %u%c",
+ id, _size,
+ compressionDescr[compression],
+ unpackSize, (container ? '+' : ' '));*/
+ return output;
+}
+
+Common::SeekableReadStream *DgdsChunk::readStream(DgdsParser &ctx) {
+ Common::SeekableReadStream *output = 0;
+
+ if (!container) {
+ output = new Common::SeekableSubReadStream(&ctx._file, ctx._file.pos(), ctx._file.pos() + _size, DisposeAfterUse::NO);
+ ctx.bytesRead += _size;
+ }
+
+ debug(" %s %u%c", _idStr, _size, (container ? '+' : ' '));
+ return output;
+}
+
+bool isFlatfile(Common::Platform platform, DGDS_EX _ex) {
+ bool flat = false;
+
+ switch (_ex) {
+ case EX_RST:
+ case EX_VIN:
+ case EX_DAT:
+ flat = true;
+ break;
+ default:
+ break;
+ }
+
+ switch (platform) {
+ case Common::kPlatformAmiga:
+ switch (_ex) {
+ case EX_BMP:
+ case EX_SCR:
+ case EX_INS:
+ // case EX_SNG:
+ case EX_AMG:
+ flat = true;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ return flat;
+}
+
+#if 0
+/*
+ input:
+ s - pointer to ASCIIZ filename string
+ idx - pointer to an array of 4 bytes (hash indexes)
+ return:
+ hash - filename hash
+*/
+int32 dgdsHash(const char *s, byte *idx) {
+ int32 i, c;
+ int16 isum, ixor;
+ isum = 0;
+ ixor = 0;
+ for (i = 0; s[i]; i++) {
+ c = toupper(s[i]);
+ isum += c;
+ ixor ^= c;
+ }
+ /* both types here MUST be int16 */
+ isum *= ixor;
+ c = 0;
+ for (ixor = 0; ixor < 4; ixor++) {
+ c <<= 8;
+ /* can use only existing characters
+ ("i" holds the string length now) */
+ if (i > idx[ixor]) {
+ c |= toupper(s[idx[ixor]]);
+ }
+ }
+ c += isum;
+ return c;
+}
+#endif
+
+#if 0
+// TAGS vs UNIQUE TAGS
+// HASHTABLE?
+
+uint32 lookupVolume(const char *rmfName, const char *filename, char *volname) {
+ Common::File index;
+ if (!index.open(rmfName))
+ return 0xFFFFFFFF;
+
+ byte salt[4];
+ int32 filehash;
+
+ index.read(salt, sizeof(salt));
+ filehash = dgdsHash(filename, salt);
+
+ uint16 nvolumes;
+ nvolumes = index.readUint16LE();
+ for (uint i = 0; i < nvolumes; i++) {
+ index.read(volname, FILENAME_LENGTH + 1);
+ volname[FILENAME_LENGTH] = '\0';
+
+ uint16 nfiles;
+ nfiles = index.readUint16LE();
+ for (uint j = 0; j < nfiles; j++) {
+ int32 hash = index.readSint32LE();
+ uint32 offset = index.readUint32LE();
+ if (hash == filehash) {
+ index.close();
+ return offset;
+ }
+ }
+ }
+ index.close();
+ return 0xFFFFFFFF;
+}
+#endif
+
+#if 0
+Common::SeekableReadStream *createReadStream(const char *rmfName, const char *filename) {
+ char volname[FILENAME_LENGTH + 1];
+ uint32 offset;
+ offset = lookupVolume(rmfName, filename, volname);
+ if (offset == 0xFFFFFFFF)
+ return 0;
+
+ Common::File *volume = new Common::File;
+ do {
+ if (!volume->open(volname))
+ break;
+ volume->seek(offset);
+ volume->read(volname, sizeof(volname));
+ volname[FILENAME_LENGTH] = '\0';
+
+ uint32 fileSize;
+ fileSize = volume->readUint32LE();
+
+ if (fileSize == 0xFFFFFFFF)
+ break;
+ if (scumm_stricmp(volname, filename))
+ break;
+ return new Common::SeekableSubReadStream(volume, volume->pos(), volume->pos() + fileSize, DisposeAfterUse::YES);
+ } while (0);
+
+ delete volume;
+ return 0;
+}
+#endif
+
+#if 0
+void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource) {
+ if (fileName) {
+ Common::File file;
+ if (file.open(fileName)) {
+ parseFile(platform, file, fileName, resource);
+ file.close();
+ return;
+ }
+ }
+
+ Common::File index, volume;
+ Common::SeekableSubReadStream *file;
+ if (index.open(indexName)) {
+ byte salt[4];
+ uint16 nvolumes;
+
+ index.read(salt, sizeof(salt));
+ nvolumes = index.readUint16LE();
+
+ if (!fileName)
+ debug("(%u,%u,%u,%u) %u", salt[0], salt[1], salt[2], salt[3], nvolumes);
+
+ for (uint i = 0; i < nvolumes; i++) {
+ char name[FILENAME_LENGTH + 1];
+ uint16 nfiles;
+
+ index.read(name, sizeof(name));
+ name[FILENAME_LENGTH] = '\0';
+
+ nfiles = index.readUint16LE();
+
+ debugN("--\n#%u %s, %u files", i, name, nfiles);
+
+ if (!volume.open(name)) {
+ debug(", failed to open");
+ continue;
+ }
+
+ debug(", %d bytes", volume.size());
+
+ for (uint j = 0; j < nfiles; j++) {
+ int32 hash;
+ uint32 offset, fileSize;
+
+ hash = index.readSint32LE();
+ offset = index.readUint32LE();
+
+ volume.seek(offset);
+ volume.read(name, sizeof(name));
+ name[FILENAME_LENGTH] = '\0';
+ fileSize = volume.readUint32LE();
+
+ if (!fileName || scumm_stricmp(name, fileName) == 0)
+ debug(" #%u %s 0x%X=0x%X %u %u\n --", j, name, hash, dgdsHash(name, salt), offset, fileSize);
+
+ if (fileSize == 0xFFFFFFFF) {
+ continue;
+ }
+
+ if (fileName && scumm_stricmp(name, fileName)) {
+ volume.skip(fileSize);
+ continue;
+ }
+
+ file = new Common::SeekableSubReadStream(&volume, volume.pos(), volume.pos() + fileSize, DisposeAfterUse::NO);
+
+ parseFile(platform, *file, name, resource);
+
+ if (!fileName)
+ debug(" #%u %s %d .", j, name, volume.pos());
+
+ if (fileName) {
+ volume.close();
+ index.close();
+ return;
+ }
+ }
+ volume.close();
+ }
+ index.close();
+ }
+}
+#endif
+
+#if 0
+int prev_id = -1;
+int prev_bk = -1;
+int prev_palette = -1;
+
+void browseInit(Common::Platform _platform, const char *_rmfName, DgdsEngine* syst) {
+ BMPs.clear();
+ explode(_platform, _rmfName, 0, -1);
+ bk = 0;
+ _idStr = 0;
+ sid = 1;
+}
+
+void browse(Common::Platform _platform, const char *_rmfName, DgdsEngine* syst) {
+ if (prev_id != _idStr || prev_bk != bk) {
+ explode(_platform, _rmfName, BMPs[_idStr].c_str(), bk);
+ prev_id = _idStr;
+ prev_bk = bk;
+
+ Common::String txt = Common::String::format("%s: %ux%u (%u/%u)", BMPs[_idStr].c_str(), _tw, _th, bk+1, _tcount);
+ g_system->displayMessageOnOSD(txt.c_str());
+ }
+ if (prev_palette != sid) {
+ sid = sid&3;
+ prev_palette = sid;
+
+ switch (sid) {
+ case 3:
+ for (uint i=0; i<256; i++) {
+ palette[i*3+0] = i;
+ palette[i*3+1] = i;
+ palette[i*3+2] = i;
+ }
+ break;
+ case 2:
+ for (uint i=0; i<256; i++) {
+ palette[i*3+0] = 255-i;
+ palette[i*3+1] = 255-i;
+ palette[i*3+2] = 255-i;
+ }
+ break;
+ case 1:
+ explode(_platform, _rmfName, "DRAGON.PAL", 0);
+ break;
+ }
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ }
+
+ if (bk != -1) {
+ if (_bmpData.h != 0) {
+ byte *_bmpData_;
+ _bmpData_ = (byte *)_bmpData.getPixels();
+ byte *vgaData_;
+ byte *binData_;
+ bw = _tw; bh = _th;
+ vgaData_ = (byte *)_bmpData.getPixels();
+ binData_ = (byte *)_binData.getPixels();
+
+ for (int i=0; i<bw*bh; i+=2) {
+ _bmpData_[i+0] = ((vgaData_[i>>1] & 0xF0) );
+ _bmpData_[i+0] |= ((binData_[i>>1] & 0xF0) >> 4);
+ _bmpData_[i+1] = ((vgaData_[i>>1] & 0x0F) << 4);
+ _bmpData_[i+1] |= ((binData_[i>>1] & 0x0F) );
+ }
+
+ const int rows = sh;
+ const int columns = sw;
+
+ byte *src = _bmpData_;
+ byte *ptr = (byte *)bottomBuffer.getBasePtr(0, 0);
+ for (int i=0; i<rows; ++i) {
+ for (int j=0; j<columns; ++j) {
+ ptr[j] = src[j];
+ }
+ ptr += bottomBuffer.pitch;
+ src += bw;
+ }
+ }
+
+ resData.clear(0);
+ Common::Rect bmpWin(0, 0, _tw, _th);
+ Graphics::Surface bmpSub = bottomBuffer.getSubArea(bmpWin);
+ resData.blitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
+ resData.frameRect(bmpWin, 1);
+
+ Graphics::Surface *dst;
+ dst = g_system->lockScreen();
+ dst->copyRectToSurface(resData, 0, 0, rect);
+ g_system->unlockScreen();
+ g_system->updateScreen();
+ }
+}
+#endif
+
+} // End of namespace Dgds
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
new file mode 100644
index 00000000000..496e02f102a
--- /dev/null
+++ b/engines/dgds/resource.h
@@ -0,0 +1,91 @@
+/* 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 DGDS_RESOURCE_H
+#define DGDS_RESOURCE_H
+
+#include "common/file.h"
+#include "common/hashmap.h"
+#include "common/platform.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Dgds {
+
+class DgdsParser;
+class Decompressor;
+
+typedef uint32 DGDS_ID;
+typedef uint32 DGDS_EX;
+#define DGDS_TYPENAME_MAX 4
+
+struct Resource {
+ byte volume;
+ uint32 pos;
+ uint32 size;
+ uint32 checksum;
+};
+
+typedef Common::HashMap<Common::String, Resource> ResourceList;
+
+#define MAX_VOLUMES 10
+
+class ResourceManager {
+public:
+ ResourceManager();
+ virtual ~ResourceManager();
+
+ Common::SeekableReadStream *getResource(Common::String name, bool ignorePatches = false);
+ Resource getResourceInfo(Common::String name);
+ ResourceList _resources;
+
+private:
+ Common::File _volumes[MAX_VOLUMES];
+};
+
+class DgdsChunk {
+public:
+ bool isSection(const Common::String §ion);
+ bool isSection(DGDS_ID section);
+ bool isPacked(DGDS_EX ex);
+
+ bool readHeader(DgdsParser &ctx);
+ Common::SeekableReadStream *decodeStream(DgdsParser &ctx, Decompressor *decompressor);
+ Common::SeekableReadStream *readStream(DgdsParser &ctx);
+
+ char _idStr[DGDS_TYPENAME_MAX + 1];
+ DGDS_ID _id;
+ uint32 _size;
+ bool container;
+ Common::SeekableReadStream *_stream;
+};
+
+bool isFlatfile(Common::Platform platform, DGDS_EX _ex);
+//int32 dgdsHash(const char *s, byte *idx);
+//uint32 lookupVolume(const char *rmfName, const char *filename, char *volname);
+//Common::SeekableReadStream *createReadStream(const char *rmfName, const char *filename);
+
+} // End of namespace Dgds
+
+#endif // DGDS_RESOURCE_H
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
new file mode 100644
index 00000000000..47b48beefcb
--- /dev/null
+++ b/engines/dgds/sound.cpp
@@ -0,0 +1,159 @@
+/* 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/debug.h"
+#include "common/endian.h"
+
+#include "dgds/sound.h"
+
+namespace Dgds {
+
+static inline
+void readHeader(byte* &pos, uint32 &sci_header) {
+ sci_header = 0;
+ if (READ_LE_UINT16(pos) == 0x0084) sci_header = 2;
+
+ pos += sci_header;
+ if (pos[0] == 0xF0) {
+ debug("SysEx transfer = %d bytes", pos[1]);
+ pos += 2;
+ pos += 6;
+ }
+}
+
+static inline
+void readPartHeader(byte* &pos, uint16 &off, uint16 &siz) {
+ pos += 2;
+ off = READ_LE_UINT16(pos);
+ pos += 2;
+ siz = READ_LE_UINT16(pos);
+ pos += 2;
+}
+
+static inline
+void skipPartHeader(byte* &pos) {
+ pos += 6;
+}
+
+uint32 availableSndTracks(byte *data, uint32 size) {
+ byte *pos = data;
+
+ uint32 sci_header;
+ readHeader(pos, sci_header);
+
+ uint32 tracks = 0;
+ while (pos[0] != 0xFF) {
+ byte drv = *pos++;
+
+ debug("(%d)", drv);
+
+ while (pos[0] != 0xFF) {
+ uint16 off, siz;
+ readPartHeader(pos, off, siz);
+ off += sci_header;
+
+ debug("%06d:%d ", off, siz);
+
+ debug("Header bytes");
+ debug("[%06X] ", data[off]);
+ debug("[%02X] ", data[off+0]);
+ debug("[%02X] ", data[off+1]);
+
+ bool digital_pcm = false;
+ if (READ_LE_UINT16(&data[off]) == 0x00FE) {
+ digital_pcm = true;
+ }
+
+ switch (drv) {
+ case 0: if (digital_pcm) {
+ debug("- Soundblaster");
+ tracks |= DIGITAL_PCM;
+ } else {
+ debug("- Adlib");
+ tracks |= TRACK_ADLIB;
+ } break;
+ case 7: debug("- General MIDI");
+ tracks |= TRACK_GM; break;
+ case 9: debug("- CMS"); break;
+ case 12: debug("- MT-32");
+ tracks |= TRACK_MT32; break;
+ case 18: debug("- PC Speaker"); break;
+ case 19: debug("- Tandy 1000"); break;
+ default: debug("- Unknown %d", drv); break;
+ }
+ }
+
+ pos++;
+ }
+ pos++;
+ return tracks;
+}
+
+byte loadSndTrack(uint32 track, byte** trackPtr, uint16* trackSiz, byte *data, uint32 size) {
+ byte matchDrv;
+ switch (track) {
+ case DIGITAL_PCM:
+ case TRACK_ADLIB: matchDrv = 0; break;
+ case TRACK_GM: matchDrv = 7; break;
+ case TRACK_MT32: matchDrv = 12; break;
+ default: return 0;
+ }
+
+ byte *pos = data;
+
+ uint32 sci_header;
+ readHeader(pos, sci_header);
+
+ while (pos[0] != 0xFF) {
+ byte drv = *pos++;
+
+ byte part;
+ byte *ptr;
+
+ part = 0;
+ for (ptr = pos; *ptr != 0xFF; skipPartHeader(ptr))
+ part++;
+
+ if (matchDrv == drv) {
+ part = 0;
+ while (pos[0] != 0xFF) {
+ uint16 off, siz;
+ readPartHeader(pos, off, siz);
+ off += sci_header;
+
+ trackPtr[part] = data + off;
+ trackSiz[part] = siz;
+ part++;
+ }
+ debug("- (%d) Play parts = %d", drv, part);
+ return part;
+ } else {
+ pos = ptr;
+ }
+ pos++;
+ }
+ pos++;
+ return 0;
+}
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
new file mode 100644
index 00000000000..0164e4b92e8
--- /dev/null
+++ b/engines/dgds/sound.h
@@ -0,0 +1,43 @@
+/* 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 DGDS_SOUND_H
+#define DGDS_SOUND_H
+
+#include "common/scummsys.h"
+
+namespace Dgds {
+
+enum {
+ DIGITAL_PCM = 1 << 0,
+ TRACK_ADLIB = 1 << 1,
+ TRACK_GM = 1 << 2,
+ TRACK_MT32 = 1 << 3
+};
+
+uint32 availableSndTracks(byte *data, uint32 size);
+byte loadSndTrack(uint32 track, byte** trackPtr, uint16* trackSiz, byte *data, uint32 size);
+
+} // End of namespace Dgds
+
+#endif // DGDS_SOUND_H
+
Commit: 348c6aca5a73f0b434c9f5906b7d516f2776d53e
https://github.com/scummvm/scummvm/commit/348c6aca5a73f0b434c9f5906b7d516f2776d53e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Update and rebase engine
* Added VQT image parsing for DOS games.
* Refactor slightly for better type and const correctness
* Re-enable sound for DOS games
Changed paths:
engines/dgds/console.cpp
engines/dgds/detection.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/includes.h
engines/dgds/metaengine.cpp
engines/dgds/movies.cpp
engines/dgds/movies.h
engines/dgds/parser.cpp
engines/dgds/parser.h
engines/dgds/resource.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 308b69cfc7b..bc3d76850f7 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -118,7 +118,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
delete res;
Common::DumpFile out;
- out.open(fileName);
+ out.open(Common::Path(fileName));
out.write(data, size);
out.flush();
out.close();
diff --git a/engines/dgds/detection.cpp b/engines/dgds/detection.cpp
index 10d6db058b5..86914e6780d 100644
--- a/engines/dgds/detection.cpp
+++ b/engines/dgds/detection.cpp
@@ -42,7 +42,7 @@ public:
_guiOptions = GUIO1(GUIO_NONE);
}
- const char* getEngineId() const override {
+ const char* getEngineName() const override {
return "dgds";
}
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7ee29118244..1d4d2cc9efd 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -33,7 +33,7 @@
#include "common/substream.h"
#include "common/system.h"
-#include "common/iff_container.h"
+#include "common/formats/iff_container.h"
#include "audio/audiostream.h"
#include "audio/decoders/aiff.h"
@@ -99,12 +99,12 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
else if (!strcmp(gameDesc->gameId, "beamish"))
_gameId = GID_BEAMISH;
- const Common::FSNode gameDataDir(ConfMan.get("path"));
+ const Common::FSNode gameDataDir(ConfMan.getPath("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "patches");
}
DgdsEngine::~DgdsEngine() {
- DebugMan.clearAllDebugChannels();
+ DebugMan.removeAllDebugChannels();
delete _image;
delete _decompressor;
@@ -132,25 +132,6 @@ struct Tag {
Common::String tag;
};
-Common::HashMap<uint16, Common::String> *readTags(Common::SeekableReadStream *stream) {
- Common::HashMap<uint16, Common::String> *tags = new Common::HashMap<uint16, Common::String>;
- uint16 count = stream->readUint16LE();
- debug(" %u:", count);
-
- for (uint16 i = 0; i < count; i++) {
- Common::String string;
- byte c = 0;
- uint16 idx = stream->readUint16LE();
- while (c = stream->readByte())
- string += c;
- debug(" %2u: %2u, \"%s\"", i, idx, string.c_str());
-
- (*tags)[idx] = string;
- }
-
- return tags;
-}
-
void readSDS(Common::SeekableReadStream *stream) {
uint32 mark;
@@ -435,15 +416,7 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
file.hexdump(leftover);
file.skip(leftover);
} else {
- uint16 tcount;
- uint16 scount;
- uint16 *tw = 0, *th = 0;
- uint32 *toffset = 0;
-
- uint16 *mtx;
- uint16 mw, mh;
-
- scount = 0;
+ uint16 scount = 0;
DgdsChunk chunk;
while (chunk.readHeader(ctx)) {
@@ -627,7 +600,7 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
} else if (chunk.isSection(ID_RES)) {
debug("res0");
if (resource == 0) {
- readTags(stream);
+ DgdsParser::readTags(stream);
} else {
readStrings(stream);
}
@@ -823,16 +796,13 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
debug("BMPs: %s", name);
}
- debug(" [%u:%u] --", file.pos(), ctx.bytesRead);
+ debug(" [%u:%u] --", (uint)file.pos(), ctx._bytesRead);
}
-void DgdsEngine::parseFile(Common::String filename, int resource) {
- //filename.toLowercase();
-
- if (filename.hasSuffix(".SNG") || filename.hasSuffix(".sng")) // TODO: Mac sound
- return;
-
+void DgdsEngine::parseFile(const Common::String &filename, int resource) {
Common::SeekableReadStream *stream = _resource->getResource(filename);
+ if (!stream)
+ error("Couldn't get resource file %s", filename.c_str());
parseFileInner(_platform, *stream, filename.c_str(), resource, _decompressor);
delete stream;
}
@@ -847,7 +817,7 @@ struct Channel {
struct Channel _channels[2];
-void DgdsEngine::playSfx(const char *fileName, byte channel, byte volume) {
+void DgdsEngine::playSfx(const Common::String &fileName, byte channel, byte volume) {
parseFile(fileName);
if (soundData) {
Channel *ch = &_channels[channel];
@@ -912,7 +882,7 @@ bool DgdsEngine::playPCM(byte *data, uint32 size) {
return true;
}
-void DgdsEngine::playMusic(const char *fileName) {
+void DgdsEngine::playMusic(const Common::String &fileName) {
//stopMusic();
parseFile(fileName);
@@ -949,6 +919,7 @@ Common::Error DgdsEngine::run() {
g_system->fillScreen(0);
+
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
@@ -957,10 +928,10 @@ Common::Error DgdsEngine::run() {
TTMState title1State, title2State;
ADSState introState;
+ TTMData title1Data, title2Data;
+ ADSData introData;
if (getGameId() == GID_DRAGON) {
- TTMData title1Data, title2Data;
- ADSData introData;
interpTTM.load("TITLE1.TTM", &title1Data);
interpTTM.load("TITLE2.TTM", &title2Data);
interpADS.load("INTRO.ADS", &introData);
@@ -972,14 +943,12 @@ Common::Error DgdsEngine::run() {
parseFile("DRAGON.FNT");
parseFile("S55.SDS");
} else if (getGameId() == GID_CHINA) {
- ADSData introData;
interpADS.load("TITLE.ADS", &introData);
interpADS.init(&introState, &introData);
parseFile("HOC.FNT");
} else if (getGameId() == GID_BEAMISH) {
- ADSData introData;
interpADS.load("TITLE.ADS", &introData);
interpADS.init(&introState, &introData);
@@ -987,7 +956,7 @@ Common::Error DgdsEngine::run() {
//parseFile("HOC.FNT");
}
- _console->attach();
+ //_console->attach();
while (!shouldQuit()) {
if (eventMan->pollEvent(ev)) {
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 1ae925bd0c7..955de90dc79 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -64,13 +64,13 @@ public:
DgdsGameId getGameId() { return _gameId; }
- void playSfx(const char* fileName, byte channel, byte volume);
+ void playSfx(const Common::String &fileName, byte channel, byte volume);
void stopSfx(byte channel);
bool playPCM(byte *data, uint32 size);
- void playMusic(const char* fileName);
+ void playMusic(const Common::String &fileName);
- void parseFile(Common::String filename, int resource = 0);
+ void parseFile(const Common::String &filename, int resource = 0);
ResourceManager *_resource;
Decompressor *_decompressor;
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index eee4ccc5b9e..e28ec015243 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -52,6 +52,8 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
const char *dot;
DGDS_EX ex;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ if (!fileStream)
+ error("Couldn't get image resource %s", filename.c_str());
DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
@@ -92,8 +94,9 @@ void Image::loadBitmap(Common::String filename, int number) {
const char *dot;
DGDS_EX ex;
uint16 *mtx;
- uint16 mw, mh;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ if (!fileStream)
+ error("Couldn't get bitmap resource %s", filename.c_str());
DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
@@ -112,15 +115,15 @@ void Image::loadBitmap(Common::String filename, int number) {
return;
}
- // Currently does not handle the VQT: and OFF: chunks
- // for the compressed pics in the DOS port.
+ int64 vqtpos = -1;
+ int32 vqtsize = -1;
+ uint16 tileWidths[64];
+ uint16 tileHeights[64];
+
while (chunk.readHeader(ctx)) {
Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
- uint16 *tileWidths = new uint16[tileCount];
- uint16 *tileHeights = new uint16[tileCount];
-
for (uint16 k = 0; k < tileCount; k++) {
tileWidths[k] = stream->readUint16LE();
if (k == number)
@@ -135,11 +138,9 @@ void Image::loadBitmap(Common::String filename, int number) {
if (k < number)
_tileOffset += tileWidths[k] * tileHeights[k];
}
-
- delete[] tileWidths;
- delete[] tileHeights;
} else if (chunk.isSection(ID_MTX)) {
// Scroll offset
+ uint16 mw, mh;
mw = stream->readUint16LE();
mh = stream->readUint16LE();
uint32 mcount = uint32(mw) * mh;
@@ -158,8 +159,43 @@ void Image::loadBitmap(Common::String filename, int number) {
} else if (chunk.isSection(ID_VGA)) {
loadBitmap4(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream, true);
} else if (chunk.isSection(ID_VQT)) {
- loadVQT(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream);
+ // Postpone parsing this until we have the offsets, which come after.
+ vqtpos = fileStream->pos();
+ vqtsize = chunk._size;
+ stream->skip(vqtsize);
+ } else if (chunk.isSection(ID_OFF)) {
+ if (vqtpos == -1)
+ error("Expect VQT chunk before OFF chunk in BMP resource %s", filename.c_str());
+
+ // 2 possibilities: A set of offsets (find the one which we need and use it)
+ // or a single value of 0xffff. If it's only one tile the offset is always
+ // zero anyway. For subsequent images, round up to the next byte to start
+ // reading.
+ if (chunk._size == 2) {
+ if (number != 0) {
+ uint16 val = stream->readUint16LE();
+ if (val != 0xffff)
+ warning("Expected 0xffff in 2-byte offset list, got %04x", val);
+ }
+
+ _tileOffset = 0;
+ uint32 nextOffset = 0;
+ for (int i = 0; i < number + 1; i++) {
+ fileStream->seek(vqtpos);
+ _bmpData.free();
+ nextOffset = loadVQT(_bmpData, tileWidths[i], tileHeights[i], nextOffset, fileStream);
+ nextOffset = ((nextOffset + 7) / 8) * 8;
+ }
+ } else {
+ if (number)
+ stream->skip(4 * number);
+ _tileOffset = stream->readUint32LE();
+ // TODO: seek stream to end for tidiness?
+ fileStream->seek(vqtpos + _tileOffset);
+ loadVQT(_bmpData, _tileWidth, _tileHeight, 0, fileStream);
+ }
}
+ delete stream;
}
delete fileStream;
@@ -220,20 +256,145 @@ void Image::loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 to
stream->read(data, uint32(outPitch) * th);
}
-void Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream) {
+struct VQTDecodeState {
+ uint32 offset;
+ const byte *srcPtr;
+ byte *dstPtr;
+ uint16 rowStarts[200];
+};
+
+static inline uint16 _getVqtBits(struct VQTDecodeState *state, int nbits) {
+ const uint32 offset = state->offset;
+ const uint32 index = offset >> 3;
+ const uint32 shift = offset & 7;
+ state->offset += nbits;
+ return (*(const uint16 *)(state->srcPtr + index) >> (shift)) & (byte)(0xff00 >> (16 - nbits));
+}
+
+static void _doVqtDecode2(struct VQTDecodeState *state, const uint16 x, const uint16 y, const uint16 w, const uint16 h) {
+ // Empty region -> nothing to do
+ if (h == 0 || w == 0)
+ return;
+
+ // 1x1 region -> put the byte directly
+ if (w == 1 && h == 1) {
+ state->dstPtr[state->rowStarts[y] + x] = _getVqtBits(state, 8);
+ return;
+ }
+
+ const uint losize = (w & 0xff) * (h & 0xff);
+ uint bitcount1 = 8;
+ if (losize < 256) {
+ bitcount1 = 0;
+ byte b = (byte)(losize - 1);
+ do {
+ bitcount1++;
+ b >>= 1;
+ } while (b != 0);
+ }
+
+ uint16 firstval = _getVqtBits(state, bitcount1);
+
+ uint16 bitcount2 = 0;
+ byte bval = (byte)firstval;
+ while (firstval != 0) {
+ bitcount2++;
+ firstval >>= 1;
+ }
+
+ bval++;
+
+ if (losize * 8 <= losize * bitcount2 + bval * 8) {
+ for (uint xx = x; xx < x + w; xx++) {
+ for (uint yy = y; yy < y + h; yy++) {
+ state->dstPtr[state->rowStarts[yy] + xx] = _getVqtBits(state, 8);
+ }
+ }
+ return;
+ }
+
+ if (bval == 1) {
+ const uint16 val = _getVqtBits(state, 8);
+ for (uint yy = y; yy < y + h; yy++) {
+ for (uint xx = x; xx < x + w; xx++) {
+ state->dstPtr[state->rowStarts[yy] + xx] = val;
+ }
+ }
+ return;
+ }
+
+ byte tmpbuf [262];
+ byte *ptmpbuf = tmpbuf;
+ for (; bval != 0; bval--) {
+ *ptmpbuf = _getVqtBits(state, 8);
+ ptmpbuf++;
+ }
+
+ for (uint xx = x; xx < x + w; xx++) {
+ for (uint yy = y; yy < y + h; yy++) {
+ state->dstPtr[state->rowStarts[yy] + xx] = tmpbuf[_getVqtBits(state, bitcount2)];
+ }
+ }
+}
+
+static void _doVqtDecode(struct VQTDecodeState *state, uint16 x, uint16 y, uint16 w, uint16 h) {
+ if (!w && !h)
+ return;
+
+ const uint16 mask = _getVqtBits(state, 4);
+
+ // Top left quadrant
+ if (mask & 8)
+ _doVqtDecode(state, x, y, w / 2, h / 2);
+ else
+ _doVqtDecode2(state, x, y, w / 2, h / 2);
+
+ // Top right quadrant
+ if (mask & 4)
+ _doVqtDecode(state, x + (w / 2), y, (w + 1) >> 1, h >> 1);
+ else
+ _doVqtDecode2(state, x + (w / 2), y, (w + 1) >> 1, h >> 1);
+
+ // Bottom left quadrant
+ if (mask & 2)
+ _doVqtDecode(state, x, y + (h / 2), w / 2, (h + 1) / 2);
+ else
+ _doVqtDecode2(state, x, y + (h / 2), w / 2, (h + 1) / 2);
+
+ // Bottom right quadrant
+ if (mask & 1)
+ _doVqtDecode(state, x + (w / 2), y + (h / 2), (w + 1) / 2, (h + 1) / 2);
+ else
+ _doVqtDecode2(state, x + (w / 2), y + (h / 2), (w + 1) / 2, (h + 1) / 2);
+}
+
+
+uint32 Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream) {
+ if (th > 200)
+ error("Max VQT height supported is 200px");
uint16 outPitch = tw;
surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
- byte *data = (byte *)surf.getPixels();
-
- // HACK
- stream->skip(toffset);
- stream->read(data, uint32(outPitch) * th);
+ VQTDecodeState state;
+ state.dstPtr = (byte *)surf.getPixels();
+ state.offset = toffset;
+ // FIXME: This sometimes reads more than it needs to..
+ uint64 nbytes = stream->size() - stream->pos();
+ byte *buf = (byte *)malloc(nbytes + 8);
+ memset(buf, 0, nbytes + 8);
+ stream->read(buf, nbytes);
+ state.srcPtr = buf;
+ for (uint i = 0; i < th; i++)
+ state.rowStarts[i] = tw * i;
+
+ _doVqtDecode(&state, 0, 0, tw, th);
+ free(buf);
+ return state.offset;
}
void Image::loadPalette(Common::String filename) {
- const char *dot;
- DGDS_EX ex;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ if (!fileStream)
+ error("Couldn't get palette resource %s", filename.c_str());
DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index a4528387a90..ff5494343b5 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -49,11 +49,12 @@ public:
void loadPalette(Common::String filename);
void setPalette();
void clearPalette();
+ bool isLoaded() const { return _bmpData.getPixels() != nullptr; }
private:
void loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
void loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
- void loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
+ uint32 loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
Graphics::Surface _bmpData;
ResourceManager *_resourceMan;
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
index c3b7cf05312..b4bd46fcb6e 100644
--- a/engines/dgds/includes.h
+++ b/engines/dgds/includes.h
@@ -43,9 +43,11 @@ namespace Dgds {
#define ID_SNG MKTAG24('S', 'N', 'G')
#define ID_TAG MKTAG24('T', 'A', 'G')
#define ID_TT3 MKTAG24('T', 'T', '3')
+#define ID_TTI MKTAG24('T', 'T', 'I')
#define ID_VER MKTAG24('V', 'E', 'R')
#define ID_VGA MKTAG24('V', 'G', 'A')
#define ID_VQT MKTAG24('V', 'Q', 'T')
+#define ID_OFF MKTAG24('O', 'F', 'F')
/* Heart of China */
#define ID_MA8 MKTAG24('M', 'A', '8')
diff --git a/engines/dgds/metaengine.cpp b/engines/dgds/metaengine.cpp
index fa95c05dae4..e3b85741547 100644
--- a/engines/dgds/metaengine.cpp
+++ b/engines/dgds/metaengine.cpp
@@ -33,7 +33,7 @@ public:
}
bool hasFeature(MetaEngineFeature f) const override;
- bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+ Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
};
bool DgdsMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -45,11 +45,11 @@ bool DgdsMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSimpleSavesNames);
}
-bool DgdsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+Common::Error DgdsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
if (desc)
*engine = new Dgds::DgdsEngine(syst, desc);
- return desc != nullptr;
+ return (desc != nullptr) ? Common::kNoError : Common::kUnknownError;
}
#if PLUGIN_ENABLED_DYNAMIC(DGDS)
diff --git a/engines/dgds/movies.cpp b/engines/dgds/movies.cpp
index 31e8c72ebeb..72ae4925fe3 100644
--- a/engines/dgds/movies.cpp
+++ b/engines/dgds/movies.cpp
@@ -55,28 +55,21 @@ extern PFont *_fntP;
Common::Rect drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
Common::String _bmpNames[16];
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(0), _filename(0) {}
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
-bool TTMInterpreter::load(const char *filename, TTMData *scriptData) {
+bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
Common::SeekableReadStream *stream = _vm->_resource->getResource(filename);
if (!stream) {
- error("Couldn't open script file '%s'", filename);
+ error("Couldn't open script file '%s'", filename.c_str());
return false;
}
- memset(scriptData, 0, sizeof(*scriptData));
- _scriptData = scriptData;
- _filename = filename;
-
- TTMParser dgds(*stream, _filename);
+ TTMParser dgds(*stream, filename);
dgds.parse(scriptData, _vm->_decompressor);
delete stream;
- Common::strlcpy(_scriptData->filename, filename, sizeof(_scriptData->filename));
- _scriptData = 0;
- _filename = 0;
return true;
}
@@ -85,7 +78,7 @@ void TTMInterpreter::unload(TTMData *data) {
return;
delete data->scr;
- data->scr = 0;
+ data->scr = nullptr;
}
void TTMInterpreter::init(TTMState *state, const TTMData *data) {
@@ -125,8 +118,10 @@ bool TTMInterpreter::run(TTMState *script) {
do {
ch[0] = scr->readByte();
ch[1] = scr->readByte();
- sval += ch[0];
- sval += ch[1];
+ if (ch[0])
+ sval += ch[0];
+ if (ch[1])
+ sval += ch[1];
} while (ch[0] != 0 && ch[1] != 0);
debugN("\"%s\"", sval.c_str());
@@ -257,10 +252,16 @@ bool TTMInterpreter::run(TTMState *script) {
if (bk != -1) {
_vm->_image->loadBitmap(_bmpNames[id], bk);
}
+ } else if (!_vm->_image->isLoaded()) {
+ // load on demand?
+ _vm->_image->loadBitmap(_bmpNames[id], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
- _vm->_image->drawBitmap(ivals[0], ivals[1], drawWin, topBuffer);
+ if (_vm->_image->isLoaded())
+ _vm->_image->drawBitmap(ivals[0], ivals[1], drawWin, topBuffer);
+ else
+ warning("request to draw null img at %d %d", ivals[0], ivals[1]);
continue;
case 0x1110: { //SET SCENE?: i:int [1..n]
@@ -270,7 +271,7 @@ bool TTMInterpreter::run(TTMState *script) {
if (!_bubbles.empty()) {
// TODO: Are these hardcoded?
- if (!scumm_stricmp(script->dataPtr->filename, "INTRO.TTM")) {
+ if (!script->dataPtr->filename.compareToIgnoreCase("INTRO.TTM")) {
switch (ivals[0]) {
case 15:
text = _bubbles[3];
@@ -303,7 +304,7 @@ bool TTMInterpreter::run(TTMState *script) {
text.clear();
break;
}
- } else if (!scumm_stricmp(script->dataPtr->filename, "BIGTV.TTM")) {
+ } else if (!script->dataPtr->filename.compareToIgnoreCase("BIGTV.TTM")) {
switch (ivals[0]) {
case 1:
text = _bubbles[0];
@@ -353,7 +354,7 @@ bool TTMInterpreter::run(TTMState *script) {
case 0x1310: //? i:int [107]
default:
- warning("Unimplemented TTM opcode: 0x%04X", op);
+ warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[1], ivals[2], ivals[3], ivals[4]);
continue;
}
break;
@@ -368,17 +369,16 @@ bool TTMInterpreter::run(TTMState *script) {
return true;
}
-ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(0), _filename(0) {}
+ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(nullptr) {}
-bool ADSInterpreter::load(const char *filename, ADSData *scriptData) {
+bool ADSInterpreter::load(const Common::String &filename, ADSData *scriptData) {
Common::SeekableReadStream *stream = _vm->_resource->getResource(filename);
if (!stream) {
- error("Couldn't open script file '%s'", filename);
+ error("Couldn't open script resource '%s'", filename.c_str());
return false;
}
- memset(scriptData, 0, sizeof(*scriptData));
_scriptData = scriptData;
_filename = filename;
@@ -397,23 +397,19 @@ bool ADSInterpreter::load(const char *filename, ADSData *scriptData) {
for (uint16 i = _scriptData->count; i--;)
interp.load(_scriptData->names[i], &_scriptData->scriptDatas[i]);
- Common::strlcpy(_scriptData->filename, filename, sizeof(_scriptData->filename));
- _scriptData = 0;
- _filename = 0;
+ _scriptData->filename = filename;
+ _scriptData = nullptr;
return true;
}
void ADSInterpreter::unload(ADSData *data) {
if (!data)
return;
- for (uint16 i = data->count; i--;)
- delete data->names[i];
- delete data->names;
+ data->names.clear();
delete data->scriptDatas;
delete data->scr;
data->count = 0;
- data->names = 0;
data->scriptDatas = 0;
data->scr = 0;
}
@@ -427,10 +423,7 @@ void ADSInterpreter::init(ADSState *state, const ADSData *data) {
TTMInterpreter interp(_vm);
- TTMState *scriptStates;
- scriptStates = new TTMState[data->count];
- assert(scriptStates);
- state->scriptStates = scriptStates;
+ state->scriptStates.resize(data->count);
for (uint16 i = data->count; i--;)
interp.init(&state->scriptStates[i], &data->scriptDatas[i]);
@@ -504,7 +497,7 @@ bool ADSInterpreter::run(ADSState *script) {
case 0x1330:
case 0x1350:
default:
- warning("Unimplemented ADS opcode: 0x%04X", code);
+ warning("Unimplemented ADS opcode: 0x%04X (count %d)", code, count);
continue;
}
break;
diff --git a/engines/dgds/movies.h b/engines/dgds/movies.h
index be9d0a54c2f..80ea2e77a30 100644
--- a/engines/dgds/movies.h
+++ b/engines/dgds/movies.h
@@ -28,51 +28,56 @@ namespace Dgds {
class DgdsEngine;
class DgdsChunk;
-struct TTMData {
- char filename[13];
+class DgdsScriptData {
+public:
+ DgdsScriptData() : scr(nullptr) {}
+ Common::String filename;
Common::SeekableReadStream *scr;
+ Common::HashMap<uint16, Common::String> _tags;
+};
+
+class TTMData : public DgdsScriptData {
+public:
};
struct TTMState {
+ TTMState() : dataPtr(nullptr), scene(0), delay(0) {}
const TTMData *dataPtr;
uint16 scene;
int delay;
};
-struct ADSData {
- char filename[13];
-
+class ADSData : public DgdsScriptData {
+public:
+ ADSData() : count(0), scriptDatas(nullptr) {}
uint16 count;
- char **names;
+ Common::Array<Common::String> names;
TTMData *scriptDatas;
-
- Common::SeekableReadStream *scr;
};
struct ADSState {
+ ADSState() : dataPtr(nullptr), scene(0), subIdx(0), subMax(0) {}
const ADSData *dataPtr;
uint16 scene;
uint16 subIdx, subMax;
- TTMState *scriptStates;
+ Common::Array<TTMState> scriptStates;
};
class ADSInterpreter {
public:
ADSInterpreter(DgdsEngine *vm);
- bool load(const char *filename, ADSData *data);
+ bool load(const Common::String &filename, ADSData *data);
void unload(ADSData *data);
- bool callback(DgdsChunk &chunk);
-
void init(ADSState *scriptState, const ADSData *scriptData);
bool run(ADSState *script);
protected:
DgdsEngine *_vm;
- const char *_filename;
+ Common::String _filename;
ADSData *_scriptData;
};
@@ -80,19 +85,17 @@ class TTMInterpreter {
public:
TTMInterpreter(DgdsEngine *vm);
- bool load(const char *filename, TTMData *data);
+ bool load(const Common::String &filename, TTMData *data);
void unload(TTMData *data);
- bool callback(DgdsChunk &chunk);
-
void init(TTMState *scriptState, const TTMData *scriptData);
bool run(TTMState *script);
protected:
DgdsEngine *_vm;
- const char *_filename;
- TTMData *_scriptData;
+ //Common::String _filename;
+ //TTMData *_scriptData;
//Common::String _bmpNames[16];
};
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index c48565ef5a2..724cbf66b3d 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -32,17 +32,15 @@
namespace Dgds {
-DgdsParser::DgdsParser(Common::SeekableReadStream &file, const char *filename) : _file(file) {
- Common::strlcpy(_filename, filename, sizeof(_filename));
- bytesRead = 0;
+DgdsParser::DgdsParser(Common::SeekableReadStream &file, const Common::String &filename) : _file(file), _filename(filename), _bytesRead(0) {
}
-void DgdsParser::parse(void *data, Decompressor *decompressor) {
- const char *dot;
+void DgdsParser::parse(DgdsScriptData *data, Decompressor *decompressor) {
DGDS_EX _ex;
- if ((dot = strrchr(_filename, '.'))) {
- _ex = MKTAG24(toupper(dot[1]), toupper(dot[2]), toupper(dot[3]));
+ uint32 dot = _filename.find('.');
+ if (dot != Common::String::npos) {
+ _ex = MKTAG24(toupper(_filename[dot + 1]), toupper(_filename[dot + 2]), toupper(_filename[dot + 3]));
} else {
_ex = 0;
}
@@ -69,60 +67,76 @@ void DgdsParser::parse(void *data, Decompressor *decompressor) {
}
}
-bool TTMParser::callback(DgdsChunk &chunk, void *data) {
+Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableReadStream *stream) {
+ Common::HashMap<uint16, Common::String> tags;
+ uint16 count = stream->readUint16LE();
+ debug(" %u:", count);
+
+ for (uint16 i = 0; i < count; i++) {
+ uint16 idx = stream->readUint16LE();
+ Common::String string = stream->readString();
+ debug(" %2u: %2u, \"%s\"", i, idx, string.c_str());
+
+ tags[idx] = string;
+ }
+
+ return tags;
+}
+
+
+bool TTMParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
TTMData *scriptData = (TTMData *)data;
switch (chunk._id) {
+ case ID_TTI: // tag container - we want the tags so don't skip
+ break;
case ID_TT3:
scriptData->scr = chunk._stream->readStream(chunk._stream->size());
break;
+ case ID_TAG:
+ scriptData->_tags = readTags(chunk._stream);
+ break;
case ID_VER:
+ case ID_PAG: // Pages - ignore?
chunk._stream->skip(chunk._size);
break;
default:
- warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename);
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename.c_str());
chunk._stream->skip(chunk._size);
break;
}
return false;
}
-bool ADSParser::callback(DgdsChunk &chunk, void *data) {
+bool ADSParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
ADSData *scriptData = (ADSData *)data;
switch (chunk._id) {
case EX_ADS:
+ case ID_TTI: // tag container - we want the tags so ignore?
break;
case ID_RES: {
uint16 count = chunk._stream->readUint16LE();
- char **strs = new char *[count];
- assert(strs);
scriptData->count = count;
for (uint16 i = 0; i < count; i++) {
- Common::String string;
- byte c = 0;
- uint16 idx;
-
- idx = chunk._stream->readUint16LE();
+ uint16 idx = chunk._stream->readUint16LE();
assert(idx == (i + 1));
- while ((c = chunk._stream->readByte()))
- string += c;
-
- strs[i] = new char[string.size() + 1];
- strcpy(strs[i], string.c_str());
+ Common::String string = chunk._stream->readString();
+ scriptData->names.push_back(string);
}
- scriptData->names = strs;
} break;
case ID_SCR:
scriptData->scr = chunk._stream->readStream(chunk._stream->size());
break;
- case ID_VER:
- // These exist in Willy Beamish
+ case ID_TAG:
+ scriptData->_tags = readTags(chunk._stream);
+ break;
+ case ID_VER: // Version - ignore
chunk._stream->skip(chunk._size);
break;
default:
- warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename);
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename.c_str());
chunk._stream->skip(chunk._size);
break;
}
diff --git a/engines/dgds/parser.h b/engines/dgds/parser.h
index 43f1144a92f..50e1b68d30a 100644
--- a/engines/dgds/parser.h
+++ b/engines/dgds/parser.h
@@ -27,32 +27,35 @@ namespace Dgds {
class DgdsChunk;
class Decompressor;
+class DgdsScriptData;
class DgdsParser {
public:
- char _filename[13];
+ Common::String _filename;
Common::SeekableReadStream &_file;
- uint32 bytesRead;
+ uint32 _bytesRead;
- DgdsParser(Common::SeekableReadStream &file, const char *filename);
- void parse(void *data, Decompressor *decompressor);
- virtual bool callback(DgdsChunk &chunk, void *data) { return false; }
+ DgdsParser(Common::SeekableReadStream &file, const Common::String &filename);
+ void parse(DgdsScriptData *data, Decompressor *decompressor);
+ virtual bool callback(DgdsChunk &chunk, DgdsScriptData *data) { return false; }
+
+ static Common::HashMap<uint16, Common::String> readTags(Common::SeekableReadStream *stream);
};
class TTMParser : public DgdsParser {
public:
- TTMParser(Common::SeekableReadStream &file, const char *filename) : DgdsParser(file, filename) {}
+ TTMParser(Common::SeekableReadStream &file, const Common::String &filename) : DgdsParser(file, filename) {}
private:
- bool callback(DgdsChunk &chunk, void *data);
+ bool callback(DgdsChunk &chunk, DgdsScriptData *data);
};
class ADSParser : public DgdsParser {
public:
- ADSParser(Common::SeekableReadStream &file, const char *filename) : DgdsParser(file, filename) {}
+ ADSParser(Common::SeekableReadStream &file, const Common::String &filename) : DgdsParser(file, filename) {}
private:
- bool callback(DgdsChunk &chunk, void *data);
+ bool callback(DgdsChunk &chunk, DgdsScriptData *data);
};
} // End of namespace Dgds
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 1ef137e2dee..701cb006d97 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -52,13 +52,14 @@ ResourceManager::ResourceManager() {
indexFile.skip(4); // salt for file hash, TODO
int volumes = indexFile.readUint16LE();
+ char fnbuf[FILENAME_LENGTH + 1];
+ fnbuf[FILENAME_LENGTH] = '\0';
+
for (int i = 0; i < volumes; i++) {
- Common::String volumeName;
- for (int j = 0; j < FILENAME_LENGTH; j++)
- volumeName += indexFile.readByte();
- volumeName.toLowercase();
+ indexFile.read(fnbuf, FILENAME_LENGTH);
+ Common::String volumeName(fnbuf);
- _volumes[i].open(volumeName);
+ _volumes[i].open(Common::Path(volumeName));
indexFile.skip(1); // unknown
int entries = indexFile.readUint16LE();
@@ -73,9 +74,8 @@ ResourceManager::ResourceManager() {
_volumes[i].seek(res.pos, SEEK_SET);
res.pos += FILENAME_LENGTH + 1 + 4;
- Common::String fileName;
- for (int k = 0; k < FILENAME_LENGTH; k++)
- fileName += _volumes[i].readByte();
+ _volumes[i].read(fnbuf, FILENAME_LENGTH);
+ Common::String fileName(fnbuf);
fileName.toLowercase();
_volumes[i].skip(1); // unknown
@@ -85,7 +85,7 @@ ResourceManager::ResourceManager() {
if (fileName == "" || res.size == 0)
continue;
- //debug(" - %s at %d, size: %d", fileName.c_str(), res.pos, res.size);
+ debug(" - %s at %d, size: %d", fileName.c_str(), res.pos, res.size);
}
}
@@ -101,9 +101,9 @@ Common::SeekableReadStream *ResourceManager::getResource(Common::String name, bo
name.toLowercase();
// Load external patches
- if (!ignorePatches && Common::File::exists(name)) {
+ if (!ignorePatches && Common::File::exists(Common::Path(name))) {
Common::File *patch = new Common::File();
- patch->open(name);
+ patch->open(Common::Path(name));
return patch;
}
@@ -230,7 +230,7 @@ bool DgdsChunk::readHeader(DgdsParser &ctx) {
ctx._file.read(_idStr, DGDS_TYPENAME_MAX);
if (_idStr[DGDS_TYPENAME_MAX - 1] != ':') {
- debug("bad header in: %s", ctx._filename);
+ debug("bad header in: %s", ctx._filename.c_str());
return false;
}
_idStr[DGDS_TYPENAME_MAX] = '\0';
@@ -260,7 +260,7 @@ Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompresso
byte *dest = new byte[unpackSize];
decompressor->decompress(compression, dest, unpackSize, &ctx._file, _size);
output = new Common::MemoryReadStream(dest, unpackSize, DisposeAfterUse::YES);
- ctx.bytesRead += unpackSize;
+ ctx._bytesRead += unpackSize;
}
/*debug(" %s %u %s %u%c",
@@ -275,7 +275,7 @@ Common::SeekableReadStream *DgdsChunk::readStream(DgdsParser &ctx) {
if (!container) {
output = new Common::SeekableSubReadStream(&ctx._file, ctx._file.pos(), ctx._file.pos() + _size, DisposeAfterUse::NO);
- ctx.bytesRead += _size;
+ ctx._bytesRead += _size;
}
debug(" %s %u%c", _idStr, _size, (container ? '+' : ' '));
Commit: b813fbd71933b6bebfacefe1db95c88e6047e3b4
https://github.com/scummvm/scummvm/commit/b813fbd71933b6bebfacefe1db95c88e6047e3b4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactors and cleanups to remove globals.
Changed paths:
A engines/dgds/dialogue.cpp
A engines/dgds/dialogue.h
A engines/dgds/scripts.cpp
A engines/dgds/scripts.h
R engines/dgds/movies.cpp
R engines/dgds/movies.h
engines/dgds/configure.engine
engines/dgds/console.cpp
engines/dgds/decompress.cpp
engines/dgds/decompress.h
engines/dgds/detection.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/module.mk
engines/dgds/music.cpp
engines/dgds/parser.cpp
engines/dgds/resource.cpp
engines/dgds/resource.h
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/configure.engine b/engines/dgds/configure.engine
index ad2a46a9208..aaac51da36c 100644
--- a/engines/dgds/configure.engine
+++ b/engines/dgds/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 dgds "DGDS" yes
+add_engine dgds "Dynamix Game Development System" yes
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index bc3d76850f7..dbcf23d95b7 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -43,7 +43,7 @@ bool Console::cmdFileInfo(int argc, const char **argv) {
return true;
}
- Resource res = _vm->_resource->getResourceInfo(argv[1]);
+ const Resource &res = _vm->getResourceManager()->getResourceInfo(argv[1]);
debugPrintf("Resource volume: %d, position: %d, size: %d, checksum: %d\n", res.volume, res.pos, res.size, res.checksum);
return true;
@@ -55,7 +55,7 @@ bool Console::cmdFileSearch(int argc, const char **argv) {
return true;
}
- ResourceList resources = _vm->_resource->_resources;
+ const ResourceList &resources = _vm->getResourceManager()->getResources();
for (ResourceList::const_iterator i = resources.begin(), end = resources.end(); i != end; ++i) {
if (i->_key.contains(argv[1])) {
Resource res = i->_value;
@@ -75,7 +75,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
Common::String fileName = argv[1];
bool ignorePatches = (argc > 2) && (!scumm_stricmp(argv[2], "true") || !strcmp(argv[2], "1"));
bool unpack = (argc > 3) && (!scumm_stricmp(argv[3], "true") || !strcmp(argv[3], "1"));
- Common::SeekableReadStream *res = _vm->_resource->getResource(fileName, ignorePatches);
+ Common::SeekableReadStream *res = _vm->getResource(fileName, ignorePatches);
if (res == nullptr) {
debugPrintf("Resource not found\n");
return true;
diff --git a/engines/dgds/decompress.cpp b/engines/dgds/decompress.cpp
index e2582e264c3..911d2df98df 100644
--- a/engines/dgds/decompress.cpp
+++ b/engines/dgds/decompress.cpp
@@ -186,13 +186,9 @@ uint32 LzwDecompressor::getCode(uint32 totalBits, Common::SeekableReadStream &in
}
Decompressor::Decompressor() {
- _rleDecompressor = new RleDecompressor();
- _lzwDecompressor = new LzwDecompressor();
}
Decompressor::~Decompressor() {
- delete _rleDecompressor;
- delete _lzwDecompressor;
}
void Decompressor::decompress(byte compression, byte *data, int uncompressedSize, Common::SeekableReadStream *input, int size) {
@@ -201,10 +197,10 @@ void Decompressor::decompress(byte compression, byte *data, int uncompressedSize
input->read(data, size);
break;
case 0x01:
- _rleDecompressor->decompress(data, uncompressedSize, *input);
+ _rleDecompressor.decompress(data, uncompressedSize, *input);
break;
case 0x02:
- _lzwDecompressor->decompress(data, uncompressedSize, *input);
+ _lzwDecompressor.decompress(data, uncompressedSize, *input);
break;
default:
input->skip(size);
diff --git a/engines/dgds/decompress.h b/engines/dgds/decompress.h
index 76d1f0acf72..ac71974551c 100644
--- a/engines/dgds/decompress.h
+++ b/engines/dgds/decompress.h
@@ -45,19 +45,23 @@ protected:
uint32 getCode(uint32 totalBits, Common::SeekableReadStream &input);
private:
- struct {
- byte str[256];
- uint8 len;
- } _codeTable[0x4000];
+ struct {
+ byte str[256];
+ uint8 len;
+ } _codeTable[0x4000];
- byte _codeCur[256];
+ byte _codeCur[256];
- uint32 _bitsData, _bitsSize;
+ uint32 _bitsData;
+ uint32 _bitsSize;
- uint32 _codeSize, _codeLen, _cacheBits;
+ uint32 _codeSize;
+ uint32 _codeLen;
+ uint32 _cacheBits;
- uint32 _tableSize, _tableMax;
- bool _tableFull;
+ uint32 _tableSize;
+ uint32 _tableMax;
+ bool _tableFull;
};
class Decompressor {
@@ -68,10 +72,10 @@ public:
void decompress(byte compression, byte *data, int uncompressedSize, Common::SeekableReadStream *input, int size);
private:
- RleDecompressor *_rleDecompressor;
- LzwDecompressor *_lzwDecompressor;
+ RleDecompressor _rleDecompressor;
+ LzwDecompressor _lzwDecompressor;
- const char *_compressionDescr[3] = {"None", "RLE", "LZW"};
+ // const char *_compressionDescr[3] = {"None", "RLE", "LZW"};
};
} // End of namespace Dgds
diff --git a/engines/dgds/detection.cpp b/engines/dgds/detection.cpp
index 86914e6780d..aa1c7dafa8e 100644
--- a/engines/dgds/detection.cpp
+++ b/engines/dgds/detection.cpp
@@ -22,7 +22,6 @@
#include "base/plugins.h"
#include "engines/advancedDetector.h"
-//#include "common/translation.h"
static const PlainGameDescriptor dgdsGames[] = {
{"dgds", "Dynamix DGDS game"},
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 1d4d2cc9efd..893187a646b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -51,43 +51,30 @@
#include "dgds/console.h"
#include "dgds/decompress.h"
+#include "dgds/dialogue.h"
#include "dgds/detection_tables.h"
#include "dgds/dgds.h"
#include "dgds/font.h"
#include "dgds/image.h"
#include "dgds/includes.h"
-#include "dgds/movies.h"
#include "dgds/music.h"
#include "dgds/parser.h"
#include "dgds/resource.h"
+#include "dgds/scripts.h"
#include "dgds/sound.h"
namespace Dgds {
-Graphics::ManagedSurface resData;
-Graphics::Surface bottomBuffer;
-Graphics::Surface topBuffer;
+//static Common::SeekableReadStream *ttm;
+//static char ttmName[DGDS_FILENAME_MAX + 1];
-Common::MemoryReadStream *soundData;
-byte *musicData;
-uint32 musicSize;
-
-Common::StringArray _bubbles;
-Common::StringArray BMPs;
-
-PFont *_fntP;
-FFont *_fntF;
-
-#define DGDS_FILENAME_MAX 12
-
-Common::SeekableReadStream *ttm;
-char ttmName[DGDS_FILENAME_MAX + 1];
-
-Common::SeekableReadStream *ads;
-char adsName[DGDS_FILENAME_MAX + 1];
+//static Common::SeekableReadStream *ads;
+//static char adsName[DGDS_FILENAME_MAX + 1];
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
- : Engine(syst) {
+ : Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
+ _midiPlayer(nullptr), _decompressor(nullptr), _musicData(nullptr), _musicSize(0),
+ _soundData(nullptr), _dialogue(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -109,6 +96,7 @@ DgdsEngine::~DgdsEngine() {
delete _image;
delete _decompressor;
delete _resource;
+ delete _dialogue;
}
void readStrings(Common::SeekableReadStream *stream) {
@@ -127,157 +115,8 @@ void readStrings(Common::SeekableReadStream *stream) {
}
}
-struct Tag {
- uint16 id;
- Common::String tag;
-};
-
-void readSDS(Common::SeekableReadStream *stream) {
- uint32 mark;
-
- // Debug
- /*uint32 pos = stream->pos();
- byte *tmp = new byte[stream->size()];
- stream->read(tmp, stream->size());
- Common::hexdump(tmp, stream->size());
- stream->seek(pos, SEEK_SET);*/
-
- mark = stream->readUint32LE();
- debug(" 0x%X", mark);
-
- char version[7];
- stream->read(version, sizeof(version));
- debug(" %s", version);
-
- uint16 idx;
- idx = stream->readUint16LE();
- debug(" S%d.SDS", idx);
-
- // gross hack to grep the strings.
- _bubbles.clear();
-
- bool inside = false;
- Common::String txt;
- while (1) {
- char buf[4];
- stream->read(buf, sizeof(buf));
- if (stream->pos() >= stream->size())
- break;
- if (Common::isPrint(buf[0]) && Common::isPrint(buf[1]) && Common::isPrint(buf[2]) && Common::isPrint(buf[3])) {
- inside = true;
- }
- stream->seek(-3, SEEK_CUR);
-
- if (inside) {
- if (buf[0] == '\0') {
- // here's where we do a clever thing. we want Pascal like strings.
- uint16 pos = txt.size() + 1;
- stream->seek(-pos - 2, SEEK_CUR);
- uint16 len = stream->readUint16LE();
- stream->seek(pos, SEEK_CUR);
-
- // gotcha!
- if (len == pos) {
- //if (resource == 0)
- _bubbles.push_back(txt);
- debug(" \"%s\"", txt.c_str());
- }
- // let's hope the string wasn't shorter than 4 chars...
- txt.clear();
- inside = false;
- } else {
- txt += buf[0];
- }
- }
- }
-#if 0
- idx = stream->readUint16LE();
- debug(" %d", idx);
-
- idx = stream->readUint16LE();
- debug(" %d", idx);
-
- uint16 count;
- while (1) {
- uint16 code;
- code = stream->readUint16LE();
- count = stream->readUint16LE();
- idx = stream->readUint16LE();
- debugN("\tOP: 0x%8.8x %2u %2u\n", code, count, idx);
-
- uint16 pitch = (count+1)&(~1); // align to word.
- if ((stream->pos()+pitch) >= stream->size()) break;
-
- if (code == 0 && count == 0) break;
-
- stream->skip(pitch);
- }
-
- Common::String sval;
- byte ch;
-
- do {
- ch = stream->readByte();
- sval += ch;
- } while (ch != 0);
-
- debug("\"%s\"", sval.c_str());
-#endif
-#if 0
- // probe for the .ADS name. are these shorts?
- uint count;
- count = 0;
- while (1) {
- uint16 x;
- x = stream->readUint16LE();
- if ((x & 0xFF00) != 0)
- break;
- debug(" %u: %u|0x%4.4X", count++, x, x);
- }
- stream->seek(-2, SEEK_CUR);
-
- // .ADS name.
- Common::String ads;
- byte ch;
- while ((ch = stream->readByte()))
- ads += ch;
- debug(" %s", ads.c_str());
-
- stream->hexdump(6);
- stream->skip(6);
-
- int w, h;
-
- w = stream->readSint16LE();
- h = stream->readSint16LE();
- debug(" %dx%d", w, h);
-
- // probe for the strings. are these shorts?
- count = 0;
- while (1) {
- uint16 x;
- x = stream->readUint16LE();
- if ((x & 0xFF00) != 0)
- break;
- if (stream->pos() >= stream->size()) break;
- debug(" %u: %u|0x%4.4X", count++, x, x);
- }
- stream->seek(-4, SEEK_CUR);
- // here we are.
-
- uint16 len;
- len = stream->readSint16LE();
- Common::String txt;
- for (uint16 j=0; j<len; j++) {
- ch = stream->readByte();
- txt += ch;
- debug(" \"%s\"", txt.c_str());
- }
-#endif
-}
-
-void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor) {
+void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor) {
const char *dot;
DGDS_EX ex = 0;
@@ -388,7 +227,7 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
/* AIFF sound sample (Amiga). */
byte *dest = new byte[file.size()];
file.read(dest, file.size());
- soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
+ _soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
} break;
case EX_SNG:
/* IFF-SMUS music (Amiga). */
@@ -420,7 +259,7 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
DgdsChunk chunk;
while (chunk.readHeader(ctx)) {
- if (chunk.container) {
+ if (chunk._container) {
parent = chunk._id;
continue;
}
@@ -476,7 +315,7 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
break;
case EX_SDS:
if (chunk.isSection(ID_SDS)) {
- readSDS(stream);
+ _dialogue->parseSDS(stream);
}
break;
case EX_TTM:
@@ -494,8 +333,8 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
uint32 size = stream->size();
byte *dest = new byte[size];
stream->read(dest, size);
- ttm = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
- Common::strlcpy(ttmName, name, sizeof(ttmName));
+ //ttm = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
+ //Common::strlcpy(ttmName, name, sizeof(ttmName));
} else {
while (!stream->eos()) {
uint16 code;
@@ -609,8 +448,8 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
uint32 size = stream->size();
byte *dest = new byte[size];
stream->read(dest, size);
- ads = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
- Common::strlcpy(adsName, name, sizeof(adsName));
+ //ads = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
+ //adsName = name;
} else {
/* this is either a script, or a property sheet, i can't decide. */
while (!stream->eos()) {
@@ -698,12 +537,12 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
case EX_SNG:
/* DOS. */
if (chunk.isSection(ID_SNG)) {
- musicSize = stream->size();
+ _musicSize = stream->size();
- debug(" %2u: %u bytes", scount, musicSize);
+ debug(" %2u: %u bytes", scount, _musicSize);
- musicData = (uint8 *)malloc(musicSize);
- stream->read(musicData, musicSize);
+ _musicData = (uint8 *)malloc(_musicSize);
+ stream->read(_musicData, _musicSize);
scount++;
} else if (chunk.isSection(ID_INF)) {
uint32 count;
@@ -744,11 +583,11 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
unpackSize = stream->readUint32LE();
//debug(" #%2u: (0x%X?) %s %u", idx, type, compressionDescr[compression], unpackSize);
- musicSize = unpackSize;
- debug(" %2u: %u bytes", scount, musicSize);
+ _musicSize = unpackSize;
+ debug(" %2u: %u bytes", scount, _musicSize);
- musicData = (uint8 *)malloc(musicSize);
- decompressor->decompress(compression, musicData, musicSize, stream, stream->size() - stream->pos());
+ _musicData = (uint8 *)malloc(_musicSize);
+ decompressor->decompress(compression, _musicData, _musicSize, stream, stream->size() - stream->pos());
scount++;
}
@@ -792,7 +631,7 @@ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file,
}
if (ex == EX_BMP) {
- BMPs.push_back(Common::String(name));
+ _BMPs.push_back(Common::String(name));
debug("BMPs: %s", name);
}
@@ -819,11 +658,11 @@ struct Channel _channels[2];
void DgdsEngine::playSfx(const Common::String &fileName, byte channel, byte volume) {
parseFile(fileName);
- if (soundData) {
+ if (_soundData) {
Channel *ch = &_channels[channel];
- Audio::AudioStream *input = Audio::makeAIFFStream(soundData, DisposeAfterUse::YES);
+ Audio::AudioStream *input = Audio::makeAIFFStream(_soundData, DisposeAfterUse::YES);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
- soundData = 0;
+ _soundData = 0;
}
}
@@ -834,21 +673,21 @@ void DgdsEngine::stopSfx(byte channel) {
}
}
-bool DgdsEngine::playPCM(byte *data, uint32 size) {
+bool DgdsEngine::playPCM(const byte *data, uint32 size) {
_mixer->stopAll();
if (!data)
return false;
byte numParts;
- byte *trackPtr[0xFF];
+ const byte *trackPtr[0xFF];
uint16 trackSiz[0xFF];
numParts = loadSndTrack(DIGITAL_PCM, trackPtr, trackSiz, data, size);
if (numParts == 0)
return false;
for (byte part = 0; part < numParts; part++) {
- byte *ptr = trackPtr[part];
+ const byte *ptr = trackPtr[part];
bool digital_pcm = false;
if (READ_LE_UINT16(ptr) == 0x00FE) {
@@ -886,34 +725,34 @@ void DgdsEngine::playMusic(const Common::String &fileName) {
//stopMusic();
parseFile(fileName);
- if (musicData) {
+ if (_musicData) {
uint32 tracks;
- tracks = availableSndTracks(musicData, musicSize);
+ tracks = availableSndTracks(_musicData, _musicSize);
if ((tracks & TRACK_MT32))
- _midiPlayer->play(musicData, musicSize);
+ _midiPlayer->play(_musicData, _musicSize);
if ((tracks & DIGITAL_PCM))
- playPCM(musicData, musicSize);
+ playPCM(_musicData, _musicSize);
}
}
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
- soundData = 0;
- musicData = 0;
+ _soundData = nullptr;
+ _musicData = nullptr;
_console = new Console(this);
_resource = new ResourceManager();
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
_midiPlayer = new DgdsMidiPlayer();
- assert(_midiPlayer);
+ _dialogue = new Dialogue();
setDebugger(_console);
- bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
debug("DgdsEngine::init");
@@ -994,4 +833,8 @@ Common::Error DgdsEngine::run() {
return Common::kNoError;
}
+Common::SeekableReadStream *DgdsEngine::getResource(const Common::String &name, bool ignorePatches) {
+ return _resource->getResource(name, ignorePatches);
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 955de90dc79..173b70b1492 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -26,6 +26,9 @@
#include "common/error.h"
#include "common/platform.h"
+#include "graphics/surface.h"
+#include "graphics/managed_surface.h"
+
#include "engines/advancedDetector.h"
#include "engines/engine.h"
@@ -37,6 +40,9 @@ class Console;
class ResourceManager;
class Decompressor;
class Image;
+class PFont;
+class FFont;
+class Dialogue;
class DgdsMidiPlayer;
struct DgdsADS;
@@ -55,6 +61,21 @@ private:
Console *_console;
DgdsMidiPlayer *_midiPlayer;
+ ResourceManager *_resource;
+ Decompressor *_decompressor;
+
+ DgdsGameId _gameId;
+ Graphics::Surface _bottomBuffer;
+ Graphics::Surface _topBuffer;
+ Dialogue *_dialogue;
+
+ PFont *_fntP;
+ FFont *_fntF;
+ Common::StringArray _BMPs;
+ uint32 _musicSize;
+ byte *_musicData;
+ Common::SeekableReadStream *_soundData;
+
protected:
virtual Common::Error run();
@@ -67,16 +88,24 @@ public:
void playSfx(const Common::String &fileName, byte channel, byte volume);
void stopSfx(byte channel);
- bool playPCM(byte *data, uint32 size);
+ bool playPCM(const byte *data, uint32 size);
void playMusic(const Common::String &fileName);
void parseFile(const Common::String &filename, int resource = 0);
- ResourceManager *_resource;
- Decompressor *_decompressor;
+ Graphics::Surface &getTopBuffer() { return _topBuffer; }
+ Graphics::Surface &getBottomBuffer() { return _bottomBuffer; }
+ Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
+ ResourceManager *getResourceManager() { return _resource; }
+ Decompressor *getDecompressor() { return _decompressor; }
+ const Dialogue *getDialogue() const { return _dialogue; }
+
+ const PFont *getFntP() const { return _fntP; }
Image *_image;
+ Graphics::ManagedSurface _resData;
- DgdsGameId _gameId;
+private:
+ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor);
};
//void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource);
diff --git a/engines/dgds/dialogue.cpp b/engines/dgds/dialogue.cpp
new file mode 100644
index 00000000000..255631e108e
--- /dev/null
+++ b/engines/dgds/dialogue.cpp
@@ -0,0 +1,184 @@
+/* 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/debug.h"
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "dgds/dialogue.h"
+
+namespace Dgds {
+
+void Dialogue::parseSDS(Common::SeekableReadStream *stream) {
+ // Debug
+ /*uint32 pos = stream->pos();
+ byte *tmp = new byte[stream->size()];
+ stream->read(tmp, stream->size());
+ Common::hexdump(tmp, stream->size());
+ stream->seek(pos, SEEK_SET);*/
+
+ uint32 mark = stream->readUint32LE();
+ debug(" 0x%X", mark);
+
+ char version[7];
+ stream->read(version, sizeof(version));
+ debug(" %s", version);
+
+ uint16 idx;
+ idx = stream->readUint16LE();
+ debug(" S%d.SDS", idx);
+
+ // gross hack to grep the strings.
+ //_bubbles.clear();
+
+ bool inside = false;
+ Common::String txt;
+ {
+ int64 start = stream->pos();
+ Common::DumpFile dump;
+ dump.open("/tmp/sds.dat");
+ dump.writeStream(stream);
+ stream->seek(start);
+ }
+
+
+ while (1) {
+ char buf[4];
+ stream->read(buf, sizeof(buf));
+ if (stream->pos() >= stream->size())
+ break;
+ if (Common::isPrint(buf[0]) && Common::isPrint(buf[1]) && Common::isPrint(buf[2]) && Common::isPrint(buf[3])) {
+ inside = true;
+ }
+ stream->seek(-3, SEEK_CUR);
+
+ if (inside) {
+ if (buf[0] == '\0') {
+ // here's where we do a clever thing. we want Pascal like strings.
+ uint16 pos = txt.size() + 1;
+ stream->seek(-pos - 2, SEEK_CUR);
+ uint16 len = stream->readUint16LE();
+ stream->seek(pos, SEEK_CUR);
+
+ // gotcha!
+ if (len == pos) {
+ //if (resource == 0)
+ //_bubbles.push_back(txt);
+ debug(" \"%s\"", txt.c_str());
+ }
+ // let's hope the string wasn't shorter than 4 chars...
+ txt.clear();
+ inside = false;
+ } else {
+ txt += buf[0];
+ }
+ }
+ }
+#if 0
+ idx = stream->readUint16LE();
+ debug(" %d", idx);
+
+ idx = stream->readUint16LE();
+ debug(" %d", idx);
+
+ uint16 count;
+ while (1) {
+ uint16 code;
+ code = stream->readUint16LE();
+ count = stream->readUint16LE();
+ idx = stream->readUint16LE();
+
+ debugN("\tOP: 0x%8.8x %2u %2u\n", code, count, idx);
+
+ uint16 pitch = (count+1)&(~1); // align to word.
+ if ((stream->pos()+pitch) >= stream->size()) break;
+
+ if (code == 0 && count == 0) break;
+
+ stream->skip(pitch);
+ }
+
+ Common::String sval;
+ byte ch;
+
+ do {
+ ch = stream->readByte();
+ sval += ch;
+ } while (ch != 0);
+
+ debug("\"%s\"", sval.c_str());
+#endif
+#if 0
+ // probe for the .ADS name. are these shorts?
+ uint count;
+ count = 0;
+ while (1) {
+ uint16 x;
+ x = stream->readUint16LE();
+ if ((x & 0xFF00) != 0)
+ break;
+ debug(" %u: %u|0x%4.4X", count++, x, x);
+ }
+ stream->seek(-2, SEEK_CUR);
+
+ // .ADS name.
+ Common::String ads;
+ byte ch;
+ while ((ch = stream->readByte()))
+ ads += ch;
+ debug(" %s", ads.c_str());
+
+ stream->hexdump(6);
+ stream->skip(6);
+
+ int w, h;
+
+ w = stream->readSint16LE();
+ h = stream->readSint16LE();
+ debug(" %dx%d", w, h);
+
+ // probe for the strings. are these shorts?
+ count = 0;
+ while (1) {
+ uint16 x;
+ x = stream->readUint16LE();
+ if ((x & 0xFF00) != 0)
+ break;
+ if (stream->pos() >= stream->size()) break;
+ debug(" %u: %u|0x%4.4X", count++, x, x);
+ }
+ stream->seek(-4, SEEK_CUR);
+ // here we are.
+
+ uint16 len;
+ len = stream->readSint16LE();
+ Common::String txt;
+ for (uint16 j=0; j<len; j++) {
+ ch = stream->readByte();
+ txt += ch;
+ debug(" \"%s\"", txt.c_str());
+ }
+#endif
+}
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/dialogue.h b/engines/dgds/dialogue.h
new file mode 100644
index 00000000000..3f034c553ee
--- /dev/null
+++ b/engines/dgds/dialogue.h
@@ -0,0 +1,64 @@
+/* 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 DGDS_DIALOUGE_H
+#define DGDS_DIALOUGE_H
+
+#include "common/stream.h"
+#include "common/array.h"
+
+namespace Dgds {
+
+class DialogueLine {
+public:
+ uint16 unk[9];
+ uint16 x;
+ uint16 y;
+ uint16 w;
+ uint16 h;
+ uint16 bgcol;
+ uint16 fontcol; // 0 = black , 0xf = white
+ uint16 unk2;
+ uint16 unk3;
+ uint16 fontsize; // 01 = 8x8, 02 = 6x6, 03 = 4x5
+ uint16 just; // 0x00 =t top, 0x03 = center
+ uint16 unk4;
+ uint16 frametype; // 01 =simple frame, 02 = with title (text before :), 03 = baloon, 04 = eliptical baloon
+ uint16 unk5;
+ uint16 unk6;
+ uint16 textLen;
+ Common::String text;
+};
+
+class Dialogue {
+public:
+ void parseSDS(Common::SeekableReadStream *s);
+
+ const Common::Array<DialogueLine> &getLines() const { return _dialogue; }
+private:
+ Common::Array<DialogueLine> _dialogue;
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_DIALOUGE_H
+
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index e28ec015243..614239bdcc4 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -39,7 +39,7 @@
namespace Dgds {
-Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor), _tileWidth(0), _tileHeight(0), _tileOffset(0) {
+Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor) {
memset(_palette, 0, 256 * 3);
memset(_blacks, 0, 256 * 3);
}
@@ -56,8 +56,6 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
error("Couldn't get image resource %s", filename.c_str());
DgdsParser ctx(*fileStream, filename.c_str());
- DgdsChunk chunk;
-
if ((dot = strrchr(filename.c_str(), '.'))) {
ex = MKTAG24(dot[1], dot[2], dot[3]);
} else {
@@ -72,8 +70,7 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
surface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- // Currently does not handle the VQT: and OFF: chunks
- // for the compressed pics in the DOS port.
+ DgdsChunk chunk;
while (chunk.readHeader(ctx)) {
Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
if (chunk.isSection(ID_BIN)) {
@@ -100,7 +97,6 @@ void Image::loadBitmap(Common::String filename, int number) {
DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
- _tileOffset = 0;
_bmpData.free();
if ((dot = strrchr(filename.c_str(), '.'))) {
@@ -119,6 +115,7 @@ void Image::loadBitmap(Common::String filename, int number) {
int32 vqtsize = -1;
uint16 tileWidths[64];
uint16 tileHeights[64];
+ int32 tileOffset = 0;
while (chunk.readHeader(ctx)) {
Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
@@ -126,17 +123,12 @@ void Image::loadBitmap(Common::String filename, int number) {
uint16 tileCount = stream->readUint16LE();
for (uint16 k = 0; k < tileCount; k++) {
tileWidths[k] = stream->readUint16LE();
- if (k == number)
- _tileWidth = tileWidths[k];
}
for (uint16 k = 0; k < tileCount; k++) {
tileHeights[k] = stream->readUint16LE();
- if (k == number)
- _tileHeight = tileHeights[k];
-
if (k < number)
- _tileOffset += tileWidths[k] * tileHeights[k];
+ tileOffset += tileWidths[k] * tileHeights[k];
}
} else if (chunk.isSection(ID_MTX)) {
// Scroll offset
@@ -155,9 +147,9 @@ void Image::loadBitmap(Common::String filename, int number) {
// TODO: Use these
delete mtx;
} else if (chunk.isSection(ID_BIN)) {
- loadBitmap4(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream, false);
+ loadBitmap4(_bmpData, tileWidths[number], tileHeights[number], tileOffset, stream, false);
} else if (chunk.isSection(ID_VGA)) {
- loadBitmap4(_bmpData, _tileWidth, _tileHeight, _tileOffset, stream, true);
+ loadBitmap4(_bmpData, tileWidths[number], tileHeights[number], tileOffset, stream, true);
} else if (chunk.isSection(ID_VQT)) {
// Postpone parsing this until we have the offsets, which come after.
vqtpos = fileStream->pos();
@@ -178,7 +170,6 @@ void Image::loadBitmap(Common::String filename, int number) {
warning("Expected 0xffff in 2-byte offset list, got %04x", val);
}
- _tileOffset = 0;
uint32 nextOffset = 0;
for (int i = 0; i < number + 1; i++) {
fileStream->seek(vqtpos);
@@ -189,10 +180,10 @@ void Image::loadBitmap(Common::String filename, int number) {
} else {
if (number)
stream->skip(4 * number);
- _tileOffset = stream->readUint32LE();
+ uint32 tileOffset = stream->readUint32LE();
// TODO: seek stream to end for tidiness?
- fileStream->seek(vqtpos + _tileOffset);
- loadVQT(_bmpData, _tileWidth, _tileHeight, 0, fileStream);
+ fileStream->seek(vqtpos + tileOffset);
+ loadVQT(_bmpData, tileWidths[number], tileHeights[number], 0, fileStream);
}
}
delete stream;
@@ -202,7 +193,7 @@ void Image::loadBitmap(Common::String filename, int number) {
}
void Image::drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &surface) {
- const Common::Rect destRect(x, y, x + _tileWidth, y + _tileHeight);
+ const Common::Rect destRect(x, y, x + _bmpData.w, y + _bmpData.h);
Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
clippedDestRect.clip(destRect);
clippedDestRect.clip(drawWin);
@@ -211,7 +202,7 @@ void Image::drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &s
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- byte *src = (byte *)_bmpData.getPixels() + croppedBy.y * _tileWidth + croppedBy.x;
+ byte *src = (byte *)_bmpData.getPixels() + croppedBy.y * _bmpData.pitch + croppedBy.x;
byte *ptr = (byte *)surface.getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
@@ -219,7 +210,7 @@ void Image::drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &s
ptr[j] = src[j];
}
ptr += surface.pitch;
- src += _tileWidth;
+ src += _bmpData.pitch;
}
}
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index ff5494343b5..7e115748956 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -59,8 +59,6 @@ private:
Graphics::Surface _bmpData;
ResourceManager *_resourceMan;
Decompressor *_decompressor;
- uint16 _tileWidth, _tileHeight;
- uint32 _tileOffset;
byte _palette[256 * 3];
byte _blacks[256 * 3];
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 3e88f7ed45f..4aa60b71fa2 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -3,14 +3,15 @@ MODULE := engines/dgds
MODULE_OBJS := \
console.o \
decompress.o \
+ dialogue.o \
dgds.o \
font.o \
image.o \
metaengine.o \
- movies.o \
music.o \
parser.o \
resource.o \
+ scripts.o \
sound.o
# This module can be built as a plugin
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
index 46053ff06ee..e6a3e2668a1 100644
--- a/engines/dgds/music.cpp
+++ b/engines/dgds/music.cpp
@@ -36,9 +36,9 @@ protected:
byte *_init;
byte *_last;
- byte numParts;
- byte *trackPtr[0xFF];
- uint16 trackSiz[0xFF];
+ byte _numParts;
+ const byte *_trackPtr[0xFF];
+ uint16 _trackSz[0xFF];
protected:
void parseNextEvent(EventInfo &info);
@@ -57,8 +57,8 @@ public:
};
MidiParser_DGDS::MidiParser_DGDS() : _init(0), _last(0) {
- numParts = 0;
- memset(trackSiz, 0, sizeof(trackSiz));
+ _numParts = 0;
+ memset(_trackSz, 0, sizeof(_trackSz));
}
void MidiParser_DGDS::sendInitCommands() {
@@ -165,12 +165,12 @@ byte MidiParser_DGDS::midiGetNextChannel(uint16 *trackPos, uint32 *trackTimer, l
byte curr = 0xFF;
uint32 closest = ticker + 1000000, next = 0;
- for (byte i = 0; i < numParts; i++) {
+ for (byte i = 0; i < _numParts; i++) {
if (trackTimer[i] == 0xFFFFFFFF) // channel ended
continue;
- if (trackPos[i] >= trackSiz[i])
+ if (trackPos[i] >= _trackSz[i])
continue;
- next = trackPtr[i][trackPos[i]]; // when the next event should occur
+ next = _trackPtr[i][trackPos[i]]; // when the next event should occur
if (next == 0xF8) // 0xF8 means 240 ticks delay
next = 240;
next += trackTimer[i];
@@ -184,7 +184,7 @@ byte MidiParser_DGDS::midiGetNextChannel(uint16 *trackPos, uint32 *trackTimer, l
}
inline bool MidiParser_DGDS::validateNextRead(uint i, uint16 *trackPos) {
- if (trackSiz[i] <= trackPos[i]) {
+ if (_trackSz[i] <= trackPos[i]) {
warning("Unexpected end. Music may sound wrong due to game resource corruption");
return false;
} else {
@@ -200,11 +200,11 @@ void MidiParser_DGDS::mixChannels() {
uint16 trackPos[0xFF];
uint32 trackTimer[0xFF];
byte _prev[0xFF];
- for (byte i = 0; i < numParts; i++) {
+ for (byte i = 0; i < _numParts; i++) {
trackTimer[i] = 0;
_prev[i] = 0;
trackPos[i] = 0;
- totalSize += trackSiz[i];
+ totalSize += _trackSz[i];
}
byte *output = (byte*)malloc(totalSize * 2);
@@ -218,7 +218,7 @@ void MidiParser_DGDS::mixChannels() {
while ((channel = midiGetNextChannel(trackPos, trackTimer, ticker)) != 0xFF) { // there is still an active channel
if (!validateNextRead(channel, trackPos))
goto end;
- curDelta = trackPtr[channel][trackPos[channel]++];
+ curDelta = _trackPtr[channel][trackPos[channel]++];
trackTimer[channel] += (curDelta == 0xF8 ? 240 : curDelta); // when the command is supposed to occur
if (curDelta == 0xF8)
continue;
@@ -227,7 +227,7 @@ void MidiParser_DGDS::mixChannels() {
if (!validateNextRead(channel, trackPos))
goto end;
- midiCommand = trackPtr[channel][trackPos[channel]++];
+ midiCommand = _trackPtr[channel][trackPos[channel]++];
if (midiCommand != 0xFC) {
// Write delta
while (newDelta > 240) {
@@ -243,7 +243,7 @@ void MidiParser_DGDS::mixChannels() {
do {
if (!validateNextRead(channel, trackPos))
goto end;
- midiParam = trackPtr[channel][trackPos[channel]++];
+ midiParam = _trackPtr[channel][trackPos[channel]++];
*output++ = midiParam;
} while (midiParam != 0xF7);
break;
@@ -254,7 +254,7 @@ void MidiParser_DGDS::mixChannels() {
if (midiCommand & 0x80) {
if (!validateNextRead(channel, trackPos))
goto end;
- midiParam = trackPtr[channel][trackPos[channel]++];
+ midiParam = _trackPtr[channel][trackPos[channel]++];
} else {// running status
midiParam = midiCommand;
midiCommand = _prev[channel];
@@ -270,7 +270,7 @@ void MidiParser_DGDS::mixChannels() {
if (commandLengths[(midiCommand >> 4) - 8] == 2) {
if (!validateNextRead(channel, trackPos))
goto end;
- *output++ = trackPtr[channel][trackPos[channel]++];
+ *output++ = _trackPtr[channel][trackPos[channel]++];
}
_prev[channel] = midiCommand;
globalPrev = midiCommand;
@@ -287,19 +287,19 @@ bool MidiParser_DGDS::loadMusic(byte *data, uint32 size) {
if (!data) return false;
- numParts = loadSndTrack(TRACK_MT32, trackPtr, trackSiz, data, size);
- if (numParts == 0) return false;
+ _numParts = loadSndTrack(TRACK_MT32, _trackPtr, _trackSz, data, size);
+ if (_numParts == 0) return false;
- for (byte part = 0; part < numParts; part++) {
- byte *ptr = trackPtr[part];
+ for (byte part = 0; part < _numParts; part++) {
+ const byte *ptr = _trackPtr[part];
byte number, voices;
number = (*ptr++);
voices = (*ptr++) & 0x0F;
debug(" - #%u: voices: %u", number, voices);
- trackPtr[part] += 2;
- trackSiz[part] -= 2;
+ _trackPtr[part] += 2;
+ _trackSz[part] -= 2;
}
mixChannels();
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 724cbf66b3d..13be683b563 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -26,9 +26,9 @@
#include "common/stream.h"
#include "common/platform.h"
#include "dgds/includes.h"
-#include "dgds/movies.h"
#include "dgds/resource.h"
#include "dgds/parser.h"
+#include "dgds/scripts.h"
namespace Dgds {
@@ -49,8 +49,7 @@ void DgdsParser::parse(DgdsScriptData *data, Decompressor *decompressor) {
while (chunk.readHeader(*this)) {
bool stop;
- //chunk._stream = 0;
- if (chunk.container) {
+ if (chunk._container) {
chunk._stream = &_file;
stop = callback(chunk, data);
} else {
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 701cb006d97..805a6dd65b9 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -123,15 +123,15 @@ Resource ResourceManager::getResourceInfo(Common::String name) {
return _resources[name];
}
-bool DgdsChunk::isSection(const Common::String §ion) {
+bool DgdsChunk::isSection(const Common::String §ion) const {
return section.equals(_idStr);
}
-bool DgdsChunk::isSection(DGDS_ID section) {
+bool DgdsChunk::isSection(DGDS_ID section) const {
return (section == _id);
}
-bool DgdsChunk::isPacked(DGDS_EX ex) {
+bool DgdsChunk::isPacked(DGDS_EX ex) const {
bool packed = false;
switch (ex) {
@@ -240,9 +240,9 @@ bool DgdsChunk::readHeader(DgdsParser &ctx) {
//ctx._file.skip(2);
if (_size & 0x80000000) {
_size &= ~0x80000000;
- container = true;
+ _container = true;
} else {
- container = false;
+ _container = false;
}
return true;
}
@@ -256,7 +256,7 @@ Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompresso
unpackSize = ctx._file.readUint32LE();
_size -= (1 + 4);
- if (!container) {
+ if (!_container) {
byte *dest = new byte[unpackSize];
decompressor->decompress(compression, dest, unpackSize, &ctx._file, _size);
output = new Common::MemoryReadStream(dest, unpackSize, DisposeAfterUse::YES);
@@ -273,12 +273,12 @@ Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompresso
Common::SeekableReadStream *DgdsChunk::readStream(DgdsParser &ctx) {
Common::SeekableReadStream *output = 0;
- if (!container) {
+ if (!_container) {
output = new Common::SeekableSubReadStream(&ctx._file, ctx._file.pos(), ctx._file.pos() + _size, DisposeAfterUse::NO);
ctx._bytesRead += _size;
}
- debug(" %s %u%c", _idStr, _size, (container ? '+' : ' '));
+ debug(" %s %u%c", _idStr, _size, (_container ? '+' : ' '));
return output;
}
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index 496e02f102a..95e24b246ca 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -58,17 +58,19 @@ public:
Common::SeekableReadStream *getResource(Common::String name, bool ignorePatches = false);
Resource getResourceInfo(Common::String name);
- ResourceList _resources;
+
+ const ResourceList &getResources() const { return _resources; }
private:
Common::File _volumes[MAX_VOLUMES];
+ ResourceList _resources;
};
class DgdsChunk {
public:
- bool isSection(const Common::String §ion);
- bool isSection(DGDS_ID section);
- bool isPacked(DGDS_EX ex);
+ bool isSection(const Common::String §ion) const;
+ bool isSection(DGDS_ID section) const;
+ bool isPacked(DGDS_EX ex) const;
bool readHeader(DgdsParser &ctx);
Common::SeekableReadStream *decodeStream(DgdsParser &ctx, Decompressor *decompressor);
@@ -77,7 +79,7 @@ public:
char _idStr[DGDS_TYPENAME_MAX + 1];
DGDS_ID _id;
uint32 _size;
- bool container;
+ bool _container;
Common::SeekableReadStream *_stream;
};
diff --git a/engines/dgds/movies.cpp b/engines/dgds/scripts.cpp
similarity index 76%
rename from engines/dgds/movies.cpp
rename to engines/dgds/scripts.cpp
index 72ae4925fe3..47b2c5236a7 100644
--- a/engines/dgds/movies.cpp
+++ b/engines/dgds/scripts.cpp
@@ -31,34 +31,27 @@
#include "graphics/palette.h"
#include "graphics/surface.h"
#include "dgds/dgds.h"
+#include "dgds/dialogue.h"
#include "dgds/font.h"
#include "dgds/image.h"
#include "dgds/includes.h"
-#include "dgds/movies.h"
+#include "dgds/scripts.h"
#include "dgds/resource.h"
#include "dgds/parser.h"
namespace Dgds {
-// TODO: Move
-extern Graphics::ManagedSurface resData;
-extern Graphics::Surface bottomBuffer;
-extern Graphics::Surface topBuffer;
-extern Common::StringArray _bubbles;
-
-const Common::Rect rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-
-int bk = -1;
-int id = 0, sid = 0;
-Common::String text;
-extern PFont *_fntP;
-Common::Rect drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-Common::String _bmpNames[16];
+// FIXME: Move these into some state
+static int currentBmpId = 0;
+static DialogueLine _text;
+static Common::Rect _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+static Common::String _bmpNames[16];
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
- Common::SeekableReadStream *stream = _vm->_resource->getResource(filename);
+ Common::SeekableReadStream *stream = _vm->getResourceManager()->getResource(filename);
+ Decompressor *decompressor = _vm->getDecompressor();
if (!stream) {
error("Couldn't open script file '%s'", filename.c_str());
@@ -66,7 +59,7 @@ bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
}
TTMParser dgds(*stream, filename);
- dgds.parse(scriptData, _vm->_decompressor);
+ dgds.parse(scriptData, decompressor);
delete stream;
@@ -143,11 +136,11 @@ bool TTMInterpreter::run(TTMState *script) {
break;
case 0xf010:
// LOAD SCR: filename:str
- _vm->_image->drawScreen(sval, bottomBuffer);
+ _vm->_image->drawScreen(sval, _vm->getBottomBuffer());
continue;
case 0xf020:
// LOAD BMP: filename:str
- _bmpNames[id] = Common::String(sval);
+ _bmpNames[currentBmpId] = sval;
continue;
case 0xf050:
// LOAD PAL: filename:str
@@ -165,21 +158,22 @@ bool TTMInterpreter::run(TTMState *script) {
}
continue;
- case 0x1030:
+ case 0x1030: {
// SET BMP: id:int [-1:n]
- bk = ivals[0];
-
+ int bk = ivals[0];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[id], bk);
+ _vm->_image->loadBitmap(_bmpNames[currentBmpId], bk);
}
continue;
+ }
case 0x1050:
// SELECT BMP: id:int [0:n]
- id = ivals[0];
+ currentBmpId = ivals[0];
continue;
case 0x1060:
// SELECT SCR|PAL: id:int [0]
- sid = ivals[0];
+ warning("Switching scene %d -> %d for opcode 0x1060 .. is that right?", script->scene, ivals[0]);
+ script->scene = ivals[0];
continue;
case 0x1090:
// SELECT SONG: id:int [0]
@@ -194,47 +188,48 @@ bool TTMInterpreter::run(TTMState *script) {
// FADE OUT: ?,?,?,?:byte
g_system->delayMillis(script->delay);
_vm->_image->clearPalette();
- bottomBuffer.fillRect(rect, 0);
+ _vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
continue;
// these 3 ops do interaction between the topBuffer (imgData) and the bottomBuffer (scrData) but... it might turn out this uses z values!
case 0xa050: { //GFX? i,j,k,l:int [i<k,j<l] // HAPPENS IN INTRO.TTM:INTRO9
// it works like a bitblit, but it doesn't write if there's something already at the destination?
- resData.blitFrom(bottomBuffer);
- resData.transBlitFrom(topBuffer);
- topBuffer.copyFrom(resData);
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ _vm->getTopBuffer().copyFrom(_vm->_resData);
continue;
}
case 0x0020: //SAVE BG?: void // OR PERHAPS SWAPBUFFERS ; it makes bmpData persist in the next frames.
- bottomBuffer.copyFrom(topBuffer);
+ _vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
continue;
case 0x4200: {
// STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- resData.blitFrom(bottomBuffer);
- resData.transBlitFrom(topBuffer);
- bottomBuffer.copyRectToSurface(resData, destRect.left, destRect.top, destRect);
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ _vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
}
continue;
case 0x0ff0: {
// REFRESH: void
- resData.blitFrom(bottomBuffer);
- Graphics::Surface bmpSub = topBuffer.getSubArea(bmpWin);
- resData.transBlitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
- topBuffer.fillRect(bmpWin, 0);
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpWin);
+ _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
+ _vm->getTopBuffer().fillRect(bmpWin, 0);
- if (!text.empty()) {
+ if (!_text.text.empty()) {
Common::StringArray lines;
- const int h = _fntP->getFontHeight();
+ const PFont *fntP = _vm->getFntP();
+ const int h = fntP->getFontHeight();
- _fntP->wordWrapText(text, SCREEN_HEIGHT, lines);
+ fntP->wordWrapText(_text.text, SCREEN_HEIGHT, lines);
Common::Rect r(0, 7, SCREEN_WIDTH, h * lines.size() + 13);
- resData.fillRect(r, 15);
+ _vm->_resData.fillRect(r, 15);
for (uint i = 0; i < lines.size(); i++) {
- const int w = _fntP->getStringWidth(lines[i]);
- _fntP->drawString(&resData, lines[i], 10, 10 + 1 + i * h, w, 0);
+ const int w = fntP->getStringWidth(lines[i]);
+ fntP->drawString(&_vm->_resData, lines[i], 10, 10 + 1 + i * h, w, 0);
}
}
} break;
@@ -242,24 +237,25 @@ bool TTMInterpreter::run(TTMState *script) {
case 0xa520:
//DRAW BMP: x,y:int ; happens once in INTRO.TTM
case 0xa500:
- debug("DRAW \"%s\"", _bmpNames[id].c_str());
+ debug("DRAW \"%s\"", _bmpNames[currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
- bk = ivals[2];
- id = ivals[3];
+ int bk = ivals[2];
+ currentBmpId = ivals[3];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[id], bk);
+ _vm->_image->loadBitmap(_bmpNames[currentBmpId], bk);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- _vm->_image->loadBitmap(_bmpNames[id], 0);
+ warning("trying to load bmp %d (%s) on demand", currentBmpId, _bmpNames[currentBmpId].c_str());
+ _vm->_image->loadBitmap(_bmpNames[currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], drawWin, topBuffer);
+ _vm->_image->drawBitmap(ivals[0], ivals[1], _drawWin, _vm->getTopBuffer());
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
continue;
@@ -268,66 +264,71 @@ bool TTMInterpreter::run(TTMState *script) {
// DESCRIPTION IN TTM TAGS.
debug("SET SCENE: %u", ivals[0]);
script->scene = ivals[0];
+
+ const Common::Array<DialogueLine> bubbles = _vm->getDialogue()->getLines();
- if (!_bubbles.empty()) {
+ if (!bubbles.empty()) {
// TODO: Are these hardcoded?
if (!script->dataPtr->filename.compareToIgnoreCase("INTRO.TTM")) {
switch (ivals[0]) {
case 15:
- text = _bubbles[3];
+ _text = bubbles[3];
break;
case 16:
- text = _bubbles[4];
+ _text = bubbles[4];
break;
case 17:
- text = _bubbles[5];
+ _text = bubbles[5];
break;
case 19:
- text = _bubbles[6];
+ _text = bubbles[6];
break;
case 20:
- text = _bubbles[7];
+ _text = bubbles[7];
break;
case 22:
- text = _bubbles[8];
+ _text = bubbles[8];
break;
case 23:
- text = _bubbles[9];
+ _text = bubbles[9];
break;
case 25:
- text = _bubbles[10];
+ _text = bubbles[10];
break;
case 26:
- text = _bubbles[11];
+ _text = bubbles[11];
break;
default:
- text.clear();
+ _text.text.clear();
break;
}
} else if (!script->dataPtr->filename.compareToIgnoreCase("BIGTV.TTM")) {
switch (ivals[0]) {
case 1:
- text = _bubbles[0];
+ _text = bubbles[0];
break;
case 2:
- text = _bubbles[1];
+ _text = bubbles[1];
break;
case 3:
- text = _bubbles[2];
+ _text = bubbles[2];
+ break;
+ default:
+ _text.text.clear();
break;
}
}
- if (!text.empty())
+ if (!_text.text.empty())
script->delay += 1500;
} else {
- text.clear();
+ _text.text.clear();
}
}
continue;
case 0x4000:
//SET WINDOW? x,y,w,h:int [0..320,0..200]
- drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ _drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
continue;
case 0xa100:
@@ -360,9 +361,8 @@ bool TTMInterpreter::run(TTMState *script) {
break;
} while (scr->pos() < scr->size());
- Graphics::Surface *dst;
- dst = g_system->lockScreen();
- dst->copyRectToSurface(resData, 0, 0, rect);
+ Graphics::Surface *dst = g_system->lockScreen();
+ dst->copyRectToSurface(_vm->_resData, 0, 0, Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
g_system->unlockScreen();
g_system->updateScreen();
g_system->delayMillis(script->delay);
@@ -372,7 +372,7 @@ bool TTMInterpreter::run(TTMState *script) {
ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(nullptr) {}
bool ADSInterpreter::load(const Common::String &filename, ADSData *scriptData) {
- Common::SeekableReadStream *stream = _vm->_resource->getResource(filename);
+ Common::SeekableReadStream *stream = _vm->getResource(filename, false);
if (!stream) {
error("Couldn't open script resource '%s'", filename.c_str());
@@ -383,7 +383,7 @@ bool ADSInterpreter::load(const Common::String &filename, ADSData *scriptData) {
_filename = filename;
ADSParser dgds(*stream, _filename);
- dgds.parse(scriptData, _vm->_decompressor);
+ dgds.parse(scriptData, _vm->getDecompressor());
delete stream;
diff --git a/engines/dgds/movies.h b/engines/dgds/scripts.h
similarity index 98%
rename from engines/dgds/movies.h
rename to engines/dgds/scripts.h
index 80ea2e77a30..1135d590ecf 100644
--- a/engines/dgds/movies.h
+++ b/engines/dgds/scripts.h
@@ -23,6 +23,8 @@
#ifndef DGDS_MOVIES_H
#define DGDS_MOVIES_H
+#include "common/rect.h"
+
namespace Dgds {
class DgdsEngine;
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 47b48beefcb..623989ef4e2 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -28,7 +28,7 @@
namespace Dgds {
static inline
-void readHeader(byte* &pos, uint32 &sci_header) {
+void readHeader(const byte* &pos, uint32 &sci_header) {
sci_header = 0;
if (READ_LE_UINT16(pos) == 0x0084) sci_header = 2;
@@ -41,7 +41,7 @@ void readHeader(byte* &pos, uint32 &sci_header) {
}
static inline
-void readPartHeader(byte* &pos, uint16 &off, uint16 &siz) {
+void readPartHeader(const byte* &pos, uint16 &off, uint16 &siz) {
pos += 2;
off = READ_LE_UINT16(pos);
pos += 2;
@@ -50,14 +50,14 @@ void readPartHeader(byte* &pos, uint16 &off, uint16 &siz) {
}
static inline
-void skipPartHeader(byte* &pos) {
+void skipPartHeader(const byte* &pos) {
pos += 6;
}
-uint32 availableSndTracks(byte *data, uint32 size) {
- byte *pos = data;
+uint32 availableSndTracks(const byte *data, uint32 size) {
+ const byte *pos = data;
- uint32 sci_header;
+ uint32 sci_header;
readHeader(pos, sci_header);
uint32 tracks = 0;
@@ -108,7 +108,7 @@ uint32 availableSndTracks(byte *data, uint32 size) {
return tracks;
}
-byte loadSndTrack(uint32 track, byte** trackPtr, uint16* trackSiz, byte *data, uint32 size) {
+byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const byte *data, uint32 size) {
byte matchDrv;
switch (track) {
case DIGITAL_PCM:
@@ -118,7 +118,7 @@ byte loadSndTrack(uint32 track, byte** trackPtr, uint16* trackSiz, byte *data, u
default: return 0;
}
- byte *pos = data;
+ const byte *pos = data;
uint32 sci_header;
readHeader(pos, sci_header);
@@ -127,7 +127,7 @@ byte loadSndTrack(uint32 track, byte** trackPtr, uint16* trackSiz, byte *data, u
byte drv = *pos++;
byte part;
- byte *ptr;
+ const byte *ptr;
part = 0;
for (ptr = pos; *ptr != 0xFF; skipPartHeader(ptr))
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 0164e4b92e8..6e36b54b725 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -34,8 +34,8 @@ enum {
TRACK_MT32 = 1 << 3
};
-uint32 availableSndTracks(byte *data, uint32 size);
-byte loadSndTrack(uint32 track, byte** trackPtr, uint16* trackSiz, byte *data, uint32 size);
+uint32 availableSndTracks(const byte *data, uint32 size);
+byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const byte *data, uint32 size);
} // End of namespace Dgds
Commit: ed1062d63eb09743f6539f17226a53fd9373605d
https://github.com/scummvm/scummvm/commit/ed1062d63eb09743f6539f17226a53fd9373605d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement full SDS (Scene data) parsing
Still a lot of unnkown data being read, but at least we now have proper
dialogue parsing so a bunch of hacks can be removed.
Changed paths:
A engines/dgds/scene.cpp
A engines/dgds/scene.h
R engines/dgds/dialogue.cpp
R engines/dgds/dialogue.h
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/includes.h
engines/dgds/module.mk
engines/dgds/parser.cpp
engines/dgds/resource.cpp
engines/dgds/resource.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index dbcf23d95b7..ca6211e8637 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -116,7 +116,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
}
delete res;
-
+
Common::DumpFile out;
out.open(Common::Path(fileName));
out.write(data, size);
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 893187a646b..a032f4de77b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -51,7 +51,7 @@
#include "dgds/console.h"
#include "dgds/decompress.h"
-#include "dgds/dialogue.h"
+#include "dgds/scene.h"
#include "dgds/detection_tables.h"
#include "dgds/dgds.h"
#include "dgds/font.h"
@@ -65,6 +65,8 @@
namespace Dgds {
+#define DUMP_ALL_CHUNKS 1
+
//static Common::SeekableReadStream *ttm;
//static char ttmName[DGDS_FILENAME_MAX + 1];
@@ -74,7 +76,7 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
_midiPlayer(nullptr), _decompressor(nullptr), _musicData(nullptr), _musicSize(0),
- _soundData(nullptr), _dialogue(nullptr) {
+ _soundData(nullptr), _scene(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -96,7 +98,9 @@ DgdsEngine::~DgdsEngine() {
delete _image;
delete _decompressor;
delete _resource;
- delete _dialogue;
+ delete _scene;
+ delete _musicData;
+ delete _soundData;
}
void readStrings(Common::SeekableReadStream *stream) {
@@ -127,10 +131,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
uint parent = 0;
DgdsParser ctx(file, name);
- if (isFlatfile(platform, ex)) {
- uint16 tcount;
- uint16 *tw, *th;
- uint32 *toffset;
+ if (DgdsChunk::isFlatfile(platform, ex)) {
Common::String line;
switch (ex) {
@@ -192,16 +193,16 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
} break;
case EX_BMP: {
/* Unknown image format (Amiga). */
- tcount = file.readUint16BE();
- tw = new uint16[tcount];
- th = new uint16[tcount];
+ uint16 tcount = file.readUint16BE();
+ uint16 *tw = new uint16[tcount];
+ uint16 *th = new uint16[tcount];
uint32 packedSize, unpackedSize;
unpackedSize = file.readUint32BE();
debug(" [%u] %u =", tcount, unpackedSize);
uint32 sz = 0;
- toffset = new uint32[tcount];
+ uint32 *toffset = new uint32[tcount];
for (uint16 k = 0; k < tcount; k++) {
tw[k] = file.readUint16BE();
th[k] = file.readUint16BE();
@@ -222,6 +223,9 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
packedSize = file.readUint32BE();
debug(" %u -> %u",
packedSize, unpackedSize);
+ delete [] toffset;
+ delete [] tw;
+ delete [] th;
} break;
case EX_INS: {
/* AIFF sound sample (Amiga). */
@@ -255,9 +259,10 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
file.hexdump(leftover);
file.skip(leftover);
} else {
- uint16 scount = 0;
+ uint16 scount = 0; // song count
DgdsChunk chunk;
+ int chunkno = 0;
while (chunk.readHeader(ctx)) {
if (chunk._container) {
parent = chunk._id;
@@ -269,6 +274,19 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
bool packed = chunk.isPacked(ex);
stream = packed ? chunk.decodeStream(ctx, decompressor) : chunk.readStream(ctx);
+#ifdef DUMP_ALL_CHUNKS
+ {
+ Common::DumpFile out;
+ int64 start = stream->pos();
+ out.open(Common::Path(Common::String::format("/tmp/dgds_%s_%02d_%.3s.dump", name, chunkno, chunk._idStr)));
+ out.writeStream(stream);
+ out.close();
+ stream->seek(start);
+ }
+
+#endif
+ chunkno++;
+
switch (ex) {
case EX_TDS:
/* Heart of China. */
@@ -315,7 +333,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
break;
case EX_SDS:
if (chunk.isSection(ID_SDS)) {
- _dialogue->parseSDS(stream);
+ _scene->parseSDS(stream);
}
break;
case EX_TTM:
@@ -394,22 +412,21 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
break;
case EX_GDS:
- if (chunk.isSection(ID_INF)) {
- //stream->hexdump(stream->size());
- uint32 mark;
- char version[7];
-
- mark = stream->readUint32LE();
- debug(" 0x%X", mark);
+ if (chunk.isSection(ID_GDS)) {
+ // do nothing, this is the container.
+ assert(chunk._container);
+ } else if (chunk.isSection(ID_INF)) {
+ uint32 checksum = stream->readUint32LE(); // probably?
+ debug(" Checksum: 0x%X", checksum);
- stream->read(version, sizeof(version));
- debug(" \"%s\"", version);
+ char gdsVersion[7];
+ stream->read(gdsVersion, sizeof(gdsVersion));
+ debug(" Scene Version: \"%s\"", gdsVersion);
} else if (chunk.isSection(ID_SDS)) {
- //stream->hexdump(stream->size());
+ stream->hexdump(stream->size());
- uint32 x;
- x = stream->readUint32LE();
+ uint32 x = stream->readUint32LE();
debug(" %u", x);
while (!stream->eos()) {
@@ -746,7 +763,7 @@ Common::Error DgdsEngine::run() {
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
_midiPlayer = new DgdsMidiPlayer();
- _dialogue = new Dialogue();
+ _scene = new Scene();
setDebugger(_console);
@@ -766,31 +783,33 @@ Common::Error DgdsEngine::run() {
TTMInterpreter interpTTM(this);
TTMState title1State, title2State;
- ADSState introState;
+ ADSState adsState;
TTMData title1Data, title2Data;
- ADSData introData;
+ ADSData adsData;
if (getGameId() == GID_DRAGON) {
+ parseFile("DRAGON.GDS");
+
interpTTM.load("TITLE1.TTM", &title1Data);
interpTTM.load("TITLE2.TTM", &title2Data);
- interpADS.load("INTRO.ADS", &introData);
+ interpADS.load("INTRO.ADS", &adsData);
interpTTM.init(&title1State, &title1Data);
interpTTM.init(&title2State, &title2Data);
- interpADS.init(&introState, &introData);
+ interpADS.init(&adsState, &adsData);
parseFile("DRAGON.FNT");
parseFile("S55.SDS");
} else if (getGameId() == GID_CHINA) {
- interpADS.load("TITLE.ADS", &introData);
+ interpADS.load("TITLE.ADS", &adsData);
- interpADS.init(&introState, &introData);
+ interpADS.init(&adsState, &adsData);
parseFile("HOC.FNT");
} else if (getGameId() == GID_BEAMISH) {
- interpADS.load("TITLE.ADS", &introData);
+ interpADS.load("TITLE.ADS", &adsData);
- interpADS.init(&introState, &introData);
+ interpADS.init(&adsState, &adsData);
//parseFile("HOC.FNT");
}
@@ -819,12 +838,12 @@ Common::Error DgdsEngine::run() {
// browse(_platform, _rmfName, this);
if (getGameId() == GID_DRAGON) {
- if (!interpTTM.run(&title1State))
- if (!interpTTM.run(&title2State))
- if (!interpADS.run(&introState))
+ //if (!interpTTM.run(&title1State))
+ //if (!interpTTM.run(&title2State))
+ if (!interpADS.run(&adsState))
return Common::kNoError;
} else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
- if (!interpADS.run(&introState))
+ if (!interpADS.run(&adsState))
return Common::kNoError;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 173b70b1492..196dc53fdad 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -42,7 +42,7 @@ class Decompressor;
class Image;
class PFont;
class FFont;
-class Dialogue;
+class Scene;
class DgdsMidiPlayer;
struct DgdsADS;
@@ -67,7 +67,7 @@ private:
DgdsGameId _gameId;
Graphics::Surface _bottomBuffer;
Graphics::Surface _topBuffer;
- Dialogue *_dialogue;
+ Scene *_scene;
PFont *_fntP;
FFont *_fntF;
@@ -98,7 +98,7 @@ public:
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
- const Dialogue *getDialogue() const { return _dialogue; }
+ const Scene *getScene() const { return _scene; }
const PFont *getFntP() const { return _fntP; }
Image *_image;
diff --git a/engines/dgds/dialogue.cpp b/engines/dgds/dialogue.cpp
deleted file mode 100644
index 255631e108e..00000000000
--- a/engines/dgds/dialogue.cpp
+++ /dev/null
@@ -1,184 +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/debug.h"
-#include "common/endian.h"
-#include "common/file.h"
-
-#include "dgds/dialogue.h"
-
-namespace Dgds {
-
-void Dialogue::parseSDS(Common::SeekableReadStream *stream) {
- // Debug
- /*uint32 pos = stream->pos();
- byte *tmp = new byte[stream->size()];
- stream->read(tmp, stream->size());
- Common::hexdump(tmp, stream->size());
- stream->seek(pos, SEEK_SET);*/
-
- uint32 mark = stream->readUint32LE();
- debug(" 0x%X", mark);
-
- char version[7];
- stream->read(version, sizeof(version));
- debug(" %s", version);
-
- uint16 idx;
- idx = stream->readUint16LE();
- debug(" S%d.SDS", idx);
-
- // gross hack to grep the strings.
- //_bubbles.clear();
-
- bool inside = false;
- Common::String txt;
- {
- int64 start = stream->pos();
- Common::DumpFile dump;
- dump.open("/tmp/sds.dat");
- dump.writeStream(stream);
- stream->seek(start);
- }
-
-
- while (1) {
- char buf[4];
- stream->read(buf, sizeof(buf));
- if (stream->pos() >= stream->size())
- break;
- if (Common::isPrint(buf[0]) && Common::isPrint(buf[1]) && Common::isPrint(buf[2]) && Common::isPrint(buf[3])) {
- inside = true;
- }
- stream->seek(-3, SEEK_CUR);
-
- if (inside) {
- if (buf[0] == '\0') {
- // here's where we do a clever thing. we want Pascal like strings.
- uint16 pos = txt.size() + 1;
- stream->seek(-pos - 2, SEEK_CUR);
- uint16 len = stream->readUint16LE();
- stream->seek(pos, SEEK_CUR);
-
- // gotcha!
- if (len == pos) {
- //if (resource == 0)
- //_bubbles.push_back(txt);
- debug(" \"%s\"", txt.c_str());
- }
- // let's hope the string wasn't shorter than 4 chars...
- txt.clear();
- inside = false;
- } else {
- txt += buf[0];
- }
- }
- }
-#if 0
- idx = stream->readUint16LE();
- debug(" %d", idx);
-
- idx = stream->readUint16LE();
- debug(" %d", idx);
-
- uint16 count;
- while (1) {
- uint16 code;
- code = stream->readUint16LE();
- count = stream->readUint16LE();
- idx = stream->readUint16LE();
-
- debugN("\tOP: 0x%8.8x %2u %2u\n", code, count, idx);
-
- uint16 pitch = (count+1)&(~1); // align to word.
- if ((stream->pos()+pitch) >= stream->size()) break;
-
- if (code == 0 && count == 0) break;
-
- stream->skip(pitch);
- }
-
- Common::String sval;
- byte ch;
-
- do {
- ch = stream->readByte();
- sval += ch;
- } while (ch != 0);
-
- debug("\"%s\"", sval.c_str());
-#endif
-#if 0
- // probe for the .ADS name. are these shorts?
- uint count;
- count = 0;
- while (1) {
- uint16 x;
- x = stream->readUint16LE();
- if ((x & 0xFF00) != 0)
- break;
- debug(" %u: %u|0x%4.4X", count++, x, x);
- }
- stream->seek(-2, SEEK_CUR);
-
- // .ADS name.
- Common::String ads;
- byte ch;
- while ((ch = stream->readByte()))
- ads += ch;
- debug(" %s", ads.c_str());
-
- stream->hexdump(6);
- stream->skip(6);
-
- int w, h;
-
- w = stream->readSint16LE();
- h = stream->readSint16LE();
- debug(" %dx%d", w, h);
-
- // probe for the strings. are these shorts?
- count = 0;
- while (1) {
- uint16 x;
- x = stream->readUint16LE();
- if ((x & 0xFF00) != 0)
- break;
- if (stream->pos() >= stream->size()) break;
- debug(" %u: %u|0x%4.4X", count++, x, x);
- }
- stream->seek(-4, SEEK_CUR);
- // here we are.
-
- uint16 len;
- len = stream->readSint16LE();
- Common::String txt;
- for (uint16 j=0; j<len; j++) {
- ch = stream->readByte();
- txt += ch;
- debug(" \"%s\"", txt.c_str());
- }
-#endif
-}
-
-} // End of namespace Dgds
-
diff --git a/engines/dgds/dialogue.h b/engines/dgds/dialogue.h
deleted file mode 100644
index 3f034c553ee..00000000000
--- a/engines/dgds/dialogue.h
+++ /dev/null
@@ -1,64 +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 DGDS_DIALOUGE_H
-#define DGDS_DIALOUGE_H
-
-#include "common/stream.h"
-#include "common/array.h"
-
-namespace Dgds {
-
-class DialogueLine {
-public:
- uint16 unk[9];
- uint16 x;
- uint16 y;
- uint16 w;
- uint16 h;
- uint16 bgcol;
- uint16 fontcol; // 0 = black , 0xf = white
- uint16 unk2;
- uint16 unk3;
- uint16 fontsize; // 01 = 8x8, 02 = 6x6, 03 = 4x5
- uint16 just; // 0x00 =t top, 0x03 = center
- uint16 unk4;
- uint16 frametype; // 01 =simple frame, 02 = with title (text before :), 03 = baloon, 04 = eliptical baloon
- uint16 unk5;
- uint16 unk6;
- uint16 textLen;
- Common::String text;
-};
-
-class Dialogue {
-public:
- void parseSDS(Common::SeekableReadStream *s);
-
- const Common::Array<DialogueLine> &getLines() const { return _dialogue; }
-private:
- Common::Array<DialogueLine> _dialogue;
-};
-
-} // End of namespace Dgds
-
-#endif // DGDS_DIALOUGE_H
-
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
index b4bd46fcb6e..73532be4e1e 100644
--- a/engines/dgds/includes.h
+++ b/engines/dgds/includes.h
@@ -34,6 +34,7 @@ namespace Dgds {
#define ID_FNT MKTAG24('F', 'N', 'T')
#define ID_GAD MKTAG24('G', 'A', 'D')
#define ID_INF MKTAG24('I', 'N', 'F')
+#define ID_GDS MKTAG24('G', 'D', 'S')
#define ID_MTX MKTAG24('M', 'T', 'X')
#define ID_PAG MKTAG24('P', 'A', 'G')
#define ID_REQ MKTAG24('R', 'E', 'Q')
@@ -43,17 +44,18 @@ namespace Dgds {
#define ID_SNG MKTAG24('S', 'N', 'G')
#define ID_TAG MKTAG24('T', 'A', 'G')
#define ID_TT3 MKTAG24('T', 'T', '3')
-#define ID_TTI MKTAG24('T', 'T', 'I')
#define ID_VER MKTAG24('V', 'E', 'R')
#define ID_VGA MKTAG24('V', 'G', 'A')
#define ID_VQT MKTAG24('V', 'Q', 'T')
#define ID_OFF MKTAG24('O', 'F', 'F')
+#define ID_TTI MKTAG24('T', 'T', 'I')
/* Heart of China */
#define ID_MA8 MKTAG24('M', 'A', '8')
#define ID_DDS MKTAG24('D', 'D', 'S')
#define ID_THD MKTAG24('T', 'H', 'D')
+/* EX_ are File extensions types */
#define EX_ADH MKTAG24('A', 'D', 'H')
#define EX_ADL MKTAG24('A', 'D', 'L')
#define EX_ADS MKTAG24('A', 'D', 'S')
@@ -72,6 +74,7 @@ namespace Dgds {
#define EX_TTM MKTAG24('T', 'T', 'M')
#define EX_VIN MKTAG24('V', 'I', 'N')
+
/* Heart of China */
#define EX_DAT MKTAG24('D', 'A', 'T')
#define EX_DDS MKTAG24('D', 'D', 'S')
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 4aa60b71fa2..55f3779c23f 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -3,7 +3,6 @@ MODULE := engines/dgds
MODULE_OBJS := \
console.o \
decompress.o \
- dialogue.o \
dgds.o \
font.o \
image.o \
@@ -12,6 +11,7 @@ MODULE_OBJS := \
parser.o \
resource.o \
scripts.o \
+ scene.o \
sound.o
# This module can be built as a plugin
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 13be683b563..fafb8aef566 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -87,7 +87,7 @@ bool TTMParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
TTMData *scriptData = (TTMData *)data;
switch (chunk._id) {
- case ID_TTI: // tag container - we want the tags so don't skip
+ case ID_TTI: // Ignore containers
break;
case ID_TT3:
scriptData->scr = chunk._stream->readStream(chunk._stream->size());
@@ -111,7 +111,7 @@ bool ADSParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
ADSData *scriptData = (ADSData *)data;
switch (chunk._id) {
case EX_ADS:
- case ID_TTI: // tag container - we want the tags so ignore?
+ case ID_TTI: // Ignore containers
break;
case ID_RES: {
uint16 count = chunk._stream->readUint16LE();
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 805a6dd65b9..45b4ddea327 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -282,10 +282,11 @@ Common::SeekableReadStream *DgdsChunk::readStream(DgdsParser &ctx) {
return output;
}
-bool isFlatfile(Common::Platform platform, DGDS_EX _ex) {
+/*static*/
+bool DgdsChunk::isFlatfile(Common::Platform platform, DGDS_EX ext) {
bool flat = false;
- switch (_ex) {
+ switch (ext) {
case EX_RST:
case EX_VIN:
case EX_DAT:
@@ -297,7 +298,7 @@ bool isFlatfile(Common::Platform platform, DGDS_EX _ex) {
switch (platform) {
case Common::kPlatformAmiga:
- switch (_ex) {
+ switch (ext) {
case EX_BMP:
case EX_SCR:
case EX_INS:
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index 95e24b246ca..f8ec76678cf 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -71,6 +71,7 @@ public:
bool isSection(const Common::String §ion) const;
bool isSection(DGDS_ID section) const;
bool isPacked(DGDS_EX ex) const;
+ static bool isFlatfile(Common::Platform platform, DGDS_EX ext);
bool readHeader(DgdsParser &ctx);
Common::SeekableReadStream *decodeStream(DgdsParser &ctx, Decompressor *decompressor);
@@ -83,7 +84,6 @@ public:
Common::SeekableReadStream *_stream;
};
-bool isFlatfile(Common::Platform platform, DGDS_EX _ex);
//int32 dgdsHash(const char *s, byte *idx);
//uint32 lookupVolume(const char *rmfName, const char *filename, char *volname);
//Common::SeekableReadStream *createReadStream(const char *rmfName, const char *filename);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
new file mode 100644
index 00000000000..18df9aab8d8
--- /dev/null
+++ b/engines/dgds/scene.cpp
@@ -0,0 +1,215 @@
+/* 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/debug.h"
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "dgds/scene.h"
+
+namespace Dgds {
+
+Scene::Scene() : _magic(0), _num(-1) {
+}
+
+bool Scene::isVersionOver(const char *version) {
+ return strncmp(_version.c_str(), version, _version.size()) > 0;
+}
+
+bool Scene::isVersionUnder(const char *version) {
+ return strncmp(_version.c_str(), version, _version.size()) < 0;
+}
+
+bool Scene::parseSDS(Common::SeekableReadStream *stream) {
+ _magic = stream->readUint32LE();
+ _version = stream->readString();
+ if (isVersionOver(" 1.211")) {
+ error("Unsupported scene version '%s'", _version.c_str());
+ }
+ _num = stream->readUint16LE();
+ readStruct5List(stream, _struct5List1);
+ readStruct5List(stream, _struct5List2);
+ if (isVersionOver(" 1.206")) {
+ readStruct5List(stream, _struct5List3);
+ }
+ readStruct5List(stream, _struct5List4);
+ _field6_0x14 = stream->readUint16LE();
+ _adsFile = stream->readString();
+ readStruct2List(stream, _struct2List);
+ readStruct4List(stream, _struct4List1);
+ if (isVersionOver(" 1.205")) {
+ readStruct4List(stream, _struct4List2);
+ }
+ readDialogueList(stream, _dialogues);
+ if (isVersionOver(" 1.203")) {
+ readStruct7List(stream, _struct7List);
+ }
+
+ return !stream->err();
+}
+
+
+bool Scene::readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) {
+ list.resize(s->readUint16LE());
+ for (SceneStruct1 &dst : list) {
+ dst.val1 = s->readUint16LE();
+ dst.flags = s->readUint16LE();
+ dst.val3 = s->readUint16LE();
+ }
+ return !s->err();
+}
+
+
+bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) {
+ list.resize(s->readUint16LE());
+ for (SceneStruct2 &dst : list) {
+ dst.rect.x = s->readUint16LE();
+ dst.rect.y = s->readUint16LE();
+ dst.rect.width = s->readUint16LE();
+ dst.rect.height = s->readUint16LE();
+ dst.field1_0x8 = s->readUint16LE();
+ dst.field2_0xa = s->readUint16LE();
+ readStruct1List(s, dst.struct1List);
+ readStruct5List(s, dst.struct5List1);
+ readStruct5List(s, dst.struct5List2);
+ readStruct5List(s, dst.struct5List3);
+ }
+ return !s->err();
+}
+
+
+bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) {
+ list.resize(s->readUint16LE());
+ for (SceneStruct4 &dst : list) {
+ if (!isVersionOver(" 1.205")) {
+ dst.val2 = s->readUint16LE();
+ dst.val1 = s->readUint16LE();
+ dst.val2 += s->readUint16LE();
+ } else {
+ dst.val1 = s->readUint16LE();
+ dst.val2 = s->readUint16LE();
+ }
+ readStruct5List(s, dst.struct5List);
+ }
+ return !s->err();
+}
+
+
+bool Scene::readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) {
+ list.resize(s->readUint16LE());
+ for (SceneStruct5 &dst : list) {
+ readStruct1List(s, dst.struct1List);
+ dst.val = s->readUint16LE();
+ int nvals = s->readUint16LE();
+ for (int i = 0; i < nvals / 2; i++) {
+ dst.uintList.push_back(s->readUint16LE());
+ }
+ }
+
+ return !s->err();
+}
+
+
+bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) {
+ list.resize(s->readUint16LE());
+ for (Dialogue &dst : list) {
+ dst.num = s->readUint16LE();
+ dst.rect.x = s->readUint16LE();
+ dst.rect.y = s->readUint16LE();
+ dst.rect.width = s->readUint16LE();
+ dst.rect.height = s->readUint16LE();
+ dst.bgColor = s->readUint16LE();
+ dst.fontColor = s->readUint16LE(); // 0 = black, 0xf = white
+ if (isVersionUnder(" 1.209")) {
+ dst.field7_0xe = dst.bgColor;
+ dst.field8_0x10 = dst.fontColor;
+ } else {
+ dst.field7_0xe = s->readUint16LE();
+ dst.field8_0x10 = s->readUint16LE();
+ }
+ dst.fontSize = s->readUint16LE(); // 01 = 8x8, 02 = 6x6, 03 = 4x5
+ if (isVersionUnder(" 1.210")) {
+ dst.flags = s->readUint16LE();
+ } else {
+ // Game reads a 32 bit int but then truncates anyway..
+ // probably never used the full thing.
+ dst.flags = (s->readUint32LE() & 0xffff);
+ }
+
+ dst.frametype = s->readUint16LE(); // 01 =simple frame, 02 = with title w/ text before :, 03 = baloon, 04 = eliptical
+ dst.field12_0x1a = s->readUint16LE();
+ if (isVersionOver(" 1.207")) {
+ dst.field13_0x1c = s->readUint16LE();
+ }
+
+ uint16 nbytes = s->readUint16LE();
+ if (nbytes > 0) {
+ dst.str = s->readString('\0', nbytes);
+ } else {
+ dst.str.clear();
+ }
+ readDialogSubstringList(s, dst.subStrings);
+
+ if (isVersionUnder(" 1.209") && !dst.subStrings.empty()) {
+ if (dst.fontColor == 0)
+ dst.field8_0x10 = 4;
+ else if (dst.fontColor == 0xff)
+ dst.fontColor = 7;
+ else
+ dst.fontColor = dst.fontColor ^ 8;
+ }
+ }
+
+ return !s->err();
+}
+
+
+bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) {
+ list.resize(s->readUint16LE());
+ for (SceneStruct7 &dst : list) {
+ dst.val = s->readUint16LE();
+ readStruct1List(s, dst.struct1List);
+ readStruct5List(s, dst.struct5List);
+ }
+
+ return !s->err();
+}
+
+
+bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) {
+ list.resize(s->readUint16LE());
+
+ if (!list.empty())
+ list[0].val = 1;
+
+ for (DialogueSubstring &dst : list) {
+ dst.strOff1 = s->readUint16LE();
+ dst.strOff2 = s->readUint16LE();
+ readStruct5List(s, dst.struct5List);
+ }
+
+ return !s->err();
+}
+
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
new file mode 100644
index 00000000000..2450200331a
--- /dev/null
+++ b/engines/dgds/scene.h
@@ -0,0 +1,170 @@
+/* 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 DGDS_SCENE_H
+#define DGDS_SCENE_H
+
+#include "common/stream.h"
+#include "common/array.h"
+
+namespace Dgds {
+
+struct SceneStruct1 {
+ uint16 val1;
+ uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
+ uint16 val3;
+};
+
+struct Rect {
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+struct SceneStruct2 {
+ struct Rect rect;
+ uint16 field1_0x8;
+ uint16 field2_0xa;
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneStruct5> struct5List1;
+ Common::Array<struct SceneStruct5> struct5List2;
+ Common::Array<struct SceneStruct5> struct5List3;
+};
+
+struct SceneStruct5 {
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<uint16> uintList;
+ uint16 val;
+};
+
+struct SceneStruct2_Extended {
+ struct Rect rect;
+ uint16 field1_0x8;
+ uint16 field2_0xa;
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneStruct5> struct5List1;
+ Common::Array<struct SceneStruct5> struct5List2;
+ Common::Array<struct SceneStruct5> struct5List3;
+ //struct SceneStruct2 *next;
+ Common::Array<struct SceneStruct5> field8_0x1c; /* this field on are only in Extended (GDS) version */
+ Common::Array<struct SceneStruct5> field9_0x20;
+ uint16 field10_0x24;
+ uint16 field11_0x26;
+ uint16 field12_0x28;
+ uint16 field13_0x2a;
+ uint16 field14_0x2c;
+};
+
+struct SceneStruct3 {
+ uint16 val1;
+ uint16 val2;
+ uint16 val3; /* Not set in loader? */
+};
+
+struct SceneStruct4 {
+ uint16 val1;
+ uint16 val2;
+ Common::Array<struct SceneStruct5> struct5List;
+};
+
+struct Dialogue {
+ uint16 num;
+ Rect rect;
+ uint16 bgColor;
+ uint16 fontColor;
+ uint16 field7_0xe;
+ uint16 field8_0x10;
+ uint16 fontSize;
+ uint32 flags; // includes justify
+ uint16 frametype;
+ uint16 field12_0x1a;
+ uint16 field13_0x1c;
+ Common::Array<struct DialogueSubstring> subStrings;
+ uint16 field15_0x22;
+ Common::String str;
+ uint16 field18_0x28;
+};
+
+struct SceneStruct7 {
+ uint16 val;
+ int16 field1_0x2;
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneStruct5> struct5List;
+};
+
+struct DialogueSubstring {
+ uint16 strOff1; // The game initializes these to pointers, but let's be a bit nicer.
+ uint16 strOff2;
+ byte unk[8]; /* Not initialized in loader */
+ Common::Array<struct SceneStruct5> struct5List;
+ uint val; /* First entry initialized to 1 in loader */
+};
+
+
+/**
+ * A scene is described by an SDS file, which points to the ADS script to load
+ * and holds the dialogue info.
+ */
+class Scene {
+public:
+ Scene();
+
+ bool parseSDS(Common::SeekableReadStream *s);
+ bool isVersionOver(const char *version);
+ bool isVersionUnder(const char *version);
+
+ const Common::Array<struct Dialogue> &getLines() const { return _dialogues; }
+
+private:
+ bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list);
+ bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list);
+ bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list);
+ bool readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list);
+ bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list);
+ bool readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list);
+ bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list);
+
+ uint32 _magic;
+ Common::String _version;
+
+ int _num;
+ Common::Array<struct SceneStruct5> _struct5List1;
+ Common::Array<struct SceneStruct5> _struct5List2;
+ Common::Array<struct SceneStruct5> _struct5List3;
+ Common::Array<struct SceneStruct5> _struct5List4;
+ uint _field5_0x12;
+ uint _field6_0x14;
+ Common::String _adsFile;
+ uint _field8_0x23;
+ Common::Array<struct SceneStruct2> _struct2List;
+ Common::Array<struct SceneStruct4> _struct4List1;
+ Common::Array<struct SceneStruct4> _struct4List2;
+ uint _field12_0x2b;
+ Common::Array<struct Dialogue> _dialogues;
+ Common::Array<struct SceneStruct7> _struct7List;
+ uint _field15_0x33;
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_SCENE_H
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 47b2c5236a7..4d4936659c4 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -31,7 +31,7 @@
#include "graphics/palette.h"
#include "graphics/surface.h"
#include "dgds/dgds.h"
-#include "dgds/dialogue.h"
+#include "dgds/scene.h"
#include "dgds/font.h"
#include "dgds/image.h"
#include "dgds/includes.h"
@@ -43,7 +43,7 @@ namespace Dgds {
// FIXME: Move these into some state
static int currentBmpId = 0;
-static DialogueLine _text;
+static Dialogue _text;
static Common::Rect _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
static Common::String _bmpNames[16];
@@ -219,17 +219,17 @@ bool TTMInterpreter::run(TTMState *script) {
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
_vm->getTopBuffer().fillRect(bmpWin, 0);
- if (!_text.text.empty()) {
+ if (!_text.str.empty()) {
Common::StringArray lines;
const PFont *fntP = _vm->getFntP();
const int h = fntP->getFontHeight();
- fntP->wordWrapText(_text.text, SCREEN_HEIGHT, lines);
- Common::Rect r(0, 7, SCREEN_WIDTH, h * lines.size() + 13);
+ fntP->wordWrapText(_text.str, SCREEN_HEIGHT, lines);
+ Common::Rect r(Common::Point(_text.rect.x, _text.rect.y), _text.rect.width, _text.rect.height);
_vm->_resData.fillRect(r, 15);
for (uint i = 0; i < lines.size(); i++) {
const int w = fntP->getStringWidth(lines[i]);
- fntP->drawString(&_vm->_resData, lines[i], 10, 10 + 1 + i * h, w, 0);
+ fntP->drawString(&_vm->_resData, lines[i], _text.rect.x, _text.rect.y + 1 + i * h, w, 0);
}
}
} break;
@@ -264,67 +264,17 @@ bool TTMInterpreter::run(TTMState *script) {
// DESCRIPTION IN TTM TAGS.
debug("SET SCENE: %u", ivals[0]);
script->scene = ivals[0];
-
- const Common::Array<DialogueLine> bubbles = _vm->getDialogue()->getLines();
-
- if (!bubbles.empty()) {
- // TODO: Are these hardcoded?
- if (!script->dataPtr->filename.compareToIgnoreCase("INTRO.TTM")) {
- switch (ivals[0]) {
- case 15:
- _text = bubbles[3];
- break;
- case 16:
- _text = bubbles[4];
- break;
- case 17:
- _text = bubbles[5];
- break;
- case 19:
- _text = bubbles[6];
- break;
- case 20:
- _text = bubbles[7];
- break;
- case 22:
- _text = bubbles[8];
- break;
- case 23:
- _text = bubbles[9];
- break;
- case 25:
- _text = bubbles[10];
- break;
- case 26:
- _text = bubbles[11];
- break;
- default:
- _text.text.clear();
- break;
- }
- } else if (!script->dataPtr->filename.compareToIgnoreCase("BIGTV.TTM")) {
- switch (ivals[0]) {
- case 1:
- _text = bubbles[0];
- break;
- case 2:
- _text = bubbles[1];
- break;
- case 3:
- _text = bubbles[2];
- break;
- default:
- _text.text.clear();
- break;
- }
- }
- if (!_text.text.empty())
- script->delay += 1500;
- } else {
- _text.text.clear();
+
+ const Common::Array<Dialogue> dialogues = _vm->getScene()->getLines();
+ _text.str.clear();
+ for (const Dialogue &dialogue: dialogues) {
+ if (dialogue.num == ivals[0])
+ _text = dialogue;
}
- }
+ if (!_text.str.empty())
+ script->delay += 1500;
continue;
+ }
case 0x4000:
//SET WINDOW? x,y,w,h:int [0..320,0..200]
@@ -340,8 +290,8 @@ bool TTMInterpreter::run(TTMState *script) {
script->delay += ivals[0] * 10;
continue;
- case 0x10a0:
- // SET SCR|PAL: id:int [0]
+ case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
+
case 0x2000: //SET FRAME1?: i,j:int [0..255]
case 0xa530: // CHINA
@@ -430,11 +380,11 @@ void ADSInterpreter::init(ADSState *state, const ADSData *data) {
}
bool ADSInterpreter::run(ADSState *script) {
- TTMInterpreter interp(_vm);
if (script->subMax != 0) {
- TTMState *state = &script->scriptStates[script->subIdx - 1];
- if (!interp.run(state) || state->scene >= script->subMax)
+ TTMInterpreter interp(_vm);
+ TTMState *ttmState = &script->scriptStates[script->subIdx - 1];
+ if (!interp.run(ttmState) || ttmState->scene >= script->subMax)
script->subMax = 0;
return true;
}
@@ -467,8 +417,9 @@ bool ADSInterpreter::run(ADSState *script) {
uint16 unk1 = scr->readUint16LE();
uint16 unk2 = scr->readUint16LE();
debug("ADSInterpreter play scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", script->subIdx, script->subMax, unk1, unk2);
- }
return true;
+ }
+
case 0xF010:
case 0xF200:
case 0xFDA8:
@@ -478,12 +429,15 @@ bool ADSInterpreter::run(ADSState *script) {
case 0xFFFF:
case 0x0190:
case 0x1070:
+ case 0x1330:
case 0x1340:
+ case 0x1350:
case 0x1360:
case 0x1370:
case 0x1420:
case 0x1430:
case 0x1500:
+ case 0x1510:
case 0x1520:
case 0x2000:
case 0x2010:
@@ -493,9 +447,6 @@ bool ADSInterpreter::run(ADSState *script) {
case 0x30FF:
case 0x4000:
case 0x4010:
- case 0x1510:
- case 0x1330:
- case 0x1350:
default:
warning("Unimplemented ADS opcode: 0x%04X (count %d)", code, count);
continue;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 1135d590ecf..65e30bac684 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DGDS_MOVIES_H
-#define DGDS_MOVIES_H
+#ifndef DGDS_SCRIPTS_H
+#define DGDS_SCRIPTS_H
#include "common/rect.h"
@@ -104,4 +104,4 @@ protected:
} // End of namespace Dgds
-#endif // DGDS_MOVIES_H
+#endif // DGDS_SCRIPTS_H
Commit: 7a0c5f4dd26ab101e90ce14ee38878913dc95bfa
https://github.com/scummvm/scummvm/commit/7a0c5f4dd26ab101e90ce14ee38878913dc95bfa
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add parsing for GDS style SDS data
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index a032f4de77b..2d9189d03a3 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -76,7 +76,7 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
_midiPlayer(nullptr), _decompressor(nullptr), _musicData(nullptr), _musicSize(0),
- _soundData(nullptr), _scene(nullptr) {
+ _soundData(nullptr), _scene(nullptr), _gdsScene(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -99,6 +99,7 @@ DgdsEngine::~DgdsEngine() {
delete _decompressor;
delete _resource;
delete _scene;
+ delete _gdsScene;
delete _musicData;
delete _soundData;
}
@@ -333,7 +334,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
break;
case EX_SDS:
if (chunk.isSection(ID_SDS)) {
- _scene->parseSDS(stream);
+ _scene->parse(stream);
}
break;
case EX_TTM:
@@ -416,33 +417,9 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
// do nothing, this is the container.
assert(chunk._container);
} else if (chunk.isSection(ID_INF)) {
- uint32 checksum = stream->readUint32LE(); // probably?
- debug(" Checksum: 0x%X", checksum);
-
- char gdsVersion[7];
- stream->read(gdsVersion, sizeof(gdsVersion));
- debug(" Scene Version: \"%s\"", gdsVersion);
-
+ _gdsScene->parseInf(stream);
} else if (chunk.isSection(ID_SDS)) {
- stream->hexdump(stream->size());
-
- uint32 x = stream->readUint32LE();
- debug(" %u", x);
-
- while (!stream->eos()) {
- uint16 x2;
- do {
- do {
- x2 = stream->readUint16LE();
- debugN(" %u: %u|%u, ", x2, (x2 & 0xF), (x2 >> 4));
- if (stream->pos() >= stream->size())
- break;
- } while ((x2 & 0x80) != 0x80);
- debug("-");
- if (stream->pos() >= stream->size())
- break;
- } while ((x2 & 0xF0) != 0xF0);
- }
+ _gdsScene->parse(stream);
}
break;
case EX_ADS:
@@ -763,7 +740,8 @@ Common::Error DgdsEngine::run() {
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
_midiPlayer = new DgdsMidiPlayer();
- _scene = new Scene();
+ _scene = new SDSScene();
+ _gdsScene = new GDSScene();
setDebugger(_console);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 196dc53fdad..fa353b45c19 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -42,7 +42,8 @@ class Decompressor;
class Image;
class PFont;
class FFont;
-class Scene;
+class SDSScene;
+class GDSScene;
class DgdsMidiPlayer;
struct DgdsADS;
@@ -67,7 +68,8 @@ private:
DgdsGameId _gameId;
Graphics::Surface _bottomBuffer;
Graphics::Surface _topBuffer;
- Scene *_scene;
+ SDSScene *_scene;
+ GDSScene *_gdsScene;
PFont *_fntP;
FFont *_fntF;
@@ -98,7 +100,7 @@ public:
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
- const Scene *getScene() const { return _scene; }
+ const SDSScene *getScene() const { return _scene; }
const PFont *getFntP() const { return _fntP; }
Image *_image;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 18df9aab8d8..cba612f1aa9 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -28,47 +28,19 @@
namespace Dgds {
-Scene::Scene() : _magic(0), _num(-1) {
+Scene::Scene() : _magic(0) {
}
-bool Scene::isVersionOver(const char *version) {
+bool Scene::isVersionOver(const char *version) const {
return strncmp(_version.c_str(), version, _version.size()) > 0;
}
-bool Scene::isVersionUnder(const char *version) {
+bool Scene::isVersionUnder(const char *version) const {
return strncmp(_version.c_str(), version, _version.size()) < 0;
}
-bool Scene::parseSDS(Common::SeekableReadStream *stream) {
- _magic = stream->readUint32LE();
- _version = stream->readString();
- if (isVersionOver(" 1.211")) {
- error("Unsupported scene version '%s'", _version.c_str());
- }
- _num = stream->readUint16LE();
- readStruct5List(stream, _struct5List1);
- readStruct5List(stream, _struct5List2);
- if (isVersionOver(" 1.206")) {
- readStruct5List(stream, _struct5List3);
- }
- readStruct5List(stream, _struct5List4);
- _field6_0x14 = stream->readUint16LE();
- _adsFile = stream->readString();
- readStruct2List(stream, _struct2List);
- readStruct4List(stream, _struct4List1);
- if (isVersionOver(" 1.205")) {
- readStruct4List(stream, _struct4List2);
- }
- readDialogueList(stream, _dialogues);
- if (isVersionOver(" 1.203")) {
- readStruct7List(stream, _struct7List);
- }
- return !stream->err();
-}
-
-
-bool Scene::readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) {
+bool Scene::readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const {
list.resize(s->readUint16LE());
for (SceneStruct1 &dst : list) {
dst.val1 = s->readUint16LE();
@@ -79,25 +51,63 @@ bool Scene::readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneSt
}
-bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) {
+bool Scene::readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const {
+ dst.rect.x = s->readUint16LE();
+ dst.rect.y = s->readUint16LE();
+ dst.rect.width = s->readUint16LE();
+ dst.rect.height = s->readUint16LE();
+ dst.field1_0x8 = s->readUint16LE();
+ dst.field2_0xa = s->readUint16LE();
+ readStruct1List(s, dst.struct1List);
+ readStruct5List(s, dst.struct5List1);
+ readStruct5List(s, dst.struct5List2);
+ readStruct5List(s, dst.struct5List3);
+ return !s->err();
+}
+
+
+bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const {
list.resize(s->readUint16LE());
for (SceneStruct2 &dst : list) {
- dst.rect.x = s->readUint16LE();
- dst.rect.y = s->readUint16LE();
- dst.rect.width = s->readUint16LE();
- dst.rect.height = s->readUint16LE();
- dst.field1_0x8 = s->readUint16LE();
- dst.field2_0xa = s->readUint16LE();
- readStruct1List(s, dst.struct1List);
- readStruct5List(s, dst.struct5List1);
- readStruct5List(s, dst.struct5List2);
- readStruct5List(s, dst.struct5List3);
+ readStruct2(s, dst);
+ }
+ return !s->err();
+}
+
+
+bool Scene::readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<SceneStruct2_Extended> &list) const {
+ list.resize(s->readUint16LE());
+ for (SceneStruct2_Extended &dst : list) {
+ readStruct2(s, dst);
+ }
+ for (SceneStruct2_Extended &dst : list) {
+ dst.field11_0x26 = s->readUint16LE();
+ dst.field12_0x28 = s->readUint16LE();
+ dst.field14_0x2c = s->readUint16LE();
+ if (!isVersionUnder(" 1.211"))
+ dst.field13_0x2a = s->readUint16LE() & 0xfffe;
+ if (!isVersionUnder(" 1.204")) {
+ dst.field10_0x24 = s->readUint16LE();
+ readStruct5List(s, dst.struct5List5);
+ readStruct5List(s, dst.struct5List6);
+ }
+ }
+ return !s->err();
+
+}
+
+
+bool Scene::readStruct3List(Common::SeekableReadStream *s, Common::Array<SceneStruct3> &list) const {
+ list.resize(s->readUint16LE());
+ for (SceneStruct3 &dst : list) {
+ dst.val1 = s->readUint16LE();
+ dst.val2 = s->readUint16LE();
}
return !s->err();
}
-bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) {
+bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const {
list.resize(s->readUint16LE());
for (SceneStruct4 &dst : list) {
if (!isVersionOver(" 1.205")) {
@@ -114,7 +124,7 @@ bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneSt
}
-bool Scene::readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) {
+bool Scene::readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) const {
list.resize(s->readUint16LE());
for (SceneStruct5 &dst : list) {
readStruct1List(s, dst.struct1List);
@@ -129,7 +139,7 @@ bool Scene::readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneSt
}
-bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) {
+bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const {
list.resize(s->readUint16LE());
for (Dialogue &dst : list) {
dst.num = s->readUint16LE();
@@ -158,7 +168,7 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
dst.frametype = s->readUint16LE(); // 01 =simple frame, 02 = with title w/ text before :, 03 = baloon, 04 = eliptical
dst.field12_0x1a = s->readUint16LE();
if (isVersionOver(" 1.207")) {
- dst.field13_0x1c = s->readUint16LE();
+ dst.maybeNextDialogNum = s->readUint16LE();
}
uint16 nbytes = s->readUint16LE();
@@ -183,7 +193,7 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
}
-bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) {
+bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) const {
list.resize(s->readUint16LE());
for (SceneStruct7 &dst : list) {
dst.val = s->readUint16LE();
@@ -195,7 +205,7 @@ bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneSt
}
-bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) {
+bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) const {
list.resize(s->readUint16LE());
if (!list.empty())
@@ -211,5 +221,70 @@ bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array
}
+SDSScene::SDSScene() : _num(-1) {
+}
+
+bool SDSScene::parse(Common::SeekableReadStream *stream) {
+ _magic = stream->readUint32LE();
+ _version = stream->readString();
+ if (isVersionOver(" 1.211")) {
+ error("Unsupported scene version '%s'", _version.c_str());
+ }
+ _num = stream->readUint16LE();
+ readStruct5List(stream, _struct5List1);
+ readStruct5List(stream, _struct5List2);
+ if (isVersionOver(" 1.206")) {
+ readStruct5List(stream, _struct5List3);
+ }
+ readStruct5List(stream, _struct5List4);
+ _field6_0x14 = stream->readUint16LE();
+ _adsFile = stream->readString();
+ readStruct2List(stream, _struct2List);
+ readStruct4List(stream, _struct4List1);
+ if (isVersionOver(" 1.205")) {
+ readStruct4List(stream, _struct4List2);
+ }
+ readDialogueList(stream, _dialogues);
+ if (isVersionOver(" 1.203")) {
+ readStruct7List(stream, _struct7List);
+ }
+
+ return !stream->err();
+}
+
+
+GDSScene::GDSScene() {
+}
+
+
+bool GDSScene::parseInf(Common::SeekableReadStream *s) {
+ _magic = s->readUint32LE();
+ _version = s->readString();
+ return !s->err();
+}
+
+
+bool GDSScene::parse(Common::SeekableReadStream *stream) {
+ readStruct5List(stream, _struct5List1);
+ readStruct5List(stream, _struct5List2);
+ if (isVersionOver(" 1.206"))
+ readStruct5List(stream, _struct5List3);
+ readStruct5List(stream, _struct5List4);
+ if (isVersionOver(" 1.208"))
+ readStruct5List(stream, _struct5List5);
+ Common::Array<struct SceneStruct1> struct1List;
+ readStruct1List(stream, struct1List);
+ Common::Array<struct SceneStruct3> struct3List;
+ _iconFile = stream->readString();
+ readStruct3List(stream, struct3List);
+ readStruct2ExtendedList(stream, _struct2ExtList);
+ readStruct4List(stream, _struct4List2);
+ if (isVersionOver(" 1.205"))
+ readStruct4List(stream, _struct4List1);
+
+ return !stream->err();
+}
+
+
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 2450200331a..227cc668602 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -28,12 +28,7 @@
namespace Dgds {
-struct SceneStruct1 {
- uint16 val1;
- uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
- uint16 val3;
-};
-
+// TODO: Use Common::Rect instead.
struct Rect {
int x;
int y;
@@ -41,6 +36,12 @@ struct Rect {
int height;
};
+struct SceneStruct1 {
+ uint16 val1;
+ uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
+ uint16 val3;
+};
+
struct SceneStruct2 {
struct Rect rect;
uint16 field1_0x8;
@@ -57,17 +58,9 @@ struct SceneStruct5 {
uint16 val;
};
-struct SceneStruct2_Extended {
- struct Rect rect;
- uint16 field1_0x8;
- uint16 field2_0xa;
- Common::Array<struct SceneStruct1> struct1List;
- Common::Array<struct SceneStruct5> struct5List1;
- Common::Array<struct SceneStruct5> struct5List2;
- Common::Array<struct SceneStruct5> struct5List3;
- //struct SceneStruct2 *next;
- Common::Array<struct SceneStruct5> field8_0x1c; /* this field on are only in Extended (GDS) version */
- Common::Array<struct SceneStruct5> field9_0x20;
+struct SceneStruct2_Extended : public SceneStruct2 {
+ Common::Array<struct SceneStruct5> struct5List5;
+ Common::Array<struct SceneStruct5> struct5List6;
uint16 field10_0x24;
uint16 field11_0x26;
uint16 field12_0x28;
@@ -95,10 +88,10 @@ struct Dialogue {
uint16 field7_0xe;
uint16 field8_0x10;
uint16 fontSize;
- uint32 flags; // includes justify
+ uint32 flags; // includes justify
uint16 frametype;
uint16 field12_0x1a;
- uint16 field13_0x1c;
+ uint16 maybeNextDialogNum;
Common::Array<struct DialogueSubstring> subStrings;
uint16 field15_0x22;
Common::String str;
@@ -129,24 +122,57 @@ class Scene {
public:
Scene();
- bool parseSDS(Common::SeekableReadStream *s);
- bool isVersionOver(const char *version);
- bool isVersionUnder(const char *version);
+ virtual bool parse(Common::SeekableReadStream *s) = 0;
- const Common::Array<struct Dialogue> &getLines() const { return _dialogues; }
+ bool isVersionOver(const char *version) const;
+ bool isVersionUnder(const char *version) const;
-private:
- bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list);
- bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list);
- bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list);
- bool readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list);
- bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list);
- bool readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list);
- bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list);
+protected:
+ bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const;
+ bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
+ bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const;
+ bool readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<SceneStruct2_Extended> &list) const;
+ bool readStruct3List(Common::SeekableReadStream *s, Common::Array<SceneStruct3> &list) const;
+ bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
+ bool readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) const;
+ bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const;
+ bool readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) const;
+ bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) const;
uint32 _magic;
Common::String _version;
+};
+
+class GDSScene : public Scene {
+public:
+ GDSScene();
+
+ bool parse(Common::SeekableReadStream *s) override;
+ bool parseInf(Common::SeekableReadStream *s);
+
+private:
+ byte _unk[32];
+ Common::String _iconFile;
+ Common::Array<struct SceneStruct2_Extended> _struct2ExtList;
+ Common::Array<struct SceneStruct5> _struct5List1;
+ Common::Array<struct SceneStruct5> _struct5List2;
+ Common::Array<struct SceneStruct5> _struct5List3;
+ Common::Array<struct SceneStruct5> _struct5List4;
+ Common::Array<struct SceneStruct5> _struct5List5;
+ Common::Array<struct SceneStruct4> _struct4List1;
+ Common::Array<struct SceneStruct4> _struct4List2;
+};
+
+class SDSScene : public Scene {
+public:
+ SDSScene();
+
+ bool parse(Common::SeekableReadStream *s) override;
+
+ const Common::Array<struct Dialogue> &getLines() const { return _dialogues; }
+
+private:
int _num;
Common::Array<struct SceneStruct5> _struct5List1;
Common::Array<struct SceneStruct5> _struct5List2;
Commit: 797b2d4a745122c9ef1e848a8a96264291a7733c
https://github.com/scummvm/scummvm/commit/797b2d4a745122c9ef1e848a8a96264291a7733c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix shadowed variable
Changed paths:
engines/dgds/image.cpp
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 614239bdcc4..018dbadeb46 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -180,9 +180,9 @@ void Image::loadBitmap(Common::String filename, int number) {
} else {
if (number)
stream->skip(4 * number);
- uint32 tileOffset = stream->readUint32LE();
+ uint32 vqtOffset = stream->readUint32LE();
// TODO: seek stream to end for tidiness?
- fileStream->seek(vqtpos + tileOffset);
+ fileStream->seek(vqtpos + vqtOffset);
loadVQT(_bmpData, tileWidths[number], tileHeights[number], 0, fileStream);
}
}
Commit: 9383f1f827af9688fdf34b3f88ef0db9be7946c6
https://github.com/scummvm/scummvm/commit/9383f1f827af9688fdf34b3f88ef0db9be7946c6
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Added a wrapper to read resource streams
This simplifies reading from resource files, and allows us to
encapsulate some of the resource file loading logic inside
the DgdsChunk class
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/parser.cpp
engines/dgds/resource.cpp
engines/dgds/resource.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index ca6211e8637..9fc139e10e1 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -101,7 +101,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
DgdsParser ctx(*res, fileName.c_str());
DgdsChunk chunk;
while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, decompressor) : chunk.readStream(ctx);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, decompressor);
memcpy(ptr, chunk._idStr, 4);
ptr += 4;
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 2d9189d03a3..02b8ea3b844 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -270,10 +270,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
continue;
}
- Common::SeekableReadStream *stream;
-
- bool packed = chunk.isPacked(ex);
- stream = packed ? chunk.decodeStream(ctx, decompressor) : chunk.readStream(ctx);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, decompressor);
#ifdef DUMP_ALL_CHUNKS
{
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 018dbadeb46..69c83fa3533 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -72,7 +72,7 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
DgdsChunk chunk;
while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
if (chunk.isSection(ID_BIN)) {
loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, false);
} else if (chunk.isSection(ID_VGA)) {
@@ -118,7 +118,7 @@ void Image::loadBitmap(Common::String filename, int number) {
int32 tileOffset = 0;
while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.isPacked(ex) ? chunk.decodeStream(ctx, _decompressor) : chunk.readStream(ctx);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
for (uint16 k = 0; k < tileCount; k++) {
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index fafb8aef566..ca3eecf5034 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -53,7 +53,7 @@ void DgdsParser::parse(DgdsScriptData *data, Decompressor *decompressor) {
chunk._stream = &_file;
stop = callback(chunk, data);
} else {
- chunk._stream = chunk.isPacked(_ex) ? chunk.decodeStream(*this, decompressor) : chunk.readStream(*this);
+ chunk._stream = chunk.getStream(_ex, *this, decompressor);
stop = callback(chunk, data);
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 45b4ddea327..309a0b11a5f 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -247,6 +247,10 @@ bool DgdsChunk::readHeader(DgdsParser &ctx) {
return true;
}
+Common::SeekableReadStream* DgdsChunk::getStream(DGDS_EX ex, DgdsParser& ctx, Decompressor* decompressor) {
+ return isPacked(ex) ? decodeStream(ctx, decompressor) : readStream(ctx);
+}
+
Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompressor *decompressor) {
byte compression;
uint32 unpackSize;
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index f8ec76678cf..bfa5d333257 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -70,23 +70,22 @@ class DgdsChunk {
public:
bool isSection(const Common::String §ion) const;
bool isSection(DGDS_ID section) const;
- bool isPacked(DGDS_EX ex) const;
static bool isFlatfile(Common::Platform platform, DGDS_EX ext);
bool readHeader(DgdsParser &ctx);
- Common::SeekableReadStream *decodeStream(DgdsParser &ctx, Decompressor *decompressor);
Common::SeekableReadStream *readStream(DgdsParser &ctx);
+ Common::SeekableReadStream *getStream(DGDS_EX ex, DgdsParser &ctx, Decompressor *decompressor);
char _idStr[DGDS_TYPENAME_MAX + 1];
DGDS_ID _id;
uint32 _size;
bool _container;
Common::SeekableReadStream *_stream;
-};
-//int32 dgdsHash(const char *s, byte *idx);
-//uint32 lookupVolume(const char *rmfName, const char *filename, char *volname);
-//Common::SeekableReadStream *createReadStream(const char *rmfName, const char *filename);
+private:
+ bool isPacked(DGDS_EX ex) const;
+ Common::SeekableReadStream *decodeStream(DgdsParser &ctx, Decompressor *decompressor);
+};
} // End of namespace Dgds
Commit: 4b3aeaa022f626100ca589c5fe7d7a347dcc6184
https://github.com/scummvm/scummvm/commit/4b3aeaa022f626100ca589c5fe7d7a347dcc6184
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Re-enable the Dragon intro credit scenes
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 02b8ea3b844..a272c6e17a1 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -813,8 +813,8 @@ Common::Error DgdsEngine::run() {
// browse(_platform, _rmfName, this);
if (getGameId() == GID_DRAGON) {
- //if (!interpTTM.run(&title1State))
- //if (!interpTTM.run(&title2State))
+ if (!interpTTM.run(&title1State))
+ if (!interpTTM.run(&title2State))
if (!interpADS.run(&adsState))
return Common::kNoError;
} else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
Commit: 230e1c5d115becf7564fec44cfcde1bcaef082a6
https://github.com/scummvm/scummvm/commit/230e1c5d115becf7564fec44cfcde1bcaef082a6
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix path for dump files
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index a272c6e17a1..2536644ca77 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -276,7 +276,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
{
Common::DumpFile out;
int64 start = stream->pos();
- out.open(Common::Path(Common::String::format("/tmp/dgds_%s_%02d_%.3s.dump", name, chunkno, chunk._idStr)));
+ out.open(Common::Path(Common::String::format("tmp/dgds_%s_%02d_%.3s.dump", name, chunkno, chunk._idStr)));
out.writeStream(stream);
out.close();
stream->seek(start);
Commit: 2d922448fbf7f33492d1e797be1703d1d9471f22
https://github.com/scummvm/scummvm/commit/2d922448fbf7f33492d1e797be1703d1d9471f22
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Encapsulate compression logic inside the Decompressor class
Changed paths:
engines/dgds/decompress.cpp
engines/dgds/decompress.h
engines/dgds/dgds.cpp
engines/dgds/font.cpp
engines/dgds/resource.cpp
diff --git a/engines/dgds/decompress.cpp b/engines/dgds/decompress.cpp
index 911d2df98df..8887b7b3c1a 100644
--- a/engines/dgds/decompress.cpp
+++ b/engines/dgds/decompress.cpp
@@ -21,8 +21,8 @@
*/
#include "common/debug.h"
-#include "common/util.h"
#include "common/stream.h"
+#include "common/util.h"
#include "dgds/decompress.h"
@@ -191,22 +191,28 @@ Decompressor::Decompressor() {
Decompressor::~Decompressor() {
}
-void Decompressor::decompress(byte compression, byte *data, int uncompressedSize, Common::SeekableReadStream *input, int size) {
+byte *Decompressor::decompress(Common::SeekableReadStream *input, int size, uint32 &uncompressedSize) {
+ byte compression = input->readByte();
+ uncompressedSize = input->readUint32LE();
+ byte *data = new byte[uncompressedSize];
+
switch (compression) {
- case 0x00:
- input->read(data, size);
- break;
- case 0x01:
- _rleDecompressor.decompress(data, uncompressedSize, *input);
- break;
- case 0x02:
- _lzwDecompressor.decompress(data, uncompressedSize, *input);
- break;
- default:
- input->skip(size);
- debug("Unknown chunk compression: 0x%x", compression);
- break;
+ case 0x00:
+ input->read(data, size);
+ break;
+ case 0x01:
+ _rleDecompressor.decompress(data, uncompressedSize, *input);
+ break;
+ case 0x02:
+ _lzwDecompressor.decompress(data, uncompressedSize, *input);
+ break;
+ default:
+ input->skip(size);
+ debug("Unknown chunk compression: 0x%x", compression);
+ break;
}
+
+ return data;
}
} // End of namespace Dgds
diff --git a/engines/dgds/decompress.h b/engines/dgds/decompress.h
index ac71974551c..e6c24cfc42e 100644
--- a/engines/dgds/decompress.h
+++ b/engines/dgds/decompress.h
@@ -69,13 +69,11 @@ public:
Decompressor();
virtual ~Decompressor();
- void decompress(byte compression, byte *data, int uncompressedSize, Common::SeekableReadStream *input, int size);
+ byte *decompress(Common::SeekableReadStream *input, int size, uint32 &uncompressedSize);
private:
RleDecompressor _rleDecompressor;
LzwDecompressor _lzwDecompressor;
-
- // const char *_compressionDescr[3] = {"None", "RLE", "LZW"};
};
} // End of namespace Dgds
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 2536644ca77..7856209b31f 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -100,7 +100,7 @@ DgdsEngine::~DgdsEngine() {
delete _resource;
delete _scene;
delete _gdsScene;
- delete _musicData;
+ delete[] _musicData;
delete _soundData;
}
@@ -532,7 +532,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
debug(" %2u: %u bytes", scount, _musicSize);
- _musicData = (uint8 *)malloc(_musicSize);
+ _musicData = new byte[_musicSize];
stream->read(_musicData, _musicSize);
scount++;
} else if (chunk.isSection(ID_INF)) {
@@ -566,19 +566,11 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
readStrings(stream);
} else if (chunk.isSection(ID_DAT)) {
uint16 idx, type;
- byte compression;
- uint32 unpackSize;
idx = stream->readUint16LE();
type = stream->readUint16LE();
- compression = stream->readByte();
- unpackSize = stream->readUint32LE();
//debug(" #%2u: (0x%X?) %s %u", idx, type, compressionDescr[compression], unpackSize);
- _musicSize = unpackSize;
- debug(" %2u: %u bytes", scount, _musicSize);
-
- _musicData = (uint8 *)malloc(_musicSize);
- decompressor->decompress(compression, _musicData, _musicSize, stream, stream->size() - stream->pos());
+ _musicData = decompressor->decompress(stream, stream->size() - stream->pos(), _musicSize);
scount++;
}
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index f8295c4960c..e0854e512ae 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -114,9 +114,8 @@ PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor
assert(magic == 0xFF);
byte w, h;
- byte unknown, start, count, compression;
+ byte unknown, start, count;
int size;
- int uncompressedSize;
w = input.readByte();
h = input.readByte();
@@ -124,18 +123,15 @@ PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor
start = input.readByte();
count = input.readByte();
size = input.readUint16LE();
- compression = input.readByte();
- uncompressedSize = input.readUint32LE();
debug(" magic: 0x%x, w: %u, h: %u, unknown: %u, start: 0x%x, count: %u\n"
- " size: %u, compression: 0x%x, uncompressedSize: %u",
+ " size: %u",
magic, w, h, unknown, start, count,
- size, compression, uncompressedSize);
- assert(uncompressedSize == size);
+ size);
- size = input.size()-input.pos();
+ size = input.size() - input.pos();
- byte *data = new byte[uncompressedSize];
- decompressor->decompress(compression, data, uncompressedSize, &input, size);
+ uint32 uncompressedSize;
+ byte *data = decompressor->decompress(&input, size, uncompressedSize);
PFont* fnt = new PFont;
fnt->_w = w;
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 309a0b11a5f..1e6200be0a9 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -252,25 +252,17 @@ Common::SeekableReadStream* DgdsChunk::getStream(DGDS_EX ex, DgdsParser& ctx, De
}
Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompressor *decompressor) {
- byte compression;
- uint32 unpackSize;
Common::SeekableReadStream *output = 0;
- compression = ctx._file.readByte();
- unpackSize = ctx._file.readUint32LE();
_size -= (1 + 4);
if (!_container) {
- byte *dest = new byte[unpackSize];
- decompressor->decompress(compression, dest, unpackSize, &ctx._file, _size);
- output = new Common::MemoryReadStream(dest, unpackSize, DisposeAfterUse::YES);
- ctx._bytesRead += unpackSize;
+ uint32 uncompressedSize;
+ byte *data = decompressor->decompress(&ctx._file, _size, uncompressedSize);
+ output = new Common::MemoryReadStream(data, uncompressedSize, DisposeAfterUse::YES);
+ ctx._bytesRead += uncompressedSize;
}
- /*debug(" %s %u %s %u%c",
- id, _size,
- compressionDescr[compression],
- unpackSize, (container ? '+' : ' '));*/
return output;
}
Commit: 888be0a6e3f055da16b4dfd700cbd555e79be44c
https://github.com/scummvm/scummvm/commit/888be0a6e3f055da16b4dfd700cbd555e79be44c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Split RST chunk parsing into a separate function
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7856209b31f..57d0130f6e3 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -120,6 +120,46 @@ void readStrings(Common::SeekableReadStream *stream) {
}
}
+void DgdsEngine::parseRstChunk(Common::SeekableReadStream &file) {
+ uint32 mark = file.readUint32LE();
+ debug(" 0x%X", mark);
+
+ // elaborate guesswork. who knows it might be true.
+ while (!file.eos()) {
+ uint16 idx;
+ uint16 vals[7];
+
+ idx = file.readUint16LE();
+ debugN(" #%u:\t", idx);
+ if (idx == 0)
+ break;
+ for (int i = 0; i < ARRAYSIZE(vals); i++) {
+ vals[i] = file.readUint16LE();
+ if (i != 0)
+ debugN(", ");
+ debugN("%u", vals[i]);
+ }
+ debug(".");
+ }
+ debug("-");
+
+ while (!file.eos()) {
+ uint16 idx;
+ uint16 vals[2];
+ idx = file.readUint16LE();
+ debugN(" #%u:\t", idx);
+ for (int i = 0; i < ARRAYSIZE(vals); i++) {
+ vals[i] = file.readUint16LE();
+ if (i != 0)
+ debugN(", ");
+ debugN("%u", vals[i]);
+ }
+ debug(".");
+ if (idx == 0)
+ break;
+ }
+ debug("-");
+}
void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor) {
const char *dot;
@@ -136,48 +176,9 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
Common::String line;
switch (ex) {
- case EX_RST: {
- uint32 mark;
-
- mark = file.readUint32LE();
- debug(" 0x%X", mark);
-
- // elaborate guesswork. who knows it might be true.
- while (!file.eos()) {
- uint16 idx;
- uint16 vals[7];
-
- idx = file.readUint16LE();
- debugN(" #%u:\t", idx);
- if (idx == 0)
- break;
- for (int i = 0; i < ARRAYSIZE(vals); i++) {
- vals[i] = file.readUint16LE();
- if (i != 0)
- debugN(", ");
- debugN("%u", vals[i]);
- }
- debug(".");
- }
- debug("-");
-
- while (!file.eos()) {
- uint16 idx;
- uint16 vals[2];
- idx = file.readUint16LE();
- debugN(" #%u:\t", idx);
- for (int i = 0; i < ARRAYSIZE(vals); i++) {
- vals[i] = file.readUint16LE();
- if (i != 0)
- debugN(", ");
- debugN("%u", vals[i]);
- }
- debug(".");
- if (idx == 0)
- break;
- }
- debug("-");
- } break;
+ case EX_RST:
+ parseRstChunk(file);
+ break;
case EX_SCR: {
/* Unknown image format (Amiga). */
byte tag[5];
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index fa353b45c19..3268679b17d 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -108,6 +108,7 @@ public:
private:
void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor);
+ void parseRstChunk(Common::SeekableReadStream &file);
};
//void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource);
Commit: 79e69816711bf825160e8fe634cbdc8febc42e50
https://github.com/scummvm/scummvm/commit/79e69816711bf825160e8fe634cbdc8febc42e50
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Split Amiga chunk handling into a separate function
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/resource.cpp
engines/dgds/resource.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 57d0130f6e3..23462029cff 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -161,6 +161,82 @@ void DgdsEngine::parseRstChunk(Common::SeekableReadStream &file) {
debug("-");
}
+void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex) {
+ Common::String line;
+
+ switch (ex) {
+ case EX_SCR: {
+ /* Unknown image format (Amiga). */
+ byte tag[5];
+ file.read(tag, 4); /* maybe */
+ tag[4] = '\0';
+
+ uint16 pitch, planes;
+ pitch = file.readUint16BE(); /* always 200 (320x200 screen). */
+ planes = file.readUint16BE(); /* always 5 (32 color). */
+
+ debug(" \"%s\" pitch:%u bpp:%u size: %u bytes",
+ tag, pitch, planes,
+ SCREEN_WIDTH * planes * SCREEN_HEIGHT / 8);
+ } break;
+ case EX_BMP: {
+ /* Unknown image format (Amiga). */
+ uint16 tcount = file.readUint16BE();
+ uint16 *tw = new uint16[tcount];
+ uint16 *th = new uint16[tcount];
+
+ uint32 packedSize, unpackedSize;
+ unpackedSize = file.readUint32BE();
+ debug(" [%u] %u =", tcount, unpackedSize);
+
+ uint32 sz = 0;
+ uint32 *toffset = new uint32[tcount];
+ for (uint16 k = 0; k < tcount; k++) {
+ tw[k] = file.readUint16BE();
+ th[k] = file.readUint16BE();
+ debug(" %ux%u ~@%u", tw[k], th[k], sz);
+
+ toffset[k] = sz;
+ sz += uint(tw[k] + 15) / 16 * th[k] * 5;
+ }
+ debug(" ~= [%u]", sz);
+
+ /* this is a wild guess. */
+ byte version[13];
+ file.read(version, 12);
+ version[12] = '\0';
+ debug(" %s", version);
+
+ unpackedSize = file.readUint32BE();
+ packedSize = file.readUint32BE();
+ debug(" %u -> %u",
+ packedSize, unpackedSize);
+ delete[] toffset;
+ delete[] tw;
+ delete[] th;
+ } break;
+ case EX_INS: {
+ /* AIFF sound sample (Amiga). */
+ byte *dest = new byte[file.size()];
+ file.read(dest, file.size());
+ _soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
+ } break;
+ case EX_SNG:
+ /* IFF-SMUS music (Amiga). */
+ break;
+ // case EX_SNG:
+ // TODO
+ case EX_AMG:
+ /* (Amiga). */
+ line = file.readLine();
+ while (!file.eos() && !line.empty()) {
+ debug(" \"%s\"", line.c_str());
+ line = file.readLine();
+ }
+ break;
+ }
+}
+
void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor) {
const char *dot;
DGDS_EX ex = 0;
@@ -172,80 +248,17 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
uint parent = 0;
DgdsParser ctx(file, name);
- if (DgdsChunk::isFlatfile(platform, ex)) {
+ if (platform == Common::kPlatformAmiga) {
+ parseAmigaChunks(file, ex);
+ }
+
+ if (DgdsChunk::isFlatfile(ex)) {
Common::String line;
switch (ex) {
case EX_RST:
parseRstChunk(file);
break;
- case EX_SCR: {
- /* Unknown image format (Amiga). */
- byte tag[5];
- file.read(tag, 4); /* maybe */
- tag[4] = '\0';
-
- uint16 pitch, planes;
- pitch = file.readUint16BE(); /* always 200 (320x200 screen). */
- planes = file.readUint16BE(); /* always 5 (32 color). */
-
- debug(" \"%s\" pitch:%u bpp:%u size: %u bytes",
- tag, pitch, planes,
- SCREEN_WIDTH * planes * SCREEN_HEIGHT / 8);
- } break;
- case EX_BMP: {
- /* Unknown image format (Amiga). */
- uint16 tcount = file.readUint16BE();
- uint16 *tw = new uint16[tcount];
- uint16 *th = new uint16[tcount];
-
- uint32 packedSize, unpackedSize;
- unpackedSize = file.readUint32BE();
- debug(" [%u] %u =", tcount, unpackedSize);
-
- uint32 sz = 0;
- uint32 *toffset = new uint32[tcount];
- for (uint16 k = 0; k < tcount; k++) {
- tw[k] = file.readUint16BE();
- th[k] = file.readUint16BE();
- debug(" %ux%u ~@%u", tw[k], th[k], sz);
-
- toffset[k] = sz;
- sz += uint(tw[k] + 15) / 16 * th[k] * 5;
- }
- debug(" ~= [%u]", sz);
-
- /* this is a wild guess. */
- byte version[13];
- file.read(version, 12);
- version[12] = '\0';
- debug(" %s", version);
-
- unpackedSize = file.readUint32BE();
- packedSize = file.readUint32BE();
- debug(" %u -> %u",
- packedSize, unpackedSize);
- delete [] toffset;
- delete [] tw;
- delete [] th;
- } break;
- case EX_INS: {
- /* AIFF sound sample (Amiga). */
- byte *dest = new byte[file.size()];
- file.read(dest, file.size());
- _soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
- } break;
- case EX_SNG:
- /* IFF-SMUS music (Amiga). */
- break;
- case EX_AMG:
- /* (Amiga). */
- line = file.readLine();
- while (!file.eos() && !line.empty()) {
- debug(" \"%s\"", line.c_str());
- line = file.readLine();
- }
- break;
case EX_VIN:
line = file.readLine();
while (!file.eos()) {
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 3268679b17d..6aab4049deb 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -34,6 +34,8 @@
#include "gui/debugger.h"
+#include "dgds/resource.h"
+
namespace Dgds {
class Console;
@@ -109,6 +111,7 @@ public:
private:
void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor);
void parseRstChunk(Common::SeekableReadStream &file);
+ void parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex);
};
//void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource);
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 1e6200be0a9..09fb60b4338 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -279,7 +279,7 @@ Common::SeekableReadStream *DgdsChunk::readStream(DgdsParser &ctx) {
}
/*static*/
-bool DgdsChunk::isFlatfile(Common::Platform platform, DGDS_EX ext) {
+bool DgdsChunk::isFlatfile(DGDS_EX ext) {
bool flat = false;
switch (ext) {
@@ -291,23 +291,6 @@ bool DgdsChunk::isFlatfile(Common::Platform platform, DGDS_EX ext) {
default:
break;
}
-
- switch (platform) {
- case Common::kPlatformAmiga:
- switch (ext) {
- case EX_BMP:
- case EX_SCR:
- case EX_INS:
- // case EX_SNG:
- case EX_AMG:
- flat = true;
- break;
- default:
- break;
- }
- default:
- break;
- }
return flat;
}
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index bfa5d333257..bf610f81bdf 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -70,7 +70,7 @@ class DgdsChunk {
public:
bool isSection(const Common::String §ion) const;
bool isSection(DGDS_ID section) const;
- static bool isFlatfile(Common::Platform platform, DGDS_EX ext);
+ static bool isFlatfile(DGDS_EX ext);
bool readHeader(DgdsParser &ctx);
Common::SeekableReadStream *readStream(DgdsParser &ctx);
Commit: 9648702c510deb1e85be79128f339ed53e282479
https://github.com/scummvm/scummvm/commit/9648702c510deb1e85be79128f339ed53e282479
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix spacing
Changed paths:
engines/dgds/sound.h
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 6e36b54b725..8d2550ee0d5 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -28,10 +28,10 @@
namespace Dgds {
enum {
- DIGITAL_PCM = 1 << 0,
- TRACK_ADLIB = 1 << 1,
- TRACK_GM = 1 << 2,
- TRACK_MT32 = 1 << 3
+ DIGITAL_PCM = 1 << 0,
+ TRACK_ADLIB = 1 << 1,
+ TRACK_GM = 1 << 2,
+ TRACK_MT32 = 1 << 3
};
uint32 availableSndTracks(const byte *data, uint32 size);
Commit: fd4d31db04cce8e8494ba083dc6891f522d1c6e0
https://github.com/scummvm/scummvm/commit/fd4d31db04cce8e8494ba083dc6891f522d1c6e0
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Remove debug variable scount
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 23462029cff..e115f278556 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -274,8 +274,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
file.hexdump(leftover);
file.skip(leftover);
} else {
- uint16 scount = 0; // song count
-
DgdsChunk chunk;
int chunkno = 0;
while (chunk.readHeader(ctx)) {
@@ -543,19 +541,13 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
/* DOS. */
if (chunk.isSection(ID_SNG)) {
_musicSize = stream->size();
-
- debug(" %2u: %u bytes", scount, _musicSize);
-
_musicData = new byte[_musicSize];
stream->read(_musicData, _musicSize);
- scount++;
} else if (chunk.isSection(ID_INF)) {
- uint32 count;
- count = stream->size() / 2;
+ uint32 count = stream->size() / 2;
debug(" [%u]", count);
for (uint32 k = 0; k < count; k++) {
- uint16 idx;
- idx = stream->readUint16LE();
+ uint16 idx = stream->readUint16LE();
debug(" %2u: %u", k, idx);
}
}
@@ -585,8 +577,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
//debug(" #%2u: (0x%X?) %s %u", idx, type, compressionDescr[compression], unpackSize);
_musicData = decompressor->decompress(stream, stream->size() - stream->pos(), _musicSize);
-
- scount++;
}
break;
case EX_PAL:
@@ -676,10 +666,9 @@ bool DgdsEngine::playPCM(const byte *data, uint32 size) {
if (!data)
return false;
- byte numParts;
const byte *trackPtr[0xFF];
uint16 trackSiz[0xFF];
- numParts = loadSndTrack(DIGITAL_PCM, trackPtr, trackSiz, data, size);
+ byte numParts = loadSndTrack(DIGITAL_PCM, trackPtr, trackSiz, data, size);
if (numParts == 0)
return false;
@@ -723,8 +712,7 @@ void DgdsEngine::playMusic(const Common::String &fileName) {
parseFile(fileName);
if (_musicData) {
- uint32 tracks;
- tracks = availableSndTracks(_musicData, _musicSize);
+ uint32 tracks = availableSndTracks(_musicData, _musicSize);
if ((tracks & TRACK_MT32))
_midiPlayer->play(_musicData, _musicSize);
if ((tracks & DIGITAL_PCM))
Commit: 0e863e764078860111739cf8d567fff47be8ba10
https://github.com/scummvm/scummvm/commit/0e863e764078860111739cf8d567fff47be8ba10
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start splitting the sound code into a separate class
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scripts.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index e115f278556..3f31947e715 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -35,11 +35,6 @@
#include "common/formats/iff_container.h"
-#include "audio/audiostream.h"
-#include "audio/decoders/aiff.h"
-#include "audio/decoders/raw.h"
-#include "audio/mixer.h"
-
#include "graphics/font.h"
#include "graphics/fontman.h"
#include "graphics/managed_surface.h"
@@ -75,8 +70,8 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
- _midiPlayer(nullptr), _decompressor(nullptr), _musicData(nullptr), _musicSize(0),
- _soundData(nullptr), _scene(nullptr), _gdsScene(nullptr) {
+ _midiPlayer(nullptr), _soundPlayer(nullptr), _decompressor(nullptr),
+ _musicData(nullptr), _musicSize(0), _scene(nullptr), _gdsScene(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -101,7 +96,9 @@ DgdsEngine::~DgdsEngine() {
delete _scene;
delete _gdsScene;
delete[] _musicData;
- delete _soundData;
+
+ delete _midiPlayer;
+ delete _soundPlayer;
}
void readStrings(Common::SeekableReadStream *stream) {
@@ -215,12 +212,9 @@ void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex)
delete[] tw;
delete[] th;
} break;
- case EX_INS: {
- /* AIFF sound sample (Amiga). */
- byte *dest = new byte[file.size()];
- file.read(dest, file.size());
- _soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
- } break;
+ case EX_INS:
+ _soundPlayer->loadAmigaAiff(file);
+ break;
case EX_SNG:
/* IFF-SMUS music (Amiga). */
break;
@@ -635,78 +629,6 @@ void DgdsEngine::parseFile(const Common::String &filename, int resource) {
int delay = 0;
-struct Channel {
- Audio::AudioStream *stream;
- Audio::SoundHandle handle;
- byte volume;
-};
-
-struct Channel _channels[2];
-
-void DgdsEngine::playSfx(const Common::String &fileName, byte channel, byte volume) {
- parseFile(fileName);
- if (_soundData) {
- Channel *ch = &_channels[channel];
- Audio::AudioStream *input = Audio::makeAIFFStream(_soundData, DisposeAfterUse::YES);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
- _soundData = 0;
- }
-}
-
-void DgdsEngine::stopSfx(byte channel) {
- if (_mixer->isSoundHandleActive(_channels[channel].handle)) {
- _mixer->stopHandle(_channels[channel].handle);
- _channels[channel].stream = 0;
- }
-}
-
-bool DgdsEngine::playPCM(const byte *data, uint32 size) {
- _mixer->stopAll();
-
- if (!data)
- return false;
-
- const byte *trackPtr[0xFF];
- uint16 trackSiz[0xFF];
- byte numParts = loadSndTrack(DIGITAL_PCM, trackPtr, trackSiz, data, size);
- if (numParts == 0)
- return false;
-
- for (byte part = 0; part < numParts; part++) {
- const byte *ptr = trackPtr[part];
-
- bool digital_pcm = false;
- if (READ_LE_UINT16(ptr) == 0x00FE) {
- digital_pcm = true;
- }
- ptr += 2;
-
- if (!digital_pcm)
- continue;
-
- uint16 rate, length, first, last;
- rate = READ_LE_UINT16(ptr);
-
- length = READ_LE_UINT16(ptr + 2);
- first = READ_LE_UINT16(ptr + 4);
- last = READ_LE_UINT16(ptr + 6);
- ptr += 8;
-
- ptr += first;
- debug(" - Digital PCM: %u Hz, [%u]=%u:%u",
- rate, length, first, last);
- trackPtr[part] = ptr;
- trackSiz[part] = length;
-
- Channel *ch = &_channels[part];
- byte volume = 255;
- Audio::AudioStream *input = Audio::makeRawStream(trackPtr[part], trackSiz[part],
- rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
- }
- return true;
-}
-
void DgdsEngine::playMusic(const Common::String &fileName) {
//stopMusic();
@@ -716,14 +638,13 @@ void DgdsEngine::playMusic(const Common::String &fileName) {
if ((tracks & TRACK_MT32))
_midiPlayer->play(_musicData, _musicSize);
if ((tracks & DIGITAL_PCM))
- playPCM(_musicData, _musicSize);
+ _soundPlayer->playPCM(_musicData, _musicSize);
}
}
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
- _soundData = nullptr;
_musicData = nullptr;
_console = new Console(this);
@@ -731,6 +652,7 @@ Common::Error DgdsEngine::run() {
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
_midiPlayer = new DgdsMidiPlayer();
+ _soundPlayer = new Sound(_mixer);
_scene = new SDSScene();
_gdsScene = new GDSScene();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 6aab4049deb..a616d6fbe3c 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -46,8 +46,9 @@ class PFont;
class FFont;
class SDSScene;
class GDSScene;
-
class DgdsMidiPlayer;
+class Sound;
+
struct DgdsADS;
enum DgdsGameId {
@@ -59,6 +60,7 @@ enum DgdsGameId {
class DgdsEngine : public Engine {
public:
Common::Platform _platform;
+ Sound *_soundPlayer;
private:
Console *_console;
@@ -78,7 +80,6 @@ private:
Common::StringArray _BMPs;
uint32 _musicSize;
byte *_musicData;
- Common::SeekableReadStream *_soundData;
protected:
virtual Common::Error run();
@@ -89,10 +90,6 @@ public:
DgdsGameId getGameId() { return _gameId; }
- void playSfx(const Common::String &fileName, byte channel, byte volume);
- void stopSfx(byte channel);
-
- bool playPCM(const byte *data, uint32 size);
void playMusic(const Common::String &fileName);
void parseFile(const Common::String &filename, int resource = 0);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 4d4936659c4..b43e9d9190d 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -36,6 +36,7 @@
#include "dgds/image.h"
#include "dgds/includes.h"
#include "dgds/scripts.h"
+#include "dgds/sound.h"
#include "dgds/resource.h"
#include "dgds/parser.h"
@@ -149,10 +150,8 @@ bool TTMInterpreter::run(TTMState *script) {
case 0xf060:
// LOAD SONG: filename:str
if (_vm->_platform == Common::kPlatformAmiga) {
- byte volume = 255;
- byte channel = 0;
- _vm->stopSfx(channel);
- _vm->playSfx("DYNAMIX.INS", channel, volume);
+ _vm->parseFile("DYNAMIX.INS"); // TODO: Unwrap this out of parseFile()
+ _vm->_soundPlayer->playAmigaSfx(0, 255);
} else {
_vm->playMusic(sval.c_str());
}
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 623989ef4e2..7ff7d134bdb 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -22,11 +22,93 @@
#include "common/debug.h"
#include "common/endian.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/aiff.h"
+#include "audio/decoders/raw.h"
+#include "audio/mixer.h"
#include "dgds/sound.h"
namespace Dgds {
+Sound::~Sound() {
+ delete _soundData;
+}
+
+void Sound::loadAmigaAiff(Common::SeekableReadStream& file) {
+ byte *dest = new byte[file.size()];
+ file.read(dest, file.size());
+ _soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
+}
+
+void Sound::playAmigaSfx(byte channel, byte volume) {
+ stopSfx(channel);
+
+ if (_soundData) {
+ Channel *ch = &_channels[channel];
+ Audio::AudioStream *input = Audio::makeAIFFStream(_soundData, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
+ _soundData = 0;
+ }
+}
+
+void Sound::stopSfx(byte channel) {
+ if (_mixer->isSoundHandleActive(_channels[channel].handle)) {
+ _mixer->stopHandle(_channels[channel].handle);
+ _channels[channel].stream = 0;
+ }
+}
+
+bool Sound::playPCM(const byte *data, uint32 size) {
+ _mixer->stopAll();
+
+ if (!data)
+ return false;
+
+ const byte *trackPtr[0xFF];
+ uint16 trackSiz[0xFF];
+ byte numParts = loadSndTrack(DIGITAL_PCM, trackPtr, trackSiz, data, size);
+ if (numParts == 0)
+ return false;
+
+ for (byte part = 0; part < numParts; part++) {
+ const byte *ptr = trackPtr[part];
+
+ bool digital_pcm = false;
+ if (READ_LE_UINT16(ptr) == 0x00FE) {
+ digital_pcm = true;
+ }
+ ptr += 2;
+
+ if (!digital_pcm)
+ continue;
+
+ uint16 rate, length, first, last;
+ rate = READ_LE_UINT16(ptr);
+
+ length = READ_LE_UINT16(ptr + 2);
+ first = READ_LE_UINT16(ptr + 4);
+ last = READ_LE_UINT16(ptr + 6);
+ ptr += 8;
+
+ ptr += first;
+ debug(" - Digital PCM: %u Hz, [%u]=%u:%u",
+ rate, length, first, last);
+ trackPtr[part] = ptr;
+ trackSiz[part] = length;
+
+ Channel *ch = &_channels[part];
+ byte volume = 255;
+ Audio::AudioStream *input = Audio::makeRawStream(trackPtr[part], trackSiz[part],
+ rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
+ }
+ return true;
+}
+
static inline
void readHeader(const byte* &pos, uint32 &sci_header) {
sci_header = 0;
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 8d2550ee0d5..dc5033dcff1 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -24,9 +24,35 @@
#define DGDS_SOUND_H
#include "common/scummsys.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
namespace Dgds {
+struct Channel {
+ Audio::AudioStream *stream;
+ Audio::SoundHandle handle;
+ byte volume;
+};
+
+class Sound {
+public:
+ Sound(Audio::Mixer *mixer) : _mixer(mixer) {}
+ ~Sound();
+
+ void playAmigaSfx(byte channel, byte volume);
+ void loadAmigaAiff(Common::SeekableReadStream &file);
+
+ void stopSfx(byte channel);
+
+ bool playPCM(const byte *data, uint32 size);
+
+private:
+ struct Channel _channels[2];
+ Common::SeekableReadStream *_soundData = nullptr;
+ Audio::Mixer *_mixer;
+};
+
enum {
DIGITAL_PCM = 1 << 0,
TRACK_ADLIB = 1 << 1,
@@ -40,4 +66,3 @@ byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const b
} // End of namespace Dgds
#endif // DGDS_SOUND_H
-
Commit: 6d1af43454b5b432afe588c917be1e164445fdee
https://github.com/scummvm/scummvm/commit/6d1af43454b5b432afe588c917be1e164445fdee
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Remove unused functions
Changed paths:
engines/dgds/resource.cpp
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 09fb60b4338..4d7d408a4d2 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -294,285 +294,4 @@ bool DgdsChunk::isFlatfile(DGDS_EX ext) {
return flat;
}
-#if 0
-/*
- input:
- s - pointer to ASCIIZ filename string
- idx - pointer to an array of 4 bytes (hash indexes)
- return:
- hash - filename hash
-*/
-int32 dgdsHash(const char *s, byte *idx) {
- int32 i, c;
- int16 isum, ixor;
- isum = 0;
- ixor = 0;
- for (i = 0; s[i]; i++) {
- c = toupper(s[i]);
- isum += c;
- ixor ^= c;
- }
- /* both types here MUST be int16 */
- isum *= ixor;
- c = 0;
- for (ixor = 0; ixor < 4; ixor++) {
- c <<= 8;
- /* can use only existing characters
- ("i" holds the string length now) */
- if (i > idx[ixor]) {
- c |= toupper(s[idx[ixor]]);
- }
- }
- c += isum;
- return c;
-}
-#endif
-
-#if 0
-// TAGS vs UNIQUE TAGS
-// HASHTABLE?
-
-uint32 lookupVolume(const char *rmfName, const char *filename, char *volname) {
- Common::File index;
- if (!index.open(rmfName))
- return 0xFFFFFFFF;
-
- byte salt[4];
- int32 filehash;
-
- index.read(salt, sizeof(salt));
- filehash = dgdsHash(filename, salt);
-
- uint16 nvolumes;
- nvolumes = index.readUint16LE();
- for (uint i = 0; i < nvolumes; i++) {
- index.read(volname, FILENAME_LENGTH + 1);
- volname[FILENAME_LENGTH] = '\0';
-
- uint16 nfiles;
- nfiles = index.readUint16LE();
- for (uint j = 0; j < nfiles; j++) {
- int32 hash = index.readSint32LE();
- uint32 offset = index.readUint32LE();
- if (hash == filehash) {
- index.close();
- return offset;
- }
- }
- }
- index.close();
- return 0xFFFFFFFF;
-}
-#endif
-
-#if 0
-Common::SeekableReadStream *createReadStream(const char *rmfName, const char *filename) {
- char volname[FILENAME_LENGTH + 1];
- uint32 offset;
- offset = lookupVolume(rmfName, filename, volname);
- if (offset == 0xFFFFFFFF)
- return 0;
-
- Common::File *volume = new Common::File;
- do {
- if (!volume->open(volname))
- break;
- volume->seek(offset);
- volume->read(volname, sizeof(volname));
- volname[FILENAME_LENGTH] = '\0';
-
- uint32 fileSize;
- fileSize = volume->readUint32LE();
-
- if (fileSize == 0xFFFFFFFF)
- break;
- if (scumm_stricmp(volname, filename))
- break;
- return new Common::SeekableSubReadStream(volume, volume->pos(), volume->pos() + fileSize, DisposeAfterUse::YES);
- } while (0);
-
- delete volume;
- return 0;
-}
-#endif
-
-#if 0
-void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource) {
- if (fileName) {
- Common::File file;
- if (file.open(fileName)) {
- parseFile(platform, file, fileName, resource);
- file.close();
- return;
- }
- }
-
- Common::File index, volume;
- Common::SeekableSubReadStream *file;
- if (index.open(indexName)) {
- byte salt[4];
- uint16 nvolumes;
-
- index.read(salt, sizeof(salt));
- nvolumes = index.readUint16LE();
-
- if (!fileName)
- debug("(%u,%u,%u,%u) %u", salt[0], salt[1], salt[2], salt[3], nvolumes);
-
- for (uint i = 0; i < nvolumes; i++) {
- char name[FILENAME_LENGTH + 1];
- uint16 nfiles;
-
- index.read(name, sizeof(name));
- name[FILENAME_LENGTH] = '\0';
-
- nfiles = index.readUint16LE();
-
- debugN("--\n#%u %s, %u files", i, name, nfiles);
-
- if (!volume.open(name)) {
- debug(", failed to open");
- continue;
- }
-
- debug(", %d bytes", volume.size());
-
- for (uint j = 0; j < nfiles; j++) {
- int32 hash;
- uint32 offset, fileSize;
-
- hash = index.readSint32LE();
- offset = index.readUint32LE();
-
- volume.seek(offset);
- volume.read(name, sizeof(name));
- name[FILENAME_LENGTH] = '\0';
- fileSize = volume.readUint32LE();
-
- if (!fileName || scumm_stricmp(name, fileName) == 0)
- debug(" #%u %s 0x%X=0x%X %u %u\n --", j, name, hash, dgdsHash(name, salt), offset, fileSize);
-
- if (fileSize == 0xFFFFFFFF) {
- continue;
- }
-
- if (fileName && scumm_stricmp(name, fileName)) {
- volume.skip(fileSize);
- continue;
- }
-
- file = new Common::SeekableSubReadStream(&volume, volume.pos(), volume.pos() + fileSize, DisposeAfterUse::NO);
-
- parseFile(platform, *file, name, resource);
-
- if (!fileName)
- debug(" #%u %s %d .", j, name, volume.pos());
-
- if (fileName) {
- volume.close();
- index.close();
- return;
- }
- }
- volume.close();
- }
- index.close();
- }
-}
-#endif
-
-#if 0
-int prev_id = -1;
-int prev_bk = -1;
-int prev_palette = -1;
-
-void browseInit(Common::Platform _platform, const char *_rmfName, DgdsEngine* syst) {
- BMPs.clear();
- explode(_platform, _rmfName, 0, -1);
- bk = 0;
- _idStr = 0;
- sid = 1;
-}
-
-void browse(Common::Platform _platform, const char *_rmfName, DgdsEngine* syst) {
- if (prev_id != _idStr || prev_bk != bk) {
- explode(_platform, _rmfName, BMPs[_idStr].c_str(), bk);
- prev_id = _idStr;
- prev_bk = bk;
-
- Common::String txt = Common::String::format("%s: %ux%u (%u/%u)", BMPs[_idStr].c_str(), _tw, _th, bk+1, _tcount);
- g_system->displayMessageOnOSD(txt.c_str());
- }
- if (prev_palette != sid) {
- sid = sid&3;
- prev_palette = sid;
-
- switch (sid) {
- case 3:
- for (uint i=0; i<256; i++) {
- palette[i*3+0] = i;
- palette[i*3+1] = i;
- palette[i*3+2] = i;
- }
- break;
- case 2:
- for (uint i=0; i<256; i++) {
- palette[i*3+0] = 255-i;
- palette[i*3+1] = 255-i;
- palette[i*3+2] = 255-i;
- }
- break;
- case 1:
- explode(_platform, _rmfName, "DRAGON.PAL", 0);
- break;
- }
- g_system->getPaletteManager()->setPalette(palette, 0, 256);
- }
-
- if (bk != -1) {
- if (_bmpData.h != 0) {
- byte *_bmpData_;
- _bmpData_ = (byte *)_bmpData.getPixels();
- byte *vgaData_;
- byte *binData_;
- bw = _tw; bh = _th;
- vgaData_ = (byte *)_bmpData.getPixels();
- binData_ = (byte *)_binData.getPixels();
-
- for (int i=0; i<bw*bh; i+=2) {
- _bmpData_[i+0] = ((vgaData_[i>>1] & 0xF0) );
- _bmpData_[i+0] |= ((binData_[i>>1] & 0xF0) >> 4);
- _bmpData_[i+1] = ((vgaData_[i>>1] & 0x0F) << 4);
- _bmpData_[i+1] |= ((binData_[i>>1] & 0x0F) );
- }
-
- const int rows = sh;
- const int columns = sw;
-
- byte *src = _bmpData_;
- byte *ptr = (byte *)bottomBuffer.getBasePtr(0, 0);
- for (int i=0; i<rows; ++i) {
- for (int j=0; j<columns; ++j) {
- ptr[j] = src[j];
- }
- ptr += bottomBuffer.pitch;
- src += bw;
- }
- }
-
- resData.clear(0);
- Common::Rect bmpWin(0, 0, _tw, _th);
- Graphics::Surface bmpSub = bottomBuffer.getSubArea(bmpWin);
- resData.blitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
- resData.frameRect(bmpWin, 1);
-
- Graphics::Surface *dst;
- dst = g_system->lockScreen();
- dst->copyRectToSurface(resData, 0, 0, rect);
- g_system->unlockScreen();
- g_system->updateScreen();
- }
-}
-#endif
-
} // End of namespace Dgds
Commit: 826630d88a9f6af482b3c40846fdfa9543fe7762
https://github.com/scummvm/scummvm/commit/826630d88a9f6af482b3c40846fdfa9543fe7762
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Cleanup
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 3f31947e715..63ff805ef40 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -107,8 +107,7 @@ void readStrings(Common::SeekableReadStream *stream) {
for (uint16 k = 0; k < count; k++) {
byte ch;
- uint16 idx;
- idx = stream->readUint16LE();
+ uint16 idx = stream->readUint16LE();
Common::String str;
while ((ch = stream->readByte()))
@@ -123,35 +122,41 @@ void DgdsEngine::parseRstChunk(Common::SeekableReadStream &file) {
// elaborate guesswork. who knows it might be true.
while (!file.eos()) {
- uint16 idx;
uint16 vals[7];
+ uint16 idx = file.readUint16LE();
- idx = file.readUint16LE();
debugN(" #%u:\t", idx);
+
if (idx == 0)
break;
+
for (int i = 0; i < ARRAYSIZE(vals); i++) {
vals[i] = file.readUint16LE();
if (i != 0)
debugN(", ");
debugN("%u", vals[i]);
}
+
debug(".");
}
+
debug("-");
while (!file.eos()) {
- uint16 idx;
uint16 vals[2];
- idx = file.readUint16LE();
+ uint16 idx = file.readUint16LE();
+
debugN(" #%u:\t", idx);
+
for (int i = 0; i < ARRAYSIZE(vals); i++) {
vals[i] = file.readUint16LE();
if (i != 0)
debugN(", ");
debugN("%u", vals[i]);
}
+
debug(".");
+
if (idx == 0)
break;
}
@@ -182,8 +187,8 @@ void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex)
uint16 *tw = new uint16[tcount];
uint16 *th = new uint16[tcount];
- uint32 packedSize, unpackedSize;
- unpackedSize = file.readUint32BE();
+ uint32 packedSize;
+ uint32 unpackedSize = file.readUint32BE(); // TODO: this is wrong - it's re-read below
debug(" [%u] %u =", tcount, unpackedSize);
uint32 sz = 0;
@@ -261,12 +266,15 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
line = file.readLine();
}
break;
+ case EX_DAT: {
+ // TODO
+ int leftover = file.size() - file.pos();
+ file.hexdump(leftover);
+ file.skip(leftover);
+ } break;
default:
break;
}
- int leftover = file.size() - file.pos();
- file.hexdump(leftover);
- file.skip(leftover);
} else {
DgdsChunk chunk;
int chunkno = 0;
@@ -611,11 +619,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
}
- if (ex == EX_BMP) {
- _BMPs.push_back(Common::String(name));
- debug("BMPs: %s", name);
- }
-
debug(" [%u:%u] --", (uint)file.pos(), ctx._bytesRead);
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index a616d6fbe3c..46617f99932 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -77,7 +77,6 @@ private:
PFont *_fntP;
FFont *_fntF;
- Common::StringArray _BMPs;
uint32 _musicSize;
byte *_musicData;
Commit: bff77cfe4708328b74028573d8244fbbb70798fc
https://github.com/scummvm/scummvm/commit/bff77cfe4708328b74028573d8244fbbb70798fc
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Move music player out of DgdsEngine
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scripts.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 63ff805ef40..1a5d187dbd3 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -52,7 +52,6 @@
#include "dgds/font.h"
#include "dgds/image.h"
#include "dgds/includes.h"
-#include "dgds/music.h"
#include "dgds/parser.h"
#include "dgds/resource.h"
#include "dgds/scripts.h"
@@ -62,16 +61,10 @@ namespace Dgds {
#define DUMP_ALL_CHUNKS 1
-//static Common::SeekableReadStream *ttm;
-//static char ttmName[DGDS_FILENAME_MAX + 1];
-
-//static Common::SeekableReadStream *ads;
-//static char adsName[DGDS_FILENAME_MAX + 1];
-
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
- _midiPlayer(nullptr), _soundPlayer(nullptr), _decompressor(nullptr),
- _musicData(nullptr), _musicSize(0), _scene(nullptr), _gdsScene(nullptr) {
+ _soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
+ _resource(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -82,6 +75,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_gameId = GID_CHINA;
else if (!strcmp(gameDesc->gameId, "beamish"))
_gameId = GID_BEAMISH;
+ else
+ error("Unknown game ID");
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "patches");
@@ -95,9 +90,6 @@ DgdsEngine::~DgdsEngine() {
delete _resource;
delete _scene;
delete _gdsScene;
- delete[] _musicData;
-
- delete _midiPlayer;
delete _soundPlayer;
}
@@ -367,15 +359,12 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
//Common::strlcpy(ttmName, name, sizeof(ttmName));
} else {
while (!stream->eos()) {
- uint16 code;
- byte count;
- uint op;
-
- code = stream->readUint16LE();
- count = code & 0x000F;
- op = code & 0xFFF0;
+ uint16 code = stream->readUint16LE();
+ byte count = code & 0x000F;
+ uint op = code & 0xFFF0;
debugN("\tOP: 0x%4.4x %2u ", op, count);
+
if (count == 0x0F) {
Common::String sval;
byte ch[2];
@@ -404,10 +393,10 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
}
} else if (chunk.isSection(ID_TAG)) {
- uint16 count;
+ uint16 count = stream->readUint16LE();
- count = stream->readUint16LE();
debug(" %u", count);
+
// something fishy here. the first two entries sometimes are an empty string or non-text junk.
// most of the time entries have text (sometimes with garbled characters).
// this parser is likely not ok. but the NUL count seems to be ok.
@@ -542,9 +531,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
case EX_SNG:
/* DOS. */
if (chunk.isSection(ID_SNG)) {
- _musicSize = stream->size();
- _musicData = new byte[_musicSize];
- stream->read(_musicData, _musicSize);
+ _soundPlayer->loadMusic(*stream);
} else if (chunk.isSection(ID_INF)) {
uint32 count = stream->size() / 2;
debug(" [%u]", count);
@@ -573,12 +560,9 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
} else if (chunk.isSection(ID_FNM)) {
readStrings(stream);
} else if (chunk.isSection(ID_DAT)) {
- uint16 idx, type;
- idx = stream->readUint16LE();
- type = stream->readUint16LE();
- //debug(" #%2u: (0x%X?) %s %u", idx, type, compressionDescr[compression], unpackSize);
-
- _musicData = decompressor->decompress(stream, stream->size() - stream->pos(), _musicSize);
+ /*uint16 idx = */stream->readUint16LE();
+ /*uint16 type = */stream->readUint16LE();
+ _soundPlayer->loadMusic(*stream, decompressor);
}
break;
case EX_PAL:
@@ -632,29 +616,13 @@ void DgdsEngine::parseFile(const Common::String &filename, int resource) {
int delay = 0;
-void DgdsEngine::playMusic(const Common::String &fileName) {
- //stopMusic();
-
- parseFile(fileName);
- if (_musicData) {
- uint32 tracks = availableSndTracks(_musicData, _musicSize);
- if ((tracks & TRACK_MT32))
- _midiPlayer->play(_musicData, _musicSize);
- if ((tracks & DIGITAL_PCM))
- _soundPlayer->playPCM(_musicData, _musicSize);
- }
-}
-
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
- _musicData = nullptr;
-
_console = new Console(this);
_resource = new ResourceManager();
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
- _midiPlayer = new DgdsMidiPlayer();
_soundPlayer = new Sound(_mixer);
_scene = new SDSScene();
_gdsScene = new GDSScene();
@@ -669,7 +637,6 @@ Common::Error DgdsEngine::run() {
g_system->fillScreen(0);
-
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 46617f99932..861adbb654e 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -46,7 +46,6 @@ class PFont;
class FFont;
class SDSScene;
class GDSScene;
-class DgdsMidiPlayer;
class Sound;
struct DgdsADS;
@@ -64,7 +63,6 @@ public:
private:
Console *_console;
- DgdsMidiPlayer *_midiPlayer;
ResourceManager *_resource;
Decompressor *_decompressor;
@@ -77,8 +75,6 @@ private:
PFont *_fntP;
FFont *_fntF;
- uint32 _musicSize;
- byte *_musicData;
protected:
virtual Common::Error run();
@@ -89,8 +85,6 @@ public:
DgdsGameId getGameId() { return _gameId; }
- void playMusic(const Common::String &fileName);
-
void parseFile(const Common::String &filename, int resource = 0);
Graphics::Surface &getTopBuffer() { return _topBuffer; }
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index b43e9d9190d..892bf6fca48 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -153,7 +153,8 @@ bool TTMInterpreter::run(TTMState *script) {
_vm->parseFile("DYNAMIX.INS"); // TODO: Unwrap this out of parseFile()
_vm->_soundPlayer->playAmigaSfx(0, 255);
} else {
- _vm->playMusic(sval.c_str());
+ _vm->parseFile(sval.c_str()); // TODO: Unwrap this out of parseFile()
+ _vm->_soundPlayer->playMusic();
}
continue;
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 7ff7d134bdb..fd95cd00e66 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -30,12 +30,20 @@
#include "audio/decoders/raw.h"
#include "audio/mixer.h"
+#include "dgds/decompress.h"
+#include "dgds/music.h"
#include "dgds/sound.h"
namespace Dgds {
+Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer) {
+ _midiPlayer = new DgdsMidiPlayer();
+}
+
Sound::~Sound() {
+ delete _midiPlayer;
delete _soundData;
+ delete[] _musicData;
}
void Sound::loadAmigaAiff(Common::SeekableReadStream& file) {
@@ -44,6 +52,16 @@ void Sound::loadAmigaAiff(Common::SeekableReadStream& file) {
_soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
}
+void Sound::loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor) {
+ if (!decompressor) {
+ _musicSize = file.size();
+ _musicData = new byte[_musicSize];
+ file.read(_musicData, _musicSize);
+ } else {
+ _musicData = decompressor->decompress(&file, file.size() - file.pos(), _musicSize);
+ }
+}
+
void Sound::playAmigaSfx(byte channel, byte volume) {
stopSfx(channel);
@@ -109,6 +127,18 @@ bool Sound::playPCM(const byte *data, uint32 size) {
return true;
}
+void Sound::playMusic() {
+ // stopMusic();
+
+ if (_musicData) {
+ uint32 tracks = availableSndTracks(_musicData, _musicSize);
+ if (tracks & TRACK_MT32)
+ _midiPlayer->play(_musicData, _musicSize);
+ else if (tracks & DIGITAL_PCM)
+ playPCM(_musicData, _musicSize);
+ }
+}
+
static inline
void readHeader(const byte* &pos, uint32 &sci_header) {
sci_header = 0;
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index dc5033dcff1..5651c88a4fb 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -29,6 +29,9 @@
namespace Dgds {
+class Decompressor;
+class DgdsMidiPlayer;
+
struct Channel {
Audio::AudioStream *stream;
Audio::SoundHandle handle;
@@ -37,11 +40,13 @@ struct Channel {
class Sound {
public:
- Sound(Audio::Mixer *mixer) : _mixer(mixer) {}
+ Sound(Audio::Mixer *mixer);
~Sound();
void playAmigaSfx(byte channel, byte volume);
void loadAmigaAiff(Common::SeekableReadStream &file);
+ void loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor = nullptr);
+ void playMusic();
void stopSfx(byte channel);
@@ -50,7 +55,10 @@ public:
private:
struct Channel _channels[2];
Common::SeekableReadStream *_soundData = nullptr;
+ uint32 _musicSize = 0;
+ byte *_musicData = nullptr;
Audio::Mixer *_mixer;
+ DgdsMidiPlayer *_midiPlayer;
};
enum {
Commit: 2556312d630d7ddcfce73737af53e8b942398735
https://github.com/scummvm/scummvm/commit/2556312d630d7ddcfce73737af53e8b942398735
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Move sound resource loading inside the Sound class
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scripts.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 1a5d187dbd3..eb2a21b7824 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -528,31 +528,15 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
}
break;
- case EX_SNG:
- /* DOS. */
- if (chunk.isSection(ID_SNG)) {
- _soundPlayer->loadMusic(*stream);
- } else if (chunk.isSection(ID_INF)) {
- uint32 count = stream->size() / 2;
- debug(" [%u]", count);
- for (uint32 k = 0; k < count; k++) {
- uint16 idx = stream->readUint16LE();
- debug(" %2u: %u", k, idx);
- }
- }
- break;
case EX_SX:
/* Macintosh. */
if (chunk.isSection(ID_INF)) {
- uint16 type, count;
-
- type = stream->readUint16LE();
- count = stream->readUint16LE();
+ uint16 type = stream->readUint16LE();
+ uint16 count = stream->readUint16LE();
debug(" %u [%u]:", type, count);
for (uint16 k = 0; k < count; k++) {
- uint16 idx;
- idx = stream->readUint16LE();
+ uint16 idx = stream->readUint16LE();
debug(" %2u: %u", k, idx);
}
} else if (chunk.isSection(ID_TAG)) {
@@ -565,11 +549,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
_soundPlayer->loadMusic(*stream, decompressor);
}
break;
- case EX_PAL:
- /* DOS & Macintosh. */
- // Handled in Image::setPalette
- error("Should not be here");
- break;
case EX_FNT:
if (resource == 0) {
if (chunk.isSection(ID_FNT)) {
@@ -584,14 +563,11 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
}
break;
- case EX_SCR:
- // Handled in Image::loadScreen
- error("Should not be here");
- break;
- case EX_BMP:
- // Handled in Image::loadBitmap
+ case EX_SNG: // Handled in Sound::playMusic
+ case EX_PAL: // Handled in Image::setPalette
+ case EX_SCR: // Handled in Image::loadScreen
+ case EX_BMP: // Handled in Image::loadBitmap
error("Should not be here");
- break;
default:
break;
}
@@ -623,7 +599,7 @@ Common::Error DgdsEngine::run() {
_resource = new ResourceManager();
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
- _soundPlayer = new Sound(_mixer);
+ _soundPlayer = new Sound(_mixer, _resource, _decompressor);
_scene = new SDSScene();
_gdsScene = new GDSScene();
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 892bf6fca48..07c6815bb28 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -153,8 +153,7 @@ bool TTMInterpreter::run(TTMState *script) {
_vm->parseFile("DYNAMIX.INS"); // TODO: Unwrap this out of parseFile()
_vm->_soundPlayer->playAmigaSfx(0, 255);
} else {
- _vm->parseFile(sval.c_str()); // TODO: Unwrap this out of parseFile()
- _vm->_soundPlayer->playMusic();
+ _vm->_soundPlayer->playMusic(sval.c_str());
}
continue;
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index fd95cd00e66..667bfb8228b 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -31,12 +31,16 @@
#include "audio/mixer.h"
#include "dgds/decompress.h"
+#include "dgds/includes.h"
#include "dgds/music.h"
+#include "dgds/parser.h"
+#include "dgds/resource.h"
#include "dgds/sound.h"
namespace Dgds {
-Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer) {
+Sound::Sound(Audio::Mixer *mixer, ResourceManager *resource, Decompressor *decompressor) :
+ _mixer(mixer), _resource(resource), _decompressor(decompressor) {
_midiPlayer = new DgdsMidiPlayer();
}
@@ -53,13 +57,7 @@ void Sound::loadAmigaAiff(Common::SeekableReadStream& file) {
}
void Sound::loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor) {
- if (!decompressor) {
- _musicSize = file.size();
- _musicData = new byte[_musicSize];
- file.read(_musicData, _musicSize);
- } else {
- _musicData = decompressor->decompress(&file, file.size() - file.pos(), _musicSize);
- }
+ _musicData = decompressor->decompress(&file, file.size() - file.pos(), _musicSize);
}
void Sound::playAmigaSfx(byte channel, byte volume) {
@@ -127,7 +125,46 @@ bool Sound::playPCM(const byte *data, uint32 size) {
return true;
}
-void Sound::playMusic() {
+void Sound::playMusic(const Common::String &filename) {
+ if (!filename.hasSuffixIgnoreCase(".sng"))
+ error("Unhandled music file type: %s", filename.c_str());
+
+ Common::SeekableReadStream *musicStream = _resource->getResource(filename);
+ if (!musicStream) {
+ // Happens in the Mac version of Dragon
+ warning("Music file %s not found", filename.c_str());
+ return;
+ }
+
+ DgdsParser ctx(*musicStream, filename);
+ DgdsChunk chunk;
+ const DGDS_EX ex = EX_SNG;
+
+ while (chunk.readHeader(ctx)) {
+ if (chunk._container) {
+ continue;
+ }
+
+ Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
+
+ if (chunk.isSection(ID_SNG)) {
+ _musicSize = stream->size();
+ _musicData = new byte[_musicSize];
+ stream->read(_musicData, _musicSize);
+ } else if (chunk.isSection(ID_INF)) {
+ uint32 count = stream->size() / 2;
+ debug(" [%u]", count);
+ for (uint32 k = 0; k < count; k++) {
+ uint16 idx = stream->readUint16LE();
+ debug(" %2u: %u", k, idx);
+ }
+ }
+
+ delete stream;
+ }
+
+ delete musicStream;
+
// stopMusic();
if (_musicData) {
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 5651c88a4fb..85b92b3c183 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -29,6 +29,7 @@
namespace Dgds {
+class ResourceManager;
class Decompressor;
class DgdsMidiPlayer;
@@ -40,13 +41,13 @@ struct Channel {
class Sound {
public:
- Sound(Audio::Mixer *mixer);
+ Sound(Audio::Mixer *mixer, ResourceManager *resource, Decompressor *decompressor);
~Sound();
void playAmigaSfx(byte channel, byte volume);
void loadAmigaAiff(Common::SeekableReadStream &file);
- void loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor = nullptr);
- void playMusic();
+ void loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor);
+ void playMusic(const Common::String &filename);
void stopSfx(byte channel);
@@ -59,6 +60,8 @@ private:
byte *_musicData = nullptr;
Audio::Mixer *_mixer;
DgdsMidiPlayer *_midiPlayer;
+ ResourceManager *_resource;
+ Decompressor *_decompressor;
};
enum {
Commit: 53386d6d547257c653a12049149ad828659af9c2
https://github.com/scummvm/scummvm/commit/53386d6d547257c653a12049149ad828659af9c2
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Moved Amiga SFX handling into Sound::playAmigaSfx()
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/scripts.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index eb2a21b7824..a6e429b672b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -209,9 +209,6 @@ void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex)
delete[] tw;
delete[] th;
} break;
- case EX_INS:
- _soundPlayer->loadAmigaAiff(file);
- break;
case EX_SNG:
/* IFF-SMUS music (Amiga). */
break;
@@ -225,6 +222,8 @@ void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex)
line = file.readLine();
}
break;
+ case EX_INS: // Handled in Sound::playAmigaSfx
+ error("Should not be here");
}
}
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 69c83fa3533..4f2be370eaf 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -384,8 +384,12 @@ uint32 Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toff
void Image::loadPalette(Common::String filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
- if (!fileStream)
- error("Couldn't get palette resource %s", filename.c_str());
+ if (!fileStream) {
+ // Happens in the Amiga version of Dragon
+ warning("Couldn't load palette resource %s", filename.c_str());
+ return;
+ }
+
DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 07c6815bb28..4fc75c4a130 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -150,8 +150,7 @@ bool TTMInterpreter::run(TTMState *script) {
case 0xf060:
// LOAD SONG: filename:str
if (_vm->_platform == Common::kPlatformAmiga) {
- _vm->parseFile("DYNAMIX.INS"); // TODO: Unwrap this out of parseFile()
- _vm->_soundPlayer->playAmigaSfx(0, 255);
+ _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
} else {
_vm->_soundPlayer->playMusic(sval.c_str());
}
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 667bfb8228b..deefe0f36e8 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -60,7 +60,21 @@ void Sound::loadMusic(Common::SeekableReadStream &file, Decompressor *decompress
_musicData = decompressor->decompress(&file, file.size() - file.pos(), _musicSize);
}
-void Sound::playAmigaSfx(byte channel, byte volume) {
+void Sound::playAmigaSfx(const Common::String &filename, byte channel, byte volume) {
+ if (!filename.hasSuffixIgnoreCase(".ins"))
+ error("Unhandled SFX file type: %s", filename.c_str());
+
+ Common::SeekableReadStream *sfxStream = _resource->getResource(filename);
+ if (!sfxStream) {
+ warning("SFX file %s not found", filename.c_str());
+ return;
+ }
+
+ byte *dest = new byte[sfxStream->size()];
+ sfxStream->read(dest, sfxStream->size());
+ _soundData = new Common::MemoryReadStream(dest, sfxStream->size(), DisposeAfterUse::YES);
+ delete sfxStream;
+
stopSfx(channel);
if (_soundData) {
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 85b92b3c183..d1d6bb0bfe1 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -44,7 +44,7 @@ public:
Sound(Audio::Mixer *mixer, ResourceManager *resource, Decompressor *decompressor);
~Sound();
- void playAmigaSfx(byte channel, byte volume);
+ void playAmigaSfx(const Common::String &filename, byte channel, byte volume);
void loadAmigaAiff(Common::SeekableReadStream &file);
void loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor);
void playMusic(const Common::String &filename);
Commit: 596de66e98a11b7bbf17d311fc60f85c37209a3a
https://github.com/scummvm/scummvm/commit/596de66e98a11b7bbf17d311fc60f85c37209a3a
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Move Mac music handling inside the Sound class
Also, remove the now obsolete loadAmigaAiff() function
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scripts.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index a6e429b672b..8c50b3f523a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -527,27 +527,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
}
break;
- case EX_SX:
- /* Macintosh. */
- if (chunk.isSection(ID_INF)) {
- uint16 type = stream->readUint16LE();
- uint16 count = stream->readUint16LE();
-
- debug(" %u [%u]:", type, count);
- for (uint16 k = 0; k < count; k++) {
- uint16 idx = stream->readUint16LE();
- debug(" %2u: %u", k, idx);
- }
- } else if (chunk.isSection(ID_TAG)) {
- readStrings(stream);
- } else if (chunk.isSection(ID_FNM)) {
- readStrings(stream);
- } else if (chunk.isSection(ID_DAT)) {
- /*uint16 idx = */stream->readUint16LE();
- /*uint16 type = */stream->readUint16LE();
- _soundPlayer->loadMusic(*stream, decompressor);
- }
- break;
case EX_FNT:
if (resource == 0) {
if (chunk.isSection(ID_FNT)) {
@@ -563,6 +542,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
break;
case EX_SNG: // Handled in Sound::playMusic
+ case EX_SX: // Handled in Sound::playMacMusic
case EX_PAL: // Handled in Image::setPalette
case EX_SCR: // Handled in Image::loadScreen
case EX_BMP: // Handled in Image::loadBitmap
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 4fc75c4a130..b456bcaa872 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -151,6 +151,8 @@ bool TTMInterpreter::run(TTMState *script) {
// LOAD SONG: filename:str
if (_vm->_platform == Common::kPlatformAmiga) {
_vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
+ } else if (_vm->_platform == Common::kPlatformMacintosh) {
+ _vm->_soundPlayer->playMacMusic(sval.c_str());
} else {
_vm->_soundPlayer->playMusic(sval.c_str());
}
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index deefe0f36e8..c2b29ca79fc 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -50,12 +50,6 @@ Sound::~Sound() {
delete[] _musicData;
}
-void Sound::loadAmigaAiff(Common::SeekableReadStream& file) {
- byte *dest = new byte[file.size()];
- file.read(dest, file.size());
- _soundData = new Common::MemoryReadStream(dest, file.size(), DisposeAfterUse::YES);
-}
-
void Sound::loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor) {
_musicData = decompressor->decompress(&file, file.size() - file.pos(), _musicSize);
}
@@ -139,16 +133,74 @@ bool Sound::playPCM(const byte *data, uint32 size) {
return true;
}
+extern void readStrings(Common::SeekableReadStream *stream);
+
+void Sound::playMacMusic(const Common::String &filename) {
+ if (filename.hasSuffixIgnoreCase(".sng")) {
+ Common::String macFileName = filename.substr(0, filename.find(".")) + ".sx";
+ playMacMusic(macFileName);
+ return;
+ }
+
+ if (!filename.hasSuffixIgnoreCase(".sx"))
+ error("Unhandled music file type: %s", filename.c_str());
+
+ Common::SeekableReadStream *musicStream = _resource->getResource(filename);
+ if (!musicStream)
+ error("Music file %s not found", filename.c_str());
+
+ DgdsParser ctx(*musicStream, filename);
+ DgdsChunk chunk;
+ const DGDS_EX ex = EX_SNG;
+
+ while (chunk.readHeader(ctx)) {
+ if (chunk._container) {
+ continue;
+ }
+
+ Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
+
+ if (chunk.isSection(ID_INF)) {
+ uint16 type = stream->readUint16LE();
+ uint16 count = stream->readUint16LE();
+
+ debug(" %u [%u]:", type, count);
+ for (uint16 k = 0; k < count; k++) {
+ uint16 idx = stream->readUint16LE();
+ debug(" %2u: %u", k, idx);
+ }
+ } else if (chunk.isSection(ID_TAG) || chunk.isSection(ID_FNM)) {
+ readStrings(stream);
+ } else if (chunk.isSection(ID_DAT)) {
+ /*uint16 idx = */ stream->readUint16LE();
+ /*uint16 type = */ stream->readUint16LE();
+ _musicData = _decompressor->decompress(stream, stream->size() - stream->pos(), _musicSize);
+ }
+
+ delete stream;
+ }
+
+ delete musicStream;
+
+ // stopMusic();
+
+ // TODO: This isn't correct
+ if (_musicData) {
+ uint32 tracks = availableSndTracks(_musicData, _musicSize);
+ if (tracks & TRACK_MT32)
+ _midiPlayer->play(_musicData, _musicSize);
+ else if (tracks & DIGITAL_PCM)
+ playPCM(_musicData, _musicSize);
+ }
+}
+
void Sound::playMusic(const Common::String &filename) {
if (!filename.hasSuffixIgnoreCase(".sng"))
error("Unhandled music file type: %s", filename.c_str());
Common::SeekableReadStream *musicStream = _resource->getResource(filename);
- if (!musicStream) {
- // Happens in the Mac version of Dragon
- warning("Music file %s not found", filename.c_str());
- return;
- }
+ if (!musicStream)
+ error("Music file %s not found", filename.c_str());
DgdsParser ctx(*musicStream, filename);
DgdsChunk chunk;
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index d1d6bb0bfe1..ab044e188ff 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -45,9 +45,9 @@ public:
~Sound();
void playAmigaSfx(const Common::String &filename, byte channel, byte volume);
- void loadAmigaAiff(Common::SeekableReadStream &file);
void loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor);
void playMusic(const Common::String &filename);
+ void playMacMusic(const Common::String &filename);
void stopSfx(byte channel);
Commit: 85c41b0c93bdb7cd1e45e6077faf246c2e360207
https://github.com/scummvm/scummvm/commit/85c41b0c93bdb7cd1e45e6077faf246c2e360207
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Silene some MSVC warnings
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/music.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 8c50b3f523a..2c575bdffdc 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -605,7 +605,7 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
parseFile("DRAGON.GDS");
-
+
interpTTM.load("TITLE1.TTM", &title1Data);
interpTTM.load("TITLE2.TTM", &title2Data);
interpADS.load("INTRO.ADS", &adsData);
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 4f2be370eaf..5abf91198c4 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -169,7 +169,7 @@ void Image::loadBitmap(Common::String filename, int number) {
if (val != 0xffff)
warning("Expected 0xffff in 2-byte offset list, got %04x", val);
}
-
+
uint32 nextOffset = 0;
for (int i = 0; i < number + 1; i++) {
fileStream->seek(vqtpos);
@@ -296,8 +296,8 @@ static void _doVqtDecode2(struct VQTDecodeState *state, const uint16 x, const ui
bval++;
if (losize * 8 <= losize * bitcount2 + bval * 8) {
- for (uint xx = x; xx < x + w; xx++) {
- for (uint yy = y; yy < y + h; yy++) {
+ for (int xx = x; xx < x + w; xx++) {
+ for (int yy = y; yy < y + h; yy++) {
state->dstPtr[state->rowStarts[yy] + xx] = _getVqtBits(state, 8);
}
}
@@ -306,8 +306,8 @@ static void _doVqtDecode2(struct VQTDecodeState *state, const uint16 x, const ui
if (bval == 1) {
const uint16 val = _getVqtBits(state, 8);
- for (uint yy = y; yy < y + h; yy++) {
- for (uint xx = x; xx < x + w; xx++) {
+ for (int yy = y; yy < y + h; yy++) {
+ for (int xx = x; xx < x + w; xx++) {
state->dstPtr[state->rowStarts[yy] + xx] = val;
}
}
@@ -321,8 +321,8 @@ static void _doVqtDecode2(struct VQTDecodeState *state, const uint16 x, const ui
ptmpbuf++;
}
- for (uint xx = x; xx < x + w; xx++) {
- for (uint yy = y; yy < y + h; yy++) {
+ for (int xx = x; xx < x + w; xx++) {
+ for (int yy = y; yy < y + h; yy++) {
state->dstPtr[state->rowStarts[yy] + xx] = tmpbuf[_getVqtBits(state, bitcount2)];
}
}
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
index e6a3e2668a1..2ec0a337516 100644
--- a/engines/dgds/music.cpp
+++ b/engines/dgds/music.cpp
@@ -261,7 +261,7 @@ void MidiParser_DGDS::mixChannels() {
}
// remember which channel got used for channel remapping
- byte midiChannel = midiCommand & 0xF;
+ //byte midiChannel = midiCommand & 0xF;
//_channelUsed[midiChannel] = true;
if (midiCommand != globalPrev)
Commit: b13a34d7a0a50f287479b389ea9942d0cfb12173
https://github.com/scummvm/scummvm/commit/b13a34d7a0a50f287479b389ea9942d0cfb12173
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add REQ file parsing and refactor parsing a bit overall
Changed paths:
A engines/dgds/request.cpp
A engines/dgds/request.h
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/module.mk
engines/dgds/parser.cpp
engines/dgds/parser.h
engines/dgds/resource.cpp
engines/dgds/resource.h
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
engines/dgds/sound.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 9fc139e10e1..b801d1da624 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -97,11 +97,9 @@ bool Console::cmdFileDump(int argc, const char **argv) {
ex = MKTAG24(dot[1], dot[2], dot[3]);
}
- Decompressor *decompressor = new Decompressor();
- DgdsParser ctx(*res, fileName.c_str());
DgdsChunk chunk;
- while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, decompressor);
+ while (chunk.readHeader(res, fileName)) {
+ Common::SeekableReadStream *stream = chunk.getStream(ex, res, _vm->getDecompressor());
memcpy(ptr, chunk._idStr, 4);
ptr += 4;
@@ -112,7 +110,6 @@ bool Console::cmdFileDump(int argc, const char **argv) {
size += 4 + stream->size();
}
- delete decompressor;
}
delete res;
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 2c575bdffdc..dbe731461dc 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -53,6 +53,7 @@
#include "dgds/image.h"
#include "dgds/includes.h"
#include "dgds/parser.h"
+#include "dgds/request.h"
#include "dgds/resource.h"
#include "dgds/scripts.h"
#include "dgds/sound.h"
@@ -227,7 +228,16 @@ void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex)
}
}
-void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor) {
+void DgdsEngine::parseFile(const Common::String &filename) {
+ Common::SeekableReadStream *stream = _resource->getResource(filename);
+ if (!stream)
+ error("Couldn't get resource file %s", filename.c_str());
+ parseFileInner(_platform, *stream, filename.c_str());
+ delete stream;
+}
+
+
+void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name) {
const char *dot;
DGDS_EX ex = 0;
@@ -237,7 +247,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
uint parent = 0;
- DgdsParser ctx(file, name);
if (platform == Common::kPlatformAmiga) {
parseAmigaChunks(file, ex);
}
@@ -269,13 +278,13 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
} else {
DgdsChunk chunk;
int chunkno = 0;
- while (chunk.readHeader(ctx)) {
+ while (chunk.readHeader(&file, name)) {
if (chunk._container) {
parent = chunk._id;
continue;
}
- Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, decompressor);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, &file, _decompressor);
#ifdef DUMP_ALL_CHUNKS
{
@@ -350,13 +359,13 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
pages = stream->readUint16LE();
debug(" %u", pages);
} else if (chunk.isSection(ID_TT3)) {
- if (resource == 0) {
- uint32 size = stream->size();
- byte *dest = new byte[size];
- stream->read(dest, size);
- //ttm = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
- //Common::strlcpy(ttmName, name, sizeof(ttmName));
- } else {
+ uint32 size = stream->size();
+ byte *dest = new byte[size];
+ stream->read(dest, size);
+ //ttm = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
+ //Common::strlcpy(ttmName, name, sizeof(ttmName));
+ delete [] dest;
+#if 0
while (!stream->eos()) {
uint16 code = stream->readUint16LE();
byte count = code & 0x000F;
@@ -391,6 +400,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
debug(" ");
}
}
+#endif
} else if (chunk.isSection(ID_TAG)) {
uint16 count = stream->readUint16LE();
@@ -430,19 +440,15 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
stream->read(version, sizeof(version));
debug(" %s", version);
} else if (chunk.isSection(ID_RES)) {
- debug("res0");
- if (resource == 0) {
- DgdsParser::readTags(stream);
- } else {
- readStrings(stream);
- }
+ DgdsParser::readTags(stream);
} else if (chunk.isSection(ID_SCR)) {
- if (resource == 0) {
uint32 size = stream->size();
byte *dest = new byte[size];
stream->read(dest, size);
//ads = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
//adsName = name;
+ delete [] dest;
+#if 0
} else {
/* this is either a script, or a property sheet, i can't decide. */
while (!stream->eos()) {
@@ -510,6 +516,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
assert(stream->size() == stream->pos());
//stream->hexdump(stream->size());
}
+#endif
} else if (chunk.isSection(ID_TAG)) {
readStrings(stream);
}
@@ -528,17 +535,15 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
break;
case EX_FNT:
- if (resource == 0) {
- if (chunk.isSection(ID_FNT)) {
- byte magic = stream->readByte();
- stream->seek(-1, SEEK_CUR);
- debug(" magic: %u", magic);
-
- if (magic != 0xFF)
- _fntF = FFont::load(*stream);
- else
- _fntP = PFont::load(*stream, decompressor);
- }
+ if (chunk.isSection(ID_FNT)) {
+ byte magic = stream->readByte();
+ stream->seek(-1, SEEK_CUR);
+ debug(" magic: %u", magic);
+
+ if (magic != 0xFF)
+ _fntF = FFont::load(*stream);
+ else
+ _fntP = PFont::load(*stream, _decompressor);
}
break;
case EX_SNG: // Handled in Sound::playMusic
@@ -558,19 +563,9 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
}
}
- debug(" [%u:%u] --", (uint)file.pos(), ctx._bytesRead);
-}
-
-void DgdsEngine::parseFile(const Common::String &filename, int resource) {
- Common::SeekableReadStream *stream = _resource->getResource(filename);
- if (!stream)
- error("Couldn't get resource file %s", filename.c_str());
- parseFileInner(_platform, *stream, filename.c_str(), resource, _decompressor);
- delete stream;
+ debug(" [%u] --", (uint)file.pos());
}
-int delay = 0;
-
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -604,8 +599,20 @@ Common::Error DgdsEngine::run() {
ADSData adsData;
if (getGameId() == GID_DRAGON) {
+ // Test parsing some things..
parseFile("DRAGON.GDS");
-
+
+ RequestData invRequestData;
+ RequestData vcrRequestData;
+ Request invRequest(_resource);
+ Request vcrRequest(_resource);
+ invRequest.parse(&invRequestData, "DINV.REQ");
+ vcrRequest.parse(&vcrRequestData, "DINV.REQ");
+ //Request vcrRequest(vcrRequestData);
+
+ //invRequest.parse(
+
+ // Load the intro and play it for now.
interpTTM.load("TITLE1.TTM", &title1Data);
interpTTM.load("TITLE2.TTM", &title2Data);
interpADS.load("INTRO.ADS", &adsData);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 861adbb654e..664efd4ffbd 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -77,7 +77,7 @@ private:
FFont *_fntF;
protected:
- virtual Common::Error run();
+ virtual Common::Error run() override;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -85,27 +85,23 @@ public:
DgdsGameId getGameId() { return _gameId; }
- void parseFile(const Common::String &filename, int resource = 0);
-
Graphics::Surface &getTopBuffer() { return _topBuffer; }
Graphics::Surface &getBottomBuffer() { return _bottomBuffer; }
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
-
const PFont *getFntP() const { return _fntP; }
Image *_image;
Graphics::ManagedSurface _resData;
private:
- void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name, int resource, Decompressor *decompressor);
+ void parseFile(const Common::String &filename);
+ void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name);
void parseRstChunk(Common::SeekableReadStream &file);
void parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex);
};
-//void explode(Common::Platform platform, const char *indexName, const char *fileName, int resource);
-
} // End of namespace Dgds
#endif // DGDS_DGDS_H
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 5abf91198c4..01fd697540f 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -54,7 +54,6 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("Couldn't get image resource %s", filename.c_str());
- DgdsParser ctx(*fileStream, filename.c_str());
if ((dot = strrchr(filename.c_str(), '.'))) {
ex = MKTAG24(dot[1], dot[2], dot[3]);
@@ -71,8 +70,8 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
surface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
DgdsChunk chunk;
- while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
+ while (chunk.readHeader(fileStream, filename)) {
+ Common::SeekableReadStream *stream = chunk.getStream(ex, fileStream, _decompressor);
if (chunk.isSection(ID_BIN)) {
loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, false);
} else if (chunk.isSection(ID_VGA)) {
@@ -94,7 +93,6 @@ void Image::loadBitmap(Common::String filename, int number) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("Couldn't get bitmap resource %s", filename.c_str());
- DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
_bmpData.free();
@@ -117,8 +115,8 @@ void Image::loadBitmap(Common::String filename, int number) {
uint16 tileHeights[64];
int32 tileOffset = 0;
- while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
+ while (chunk.readHeader(fileStream, filename)) {
+ Common::SeekableReadStream *stream = chunk.getStream(ex, fileStream, _decompressor);
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
for (uint16 k = 0; k < tileCount; k++) {
@@ -389,13 +387,11 @@ void Image::loadPalette(Common::String filename) {
warning("Couldn't load palette resource %s", filename.c_str());
return;
}
-
- DgdsParser ctx(*fileStream, filename.c_str());
DgdsChunk chunk;
- while (chunk.readHeader(ctx)) {
- Common::SeekableReadStream *stream = chunk.readStream(ctx);
+ while (chunk.readHeader(fileStream, filename)) {
+ Common::SeekableReadStream *stream = chunk.readStream(fileStream);
if (chunk.isSection(ID_VGA)) {
stream->read(_palette, 256 * 3);
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 55f3779c23f..a207572876c 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS := \
music.o \
parser.o \
resource.o \
+ request.o \
scripts.o \
scene.o \
sound.o
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index ca3eecf5034..b178d34ceab 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -32,12 +32,19 @@
namespace Dgds {
-DgdsParser::DgdsParser(Common::SeekableReadStream &file, const Common::String &filename) : _file(file), _filename(filename), _bytesRead(0) {
+DgdsParser::DgdsParser(ResourceManager *resman) : _resman(resman), _file(nullptr), _bytesRead(0) {
}
-void DgdsParser::parse(DgdsScriptData *data, Decompressor *decompressor) {
+bool DgdsParser::parse(ParserData *data, const Common::String &filename) {
DGDS_EX _ex;
+ Common::SeekableReadStream *stream = _resman->getResource(filename);
+
+ if (!stream) {
+ error("Couldn't open script file '%s'", filename.c_str());
+ return false;
+ }
+
uint32 dot = _filename.find('.');
if (dot != Common::String::npos) {
_ex = MKTAG24(toupper(_filename[dot + 1]), toupper(_filename[dot + 2]), toupper(_filename[dot + 3]));
@@ -46,16 +53,16 @@ void DgdsParser::parse(DgdsScriptData *data, Decompressor *decompressor) {
}
DgdsChunk chunk;
- while (chunk.readHeader(*this)) {
+ while (chunk.readHeader(_file, _filename)) {
bool stop;
if (chunk._container) {
- chunk._stream = &_file;
- stop = callback(chunk, data);
+ chunk._stream = _file;
+ stop = handleChunk(chunk, data);
} else {
- chunk._stream = chunk.getStream(_ex, *this, decompressor);
+ chunk._stream = chunk.getStream(_ex, _file, &_decomp);
- stop = callback(chunk, data);
+ stop = handleChunk(chunk, data);
int leftover = chunk._stream->size() - chunk._stream->pos();
chunk._stream->skip(leftover);
@@ -64,6 +71,9 @@ void DgdsParser::parse(DgdsScriptData *data, Decompressor *decompressor) {
if (stop)
break;
}
+
+ delete stream;
+ return true;
}
Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableReadStream *stream) {
@@ -83,7 +93,7 @@ Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableRea
}
-bool TTMParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
+bool TTMParser::handleChunk(DgdsChunk &chunk, ParserData *data) {
TTMData *scriptData = (TTMData *)data;
switch (chunk._id) {
@@ -107,7 +117,7 @@ bool TTMParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
return false;
}
-bool ADSParser::callback(DgdsChunk &chunk, DgdsScriptData *data) {
+bool ADSParser::handleChunk(DgdsChunk &chunk, ParserData *data) {
ADSData *scriptData = (ADSData *)data;
switch (chunk._id) {
case EX_ADS:
diff --git a/engines/dgds/parser.h b/engines/dgds/parser.h
index 50e1b68d30a..0c9e0e6a393 100644
--- a/engines/dgds/parser.h
+++ b/engines/dgds/parser.h
@@ -23,39 +23,49 @@
#ifndef DGDS_PARSER_H
#define DGDS_PARSER_H
+#include "dgds/decompress.h"
+
namespace Dgds {
class DgdsChunk;
-class Decompressor;
-class DgdsScriptData;
+class ResourceManager;
+
+class ParserData {};
class DgdsParser {
public:
- Common::String _filename;
- Common::SeekableReadStream &_file;
+ // FIXME: Make these private/protected
uint32 _bytesRead;
+ Common::SeekableReadStream *_file;
- DgdsParser(Common::SeekableReadStream &file, const Common::String &filename);
- void parse(DgdsScriptData *data, Decompressor *decompressor);
- virtual bool callback(DgdsChunk &chunk, DgdsScriptData *data) { return false; }
+ DgdsParser(ResourceManager *resman);
+ bool parse(ParserData *data, const Common::String &filename);
+ virtual bool handleChunk(DgdsChunk &chunk, ParserData *data) { return false; };
static Common::HashMap<uint16, Common::String> readTags(Common::SeekableReadStream *stream);
+
+protected:
+ Common::String _filename;
+
+private:
+ ResourceManager *_resman;
+ Decompressor _decomp;
};
class TTMParser : public DgdsParser {
public:
- TTMParser(Common::SeekableReadStream &file, const Common::String &filename) : DgdsParser(file, filename) {}
+ TTMParser(ResourceManager *resman) : DgdsParser(resman) {}
private:
- bool callback(DgdsChunk &chunk, DgdsScriptData *data);
+ bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
};
class ADSParser : public DgdsParser {
public:
- ADSParser(Common::SeekableReadStream &file, const Common::String &filename) : DgdsParser(file, filename) {}
+ ADSParser(ResourceManager *resman) : DgdsParser(resman) {}
private:
- bool callback(DgdsChunk &chunk, DgdsScriptData *data);
+ bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
};
} // End of namespace Dgds
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
new file mode 100644
index 00000000000..1102a52dd04
--- /dev/null
+++ b/engines/dgds/request.cpp
@@ -0,0 +1,201 @@
+/* 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/debug.h"
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "dgds/includes.h"
+#include "dgds/request.h"
+#include "dgds/resource.h"
+
+namespace Dgds {
+
+Request::Request(ResourceManager *resman) : DgdsParser(resman) {
+}
+
+
+bool Request::parseGADChunk(RequestData &data, DgdsChunk &chunk, int num) {
+ Common::SeekableReadStream *str = chunk._stream;
+
+ uint16 numGadgets = str->readUint16LE();
+ data._gadgets.resize(numGadgets);
+ for (Common::SharedPtr<Gadget> &gptr : data._gadgets) {
+ uint16 vals[12];
+ for (int i = 0; i < 12; i++)
+ vals[i] = str->readUint16LE();
+
+ uint16 gadgetTypeFlag = vals[5];
+ if (num == 0 || num == vals[0]) {
+ if (gadgetTypeFlag == 1)
+ gptr.reset(new Gadget1());
+ else if (gadgetTypeFlag == 2)
+ gptr.reset(new Gadget2());
+ else if (gadgetTypeFlag == 8)
+ gptr.reset(new Gadget8());
+ else
+ gptr.reset(new Gadget());
+ }
+
+ gptr->_gadgetNo = vals[0];
+ gptr->_x = vals[1];
+ gptr->_y = vals[2];
+ gptr->_width = vals[3];
+ gptr->_height = vals[4];
+ gptr->_gadgetType = vals[5];
+ gptr->_flags2 = vals[6];
+ gptr->_flags3 = vals[7];
+ gptr->_field14_0x20 = vals[8];
+ gptr->_field15_0x22 = vals[9];
+ gptr->_field15_0x22 = vals[10];
+ gptr->_field16_0x24 = vals[11];
+ gptr->_parentX = data._x;
+ gptr->_parentY = data._y;
+
+ uint16 type1 = str->readUint16LE();
+ if (type1 == 1) {
+ Common::String s = str->readString();
+ if (gptr)
+ gptr->_sval1S = s;
+ } else {
+ uint16 i = str->readUint16LE();
+ if (gptr)
+ gptr->_sval1I = i;
+ }
+
+ uint16 type2 = str->readUint16LE();
+ if (type2 == 1) {
+ Common::String s = str->readString();
+ if (gptr)
+ gptr->_sval2S = s;
+ } else {
+ uint16 i = str->readUint16LE();
+ if (gptr)
+ gptr->_sval2I = i;
+ }
+
+ uint16 type3 = str->readUint16LE();
+
+ // TODO: In each of these cases, work out the true offsets to these fields.
+ // and if they are shared between gadget types.
+ switch (gadgetTypeFlag) {
+ case 1: {
+ uint16 i1 = str->readUint16LE();
+ uint16 i2 = str->readUint16LE();
+ if (gptr) {
+ Gadget1 *g1 = static_cast<Gadget1 *>(gptr.get());
+ // TODO: These fields might are actually shared with other gadget types?
+ g1->_gadget1_i1 = i1;
+ g1->_gadget1_i2 = i2;
+ }
+ break;
+ }
+ case 2: {
+ uint16 i1 = str->readUint16LE();
+ uint16 i2 = str->readUint16LE();
+ uint16 i3 = str->readUint16LE();
+ uint16 i4 = str->readUint16LE();
+ if (gptr) {
+ Gadget2 *g2 = static_cast<Gadget2 *>(gptr.get());
+ g2->_gadget2_i1 = i1;
+ g2->_gadget2_i2 = i2;
+ g2->_gadget2_i3 = i3;
+ g2->_gadget2_i4 = i4;
+ }
+ break;
+ }
+ case 4: {
+ Common::String s = str->readString();
+ if (gptr)
+ gptr->_sval3 = s;
+ break;
+ }
+ case 8: {
+ uint16 i1 = str->readUint16LE();
+ uint16 i2 = str->readUint16LE();
+ if (gptr) {
+ Gadget8 *g8 = static_cast<Gadget8 *>(gptr.get());
+ g8->_gadget8_i1 = i1;
+ g8->_gadget8_i2 = i2;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return str->err();
+}
+
+
+bool Request::parseREQChunk(RequestData &data, DgdsChunk &chunk, int num) {
+ Common::SeekableReadStream *str = chunk._stream;
+
+ uint16 fileNum = str->readUint16LE();
+
+ if (num != 0 && num != fileNum)
+ return true;
+
+ data._fileNum = fileNum;
+ data._x = str->readUint16LE();
+ data._y = str->readUint16LE();
+ for (int i = 0; i < 5; i++)
+ data._vals[i] = str->readUint16LE();
+
+ uint16 numStruct1 = str->readUint16LE();
+ data._struct1List.resize(numStruct1);
+ for (int i = 0; i < numStruct1; i++) {
+ RequestStruct1 &dst = data._struct1List[i];
+ for (int j = 0; j < 4; j++) {
+ dst._vals[j] = str->readUint16LE();
+ }
+ dst._str = str->readString();
+ }
+
+ uint16 numStruct2 = str->readUint16LE();
+ data._struct2List.resize(numStruct2);
+ for (int i = 0; i < numStruct2; i++) {
+ RequestStruct2 &dst = data._struct2List[i];
+ for (int j = 0; j < 6; j++) {
+ dst._vals[j] = str->readUint16LE();
+ }
+ }
+
+ return str->err();
+}
+
+
+bool Request::handleChunk(DgdsChunk &chunk, ParserData *data) {
+ RequestData &rdata = *(RequestData *)data;
+ int num = -1;
+
+ if (chunk._id == ID_REQ)
+ parseREQChunk(rdata, chunk, num);
+ else if (chunk._id == ID_GAD)
+ parseGADChunk(rdata, chunk, num);
+
+ return chunk._stream->err();
+}
+
+
+} // End of namespace Dgds
+
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
new file mode 100644
index 00000000000..083e447484c
--- /dev/null
+++ b/engines/dgds/request.h
@@ -0,0 +1,126 @@
+/* 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 DGDS_REQUEST_H
+#define DGDS_REQUEST_H
+
+#include "common/stream.h"
+#include "common/array.h"
+
+#include "dgds/parser.h"
+
+namespace Dgds {
+
+struct RequestStruct1 {
+ uint16 _vals[4];
+ Common::String _str;
+};
+
+struct RequestStruct2 {
+ uint16 _vals[6];
+};
+
+// basic gadget is 52 (0x34) bytes
+struct Gadget {
+ // NOTE: Most of these names are still guesses
+ uint16 _gadgetNo;
+ uint16 _x;
+ uint16 _y;
+ uint16 _width;
+ uint16 _height;
+ uint16 _gadgetType;
+ uint16 _flags2;
+ uint16 _flags3;
+
+ uint16 _sval1Type; // if 1 then use the string, else use the int
+ Common::String _sval1S;
+ uint16 _sval1I;
+
+ uint16 _sval2Type; // if 1 then use the string, else use the int
+ Common::String _sval2S;
+ uint16 _sval2I;
+
+ Common::String _sval3;
+
+ // some other fields..
+ uint16 _field14_0x20;
+ uint16 _field15_0x22;
+ uint16 _field16_0x24;
+ uint16 _field17_0x26;
+
+ uint16 _parentX;
+ uint16 _parentY;
+};
+
+// extended gadget type 1 is 62 (0x3e) bytes
+struct Gadget1 : public Gadget {
+ uint16 _gadget1_i1;
+ uint16 _gadget1_i2;
+};
+
+// extended gadget type 2 is 74 (0x4a) bytes
+struct Gadget2 : public Gadget {
+ uint16 _gadget2_i1;
+ uint16 _gadget2_i2;
+ uint16 _gadget2_i3;
+ uint16 _gadget2_i4;
+};
+
+// extended gadget type 8 is 68 (0x44) bytes
+struct Gadget8 : public Gadget {
+ uint16 _gadget8_i1;
+ uint16 _gadget8_i2;
+};
+
+class RequestData : public ParserData {
+public:
+ uint16 _fileNum;
+ uint16 _x;
+ uint16 _y;
+ uint16 _vals[7];
+ Common::Array<RequestStruct1> _struct1List;
+ Common::Array<RequestStruct2> _struct2List;
+ Common::Array<Common::SharedPtr<Gadget>> _gadgets;
+};
+
+/**
+ * A "Request" is described by a REQ file. Requests are things like menus,
+ * inventory items, etc.
+ *
+ * Request files include REQ and GAD (Gadget) chunks.
+ */
+class Request : public DgdsParser {
+public:
+ Request(ResourceManager *resman);
+
+ bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
+
+protected:
+ bool parseREQChunk(RequestData &data, DgdsChunk &chunk, int num);
+ bool parseGADChunk(RequestData &data, DgdsChunk &chunk, int num);
+
+};
+
+
+} // End of namespace Dgds
+
+#endif // DGDS_REQUEST_H
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 4d7d408a4d2..932cea08341 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -30,7 +30,6 @@
#include "common/substream.h"
#include "dgds/decompress.h"
#include "dgds/includes.h"
-#include "dgds/parser.h"
namespace Dgds {
@@ -219,24 +218,26 @@ bool DgdsChunk::isPacked(DGDS_EX ex) const {
return packed;
}
-bool DgdsChunk::readHeader(DgdsParser &ctx) {
+bool DgdsChunk::readHeader(Common::SeekableReadStream *file, const Common::String &filename) {
memset(_idStr, 0, sizeof(_idStr));
_id = 0;
- if (ctx._file.pos() >= ctx._file.size()) {
+ if (file->pos() >= file->size()) {
return false;
}
+
+ _stream = file;
- ctx._file.read(_idStr, DGDS_TYPENAME_MAX);
+ file->read(_idStr, DGDS_TYPENAME_MAX);
if (_idStr[DGDS_TYPENAME_MAX - 1] != ':') {
- debug("bad header in: %s", ctx._filename.c_str());
+ debug("bad header in: %s", filename.c_str());
return false;
}
_idStr[DGDS_TYPENAME_MAX] = '\0';
_id = MKTAG24(uint32(_idStr[0]), uint32(_idStr[1]), uint32(_idStr[2]));
- _size = ctx._file.readUint32LE();
+ _size = file->readUint32LE();
//ctx._file.skip(2);
if (_size & 0x80000000) {
_size &= ~0x80000000;
@@ -247,31 +248,29 @@ bool DgdsChunk::readHeader(DgdsParser &ctx) {
return true;
}
-Common::SeekableReadStream* DgdsChunk::getStream(DGDS_EX ex, DgdsParser& ctx, Decompressor* decompressor) {
- return isPacked(ex) ? decodeStream(ctx, decompressor) : readStream(ctx);
+Common::SeekableReadStream* DgdsChunk::getStream(DGDS_EX ex, Common::SeekableReadStream *file, Decompressor* decompressor) {
+ return isPacked(ex) ? decodeStream(file, decompressor) : readStream(file);
}
-Common::SeekableReadStream *DgdsChunk::decodeStream(DgdsParser &ctx, Decompressor *decompressor) {
+Common::SeekableReadStream *DgdsChunk::decodeStream(Common::SeekableReadStream *file, Decompressor *decompressor) {
Common::SeekableReadStream *output = 0;
_size -= (1 + 4);
if (!_container) {
uint32 uncompressedSize;
- byte *data = decompressor->decompress(&ctx._file, _size, uncompressedSize);
+ byte *data = decompressor->decompress(file, _size, uncompressedSize);
output = new Common::MemoryReadStream(data, uncompressedSize, DisposeAfterUse::YES);
- ctx._bytesRead += uncompressedSize;
}
return output;
}
-Common::SeekableReadStream *DgdsChunk::readStream(DgdsParser &ctx) {
+Common::SeekableReadStream *DgdsChunk::readStream(Common::SeekableReadStream *file) {
Common::SeekableReadStream *output = 0;
if (!_container) {
- output = new Common::SeekableSubReadStream(&ctx._file, ctx._file.pos(), ctx._file.pos() + _size, DisposeAfterUse::NO);
- ctx._bytesRead += _size;
+ output = new Common::SeekableSubReadStream(file, file->pos(), file->pos() + _size, DisposeAfterUse::NO);
}
debug(" %s %u%c", _idStr, _size, (_container ? '+' : ' '));
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index bf610f81bdf..3e55c400b57 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -33,7 +33,6 @@ class SeekableReadStream;
namespace Dgds {
-class DgdsParser;
class Decompressor;
typedef uint32 DGDS_ID;
@@ -72,9 +71,9 @@ public:
bool isSection(DGDS_ID section) const;
static bool isFlatfile(DGDS_EX ext);
- bool readHeader(DgdsParser &ctx);
- Common::SeekableReadStream *readStream(DgdsParser &ctx);
- Common::SeekableReadStream *getStream(DGDS_EX ex, DgdsParser &ctx, Decompressor *decompressor);
+ bool readHeader(Common::SeekableReadStream *file, const Common::String &filename);
+ Common::SeekableReadStream *readStream(Common::SeekableReadStream *file);
+ Common::SeekableReadStream *getStream(DGDS_EX ex, Common::SeekableReadStream *file, Decompressor *decompressor);
char _idStr[DGDS_TYPENAME_MAX + 1];
DGDS_ID _id;
@@ -84,7 +83,7 @@ public:
private:
bool isPacked(DGDS_EX ex) const;
- Common::SeekableReadStream *decodeStream(DgdsParser &ctx, Decompressor *decompressor);
+ Common::SeekableReadStream *decodeStream(Common::SeekableReadStream *file, Decompressor *decompressor);
};
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 227cc668602..25f8885ac85 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -80,6 +80,7 @@ struct SceneStruct4 {
Common::Array<struct SceneStruct5> struct5List;
};
+
struct Dialogue {
uint16 num;
Rect rect;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index b456bcaa872..d17adefa5a1 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -51,20 +51,8 @@ static Common::String _bmpNames[16];
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
- Common::SeekableReadStream *stream = _vm->getResourceManager()->getResource(filename);
- Decompressor *decompressor = _vm->getDecompressor();
-
- if (!stream) {
- error("Couldn't open script file '%s'", filename.c_str());
- return false;
- }
-
- TTMParser dgds(*stream, filename);
- dgds.parse(scriptData, decompressor);
-
- delete stream;
-
- return true;
+ TTMParser dgds(_vm->getResourceManager());
+ return dgds.parse(scriptData, filename);
}
void TTMInterpreter::unload(TTMData *data) {
@@ -322,20 +310,11 @@ bool TTMInterpreter::run(TTMState *script) {
ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(nullptr) {}
bool ADSInterpreter::load(const Common::String &filename, ADSData *scriptData) {
- Common::SeekableReadStream *stream = _vm->getResource(filename, false);
-
- if (!stream) {
- error("Couldn't open script resource '%s'", filename.c_str());
- return false;
- }
-
_scriptData = scriptData;
_filename = filename;
- ADSParser dgds(*stream, _filename);
- dgds.parse(scriptData, _vm->getDecompressor());
-
- delete stream;
+ ADSParser dgds(_vm->getResourceManager());
+ dgds.parse(scriptData, filename);
TTMInterpreter interp(_vm);
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 65e30bac684..e00afc1e933 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -24,21 +24,23 @@
#define DGDS_SCRIPTS_H
#include "common/rect.h"
+#include "dgds/parser.h"
namespace Dgds {
class DgdsEngine;
class DgdsChunk;
-class DgdsScriptData {
+
+class ScriptParserData : public ParserData {
public:
- DgdsScriptData() : scr(nullptr) {}
+ ScriptParserData() : scr(nullptr) {}
Common::String filename;
Common::SeekableReadStream *scr;
Common::HashMap<uint16, Common::String> _tags;
};
-class TTMData : public DgdsScriptData {
+class TTMData : public ScriptParserData {
public:
};
@@ -49,7 +51,7 @@ struct TTMState {
int delay;
};
-class ADSData : public DgdsScriptData {
+class ADSData : public ScriptParserData {
public:
ADSData() : count(0), scriptDatas(nullptr) {}
uint16 count;
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index c2b29ca79fc..0518b0b84a0 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -149,16 +149,15 @@ void Sound::playMacMusic(const Common::String &filename) {
if (!musicStream)
error("Music file %s not found", filename.c_str());
- DgdsParser ctx(*musicStream, filename);
DgdsChunk chunk;
const DGDS_EX ex = EX_SNG;
- while (chunk.readHeader(ctx)) {
+ while (chunk.readHeader(musicStream, filename)) {
if (chunk._container) {
continue;
}
- Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, musicStream, _decompressor);
if (chunk.isSection(ID_INF)) {
uint16 type = stream->readUint16LE();
@@ -202,16 +201,15 @@ void Sound::playMusic(const Common::String &filename) {
if (!musicStream)
error("Music file %s not found", filename.c_str());
- DgdsParser ctx(*musicStream, filename);
DgdsChunk chunk;
const DGDS_EX ex = EX_SNG;
- while (chunk.readHeader(ctx)) {
+ while (chunk.readHeader(musicStream, filename)) {
if (chunk._container) {
continue;
}
- Common::SeekableReadStream *stream = chunk.getStream(ex, ctx, _decompressor);
+ Common::SeekableReadStream *stream = chunk.getStream(ex, musicStream, _decompressor);
if (chunk.isSection(ID_SNG)) {
_musicSize = stream->size();
Commit: 4c4d8b9c3defd1dd37a82a748f9656881e6e6d9e
https://github.com/scummvm/scummvm/commit/4c4d8b9c3defd1dd37a82a748f9656881e6e6d9e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix some clang warnings
Changed paths:
engines/dgds/dgds.h
engines/dgds/parser.h
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 664efd4ffbd..ff347b14788 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -60,6 +60,8 @@ class DgdsEngine : public Engine {
public:
Common::Platform _platform;
Sound *_soundPlayer;
+ Image *_image;
+ Graphics::ManagedSurface _resData;
private:
Console *_console;
@@ -76,13 +78,12 @@ private:
PFont *_fntP;
FFont *_fntF;
-protected:
- virtual Common::Error run() override;
-
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
virtual ~DgdsEngine();
+ virtual Common::Error run() override;
+
DgdsGameId getGameId() { return _gameId; }
Graphics::Surface &getTopBuffer() { return _topBuffer; }
@@ -92,8 +93,6 @@ public:
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
const PFont *getFntP() const { return _fntP; }
- Image *_image;
- Graphics::ManagedSurface _resData;
private:
void parseFile(const Common::String &filename);
diff --git a/engines/dgds/parser.h b/engines/dgds/parser.h
index 0c9e0e6a393..461bd8d7fb1 100644
--- a/engines/dgds/parser.h
+++ b/engines/dgds/parser.h
@@ -38,7 +38,10 @@ public:
uint32 _bytesRead;
Common::SeekableReadStream *_file;
+
+public:
DgdsParser(ResourceManager *resman);
+ virtual ~DgdsParser() {};
bool parse(ParserData *data, const Common::String &filename);
virtual bool handleChunk(DgdsChunk &chunk, ParserData *data) { return false; };
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 1102a52dd04..128cc0af3be 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -93,7 +93,8 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunk &chunk, int num) {
gptr->_sval2I = i;
}
- uint16 type3 = str->readUint16LE();
+ // FIXME: Where is this used?
+ /*uint16 type3 = */str->readUint16LE();
// TODO: In each of these cases, work out the true offsets to these fields.
// and if they are shared between gadget types.
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 083e447484c..5fa929dfdab 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -111,6 +111,7 @@ public:
class Request : public DgdsParser {
public:
Request(ResourceManager *resman);
+ virtual ~Request() {}
bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 25f8885ac85..d3376a77c2e 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -122,6 +122,7 @@ struct DialogueSubstring {
class Scene {
public:
Scene();
+ virtual ~Scene() {};
virtual bool parse(Common::SeekableReadStream *s) = 0;
@@ -153,7 +154,7 @@ public:
bool parseInf(Common::SeekableReadStream *s);
private:
- byte _unk[32];
+ //byte _unk[32];
Common::String _iconFile;
Common::Array<struct SceneStruct2_Extended> _struct2ExtList;
Common::Array<struct SceneStruct5> _struct5List1;
@@ -179,17 +180,17 @@ private:
Common::Array<struct SceneStruct5> _struct5List2;
Common::Array<struct SceneStruct5> _struct5List3;
Common::Array<struct SceneStruct5> _struct5List4;
- uint _field5_0x12;
+ //uint _field5_0x12;
uint _field6_0x14;
Common::String _adsFile;
- uint _field8_0x23;
+ //uint _field8_0x23;
Common::Array<struct SceneStruct2> _struct2List;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
- uint _field12_0x2b;
+ //uint _field12_0x2b;
Common::Array<struct Dialogue> _dialogues;
Common::Array<struct SceneStruct7> _struct7List;
- uint _field15_0x33;
+ //uint _field15_0x33;
};
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index d17adefa5a1..9ad4ab09585 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -43,12 +43,9 @@
namespace Dgds {
// FIXME: Move these into some state
-static int currentBmpId = 0;
-static Dialogue _text;
-static Common::Rect _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
static Common::String _bmpNames[16];
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
TTMParser dgds(_vm->getResourceManager());
@@ -129,7 +126,7 @@ bool TTMInterpreter::run(TTMState *script) {
continue;
case 0xf020:
// LOAD BMP: filename:str
- _bmpNames[currentBmpId] = sval;
+ _bmpNames[_currentBmpId] = sval;
continue;
case 0xf050:
// LOAD PAL: filename:str
@@ -150,13 +147,13 @@ bool TTMInterpreter::run(TTMState *script) {
// SET BMP: id:int [-1:n]
int bk = ivals[0];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[currentBmpId], bk);
+ _vm->_image->loadBitmap(_bmpNames[_currentBmpId], bk);
}
continue;
}
case 0x1050:
// SELECT BMP: id:int [0:n]
- currentBmpId = ivals[0];
+ _currentBmpId = ivals[0];
continue;
case 0x1060:
// SELECT SCR|PAL: id:int [0]
@@ -225,20 +222,20 @@ bool TTMInterpreter::run(TTMState *script) {
case 0xa520:
//DRAW BMP: x,y:int ; happens once in INTRO.TTM
case 0xa500:
- debug("DRAW \"%s\"", _bmpNames[currentBmpId].c_str());
+ debug("DRAW \"%s\"", _bmpNames[_currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
int bk = ivals[2];
- currentBmpId = ivals[3];
+ _currentBmpId = ivals[3];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[currentBmpId], bk);
+ _vm->_image->loadBitmap(_bmpNames[_currentBmpId], bk);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", currentBmpId, _bmpNames[currentBmpId].c_str());
- _vm->_image->loadBitmap(_bmpNames[currentBmpId], 0);
+ warning("trying to load bmp %d (%s) on demand", _currentBmpId, _bmpNames[_currentBmpId].c_str());
+ _vm->_image->loadBitmap(_bmpNames[_currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
@@ -377,12 +374,9 @@ bool ADSInterpreter::run(ADSState *script) {
return false;
do {
- uint16 code;
- byte count;
- uint op;
- code = scr->readUint16LE();
- count = code & 0x000F;
- op = code & 0xFFF0;
+ uint16 code = scr->readUint16LE();
+ byte count = code & 0x000F;
+ //uint op = code & 0xFFF0;
if ((code & 0xFF00) == 0) {
continue;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index e00afc1e933..9ee6b8f33f8 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -25,6 +25,7 @@
#include "common/rect.h"
#include "dgds/parser.h"
+#include "dgds/scene.h"
namespace Dgds {
@@ -98,6 +99,9 @@ public:
protected:
DgdsEngine *_vm;
+ Dialogue _text;
+ Common::Rect _drawWin;
+ int _currentBmpId;
//Common::String _filename;
//TTMData *_scriptData;
Commit: 6f1df860d9869b49b9f549113e7936da2db2b4d5
https://github.com/scummvm/scummvm/commit/6f1df860d9869b49b9f549113e7936da2db2b4d5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix decompressor usage
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/parser.cpp
engines/dgds/parser.h
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/resource.cpp
engines/dgds/resource.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
engines/dgds/sound.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index b801d1da624..2552effb907 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -75,17 +75,17 @@ bool Console::cmdFileDump(int argc, const char **argv) {
Common::String fileName = argv[1];
bool ignorePatches = (argc > 2) && (!scumm_stricmp(argv[2], "true") || !strcmp(argv[2], "1"));
bool unpack = (argc > 3) && (!scumm_stricmp(argv[3], "true") || !strcmp(argv[3], "1"));
- Common::SeekableReadStream *res = _vm->getResource(fileName, ignorePatches);
- if (res == nullptr) {
+ Common::SeekableReadStream *resStream = _vm->getResource(fileName, ignorePatches);
+ if (resStream == nullptr) {
debugPrintf("Resource not found\n");
return true;
}
- int32 size = res->size();
+ int32 size = resStream->size();
byte *data;
if (!unpack) {
data = new byte[size];
- res->read(data, size);
+ resStream->read(data, size);
} else {
data = new byte[2000000]; // about 2MB, but maximum container size is around 1.5MB
byte *ptr = data;
@@ -97,22 +97,22 @@ bool Console::cmdFileDump(int argc, const char **argv) {
ex = MKTAG24(dot[1], dot[2], dot[3]);
}
- DgdsChunk chunk;
- while (chunk.readHeader(res, fileName)) {
- Common::SeekableReadStream *stream = chunk.getStream(ex, res, _vm->getDecompressor());
+ DgdsChunkReader chunk(resStream);
+ while (chunk.readNextHeader(ex, fileName)) {
+ chunk.readContent(_vm->getDecompressor());
- memcpy(ptr, chunk._idStr, 4);
+ memcpy(ptr, chunk.getIdStr(), 4);
ptr += 4;
- stream->read(ptr, stream->size());
- ptr += stream->size();
+ chunk.getContent()->read(ptr, chunk.getContent()->size());
+ ptr += chunk.getContent()->size();
- size += 4 + stream->size();
+ size += 4 + chunk.getContent()->size();
}
}
- delete res;
+ delete resStream;
Common::DumpFile out;
out.open(Common::Path(fileName));
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index dbe731461dc..5f271e733b2 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -251,7 +251,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
parseAmigaChunks(file, ex);
}
- if (DgdsChunk::isFlatfile(ex)) {
+ if (DgdsChunkReader::isFlatfile(ex)) {
Common::String line;
switch (ex) {
@@ -276,21 +276,22 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
break;
}
} else {
- DgdsChunk chunk;
+ DgdsChunkReader chunk(&file);
int chunkno = 0;
- while (chunk.readHeader(&file, name)) {
- if (chunk._container) {
- parent = chunk._id;
+ while (chunk.readNextHeader(ex, name)) {
+ if (chunk.isContainer()) {
+ parent = chunk.getId();
continue;
}
- Common::SeekableReadStream *stream = chunk.getStream(ex, &file, _decompressor);
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
#ifdef DUMP_ALL_CHUNKS
{
Common::DumpFile out;
int64 start = stream->pos();
- out.open(Common::Path(Common::String::format("tmp/dgds_%s_%02d_%.3s.dump", name, chunkno, chunk._idStr)));
+ out.open(Common::Path(Common::String::format("tmp/dgds_%s_%02d_%.3s.dump", name, chunkno, chunk.getIdStr())));
out.writeStream(stream);
out.close();
stream->seek(start);
@@ -424,7 +425,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
case EX_GDS:
if (chunk.isSection(ID_GDS)) {
// do nothing, this is the container.
- assert(chunk._container);
+ assert(chunk.isContainer());
} else if (chunk.isSection(ID_INF)) {
_gdsScene->parseInf(stream);
} else if (chunk.isSection(ID_SDS)) {
@@ -558,8 +559,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
int leftover = stream->size() - stream->pos();
//stream->hexdump(leftover);
stream->skip(leftover);
-
- delete stream;
}
}
@@ -601,16 +600,14 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
// Test parsing some things..
parseFile("DRAGON.GDS");
-
+ /*
RequestData invRequestData;
RequestData vcrRequestData;
Request invRequest(_resource);
Request vcrRequest(_resource);
invRequest.parse(&invRequestData, "DINV.REQ");
vcrRequest.parse(&vcrRequestData, "DINV.REQ");
- //Request vcrRequest(vcrRequestData);
-
- //invRequest.parse(
+ */
// Load the intro and play it for now.
interpTTM.load("TITLE1.TTM", &title1Data);
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 01fd697540f..1c7075445aa 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -69,9 +69,10 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
surface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- DgdsChunk chunk;
- while (chunk.readHeader(fileStream, filename)) {
- Common::SeekableReadStream *stream = chunk.getStream(ex, fileStream, _decompressor);
+ DgdsChunkReader chunk(fileStream);
+ while (chunk.readNextHeader(ex, filename)) {
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_BIN)) {
loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, false);
} else if (chunk.isSection(ID_VGA)) {
@@ -93,7 +94,6 @@ void Image::loadBitmap(Common::String filename, int number) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("Couldn't get bitmap resource %s", filename.c_str());
- DgdsChunk chunk;
_bmpData.free();
@@ -115,8 +115,10 @@ void Image::loadBitmap(Common::String filename, int number) {
uint16 tileHeights[64];
int32 tileOffset = 0;
- while (chunk.readHeader(fileStream, filename)) {
- Common::SeekableReadStream *stream = chunk.getStream(ex, fileStream, _decompressor);
+ DgdsChunkReader chunk(fileStream);
+ while (chunk.readNextHeader(ex, filename)) {
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
for (uint16 k = 0; k < tileCount; k++) {
@@ -151,7 +153,7 @@ void Image::loadBitmap(Common::String filename, int number) {
} else if (chunk.isSection(ID_VQT)) {
// Postpone parsing this until we have the offsets, which come after.
vqtpos = fileStream->pos();
- vqtsize = chunk._size;
+ vqtsize = chunk.getSize();
stream->skip(vqtsize);
} else if (chunk.isSection(ID_OFF)) {
if (vqtpos == -1)
@@ -161,7 +163,7 @@ void Image::loadBitmap(Common::String filename, int number) {
// or a single value of 0xffff. If it's only one tile the offset is always
// zero anyway. For subsequent images, round up to the next byte to start
// reading.
- if (chunk._size == 2) {
+ if (chunk.getSize() == 2) {
if (number != 0) {
uint16 val = stream->readUint16LE();
if (val != 0xffff)
@@ -184,7 +186,6 @@ void Image::loadBitmap(Common::String filename, int number) {
loadVQT(_bmpData, tileWidths[number], tileHeights[number], 0, fileStream);
}
}
- delete stream;
}
delete fileStream;
@@ -388,12 +389,13 @@ void Image::loadPalette(Common::String filename) {
return;
}
- DgdsChunk chunk;
- while (chunk.readHeader(fileStream, filename)) {
- Common::SeekableReadStream *stream = chunk.readStream(fileStream);
+ DgdsChunkReader chunk(fileStream);
+ while (chunk.readNextHeader(EX_PAL, filename)) {
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *chunkStream = chunk.getContent();
if (chunk.isSection(ID_VGA)) {
- stream->read(_palette, 256 * 3);
+ chunkStream->read(_palette, 256 * 3);
for (uint k = 0; k < 256 * 3; k += 3) {
_palette[k + 0] <<= 2;
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 7e115748956..e7d926c591d 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -34,7 +34,7 @@ struct Surface;
namespace Dgds {
class Decompressor;
-class DgdsChunk;
+class DgdsChunkReader;
class ResourceManager;
class Image {
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index b178d34ceab..77527cdea85 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -32,47 +32,44 @@
namespace Dgds {
-DgdsParser::DgdsParser(ResourceManager *resman) : _resman(resman), _file(nullptr), _bytesRead(0) {
+DgdsParser::DgdsParser(ResourceManager *resman, Decompressor *decompressor) :
+_resman(resman), _decompressor(decompressor), _bytesRead(0) {
}
bool DgdsParser::parse(ParserData *data, const Common::String &filename) {
- DGDS_EX _ex;
+ DGDS_EX ex;
- Common::SeekableReadStream *stream = _resman->getResource(filename);
+ _filename = filename;
+ Common::SeekableReadStream *resStream = _resman->getResource(filename);
- if (!stream) {
+ if (!resStream) {
error("Couldn't open script file '%s'", filename.c_str());
return false;
}
uint32 dot = _filename.find('.');
if (dot != Common::String::npos) {
- _ex = MKTAG24(toupper(_filename[dot + 1]), toupper(_filename[dot + 2]), toupper(_filename[dot + 3]));
+ ex = MKTAG24(toupper(_filename[dot + 1]), toupper(_filename[dot + 2]), toupper(_filename[dot + 3]));
} else {
- _ex = 0;
+ ex = 0;
}
- DgdsChunk chunk;
- while (chunk.readHeader(_file, _filename)) {
+ DgdsChunkReader chunk(resStream);
+ while (chunk.readNextHeader(ex, _filename)) {
bool stop;
- if (chunk._container) {
- chunk._stream = _file;
+ if (chunk.isContainer()) {
stop = handleChunk(chunk, data);
} else {
- chunk._stream = chunk.getStream(_ex, _file, &_decomp);
-
+ chunk.readContent(_decompressor);
stop = handleChunk(chunk, data);
-
- int leftover = chunk._stream->size() - chunk._stream->pos();
- chunk._stream->skip(leftover);
- delete chunk._stream;
}
+
if (stop)
break;
}
- delete stream;
+ delete resStream;
return true;
}
@@ -93,60 +90,60 @@ Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableRea
}
-bool TTMParser::handleChunk(DgdsChunk &chunk, ParserData *data) {
+bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
TTMData *scriptData = (TTMData *)data;
- switch (chunk._id) {
+ switch (chunk.getId()) {
case ID_TTI: // Ignore containers
break;
case ID_TT3:
- scriptData->scr = chunk._stream->readStream(chunk._stream->size());
+ // Make a memory read stream from the chunk data
+ scriptData->scr = chunk.makeMemoryStream();
break;
case ID_TAG:
- scriptData->_tags = readTags(chunk._stream);
+ scriptData->_tags = readTags(chunk.getContent());
break;
case ID_VER:
case ID_PAG: // Pages - ignore?
- chunk._stream->skip(chunk._size);
+ //chunk._contentStream->skip(chunk._size);
break;
default:
- warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename.c_str());
- chunk._stream->skip(chunk._size);
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk.getId()), chunk.getSize(), _filename.c_str());
+ //chunk._contentStream->skip(chunk._size);
break;
}
return false;
}
-bool ADSParser::handleChunk(DgdsChunk &chunk, ParserData *data) {
+bool ADSParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
ADSData *scriptData = (ADSData *)data;
- switch (chunk._id) {
+ Common::SeekableReadStream *chunkStream = chunk.getContent();
+ switch (chunk.getId()) {
case EX_ADS:
case ID_TTI: // Ignore containers
break;
case ID_RES: {
- uint16 count = chunk._stream->readUint16LE();
+ uint16 count = chunkStream->readUint16LE();
scriptData->count = count;
for (uint16 i = 0; i < count; i++) {
- uint16 idx = chunk._stream->readUint16LE();
+ uint16 idx = chunkStream->readUint16LE();
assert(idx == (i + 1));
- Common::String string = chunk._stream->readString();
+ Common::String string = chunkStream->readString();
scriptData->names.push_back(string);
}
} break;
case ID_SCR:
- scriptData->scr = chunk._stream->readStream(chunk._stream->size());
+ scriptData->scr = chunk.makeMemoryStream();
break;
case ID_TAG:
- scriptData->_tags = readTags(chunk._stream);
+ scriptData->_tags = readTags(chunkStream);
break;
case ID_VER: // Version - ignore
- chunk._stream->skip(chunk._size);
break;
default:
- warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk._id), chunk._size, _filename.c_str());
- chunk._stream->skip(chunk._size);
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk.getId()), chunk.getSize(), _filename.c_str());
break;
}
return false;
diff --git a/engines/dgds/parser.h b/engines/dgds/parser.h
index 461bd8d7fb1..af3299d5297 100644
--- a/engines/dgds/parser.h
+++ b/engines/dgds/parser.h
@@ -23,12 +23,11 @@
#ifndef DGDS_PARSER_H
#define DGDS_PARSER_H
-#include "dgds/decompress.h"
-
namespace Dgds {
-class DgdsChunk;
+class DgdsChunkReader;
class ResourceManager;
+class Decompressor;
class ParserData {};
@@ -36,14 +35,13 @@ class DgdsParser {
public:
// FIXME: Make these private/protected
uint32 _bytesRead;
- Common::SeekableReadStream *_file;
-
+ //Common::SeekableReadStream *_file;
public:
- DgdsParser(ResourceManager *resman);
+ DgdsParser(ResourceManager *resman, Decompressor *decompressor);
virtual ~DgdsParser() {};
bool parse(ParserData *data, const Common::String &filename);
- virtual bool handleChunk(DgdsChunk &chunk, ParserData *data) { return false; };
+ virtual bool handleChunk(DgdsChunkReader &chunk, ParserData *data) { return false; };
static Common::HashMap<uint16, Common::String> readTags(Common::SeekableReadStream *stream);
@@ -52,23 +50,23 @@ protected:
private:
ResourceManager *_resman;
- Decompressor _decomp;
+ Decompressor *_decompressor;
};
class TTMParser : public DgdsParser {
public:
- TTMParser(ResourceManager *resman) : DgdsParser(resman) {}
+ TTMParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {}
private:
- bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
+ bool handleChunk(DgdsChunkReader &chunk, ParserData *data) override;
};
class ADSParser : public DgdsParser {
public:
- ADSParser(ResourceManager *resman) : DgdsParser(resman) {}
+ ADSParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {}
private:
- bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
+ bool handleChunk(DgdsChunkReader &chunk, ParserData *data) override;
};
} // End of namespace Dgds
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 128cc0af3be..88e4a5f83d7 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -30,12 +30,12 @@
namespace Dgds {
-Request::Request(ResourceManager *resman) : DgdsParser(resman) {
+Request::Request(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
}
-bool Request::parseGADChunk(RequestData &data, DgdsChunk &chunk, int num) {
- Common::SeekableReadStream *str = chunk._stream;
+bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
+ Common::SeekableReadStream *str = chunk.getContent();
uint16 numGadgets = str->readUint16LE();
data._gadgets.resize(numGadgets);
@@ -148,8 +148,8 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunk &chunk, int num) {
}
-bool Request::parseREQChunk(RequestData &data, DgdsChunk &chunk, int num) {
- Common::SeekableReadStream *str = chunk._stream;
+bool Request::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
+ Common::SeekableReadStream *str = chunk.getContent();
uint16 fileNum = str->readUint16LE();
@@ -185,16 +185,16 @@ bool Request::parseREQChunk(RequestData &data, DgdsChunk &chunk, int num) {
}
-bool Request::handleChunk(DgdsChunk &chunk, ParserData *data) {
+bool Request::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
RequestData &rdata = *(RequestData *)data;
int num = -1;
- if (chunk._id == ID_REQ)
+ if (chunk.getId() == ID_REQ)
parseREQChunk(rdata, chunk, num);
- else if (chunk._id == ID_GAD)
+ else if (chunk.getId() == ID_GAD)
parseGADChunk(rdata, chunk, num);
- return chunk._stream->err();
+ return chunk.getContent()->err();
}
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 5fa929dfdab..e5933e08177 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -110,14 +110,14 @@ public:
*/
class Request : public DgdsParser {
public:
- Request(ResourceManager *resman);
+ Request(ResourceManager *resman, Decompressor *decompressor);
virtual ~Request() {}
- bool handleChunk(DgdsChunk &chunk, ParserData *data) override;
+ bool handleChunk(DgdsChunkReader &chunk, ParserData *data) override;
protected:
- bool parseREQChunk(RequestData &data, DgdsChunk &chunk, int num);
- bool parseGADChunk(RequestData &data, DgdsChunk &chunk, int num);
+ bool parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num);
+ bool parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num);
};
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 932cea08341..59e7e36d3fd 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -122,18 +122,18 @@ Resource ResourceManager::getResourceInfo(Common::String name) {
return _resources[name];
}
-bool DgdsChunk::isSection(const Common::String §ion) const {
+bool DgdsChunkReader::isSection(const Common::String §ion) const {
return section.equals(_idStr);
}
-bool DgdsChunk::isSection(DGDS_ID section) const {
+bool DgdsChunkReader::isSection(DGDS_ID section) const {
return (section == _id);
}
-bool DgdsChunk::isPacked(DGDS_EX ex) const {
+bool DgdsChunkReader::isPacked() const {
bool packed = false;
- switch (ex) {
+ switch (_ex) {
case EX_ADS:
case EX_ADL:
case EX_ADH:
@@ -162,7 +162,7 @@ bool DgdsChunk::isPacked(DGDS_EX ex) const {
break;
}
- switch (ex) {
+ switch (_ex) {
case EX_DDS:
packed = !strcmp(_idStr, "DDS:");
break;
@@ -218,26 +218,33 @@ bool DgdsChunk::isPacked(DGDS_EX ex) const {
return packed;
}
-bool DgdsChunk::readHeader(Common::SeekableReadStream *file, const Common::String &filename) {
+bool DgdsChunkReader::readNextHeader(DGDS_EX ex, const Common::String &filename) {
+ if (_contentStream) {
+ _sourceStream->seek(_startPos + _size);
+ delete _contentStream;
+ _contentStream = nullptr;
+ }
+ _size = 0;
+
memset(_idStr, 0, sizeof(_idStr));
_id = 0;
+ _ex = ex;
- if (file->pos() >= file->size()) {
+ if (_sourceStream->pos() >= _sourceStream->size()) {
return false;
}
-
- _stream = file;
- file->read(_idStr, DGDS_TYPENAME_MAX);
+ _sourceStream->read(_idStr, DGDS_TYPENAME_MAX);
if (_idStr[DGDS_TYPENAME_MAX - 1] != ':') {
- debug("bad header in: %s", filename.c_str());
+ error("bad header reading chunk from %s at %d", filename.c_str(), (int)_sourceStream->pos() - 4);
return false;
}
_idStr[DGDS_TYPENAME_MAX] = '\0';
_id = MKTAG24(uint32(_idStr[0]), uint32(_idStr[1]), uint32(_idStr[2]));
- _size = file->readUint32LE();
+ _size = _sourceStream->readUint32LE();
+ _startPos = _sourceStream->pos();
//ctx._file.skip(2);
if (_size & 0x80000000) {
_size &= ~0x80000000;
@@ -248,37 +255,50 @@ bool DgdsChunk::readHeader(Common::SeekableReadStream *file, const Common::Strin
return true;
}
-Common::SeekableReadStream* DgdsChunk::getStream(DGDS_EX ex, Common::SeekableReadStream *file, Decompressor* decompressor) {
- return isPacked(ex) ? decodeStream(file, decompressor) : readStream(file);
+bool DgdsChunkReader::readContent(Decompressor* decompressor) {
+ assert(!_contentStream);
+ _contentStream = isPacked() ? decodeStream(decompressor) : readStream();
+ return _contentStream != nullptr;
}
-Common::SeekableReadStream *DgdsChunk::decodeStream(Common::SeekableReadStream *file, Decompressor *decompressor) {
- Common::SeekableReadStream *output = 0;
-
- _size -= (1 + 4);
+Common::SeekableReadStream *DgdsChunkReader::decodeStream(Decompressor *decompressor) {
+ Common::SeekableReadStream *output = nullptr;
if (!_container) {
uint32 uncompressedSize;
- byte *data = decompressor->decompress(file, _size, uncompressedSize);
+ byte *data = decompressor->decompress(_sourceStream, _size - (1 + 4), uncompressedSize);
output = new Common::MemoryReadStream(data, uncompressedSize, DisposeAfterUse::YES);
}
return output;
}
-Common::SeekableReadStream *DgdsChunk::readStream(Common::SeekableReadStream *file) {
- Common::SeekableReadStream *output = 0;
+Common::SeekableReadStream *DgdsChunkReader::readStream() {
+ Common::SeekableReadStream *output = nullptr;
if (!_container) {
- output = new Common::SeekableSubReadStream(file, file->pos(), file->pos() + _size, DisposeAfterUse::NO);
+ output = new Common::SeekableSubReadStream(_sourceStream, _startPos, _startPos + _size, DisposeAfterUse::NO);
}
debug(" %s %u%c", _idStr, _size, (_container ? '+' : ' '));
return output;
}
+Common::SeekableReadStream *DgdsChunkReader::makeMemoryStream() {
+ assert(_contentStream);
+ assert(_contentStream->pos() == 0);
+
+ int64 startPos = _contentStream->pos();
+ int16 dataSize = _contentStream->size() - startPos;
+ byte *data = (byte *)malloc(dataSize);
+ _contentStream->read(data, dataSize);
+ Common::MemoryReadStream *output = new Common::MemoryReadStream(data, dataSize, DisposeAfterUse::YES);
+ _contentStream->seek(startPos);
+ return output;
+}
+
/*static*/
-bool DgdsChunk::isFlatfile(DGDS_EX ext) {
+bool DgdsChunkReader::isFlatfile(DGDS_EX ext) {
bool flat = false;
switch (ext) {
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index 3e55c400b57..43c20045276 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -26,10 +26,7 @@
#include "common/file.h"
#include "common/hashmap.h"
#include "common/platform.h"
-
-namespace Common {
-class SeekableReadStream;
-}
+#include "common/stream.h"
namespace Dgds {
@@ -65,25 +62,46 @@ private:
ResourceList _resources;
};
-class DgdsChunk {
+class DgdsChunkReader {
public:
+ DgdsChunkReader(Common::SeekableReadStream *stream) : _sourceStream(stream), _contentStream(nullptr), _size(0), _container(false), _startPos(0) {}
+
bool isSection(const Common::String §ion) const;
bool isSection(DGDS_ID section) const;
static bool isFlatfile(DGDS_EX ext);
- bool readHeader(Common::SeekableReadStream *file, const Common::String &filename);
- Common::SeekableReadStream *readStream(Common::SeekableReadStream *file);
- Common::SeekableReadStream *getStream(DGDS_EX ex, Common::SeekableReadStream *file, Decompressor *decompressor);
+ bool readNextHeader(DGDS_EX ex, const Common::String &filename);
+
+ /// Get a stream of the (decompressed if appropriate) content.
+ /// This stream is owned by this object and invalidated when
+ /// another header or content block is read. Do not delete it.
+ bool readContent(Decompressor *decompressor);
+
+ // Duplicate the buffer in the current content stream so
+ // that it can be retained in another object.
+ Common::SeekableReadStream *makeMemoryStream();
+
+ Common::SeekableReadStream *getContent() { return _contentStream; }
+
+ bool isContainer() const { return _container; }
+ DGDS_ID getId() const { return _id; }
+ const char *getIdStr() const { return _idStr; }
+ uint32 getSize() const { return _size; }
+ DGDS_EX _ex;
+
+private:
+ uint32 _size;
+ uint64 _startPos;
char _idStr[DGDS_TYPENAME_MAX + 1];
DGDS_ID _id;
- uint32 _size;
bool _container;
- Common::SeekableReadStream *_stream;
+ Common::SeekableReadStream *_contentStream;
+ Common::SeekableReadStream *_sourceStream;
-private:
- bool isPacked(DGDS_EX ex) const;
- Common::SeekableReadStream *decodeStream(Common::SeekableReadStream *file, Decompressor *decompressor);
+ bool isPacked() const;
+ Common::SeekableReadStream *decodeStream(Decompressor *decompressor);
+ Common::SeekableReadStream *readStream();
};
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 9ad4ab09585..1bec6dfcdfc 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -48,7 +48,7 @@ static Common::String _bmpNames[16];
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
- TTMParser dgds(_vm->getResourceManager());
+ TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
return dgds.parse(scriptData, filename);
}
@@ -89,6 +89,9 @@ bool TTMInterpreter::run(TTMState *script) {
code = scr->readUint16LE();
count = code & 0x000F;
op = code & 0xFFF0;
+
+ if (count > 8 && count != 0x0f)
+ error("Invalid TTM opcode %04x requires %d locals", code, count);
debugN("\tOP: 0x%4.4x %2u ", op, count);
if (count == 0x0F) {
@@ -310,7 +313,7 @@ bool ADSInterpreter::load(const Common::String &filename, ADSData *scriptData) {
_scriptData = scriptData;
_filename = filename;
- ADSParser dgds(_vm->getResourceManager());
+ ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
dgds.parse(scriptData, filename);
TTMInterpreter interp(_vm);
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 9ee6b8f33f8..b9d36e3c53f 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -30,7 +30,7 @@
namespace Dgds {
class DgdsEngine;
-class DgdsChunk;
+class DgdsChunkReader;
class ScriptParserData : public ParserData {
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 0518b0b84a0..af78042c228 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -149,15 +149,16 @@ void Sound::playMacMusic(const Common::String &filename) {
if (!musicStream)
error("Music file %s not found", filename.c_str());
- DgdsChunk chunk;
+ DgdsChunkReader chunk(musicStream);
const DGDS_EX ex = EX_SNG;
- while (chunk.readHeader(musicStream, filename)) {
- if (chunk._container) {
+ while (chunk.readNextHeader(ex, filename)) {
+ if (chunk.isContainer()) {
continue;
}
- Common::SeekableReadStream *stream = chunk.getStream(ex, musicStream, _decompressor);
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_INF)) {
uint16 type = stream->readUint16LE();
@@ -175,8 +176,6 @@ void Sound::playMacMusic(const Common::String &filename) {
/*uint16 type = */ stream->readUint16LE();
_musicData = _decompressor->decompress(stream, stream->size() - stream->pos(), _musicSize);
}
-
- delete stream;
}
delete musicStream;
@@ -201,15 +200,17 @@ void Sound::playMusic(const Common::String &filename) {
if (!musicStream)
error("Music file %s not found", filename.c_str());
- DgdsChunk chunk;
+ DgdsChunkReader chunk(musicStream);
const DGDS_EX ex = EX_SNG;
- while (chunk.readHeader(musicStream, filename)) {
- if (chunk._container) {
+ while (chunk.readNextHeader(ex, filename)) {
+ if (chunk.isContainer()) {
continue;
}
+
+ chunk.readContent(_decompressor);
- Common::SeekableReadStream *stream = chunk.getStream(ex, musicStream, _decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_SNG)) {
_musicSize = stream->size();
@@ -223,8 +224,6 @@ void Sound::playMusic(const Common::String &filename) {
debug(" %2u: %u", k, idx);
}
}
-
- delete stream;
}
delete musicStream;
Commit: 527c5037b989cf743ca213c2d7abe30a61e44798
https://github.com/scummvm/scummvm/commit/527c5037b989cf743ca213c2d7abe30a61e44798
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: move bmpId and drawWin to script state
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 1bec6dfcdfc..d3a6738850f 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -45,7 +45,7 @@ namespace Dgds {
// FIXME: Move these into some state
static Common::String _bmpNames[16];
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
@@ -129,7 +129,7 @@ bool TTMInterpreter::run(TTMState *script) {
continue;
case 0xf020:
// LOAD BMP: filename:str
- _bmpNames[_currentBmpId] = sval;
+ _bmpNames[script->_currentBmpId] = sval;
continue;
case 0xf050:
// LOAD PAL: filename:str
@@ -150,13 +150,13 @@ bool TTMInterpreter::run(TTMState *script) {
// SET BMP: id:int [-1:n]
int bk = ivals[0];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[_currentBmpId], bk);
+ _vm->_image->loadBitmap(_bmpNames[script->_currentBmpId], bk);
}
continue;
}
case 0x1050:
// SELECT BMP: id:int [0:n]
- _currentBmpId = ivals[0];
+ script->_currentBmpId = ivals[0];
continue;
case 0x1060:
// SELECT SCR|PAL: id:int [0]
@@ -225,25 +225,25 @@ bool TTMInterpreter::run(TTMState *script) {
case 0xa520:
//DRAW BMP: x,y:int ; happens once in INTRO.TTM
case 0xa500:
- debug("DRAW \"%s\"", _bmpNames[_currentBmpId].c_str());
+ debug("DRAW \"%s\"", _bmpNames[script->_currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
int bk = ivals[2];
- _currentBmpId = ivals[3];
+ script->_currentBmpId = ivals[3];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[_currentBmpId], bk);
+ _vm->_image->loadBitmap(_bmpNames[script->_currentBmpId], bk);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", _currentBmpId, _bmpNames[_currentBmpId].c_str());
- _vm->_image->loadBitmap(_bmpNames[_currentBmpId], 0);
+ warning("trying to load bmp %d (%s) on demand", script->_currentBmpId, _bmpNames[script->_currentBmpId].c_str());
+ _vm->_image->loadBitmap(_bmpNames[script->_currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], _drawWin, _vm->getTopBuffer());
+ _vm->_image->drawBitmap(ivals[0], ivals[1], script->_drawWin, _vm->getTopBuffer());
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
continue;
@@ -266,7 +266,7 @@ bool TTMInterpreter::run(TTMState *script) {
case 0x4000:
//SET WINDOW? x,y,w,h:int [0..320,0..200]
- _drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ script->_drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
continue;
case 0xa100:
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index b9d36e3c53f..4b80b93ee9a 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -46,10 +46,12 @@ public:
};
struct TTMState {
- TTMState() : dataPtr(nullptr), scene(0), delay(0) {}
+ TTMState() : dataPtr(nullptr), scene(0), delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
const TTMData *dataPtr;
uint16 scene;
int delay;
+ Common::Rect _drawWin;
+ int _currentBmpId;
};
class ADSData : public ScriptParserData {
@@ -100,8 +102,6 @@ protected:
DgdsEngine *_vm;
Dialogue _text;
- Common::Rect _drawWin;
- int _currentBmpId;
//Common::String _filename;
//TTMData *_scriptData;
Commit: 9f72cad6e77fa7a0f74d60ed12afe642948f112a
https://github.com/scummvm/scummvm/commit/9f72cad6e77fa7a0f74d60ed12afe642948f112a
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactor the TTM and ADS player and remove external data and state
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/parser.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 5f271e733b2..6df3f7af264 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -590,12 +590,8 @@ Common::Error DgdsEngine::run() {
Common::Event ev;
ADSInterpreter interpADS(this);
- TTMInterpreter interpTTM(this);
-
- TTMState title1State, title2State;
- ADSState adsState;
- TTMData title1Data, title2Data;
- ADSData adsData;
+ TTMInterpreter interpTTM1(this);
+ TTMInterpreter interpTTM2(this);
if (getGameId() == GID_DRAGON) {
// Test parsing some things..
@@ -610,26 +606,18 @@ Common::Error DgdsEngine::run() {
*/
// Load the intro and play it for now.
- interpTTM.load("TITLE1.TTM", &title1Data);
- interpTTM.load("TITLE2.TTM", &title2Data);
- interpADS.load("INTRO.ADS", &adsData);
-
- interpTTM.init(&title1State, &title1Data);
- interpTTM.init(&title2State, &title2Data);
- interpADS.init(&adsState, &adsData);
+ interpTTM1.load("TITLE1.TTM");
+ interpTTM2.load("TITLE2.TTM");
+ interpADS.load("INTRO.ADS");
parseFile("DRAGON.FNT");
parseFile("S55.SDS");
} else if (getGameId() == GID_CHINA) {
- interpADS.load("TITLE.ADS", &adsData);
-
- interpADS.init(&adsState, &adsData);
+ interpADS.load("TITLE.ADS");
parseFile("HOC.FNT");
} else if (getGameId() == GID_BEAMISH) {
- interpADS.load("TITLE.ADS", &adsData);
-
- interpADS.init(&adsState, &adsData);
+ interpADS.load("TITLE.ADS");
//parseFile("HOC.FNT");
}
@@ -655,15 +643,13 @@ Common::Error DgdsEngine::run() {
}
}
- // browse(_platform, _rmfName, this);
-
if (getGameId() == GID_DRAGON) {
- if (!interpTTM.run(&title1State))
- if (!interpTTM.run(&title2State))
- if (!interpADS.run(&adsState))
+ //if (!interpTTM1.run())
+ // if (!interpTTM2.run())
+ if (!interpADS.run())
return Common::kNoError;
} else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
- if (!interpADS.run(&adsState))
+ if (!interpADS.run())
return Common::kNoError;
}
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 77527cdea85..e450434fb50 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -125,7 +125,6 @@ bool ADSParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
case ID_RES: {
uint16 count = chunkStream->readUint16LE();
- scriptData->count = count;
for (uint16 i = 0; i < count; i++) {
uint16 idx = chunkStream->readUint16LE();
assert(idx == (i + 1));
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index d3a6738850f..1eead235db8 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -42,53 +42,39 @@
namespace Dgds {
-// FIXME: Move these into some state
-static Common::String _bmpNames[16];
-
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
-bool TTMInterpreter::load(const Common::String &filename, TTMData *scriptData) {
+bool TTMInterpreter::load(const Common::String &filename) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- return dgds.parse(scriptData, filename);
-}
+ bool parseResult = dgds.parse(&_scriptData, filename);
-void TTMInterpreter::unload(TTMData *data) {
- if (!data)
- return;
- delete data->scr;
+ _state.delay = 0;
+ _state.scene = 0;
+ _scriptData.scr->seek(0);
- data->scr = nullptr;
+ return parseResult;
}
-void TTMInterpreter::init(TTMState *state, const TTMData *data) {
- state->dataPtr = data;
- state->delay = 0;
- state->scene = 0;
- data->scr->seek(0);
+void TTMInterpreter::unload() {
+ delete _scriptData.scr;
+ _scriptData.scr = nullptr;
}
-bool TTMInterpreter::run(TTMState *script) {
- if (!script)
- return false;
-
- Common::SeekableReadStream *scr = script->dataPtr->scr;
+bool TTMInterpreter::run() {
+ Common::SeekableReadStream *scr = _scriptData.scr;
if (!scr)
return false;
if (scr->pos() >= scr->size())
return false;
- script->delay = 0;
+ _state.delay = 0;
+
do {
- uint16 code;
- byte count;
- uint op;
+ uint16 code = scr->readUint16LE();
+ byte count = code & 0x000F;
+ uint op = code & 0xFFF0;
int16 ivals[8];
-
Common::String sval;
-
- code = scr->readUint16LE();
- count = code & 0x000F;
- op = code & 0xFFF0;
if (count > 8 && count != 0x0f)
error("Invalid TTM opcode %04x requires %d locals", code, count);
@@ -129,7 +115,7 @@ bool TTMInterpreter::run(TTMState *script) {
continue;
case 0xf020:
// LOAD BMP: filename:str
- _bmpNames[script->_currentBmpId] = sval;
+ _state.bmpNames[_state._currentBmpId] = sval;
continue;
case 0xf050:
// LOAD PAL: filename:str
@@ -150,18 +136,18 @@ bool TTMInterpreter::run(TTMState *script) {
// SET BMP: id:int [-1:n]
int bk = ivals[0];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[script->_currentBmpId], bk);
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], bk);
}
continue;
}
case 0x1050:
// SELECT BMP: id:int [0:n]
- script->_currentBmpId = ivals[0];
+ _state._currentBmpId = ivals[0];
continue;
case 0x1060:
// SELECT SCR|PAL: id:int [0]
- warning("Switching scene %d -> %d for opcode 0x1060 .. is that right?", script->scene, ivals[0]);
- script->scene = ivals[0];
+ warning("Switching scene %d -> %d for opcode 0x1060 .. is that right?", _state.scene, ivals[0]);
+ _state.scene = ivals[0];
continue;
case 0x1090:
// SELECT SONG: id:int [0]
@@ -174,7 +160,7 @@ bool TTMInterpreter::run(TTMState *script) {
case 0x4110:
// FADE OUT: ?,?,?,?:byte
- g_system->delayMillis(script->delay);
+ g_system->delayMillis(_state.delay);
_vm->_image->clearPalette();
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
continue;
@@ -225,25 +211,25 @@ bool TTMInterpreter::run(TTMState *script) {
case 0xa520:
//DRAW BMP: x,y:int ; happens once in INTRO.TTM
case 0xa500:
- debug("DRAW \"%s\"", _bmpNames[script->_currentBmpId].c_str());
+ debug("DRAW \"%s\"", _state.bmpNames[_state._currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
int bk = ivals[2];
- script->_currentBmpId = ivals[3];
+ _state._currentBmpId = ivals[3];
if (bk != -1) {
- _vm->_image->loadBitmap(_bmpNames[script->_currentBmpId], bk);
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], bk);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", script->_currentBmpId, _bmpNames[script->_currentBmpId].c_str());
- _vm->_image->loadBitmap(_bmpNames[script->_currentBmpId], 0);
+ warning("trying to load bmp %d (%s) on demand", _state._currentBmpId, _state.bmpNames[_state._currentBmpId].c_str());
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], script->_drawWin, _vm->getTopBuffer());
+ _vm->_image->drawBitmap(ivals[0], ivals[1], _state._drawWin, _vm->getTopBuffer());
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
continue;
@@ -251,7 +237,7 @@ bool TTMInterpreter::run(TTMState *script) {
case 0x1110: { //SET SCENE?: i:int [1..n]
// DESCRIPTION IN TTM TAGS.
debug("SET SCENE: %u", ivals[0]);
- script->scene = ivals[0];
+ _state.scene = ivals[0];
const Common::Array<Dialogue> dialogues = _vm->getScene()->getLines();
_text.str.clear();
@@ -260,13 +246,13 @@ bool TTMInterpreter::run(TTMState *script) {
_text = dialogue;
}
if (!_text.str.empty())
- script->delay += 1500;
+ _state.delay += 1500;
continue;
}
case 0x4000:
//SET WINDOW? x,y,w,h:int [0..320,0..200]
- script->_drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ _state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
continue;
case 0xa100:
@@ -275,7 +261,7 @@ bool TTMInterpreter::run(TTMState *script) {
continue;
case 0x1020: //DELAY?: i:int [0..n]
- script->delay += ivals[0] * 10;
+ _state.delay += ivals[0] * 10;
continue;
case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
@@ -303,74 +289,59 @@ bool TTMInterpreter::run(TTMState *script) {
dst->copyRectToSurface(_vm->_resData, 0, 0, Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
g_system->unlockScreen();
g_system->updateScreen();
- g_system->delayMillis(script->delay);
+ g_system->delayMillis(_state.delay);
return true;
}
-ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _scriptData(nullptr) {}
+ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm) {
+ _ttmInterpreter = new TTMInterpreter(_vm);
+}
-bool ADSInterpreter::load(const Common::String &filename, ADSData *scriptData) {
- _scriptData = scriptData;
- _filename = filename;
+ADSInterpreter::~ADSInterpreter() {
+ delete _ttmInterpreter;
+ _ttmInterpreter = nullptr;
+}
+bool ADSInterpreter::load(const Common::String &filename) {
ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- dgds.parse(scriptData, filename);
-
- TTMInterpreter interp(_vm);
-
- TTMData *scriptDatas;
- scriptDatas = new TTMData[_scriptData->count];
- assert(scriptDatas);
- _scriptData->scriptDatas = scriptDatas;
+ dgds.parse(&_scriptData, filename);
- for (uint16 i = _scriptData->count; i--;)
- interp.load(_scriptData->names[i], &_scriptData->scriptDatas[i]);
+ _state.scene = 0;
+ _state.subIdx = 0;
+ _state.subMax = 0;
+ _scriptData.scr->seek(0);
+ _scriptData.filename = filename;
- _scriptData->filename = filename;
- _scriptData = nullptr;
return true;
}
-void ADSInterpreter::unload(ADSData *data) {
- if (!data)
- return;
- data->names.clear();
- delete data->scriptDatas;
- delete data->scr;
-
- data->count = 0;
- data->scriptDatas = 0;
- data->scr = 0;
-}
-
-void ADSInterpreter::init(ADSState *state, const ADSData *data) {
- state->dataPtr = data;
- state->scene = 0;
- state->subIdx = 0;
- state->subMax = 0;
- data->scr->seek(0);
-
- TTMInterpreter interp(_vm);
-
- state->scriptStates.resize(data->count);
-
- for (uint16 i = data->count; i--;)
- interp.init(&state->scriptStates[i], &data->scriptDatas[i]);
+void ADSInterpreter::unload() {
+ _scriptData.names.clear();
+ delete _scriptData.scr;
+ _scriptData.scr = nullptr;
}
-bool ADSInterpreter::run(ADSState *script) {
-
- if (script->subMax != 0) {
- TTMInterpreter interp(_vm);
- TTMState *ttmState = &script->scriptStates[script->subIdx - 1];
- if (!interp.run(ttmState) || ttmState->scene >= script->subMax)
- script->subMax = 0;
+bool ADSInterpreter::run() {
+ // This is the main scene player loop, which will run
+ // after the first time the ADS script is loaded below
+ // TODO/FIXME: Rewrite this
+ if (_state.subMax != 0) {
+ if (!_ttmInterpreter->run()) {
+ if (_ttmInterpreter->getScene() >= _state.subMax) {
+ const uint16 id = _state.subIdx - 1;
+ if (id + 1 < _scriptData.names.size()) {
+ _state.subIdx++;
+ _ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
+ } else {
+ return false;
+ }
+ }
+ }
+
return true;
}
- if (!script)
- return false;
- Common::SeekableReadStream *scr = script->dataPtr->scr;
+ Common::SeekableReadStream *scr = _scriptData.scr;
if (!scr)
return false;
if (scr->pos() >= scr->size())
@@ -388,11 +359,12 @@ bool ADSInterpreter::run(ADSState *script) {
switch (code) {
case 0x2005: {
// play scene.
- script->subIdx = scr->readUint16LE();
- script->subMax = scr->readUint16LE();
+ _state.subIdx = scr->readUint16LE();
+ _state.subMax = scr->readUint16LE();
uint16 unk1 = scr->readUint16LE();
uint16 unk2 = scr->readUint16LE();
- debug("ADSInterpreter play scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", script->subIdx, script->subMax, unk1, unk2);
+ _ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
+ debug("ADSInterpreter play scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", _state.subIdx, _state.subMax, unk1, unk2);
return true;
}
@@ -429,6 +401,7 @@ bool ADSInterpreter::run(ADSState *script) {
}
break;
} while (scr->pos() < scr->size());
+
return false;
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 4b80b93ee9a..9a6f02fea85 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -46,66 +46,59 @@ public:
};
struct TTMState {
- TTMState() : dataPtr(nullptr), scene(0), delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
- const TTMData *dataPtr;
+ TTMState() : scene(0), delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
uint16 scene;
int delay;
Common::Rect _drawWin;
int _currentBmpId;
+ Common::String bmpNames[16];
};
class ADSData : public ScriptParserData {
public:
- ADSData() : count(0), scriptDatas(nullptr) {}
- uint16 count;
+ ADSData() {}
Common::Array<Common::String> names;
- TTMData *scriptDatas;
};
struct ADSState {
- ADSState() : dataPtr(nullptr), scene(0), subIdx(0), subMax(0) {}
- const ADSData *dataPtr;
+ ADSState() : scene(0), subIdx(0), subMax(0) {}
uint16 scene;
uint16 subIdx, subMax;
-
- Common::Array<TTMState> scriptStates;
};
-class ADSInterpreter {
+class TTMInterpreter {
public:
- ADSInterpreter(DgdsEngine *vm);
+ TTMInterpreter(DgdsEngine *vm);
- bool load(const Common::String &filename, ADSData *data);
- void unload(ADSData *data);
+ bool load(const Common::String &filename);
+ void unload();
+ bool run();
- void init(ADSState *scriptState, const ADSData *scriptData);
- bool run(ADSState *script);
+ uint16 getScene() const { return _state.scene; }
protected:
DgdsEngine *_vm;
- Common::String _filename;
- ADSData *_scriptData;
+ Dialogue _text;
+ TTMData _scriptData;
+ TTMState _state;
};
-class TTMInterpreter {
+class ADSInterpreter {
public:
- TTMInterpreter(DgdsEngine *vm);
-
- bool load(const Common::String &filename, TTMData *data);
- void unload(TTMData *data);
+ ADSInterpreter(DgdsEngine *vm);
+ ~ADSInterpreter();
- void init(TTMState *scriptState, const TTMData *scriptData);
- bool run(TTMState *script);
+ bool load(const Common::String &filename);
+ void unload();
+ bool run();
protected:
DgdsEngine *_vm;
+ TTMInterpreter *_ttmInterpreter;
- Dialogue _text;
- //Common::String _filename;
- //TTMData *_scriptData;
-
- //Common::String _bmpNames[16];
+ ADSData _scriptData;
+ ADSState _state;
};
} // End of namespace Dgds
Commit: 98b8305a52199effbe69547e394e5c66f22ac1ee
https://github.com/scummvm/scummvm/commit/98b8305a52199effbe69547e394e5c66f22ac1ee
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Play intro credits and scenes from their respective ADS files
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 6df3f7af264..94cd315adcf 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -589,9 +589,8 @@ Common::Error DgdsEngine::run() {
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
- ADSInterpreter interpADS(this);
- TTMInterpreter interpTTM1(this);
- TTMInterpreter interpTTM2(this);
+ ADSInterpreter interpIntro(this);
+ bool creditsShown = false;
if (getGameId() == GID_DRAGON) {
// Test parsing some things..
@@ -606,18 +605,16 @@ Common::Error DgdsEngine::run() {
*/
// Load the intro and play it for now.
- interpTTM1.load("TITLE1.TTM");
- interpTTM2.load("TITLE2.TTM");
- interpADS.load("INTRO.ADS");
+ interpIntro.load("TITLE1.ADS");
parseFile("DRAGON.FNT");
- parseFile("S55.SDS");
+ parseFile("S55.SDS"); // FIXME: Removing this breaks the Bahumat scene dialog
} else if (getGameId() == GID_CHINA) {
- interpADS.load("TITLE.ADS");
+ interpIntro.load("TITLE.ADS");
parseFile("HOC.FNT");
} else if (getGameId() == GID_BEAMISH) {
- interpADS.load("TITLE.ADS");
+ interpIntro.load("TITLE.ADS");
//parseFile("HOC.FNT");
}
@@ -644,12 +641,16 @@ Common::Error DgdsEngine::run() {
}
if (getGameId() == GID_DRAGON) {
- //if (!interpTTM1.run())
- // if (!interpTTM2.run())
- if (!interpADS.run())
- return Common::kNoError;
+ if (!interpIntro.run()) {
+ if (!creditsShown) {
+ creditsShown = true;
+ interpIntro.load("INTRO.ADS");
+ } else {
+ return Common::kNoError;
+ }
+ }
} else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
- if (!interpADS.run())
+ if (!interpIntro.run())
return Common::kNoError;
}
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 1eead235db8..79d2975ff0a 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -303,6 +303,8 @@ ADSInterpreter::~ADSInterpreter() {
}
bool ADSInterpreter::load(const Common::String &filename) {
+ unload();
+
ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
dgds.parse(&_scriptData, filename);
Commit: 1c281ed585b3bfcf0f0053474a6b7499a5a45cf1
https://github.com/scummvm/scummvm/commit/1c281ed585b3bfcf0f0053474a6b7499a5a45cf1
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix Request and Gadget object parsing
REQ files are now correctly parsed (although Gadget names are skipped)
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/resource.cpp
engines/dgds/resource.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 94cd315adcf..11e05343d25 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -595,15 +595,14 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
// Test parsing some things..
parseFile("DRAGON.GDS");
- /*
+
RequestData invRequestData;
RequestData vcrRequestData;
- Request invRequest(_resource);
- Request vcrRequest(_resource);
+ Request invRequest(_resource, _decompressor);
+ Request vcrRequest(_resource, _decompressor);
invRequest.parse(&invRequestData, "DINV.REQ");
- vcrRequest.parse(&vcrRequestData, "DINV.REQ");
- */
-
+ vcrRequest.parse(&vcrRequestData, "DVCR.REQ");
+
// Load the intro and play it for now.
interpIntro.load("TITLE1.ADS");
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 88e4a5f83d7..d7d99a1417b 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -39,6 +39,7 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num)
uint16 numGadgets = str->readUint16LE();
data._gadgets.resize(numGadgets);
+
for (Common::SharedPtr<Gadget> &gptr : data._gadgets) {
uint16 vals[12];
for (int i = 0; i < 12; i++)
@@ -56,20 +57,22 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num)
gptr.reset(new Gadget());
}
- gptr->_gadgetNo = vals[0];
- gptr->_x = vals[1];
- gptr->_y = vals[2];
- gptr->_width = vals[3];
- gptr->_height = vals[4];
- gptr->_gadgetType = vals[5];
- gptr->_flags2 = vals[6];
- gptr->_flags3 = vals[7];
- gptr->_field14_0x20 = vals[8];
- gptr->_field15_0x22 = vals[9];
- gptr->_field15_0x22 = vals[10];
- gptr->_field16_0x24 = vals[11];
- gptr->_parentX = data._x;
- gptr->_parentY = data._y;
+ if (gptr) {
+ gptr->_gadgetNo = vals[0];
+ gptr->_x = vals[1];
+ gptr->_y = vals[2];
+ gptr->_width = vals[3];
+ gptr->_height = vals[4];
+ gptr->_gadgetType = vals[5];
+ gptr->_flags2 = vals[6];
+ gptr->_flags3 = vals[7];
+ gptr->_field14_0x20 = vals[8];
+ gptr->_field15_0x22 = vals[9];
+ gptr->_field15_0x22 = vals[10];
+ gptr->_field16_0x24 = vals[11];
+ gptr->_parentX = data._x;
+ gptr->_parentY = data._y;
+ }
uint16 type1 = str->readUint16LE();
if (type1 == 1) {
@@ -127,7 +130,7 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num)
case 4: {
Common::String s = str->readString();
if (gptr)
- gptr->_sval3 = s;
+ gptr->_buttonName = s;
break;
}
case 8: {
@@ -189,6 +192,14 @@ bool Request::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
RequestData &rdata = *(RequestData *)data;
int num = -1;
+ if (chunk.isContainer()) {
+ // TAG: contains tags for the request data, all content
+ if (chunk.getId() == ID_TAG)
+ chunk.skipContent();
+
+ return false; // continue parsing
+ }
+
if (chunk.getId() == ID_REQ)
parseREQChunk(rdata, chunk, num);
else if (chunk.getId() == ID_GAD)
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index e5933e08177..1d508c4b5af 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -59,7 +59,7 @@ struct Gadget {
Common::String _sval2S;
uint16 _sval2I;
- Common::String _sval3;
+ Common::String _buttonName;
// some other fields..
uint16 _field14_0x20;
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 59e7e36d3fd..50c73b51396 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -122,6 +122,11 @@ Resource ResourceManager::getResourceInfo(Common::String name) {
return _resources[name];
}
+DgdsChunkReader::~DgdsChunkReader() {
+ if (_contentStream)
+ delete _contentStream;
+}
+
bool DgdsChunkReader::isSection(const Common::String §ion) const {
return section.equals(_idStr);
}
@@ -255,12 +260,19 @@ bool DgdsChunkReader::readNextHeader(DGDS_EX ex, const Common::String &filename)
return true;
}
+
+
bool DgdsChunkReader::readContent(Decompressor* decompressor) {
- assert(!_contentStream);
+ assert(_sourceStream && !_contentStream);
_contentStream = isPacked() ? decodeStream(decompressor) : readStream();
return _contentStream != nullptr;
}
+void DgdsChunkReader::skipContent() {
+ assert(_sourceStream && !_contentStream);
+ _sourceStream->seek(_startPos + _size);
+}
+
Common::SeekableReadStream *DgdsChunkReader::decodeStream(Decompressor *decompressor) {
Common::SeekableReadStream *output = nullptr;
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index 43c20045276..c1050f04722 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -65,6 +65,7 @@ private:
class DgdsChunkReader {
public:
DgdsChunkReader(Common::SeekableReadStream *stream) : _sourceStream(stream), _contentStream(nullptr), _size(0), _container(false), _startPos(0) {}
+ ~DgdsChunkReader();
bool isSection(const Common::String §ion) const;
bool isSection(DGDS_ID section) const;
@@ -76,9 +77,13 @@ public:
/// This stream is owned by this object and invalidated when
/// another header or content block is read. Do not delete it.
bool readContent(Decompressor *decompressor);
-
- // Duplicate the buffer in the current content stream so
- // that it can be retained in another object.
+
+ /// Don't bother reading the current chunk, just move to the
+ /// next one. This is the alternative to readContent().
+ void skipContent();
+
+ /// Duplicate the buffer in the current content stream so
+ /// that it can be retained in another object.
Common::SeekableReadStream *makeMemoryStream();
Common::SeekableReadStream *getContent() { return _contentStream; }
Commit: ba280b159f2d292fce6e288132f248cf5e4be9bc
https://github.com/scummvm/scummvm/commit/ba280b159f2d292fce6e288132f248cf5e4be9bc
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Remove incorrect check. Fixes the intros of Beamish and HoC
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 79d2975ff0a..c4bc00f2058 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -329,14 +329,12 @@ bool ADSInterpreter::run() {
// TODO/FIXME: Rewrite this
if (_state.subMax != 0) {
if (!_ttmInterpreter->run()) {
- if (_ttmInterpreter->getScene() >= _state.subMax) {
- const uint16 id = _state.subIdx - 1;
- if (id + 1 < _scriptData.names.size()) {
- _state.subIdx++;
- _ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
- } else {
- return false;
- }
+ const uint16 id = _state.subIdx - 1;
+ if (id + 1 < _scriptData.names.size()) {
+ _state.subIdx++;
+ _ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
+ } else {
+ return false;
}
}
Commit: 98d1c4099513d5d45998ce48926ea930665087ff
https://github.com/scummvm/scummvm/commit/98d1c4099513d5d45998ce48926ea930665087ff
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Remove dead code
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 11e05343d25..08e89ce8942 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -60,7 +60,7 @@
namespace Dgds {
-#define DUMP_ALL_CHUNKS 1
+//#define DUMP_ALL_CHUNKS 1
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
@@ -213,8 +213,6 @@ void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex)
case EX_SNG:
/* IFF-SMUS music (Amiga). */
break;
- // case EX_SNG:
- // TODO
case EX_AMG:
/* (Amiga). */
line = file.readLine();
@@ -349,79 +347,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
_scene->parse(stream);
}
break;
- case EX_TTM:
- if (chunk.isSection(ID_VER)) {
- char version[5];
-
- stream->read(version, sizeof(version));
- debug(" %s", version);
- } else if (chunk.isSection(ID_PAG)) {
- uint16 pages;
- pages = stream->readUint16LE();
- debug(" %u", pages);
- } else if (chunk.isSection(ID_TT3)) {
- uint32 size = stream->size();
- byte *dest = new byte[size];
- stream->read(dest, size);
- //ttm = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
- //Common::strlcpy(ttmName, name, sizeof(ttmName));
- delete [] dest;
-#if 0
- while (!stream->eos()) {
- uint16 code = stream->readUint16LE();
- byte count = code & 0x000F;
- uint op = code & 0xFFF0;
-
- debugN("\tOP: 0x%4.4x %2u ", op, count);
-
- if (count == 0x0F) {
- Common::String sval;
- byte ch[2];
-
- do {
- ch[0] = stream->readByte();
- ch[1] = stream->readByte();
- sval += ch[0];
- sval += ch[1];
- } while (ch[0] != 0 && ch[1] != 0);
-
- debugN("\"%s\"", sval.c_str());
- } else {
- int ival;
-
- for (byte k = 0; k < count; k++) {
- ival = stream->readSint16LE();
-
- if (k == 0)
- debugN("%d", ival);
- else
- debugN(", %d", ival);
- }
- }
- debug(" ");
- }
- }
-#endif
- } else if (chunk.isSection(ID_TAG)) {
- uint16 count = stream->readUint16LE();
-
- debug(" %u", count);
-
- // something fishy here. the first two entries sometimes are an empty string or non-text junk.
- // most of the time entries have text (sometimes with garbled characters).
- // this parser is likely not ok. but the NUL count seems to be ok.
- for (uint16 k = 0; k < count; k++) {
- byte ch;
- uint16 idx;
- Common::String str;
-
- idx = stream->readUint16LE();
- while ((ch = stream->readByte()))
- str += ch;
- debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
- }
- }
- break;
case EX_GDS:
if (chunk.isSection(ID_GDS)) {
// do nothing, this is the container.
@@ -432,109 +357,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
_gdsScene->parse(stream);
}
break;
- case EX_ADS:
- case EX_ADL:
- case EX_ADH:
- if (chunk.isSection(ID_VER)) {
- char version[5];
-
- stream->read(version, sizeof(version));
- debug(" %s", version);
- } else if (chunk.isSection(ID_RES)) {
- DgdsParser::readTags(stream);
- } else if (chunk.isSection(ID_SCR)) {
- uint32 size = stream->size();
- byte *dest = new byte[size];
- stream->read(dest, size);
- //ads = new Common::MemoryReadStream(dest, size, DisposeAfterUse::YES);
- //adsName = name;
- delete [] dest;
-#if 0
- } else {
- /* this is either a script, or a property sheet, i can't decide. */
- while (!stream->eos()) {
- uint16 code;
- code = stream->readUint16LE();
- if ((code & 0xFF00) == 0) {
- uint16 tag = (code & 0xFF);
- debug(" PUSH %d (0x%4.4X)", tag, tag); // ADS:TAG or TTM:TAG id.
- } else {
- const char *desc = "";
- switch (code) {
- case 0xF010:
- case 0xF200:
- case 0xFDA8:
- case 0xFE98:
- case 0xFF88:
- case 0xFF10:
- debug(" INT 0x%4.4X\t;", code);
- continue;
-
- case 0xFFFF:
- debug(" INT 0x%4.4X\t; return", code);
- debug("-");
- continue;
-
- case 0x0190:
- case 0x1070:
- case 0x1340:
- case 0x1360:
- case 0x1370:
- case 0x1420:
- case 0x1430:
- case 0x1500:
- case 0x1520:
- case 0x2000:
- case 0x2010:
- case 0x2020:
- case 0x3010:
- case 0x3020:
- case 0x30FF:
- case 0x4000:
- case 0x4010:
- desc = "?";
- break;
-
- case 0x1330:
- break;
- case 0x1350:
- desc = "? (res,rtag)";
- break;
-
- case 0x1510:
- desc = "? ()";
- break;
- case 0x2005:
- desc = "? (res,rtag,?,?)";
- break;
-
- default:
- break;
- }
- debug(" OP 0x%4.4X\t;%s", code, desc);
- }
- }
- assert(stream->size() == stream->pos());
- //stream->hexdump(stream->size());
- }
-#endif
- } else if (chunk.isSection(ID_TAG)) {
- readStrings(stream);
- }
- break;
- case EX_REQ:
- if (parent == ID_TAG) {
- if (chunk.isSection(ID_REQ)) {
- readStrings(stream);
- } else if (chunk.isSection(ID_GAD)) {
- readStrings(stream);
- }
- } else if (parent == ID_REQ) {
- if (chunk.isSection(ID_REQ)) {
- } else if (chunk.isSection(ID_GAD)) {
- }
- }
- break;
case EX_FNT:
if (chunk.isSection(ID_FNT)) {
byte magic = stream->readByte();
@@ -552,6 +374,11 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
case EX_PAL: // Handled in Image::setPalette
case EX_SCR: // Handled in Image::loadScreen
case EX_BMP: // Handled in Image::loadBitmap
+ case EX_TTM: // Handled by TTMParser
+ case EX_REQ: // Handled by Request
+ case EX_ADS: // Handled by ADSParser
+ case EX_ADL: // Handled by ADSParser
+ case EX_ADH: // Handled by ADSParser
error("Should not be here");
default:
break;
@@ -607,7 +434,6 @@ Common::Error DgdsEngine::run() {
interpIntro.load("TITLE1.ADS");
parseFile("DRAGON.FNT");
- parseFile("S55.SDS"); // FIXME: Removing this breaks the Bahumat scene dialog
} else if (getGameId() == GID_CHINA) {
interpIntro.load("TITLE.ADS");
@@ -643,6 +469,7 @@ Common::Error DgdsEngine::run() {
if (!interpIntro.run()) {
if (!creditsShown) {
creditsShown = true;
+ parseFile("S55.SDS"); // FIXME: Removing this breaks the Bahumat scene dialog
interpIntro.load("INTRO.ADS");
} else {
return Common::kNoError;
Commit: fc77e762281bbbf8c182830e99f3044bd8f7bf36
https://github.com/scummvm/scummvm/commit/fc77e762281bbbf8c182830e99f3044bd8f7bf36
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Move font loading logic in the Font class
Also, disable the FFont class until we find a use case for it
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/font.cpp
engines/dgds/font.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 08e89ce8942..6256f4e73b9 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -63,7 +63,7 @@ namespace Dgds {
//#define DUMP_ALL_CHUNKS 1
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
- : Engine(syst), _image(nullptr), _fntF(nullptr), _fntP(nullptr), _console(nullptr),
+ : Engine(syst), _image(nullptr), /*_fntF(nullptr),*/ _fntP(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
_resource(nullptr) {
syncSoundSettings();
@@ -357,18 +357,6 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
_gdsScene->parse(stream);
}
break;
- case EX_FNT:
- if (chunk.isSection(ID_FNT)) {
- byte magic = stream->readByte();
- stream->seek(-1, SEEK_CUR);
- debug(" magic: %u", magic);
-
- if (magic != 0xFF)
- _fntF = FFont::load(*stream);
- else
- _fntP = PFont::load(*stream, _decompressor);
- }
- break;
case EX_SNG: // Handled in Sound::playMusic
case EX_SX: // Handled in Sound::playMacMusic
case EX_PAL: // Handled in Image::setPalette
@@ -379,6 +367,7 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
case EX_ADS: // Handled by ADSParser
case EX_ADL: // Handled by ADSParser
case EX_ADH: // Handled by ADSParser
+ case EX_FNT: // Handled by Font::load
error("Should not be here");
default:
break;
@@ -409,8 +398,6 @@ Common::Error DgdsEngine::run() {
_topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- debug("DgdsEngine::init");
-
g_system->fillScreen(0);
Common::EventManager *eventMan = g_system->getEventManager();
@@ -432,16 +419,17 @@ Common::Error DgdsEngine::run() {
// Load the intro and play it for now.
interpIntro.load("TITLE1.ADS");
+ //interpIntro.load("INTRO.ADS");
- parseFile("DRAGON.FNT");
+ _fntP = (PFont *)Font::load("DRAGON.FNT", _resource, _decompressor);
} else if (getGameId() == GID_CHINA) {
interpIntro.load("TITLE.ADS");
- parseFile("HOC.FNT");
+ _fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
} else if (getGameId() == GID_BEAMISH) {
interpIntro.load("TITLE.ADS");
- //parseFile("HOC.FNT");
+ //_fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
}
//_console->attach();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index ff347b14788..91c824706f9 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -76,7 +76,7 @@ private:
GDSScene *_gdsScene;
PFont *_fntP;
- FFont *_fntF;
+ //FFont *_fntF;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index e0854e512ae..e6fe8d3c048 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -26,19 +26,56 @@
#include "dgds/decompress.h"
#include "dgds/font.h"
+#include "dgds/includes.h"
+#include "dgds/resource.h"
namespace Dgds {
+Font *Font::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
+ Common::SeekableReadStream *fontFile = resourceManager->getResource(filename);
+ if (!fontFile)
+ error("Font file %s not found", filename.c_str());
+
+ DgdsChunkReader chunk(fontFile);
+
+ Font *font = nullptr;
+
+ while (chunk.readNextHeader(EX_FNT, filename)) {
+ if (chunk.isContainer()) {
+ continue;
+ }
+
+ chunk.readContent(decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
+
+ if (chunk.isSection(ID_FNT)) {
+ byte magic = stream->readByte();
+ stream->seek(-1, SEEK_CUR);
+ debug(" magic: %u", magic);
+
+ if (magic != 0xFF)
+ // font = FFont::load(*stream); // TODO: Where is this used?
+ error("Font::load(): Attempted to load a font of type FFont");
+ else
+ font = PFont::load(*stream, decompressor);
+ }
+ }
+
+ delete fontFile;
+
+ return font;
+}
+
bool Font::hasChar(byte chr) const {
- return (chr >= _start && chr <= (_start+_count));
+ return (chr >= _start && chr <= (_start + _count));
}
static inline uint isSet(byte *set, uint bit) {
- return (set[(bit >> 3)] & (1 << (bit & 7)));
+ return (set[bit >> 3] & (1 << (bit & 7)));
}
void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const {
- const Common::Rect destRect(x, y, x+_w, y+_h);
+ const Common::Rect destRect(x, y, x + _w, y + _h);
Common::Rect clippedDestRect(0, 0, dst->w, dst->h);
clippedDestRect.clip(destRect);
@@ -50,9 +87,10 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
int idx = bit + croppedBy.x;
byte *src = _data + pos + croppedBy.y;
byte *ptr = (byte *)dst->getBasePtr(clippedDestRect.left, clippedDestRect.top);
- for (int i=0; i<rows; ++i) {
- for (int j=0; j<columns; ++j) {
- if (isSet(src, idx+_w-1-j))
+
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j) {
+ if (isSet(src, idx + _w - 1 - j))
ptr[j] = color;
}
ptr += dst->pitch;
@@ -60,13 +98,15 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
}
}
-void FFont::mapChar(byte chr, int& pos, int& bit) const {
- pos = (chr-_start)*_h;
- bit = 8-_w;
+#if 0
+void FFont::mapChar(byte chr, int &pos, int &bit) const {
+ pos = (chr - _start) * _h;
+ bit = 8 - _w;
}
void FFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const {
- if (!hasChar(chr)) return;
+ if (!hasChar(chr))
+ return;
int pos, bit;
mapChar(chr, pos, bit);
@@ -74,33 +114,36 @@ void FFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 co
}
FFont *FFont::load(Common::SeekableReadStream &input) {
- byte w, h, start, count;
- w = input.readByte();
- h = input.readByte();
- start = input.readByte();
- count = input.readByte();
+ byte w = input.readByte();
+ byte h = input.readByte();
+ byte start = input.readByte();
+ byte count = input.readByte();
+ int size = h * count;
+
+ assert((4 + size) == input.size());
- int size = h*count;
debug(" w: %u, h: %u, start: 0x%x, count: %u", w, h, start, count);
- assert((4+size) == input.size());
- FFont* fnt = new FFont;
+ FFont *fnt = new FFont;
fnt->_w = w;
fnt->_h = h;
fnt->_start = start;
fnt->_count = count;
fnt->_data = new byte[size];
input.read(fnt->_data, size);
+
return fnt;
}
+#endif
void PFont::mapChar(byte chr, int& pos, int& bit) const {
- pos = READ_LE_UINT16(&_offsets[chr-_start]);
+ pos = READ_LE_UINT16(&_offsets[chr - _start]);
bit = 0;
}
void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const {
- if (!hasChar(chr)) return;
+ if (!hasChar(chr))
+ return;
int pos, bit;
mapChar(chr, pos, bit);
@@ -108,40 +151,36 @@ void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 co
}
PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor) {
- byte magic;
+ byte magic = input.readByte();
+ byte w = input.readByte();
+ byte h = input.readByte();
+ byte unknown = input.readByte();
+ byte start = input.readByte();
+ byte count = input.readByte();
+ int size = input.readUint16LE();
- magic = input.readByte();
- assert(magic == 0xFF);
-
- byte w, h;
- byte unknown, start, count;
- int size;
-
- w = input.readByte();
- h = input.readByte();
- unknown = input.readByte();
- start = input.readByte();
- count = input.readByte();
- size = input.readUint16LE();
debug(" magic: 0x%x, w: %u, h: %u, unknown: %u, start: 0x%x, count: %u\n"
" size: %u",
magic, w, h, unknown, start, count,
size);
+ assert(magic == 0xFF);
+
size = input.size() - input.pos();
uint32 uncompressedSize;
byte *data = decompressor->decompress(&input, size, uncompressedSize);
- PFont* fnt = new PFont;
+ PFont *fnt = new PFont;
fnt->_w = w;
fnt->_h = h;
fnt->_start = start;
fnt->_count = count;
fnt->_offsets = (uint16*)data;
- fnt->_widths = data+2*count;
- fnt->_data = data+3*count;
+ fnt->_widths = data + 2 * count;
+ fnt->_data = data + 3 * count;
+
return fnt;
}
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index 7874345b7d2..cf187721c02 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -37,6 +37,7 @@ class SeekableReadStream;
namespace Dgds {
+class ResourceManager;
class Decompressor;
class Font : public Graphics::Font {
@@ -45,6 +46,7 @@ public:
int getMaxCharWidth() const { return _w; }
virtual int getCharWidth(uint32 chr) const = 0;
void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const;
+ static Font *load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
protected:
byte _w;
@@ -59,7 +61,7 @@ protected:
class PFont : public Font {
public:
int getCharWidth(uint32 chr) const { return _widths[chr - _start]; }
- void drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const;
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static PFont *load(Common::SeekableReadStream &input, Decompressor *decompressor);
protected:
@@ -69,15 +71,17 @@ protected:
void mapChar(byte chr, int &pos, int &bit) const;
};
+#if 0
class FFont : public Font {
public:
int getCharWidth(uint32 chr) const { return _w; }
- void drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const;
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static FFont *load(Common::SeekableReadStream &input);
protected:
void mapChar(byte chr, int &pos, int &bit) const;
};
+#endif
} // End of namespace Dgds
Commit: fea0a4ac92b59abf0c8bb904560132b9387c8aec
https://github.com/scummvm/scummvm/commit/fea0a4ac92b59abf0c8bb904560132b9387c8aec
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Remove superfluous variables and fix Mac music resource ID
Changed paths:
engines/dgds/sound.cpp
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index af78042c228..1ce432d8bdf 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -150,9 +150,8 @@ void Sound::playMacMusic(const Common::String &filename) {
error("Music file %s not found", filename.c_str());
DgdsChunkReader chunk(musicStream);
- const DGDS_EX ex = EX_SNG;
- while (chunk.readNextHeader(ex, filename)) {
+ while (chunk.readNextHeader(EX_SX, filename)) {
if (chunk.isContainer()) {
continue;
}
@@ -201,9 +200,8 @@ void Sound::playMusic(const Common::String &filename) {
error("Music file %s not found", filename.c_str());
DgdsChunkReader chunk(musicStream);
- const DGDS_EX ex = EX_SNG;
- while (chunk.readNextHeader(ex, filename)) {
+ while (chunk.readNextHeader(EX_SNG, filename)) {
if (chunk.isContainer()) {
continue;
}
Commit: a4e33facc8a9f58bc0d8df9e919ffa1e04645865
https://github.com/scummvm/scummvm/commit/a4e33facc8a9f58bc0d8df9e919ffa1e04645865
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Mark SDS file versions for HoC and Willy
Changed paths:
engines/dgds/scene.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index cba612f1aa9..833547298c1 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -228,6 +228,8 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
_magic = stream->readUint32LE();
_version = stream->readString();
if (isVersionOver(" 1.211")) {
+ //if (isVersionOver(" 1.216")) { // HoC
+ //if (isVersionOver(" 1.224")) { // Beamish
error("Unsupported scene version '%s'", _version.c_str());
}
_num = stream->readUint16LE();
Commit: 12db5e1224a03a89b8616e58345d58db1656dc08
https://github.com/scummvm/scummvm/commit/12db5e1224a03a89b8616e58345d58db1656dc08
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Load font for Beamish
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 6256f4e73b9..ac0a1d7d369 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -423,13 +423,15 @@ Common::Error DgdsEngine::run() {
_fntP = (PFont *)Font::load("DRAGON.FNT", _resource, _decompressor);
} else if (getGameId() == GID_CHINA) {
+ //parseFile("S101.SDS");
interpIntro.load("TITLE.ADS");
_fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
} else if (getGameId() == GID_BEAMISH) {
+ //parseFile("S34.SDS");
interpIntro.load("TITLE.ADS");
- //_fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
+ _fntP = (PFont *)Font::load("WILLY.FNT", _resource, _decompressor);
}
//_console->attach();
Commit: da940c29aed3b2985f60e577ef55f622b814e40d
https://github.com/scummvm/scummvm/commit/da940c29aed3b2985f60e577ef55f622b814e40d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactored the last parts of the file parser
- Moved scene loading in the GDSScene and SDSScene classes
- Removed all the parseFile() functions
- Removed the Amiga file handlers, as they were very early guesswork
- Kept some semi-implemented file handlers as a reference, for now
- Removed the file dump code - we got debugger functions for that use
- Removed isFlatFile() - it's no longer used
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/resource.cpp
engines/dgds/resource.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index ac0a1d7d369..2a81941c1c1 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -60,8 +60,6 @@
namespace Dgds {
-//#define DUMP_ALL_CHUNKS 1
-
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), /*_fntF(nullptr),*/ _fntP(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
@@ -109,132 +107,99 @@ void readStrings(Common::SeekableReadStream *stream) {
}
}
-void DgdsEngine::parseRstChunk(Common::SeekableReadStream &file) {
- uint32 mark = file.readUint32LE();
- debug(" 0x%X", mark);
+Common::Error DgdsEngine::run() {
+ initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
- // elaborate guesswork. who knows it might be true.
- while (!file.eos()) {
- uint16 vals[7];
- uint16 idx = file.readUint16LE();
+ _console = new Console(this);
+ _resource = new ResourceManager();
+ _decompressor = new Decompressor();
+ _image = new Image(_resource, _decompressor);
+ _soundPlayer = new Sound(_mixer, _resource, _decompressor);
+ _scene = new SDSScene();
+ _gdsScene = new GDSScene();
- debugN(" #%u:\t", idx);
+ setDebugger(_console);
- if (idx == 0)
- break;
+ _bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- for (int i = 0; i < ARRAYSIZE(vals); i++) {
- vals[i] = file.readUint16LE();
- if (i != 0)
- debugN(", ");
- debugN("%u", vals[i]);
- }
-
- debug(".");
- }
+ g_system->fillScreen(0);
- debug("-");
+ Common::EventManager *eventMan = g_system->getEventManager();
+ Common::Event ev;
- while (!file.eos()) {
- uint16 vals[2];
- uint16 idx = file.readUint16LE();
-
- debugN(" #%u:\t", idx);
+ ADSInterpreter interpIntro(this);
+ bool creditsShown = false;
- for (int i = 0; i < ARRAYSIZE(vals); i++) {
- vals[i] = file.readUint16LE();
- if (i != 0)
- debugN(", ");
- debugN("%u", vals[i]);
- }
+ if (getGameId() == GID_DRAGON) {
+ // Test parsing some things..
+ _gdsScene->load("DRAGON.GDS", _resource, _decompressor);
+
+ RequestData invRequestData;
+ RequestData vcrRequestData;
+ Request invRequest(_resource, _decompressor);
+ Request vcrRequest(_resource, _decompressor);
+ invRequest.parse(&invRequestData, "DINV.REQ");
+ vcrRequest.parse(&vcrRequestData, "DVCR.REQ");
+
+ // Load the intro and play it for now.
+ interpIntro.load("TITLE1.ADS");
+ //interpIntro.load("INTRO.ADS");
- debug(".");
+ _fntP = (PFont *)Font::load("DRAGON.FNT", _resource, _decompressor);
+ } else if (getGameId() == GID_CHINA) {
+ //_scene->load("S101.SDS", _resource, _decompressor);
+ interpIntro.load("TITLE.ADS");
- if (idx == 0)
- break;
+ _fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
+ } else if (getGameId() == GID_BEAMISH) {
+ //_scene->load("S34.SDS", _resource, _decompressor);
+ interpIntro.load("TITLE.ADS");
+
+ _fntP = (PFont *)Font::load("WILLY.FNT", _resource, _decompressor);
}
- debug("-");
-}
-void DgdsEngine::parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex) {
- Common::String line;
-
- switch (ex) {
- case EX_SCR: {
- /* Unknown image format (Amiga). */
- byte tag[5];
- file.read(tag, 4); /* maybe */
- tag[4] = '\0';
-
- uint16 pitch, planes;
- pitch = file.readUint16BE(); /* always 200 (320x200 screen). */
- planes = file.readUint16BE(); /* always 5 (32 color). */
-
- debug(" \"%s\" pitch:%u bpp:%u size: %u bytes",
- tag, pitch, planes,
- SCREEN_WIDTH * planes * SCREEN_HEIGHT / 8);
- } break;
- case EX_BMP: {
- /* Unknown image format (Amiga). */
- uint16 tcount = file.readUint16BE();
- uint16 *tw = new uint16[tcount];
- uint16 *th = new uint16[tcount];
-
- uint32 packedSize;
- uint32 unpackedSize = file.readUint32BE(); // TODO: this is wrong - it's re-read below
- debug(" [%u] %u =", tcount, unpackedSize);
-
- uint32 sz = 0;
- uint32 *toffset = new uint32[tcount];
- for (uint16 k = 0; k < tcount; k++) {
- tw[k] = file.readUint16BE();
- th[k] = file.readUint16BE();
- debug(" %ux%u ~@%u", tw[k], th[k], sz);
-
- toffset[k] = sz;
- sz += uint(tw[k] + 15) / 16 * th[k] * 5;
+ while (!shouldQuit()) {
+ if (eventMan->pollEvent(ev)) {
+ if (ev.type == Common::EVENT_KEYDOWN) {
+ switch (ev.kbd.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ return Common::kNoError;
+ default:
+ break;
+ }
+ }
}
- debug(" ~= [%u]", sz);
-
- /* this is a wild guess. */
- byte version[13];
- file.read(version, 12);
- version[12] = '\0';
- debug(" %s", version);
-
- unpackedSize = file.readUint32BE();
- packedSize = file.readUint32BE();
- debug(" %u -> %u",
- packedSize, unpackedSize);
- delete[] toffset;
- delete[] tw;
- delete[] th;
- } break;
- case EX_SNG:
- /* IFF-SMUS music (Amiga). */
- break;
- case EX_AMG:
- /* (Amiga). */
- line = file.readLine();
- while (!file.eos() && !line.empty()) {
- debug(" \"%s\"", line.c_str());
- line = file.readLine();
+
+ if (getGameId() == GID_DRAGON) {
+ if (!interpIntro.run()) {
+ if (!creditsShown) {
+ creditsShown = true;
+ _scene->load("S55.SDS", _resource, _decompressor); // FIXME: Removing this breaks the Bahumat scene dialog
+ interpIntro.load("INTRO.ADS");
+ } else {
+ return Common::kNoError;
+ }
+ }
+ } else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
+ if (!interpIntro.run())
+ return Common::kNoError;
}
- break;
- case EX_INS: // Handled in Sound::playAmigaSfx
- error("Should not be here");
+
+ g_system->delayMillis(40);
}
+ return Common::kNoError;
}
-void DgdsEngine::parseFile(const Common::String &filename) {
- Common::SeekableReadStream *stream = _resource->getResource(filename);
- if (!stream)
- error("Couldn't get resource file %s", filename.c_str());
- parseFileInner(_platform, *stream, filename.c_str());
- delete stream;
+Common::SeekableReadStream *DgdsEngine::getResource(const Common::String &name, bool ignorePatches) {
+ return _resource->getResource(name, ignorePatches);
}
+
+// Parts of the old parse file code, kept temporarily for reference
+#if 0
void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name) {
const char *dot;
DGDS_EX ex = 0;
@@ -245,37 +210,15 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
uint parent = 0;
- if (platform == Common::kPlatformAmiga) {
- parseAmigaChunks(file, ex);
- }
-
- if (DgdsChunkReader::isFlatfile(ex)) {
- Common::String line;
-
- switch (ex) {
- case EX_RST:
- parseRstChunk(file);
- break;
- case EX_VIN:
+ if (ex == EX_VIN || ex == EX_AMG) {
+ Common::String line = file.readLine();
+ while (!file.eos()) {
+ if (!line.empty())
+ debug(" \"%s\"", line.c_str());
line = file.readLine();
- while (!file.eos()) {
- if (!line.empty())
- debug(" \"%s\"", line.c_str());
- line = file.readLine();
- }
- break;
- case EX_DAT: {
- // TODO
- int leftover = file.size() - file.pos();
- file.hexdump(leftover);
- file.skip(leftover);
- } break;
- default:
- break;
}
} else {
DgdsChunkReader chunk(&file);
- int chunkno = 0;
while (chunk.readNextHeader(ex, name)) {
if (chunk.isContainer()) {
parent = chunk.getId();
@@ -285,26 +228,11 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
chunk.readContent(_decompressor);
Common::SeekableReadStream *stream = chunk.getContent();
-#ifdef DUMP_ALL_CHUNKS
- {
- Common::DumpFile out;
- int64 start = stream->pos();
- out.open(Common::Path(Common::String::format("tmp/dgds_%s_%02d_%.3s.dump", name, chunkno, chunk.getIdStr())));
- out.writeStream(stream);
- out.close();
- stream->seek(start);
- }
-
-#endif
- chunkno++;
-
switch (ex) {
case EX_TDS:
/* Heart of China. */
if (chunk.isSection(ID_THD)) {
- uint32 mark;
-
- mark = stream->readUint32LE();
+ uint32 mark = stream->readUint32LE();
debug(" 0x%X", mark);
char version[7];
@@ -342,141 +270,12 @@ void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadS
debug(" \"%s\"", tag.c_str());
}
break;
- case EX_SDS:
- if (chunk.isSection(ID_SDS)) {
- _scene->parse(stream);
- }
- break;
- case EX_GDS:
- if (chunk.isSection(ID_GDS)) {
- // do nothing, this is the container.
- assert(chunk.isContainer());
- } else if (chunk.isSection(ID_INF)) {
- _gdsScene->parseInf(stream);
- } else if (chunk.isSection(ID_SDS)) {
- _gdsScene->parse(stream);
- }
- break;
- case EX_SNG: // Handled in Sound::playMusic
- case EX_SX: // Handled in Sound::playMacMusic
- case EX_PAL: // Handled in Image::setPalette
- case EX_SCR: // Handled in Image::loadScreen
- case EX_BMP: // Handled in Image::loadBitmap
- case EX_TTM: // Handled by TTMParser
- case EX_REQ: // Handled by Request
- case EX_ADS: // Handled by ADSParser
- case EX_ADL: // Handled by ADSParser
- case EX_ADH: // Handled by ADSParser
- case EX_FNT: // Handled by Font::load
- error("Should not be here");
default:
break;
}
- int leftover = stream->size() - stream->pos();
- //stream->hexdump(leftover);
- stream->skip(leftover);
}
}
-
- debug(" [%u] --", (uint)file.pos());
-}
-
-Common::Error DgdsEngine::run() {
- initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
-
- _console = new Console(this);
- _resource = new ResourceManager();
- _decompressor = new Decompressor();
- _image = new Image(_resource, _decompressor);
- _soundPlayer = new Sound(_mixer, _resource, _decompressor);
- _scene = new SDSScene();
- _gdsScene = new GDSScene();
-
- setDebugger(_console);
-
- _bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- _topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- _resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
-
- g_system->fillScreen(0);
-
- Common::EventManager *eventMan = g_system->getEventManager();
- Common::Event ev;
-
- ADSInterpreter interpIntro(this);
- bool creditsShown = false;
-
- if (getGameId() == GID_DRAGON) {
- // Test parsing some things..
- parseFile("DRAGON.GDS");
-
- RequestData invRequestData;
- RequestData vcrRequestData;
- Request invRequest(_resource, _decompressor);
- Request vcrRequest(_resource, _decompressor);
- invRequest.parse(&invRequestData, "DINV.REQ");
- vcrRequest.parse(&vcrRequestData, "DVCR.REQ");
-
- // Load the intro and play it for now.
- interpIntro.load("TITLE1.ADS");
- //interpIntro.load("INTRO.ADS");
-
- _fntP = (PFont *)Font::load("DRAGON.FNT", _resource, _decompressor);
- } else if (getGameId() == GID_CHINA) {
- //parseFile("S101.SDS");
- interpIntro.load("TITLE.ADS");
-
- _fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
- } else if (getGameId() == GID_BEAMISH) {
- //parseFile("S34.SDS");
- interpIntro.load("TITLE.ADS");
-
- _fntP = (PFont *)Font::load("WILLY.FNT", _resource, _decompressor);
- }
-
- //_console->attach();
-
- while (!shouldQuit()) {
- if (eventMan->pollEvent(ev)) {
- if (ev.type == Common::EVENT_KEYDOWN) {
- switch (ev.kbd.keycode) {
- /*
- case Common::KEYCODE_TAB: sid++; break;
- case Common::KEYCODE_UP: if (id > 0) id--; bk=0; break;
- case Common::KEYCODE_DOWN: if (id < BMPs.size()) id++; bk=0; break;
- case Common::KEYCODE_LEFT: if (bk > 0) bk--; break;
- case Common::KEYCODE_RIGHT: if (bk < (_tcount-1)) bk++; break;
- */
- case Common::KEYCODE_ESCAPE:
- return Common::kNoError;
- default:
- break;
- }
- }
- }
-
- if (getGameId() == GID_DRAGON) {
- if (!interpIntro.run()) {
- if (!creditsShown) {
- creditsShown = true;
- parseFile("S55.SDS"); // FIXME: Removing this breaks the Bahumat scene dialog
- interpIntro.load("INTRO.ADS");
- } else {
- return Common::kNoError;
- }
- }
- } else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
- if (!interpIntro.run())
- return Common::kNoError;
- }
-
- g_system->delayMillis(40);
- }
- return Common::kNoError;
-}
-
-Common::SeekableReadStream *DgdsEngine::getResource(const Common::String &name, bool ignorePatches) {
- return _resource->getResource(name, ignorePatches);
}
+#endif
} // End of namespace Dgds
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 91c824706f9..8de2f66822e 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -93,12 +93,6 @@ public:
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
const PFont *getFntP() const { return _fntP; }
-
-private:
- void parseFile(const Common::String &filename);
- void parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name);
- void parseRstChunk(Common::SeekableReadStream &file);
- void parseAmigaChunks(Common::SeekableReadStream &file, DGDS_EX ex);
};
} // End of namespace Dgds
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 50c73b51396..ebbe51c6dec 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -309,20 +309,4 @@ Common::SeekableReadStream *DgdsChunkReader::makeMemoryStream() {
return output;
}
-/*static*/
-bool DgdsChunkReader::isFlatfile(DGDS_EX ext) {
- bool flat = false;
-
- switch (ext) {
- case EX_RST:
- case EX_VIN:
- case EX_DAT:
- flat = true;
- break;
- default:
- break;
- }
- return flat;
-}
-
} // End of namespace Dgds
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index c1050f04722..2affffff710 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -69,7 +69,6 @@ public:
bool isSection(const Common::String §ion) const;
bool isSection(DGDS_ID section) const;
- static bool isFlatfile(DGDS_EX ext);
bool readNextHeader(DGDS_EX ex, const Common::String &filename);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 833547298c1..d2eaa5f217b 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -24,6 +24,8 @@
#include "common/endian.h"
#include "common/file.h"
+#include "dgds/includes.h"
+#include "dgds/resource.h"
#include "dgds/scene.h"
namespace Dgds {
@@ -224,6 +226,33 @@ bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array
SDSScene::SDSScene() : _num(-1) {
}
+bool SDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
+ Common::SeekableReadStream *sceneFile = resourceManager->getResource(filename);
+ if (!sceneFile)
+ error("Scene file %s not found", filename.c_str());
+
+ DgdsChunkReader chunk(sceneFile);
+
+ bool result = false;
+
+ while (chunk.readNextHeader(EX_SDS, filename)) {
+ if (chunk.isContainer()) {
+ continue;
+ }
+
+ chunk.readContent(decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
+
+ if (chunk.isSection(ID_SDS)) {
+ result = parse(stream);
+ }
+ }
+
+ delete sceneFile;
+
+ return result;
+}
+
bool SDSScene::parse(Common::SeekableReadStream *stream) {
_magic = stream->readUint32LE();
_version = stream->readString();
@@ -258,6 +287,37 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
GDSScene::GDSScene() {
}
+bool GDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
+ Common::SeekableReadStream *sceneFile = resourceManager->getResource(filename);
+ if (!sceneFile)
+ error("Scene file %s not found", filename.c_str());
+
+ DgdsChunkReader chunk(sceneFile);
+
+ bool result = false;
+
+ while (chunk.readNextHeader(EX_GDS, filename)) {
+ if (chunk.isContainer()) {
+ continue;
+ }
+
+ chunk.readContent(decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
+
+ if (chunk.isSection(ID_GDS)) {
+ // do nothing, this is the container.
+ assert(chunk.isContainer());
+ } else if (chunk.isSection(ID_INF)) {
+ result = parseInf(stream);
+ } else if (chunk.isSection(ID_SDS)) {
+ result = parse(stream);
+ }
+ }
+
+ delete sceneFile;
+
+ return result;
+}
bool GDSScene::parseInf(Common::SeekableReadStream *s) {
_magic = s->readUint32LE();
@@ -265,7 +325,6 @@ bool GDSScene::parseInf(Common::SeekableReadStream *s) {
return !s->err();
}
-
bool GDSScene::parse(Common::SeekableReadStream *stream) {
readStruct5List(stream, _struct5List1);
readStruct5List(stream, _struct5List2);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index d3376a77c2e..e7af16891fd 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -145,11 +145,14 @@ protected:
Common::String _version;
};
+class ResourceManager;
+class Decompressor;
class GDSScene : public Scene {
public:
GDSScene();
+ bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
bool parseInf(Common::SeekableReadStream *s);
@@ -170,6 +173,7 @@ class SDSScene : public Scene {
public:
SDSScene();
+ bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
const Common::Array<struct Dialogue> &getLines() const { return _dialogues; }
Commit: af8e6da0b211ca47c29ff3d324371e1bc661cf63
https://github.com/scummvm/scummvm/commit/af8e6da0b211ca47c29ff3d324371e1bc661cf63
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add detection for beamish FDD data
This comes inside the GOG CD edition but should work on its own as the CD seems
to be this plus extra voice data.
Also:
* Add a better error message when it inevitably crashes
* spaces->tabs in detection table
Changed paths:
engines/dgds/detection_tables.h
engines/dgds/image.cpp
engines/dgds/includes.h
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index e74c6645776..c2e9b8d9cc7 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -84,33 +84,48 @@ static const ADGameDescription gameDescriptions[] = {
},
// Adventures of Willy Beamish (PC)
- {
- "beamish",
- 0,
- {
+ {
+ "beamish",
+ 0,
+ {
{"volume.rmf", 0, "c2be5cd4693dfcdbe45dd0e74dd5306d", 9896},
{"volume.001", 0, "7e9f3b0b7a5ec9989d3149f5e1f011a9", 1263007},
AD_LISTEND
},
- Common::EN_ANY,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
},
// Adventures of Willy Beamish (Macintosh)
- {
- "beamish",
- 0,
- {
+ {
+ "beamish",
+ 0,
+ {
{"volume.rmf", 0, "a8cd2d95b9c972fd33bf22b6de0b50c8", 9832},
{"volume.001", 0, "0849203c8da5f2b7868e11a77a537ee5", 1359359},
AD_LISTEND
},
- Common::EN_ANY,
- Common::kPlatformMacintosh,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Adventures of Willy Beamish (GOG FDD data)
+ {
+ "beamish",
+ "FDD",
+ {
+ {"volume.rmf", 0, "d270e05a95d85dd4096a099d9471438f", 9943},
+ {"volume.001", 0, "be08868abb909dcf24808676d063cba1", 1170013},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
},
// Heart of China (PC) : GOG
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 1c7075445aa..b11fc127ee4 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -155,6 +155,9 @@ void Image::loadBitmap(Common::String filename, int number) {
vqtpos = fileStream->pos();
vqtsize = chunk.getSize();
stream->skip(vqtsize);
+ } else if (chunk.isSection(ID_SCN)) {
+ // TODO: SCN file parsing - eg, "WILLCRED.BMP" from Willy Beamish
+ error("TODO: Implement SCN type BMP file parsing for %s", filename.c_str());
} else if (chunk.isSection(ID_OFF)) {
if (vqtpos == -1)
error("Expect VQT chunk before OFF chunk in BMP resource %s", filename.c_str());
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
index 73532be4e1e..17bf44773aa 100644
--- a/engines/dgds/includes.h
+++ b/engines/dgds/includes.h
@@ -40,6 +40,7 @@ namespace Dgds {
#define ID_REQ MKTAG24('R', 'E', 'Q')
#define ID_RES MKTAG24('R', 'E', 'S')
#define ID_SCR MKTAG24('S', 'C', 'R')
+#define ID_SCN MKTAG24('S', 'C', 'N')
#define ID_SDS MKTAG24('S', 'D', 'S')
#define ID_SNG MKTAG24('S', 'N', 'G')
#define ID_TAG MKTAG24('T', 'A', 'G')
Commit: a97a50f4cf6fc5bba3a5c7fbf5de9302de27f2d6
https://github.com/scummvm/scummvm/commit/a97a50f4cf6fc5bba3a5c7fbf5de9302de27f2d6
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Better handling of scene skipping
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 2a81941c1c1..96536197fa2 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -160,29 +160,34 @@ Common::Error DgdsEngine::run() {
_fntP = (PFont *)Font::load("WILLY.FNT", _resource, _decompressor);
}
+ bool moveToNext = false;
+
while (!shouldQuit()) {
if (eventMan->pollEvent(ev)) {
if (ev.type == Common::EVENT_KEYDOWN) {
switch (ev.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
- return Common::kNoError;
+ moveToNext = true;
default:
break;
}
}
}
- if (getGameId() == GID_DRAGON) {
- if (!interpIntro.run()) {
+ if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
+ if (moveToNext || !interpIntro.run()) {
+ moveToNext = false;
+
if (!creditsShown) {
creditsShown = true;
- _scene->load("S55.SDS", _resource, _decompressor); // FIXME: Removing this breaks the Bahumat scene dialog
+ if (getGameId() == GID_DRAGON)
+ _scene->load("S55.SDS", _resource, _decompressor); // FIXME: Removing this breaks the Bahumat scene dialog
interpIntro.load("INTRO.ADS");
} else {
return Common::kNoError;
}
}
- } else if (getGameId() == GID_CHINA || getGameId() == GID_BEAMISH) {
+ } else if (getGameId() == GID_BEAMISH) {
if (!interpIntro.run())
return Common::kNoError;
}
Commit: 379ef4c67dacb7126d3dd0704091d4e270ac48cb
https://github.com/scummvm/scummvm/commit/379ef4c67dacb7126d3dd0704091d4e270ac48cb
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Whitespace and variable initialization fixes
Changed paths:
engines/dgds/decompress.cpp
diff --git a/engines/dgds/decompress.cpp b/engines/dgds/decompress.cpp
index 8887b7b3c1a..a9653921da3 100644
--- a/engines/dgds/decompress.cpp
+++ b/engines/dgds/decompress.cpp
@@ -137,13 +137,13 @@ uint32 LzwDecompressor::decompress(byte *dest, uint32 sz, Common::SeekableReadSt
_tableMax <<= 1;
}
- for (uint32 j=0; j<_codeLen; j++) {
+ for (uint32 j = 0; j < _codeLen; j++) {
_codeTable[i].str[j] = _codeCur[j];
_codeTable[i].len++;
}
}
- for (uint32 i=0; i<_codeTable[code].len; i++)
+ for (uint32 i = 0; i < _codeTable[code].len; i++)
_codeCur[i] = _codeTable[code].str[i];
_codeLen = _codeTable[code].len;
@@ -155,17 +155,17 @@ uint32 LzwDecompressor::decompress(byte *dest, uint32 sz, Common::SeekableReadSt
}
uint32 LzwDecompressor::getCode(uint32 totalBits, Common::SeekableReadStream &input) {
- uint32 result, numBits;
const byte bitMasks[9] = {
0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
};
- numBits = totalBits;
- result = 0;
- while (numBits > 0) {
- uint32 useBits;
+ uint32 numBits = totalBits;
+ uint32 useBits = numBits;
+ uint32 result = 0;
- if (input.pos() >= input.size()) return 0xFFFFFFFF;
+ while (numBits > 0) {
+ if (input.pos() >= input.size())
+ return 0xFFFFFFFF;
if (_bitsSize == 0) {
_bitsSize = 8;
@@ -173,8 +173,10 @@ uint32 LzwDecompressor::getCode(uint32 totalBits, Common::SeekableReadStream &in
}
useBits = numBits;
- if (useBits > 8) useBits = 8;
- if (useBits > _bitsSize) useBits = _bitsSize;
+ if (useBits > 8)
+ useBits = 8;
+ if (useBits > _bitsSize)
+ useBits = _bitsSize;
result |= (_bitsData & bitMasks[useBits]) << (totalBits - numBits);
@@ -182,6 +184,7 @@ uint32 LzwDecompressor::getCode(uint32 totalBits, Common::SeekableReadStream &in
_bitsSize -= useBits;
_bitsData >>= useBits;
}
+
return result;
}
Commit: bda43200f5387a98d87958440e593142c1882051
https://github.com/scummvm/scummvm/commit/bda43200f5387a98d87958440e593142c1882051
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Read page count for ttm scripts
Changed paths:
engines/dgds/parser.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index e450434fb50..eb614bd5d73 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -103,9 +103,14 @@ bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
case ID_TAG:
scriptData->_tags = readTags(chunk.getContent());
break;
- case ID_VER:
- case ID_PAG: // Pages - ignore?
- //chunk._contentStream->skip(chunk._size);
+ case ID_VER: // Version - ignore
+ break;
+ case ID_PAG:
+ if (chunk.getSize() != 2) {
+ warning("unspected PAG chunk size %d in %s", chunk.getSize(), _filename.c_str());
+ break;
+ }
+ scriptData->_pages = chunk.getContent()->readUint16LE();
break;
default:
warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk.getId()), chunk.getSize(), _filename.c_str());
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 9a6f02fea85..ff0817eb98b 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -43,6 +43,7 @@ public:
class TTMData : public ScriptParserData {
public:
+ uint16 _pages;
};
struct TTMState {
Commit: bf9f08824a7213d1e1c453cb09155e1405df2189
https://github.com/scummvm/scummvm/commit/bf9f08824a7213d1e1c453cb09155e1405df2189
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add SCN format image parsing
Changed paths:
engines/dgds/image.cpp
engines/dgds/image.h
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index b11fc127ee4..46f162e537d 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -110,7 +110,7 @@ void Image::loadBitmap(Common::String filename, int number) {
}
int64 vqtpos = -1;
- int32 vqtsize = -1;
+ int64 scnpos = -1;
uint16 tileWidths[64];
uint16 tileHeights[64];
int32 tileOffset = 0;
@@ -121,6 +121,8 @@ void Image::loadBitmap(Common::String filename, int number) {
Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
+ if (tileCount > 64)
+ error("Image::loadBitmap: Unexpectedly large number of tiles in image (%d)", tileCount);
for (uint16 k = 0; k < tileCount; k++) {
tileWidths[k] = stream->readUint16LE();
}
@@ -153,20 +155,19 @@ void Image::loadBitmap(Common::String filename, int number) {
} else if (chunk.isSection(ID_VQT)) {
// Postpone parsing this until we have the offsets, which come after.
vqtpos = fileStream->pos();
- vqtsize = chunk.getSize();
- stream->skip(vqtsize);
} else if (chunk.isSection(ID_SCN)) {
- // TODO: SCN file parsing - eg, "WILLCRED.BMP" from Willy Beamish
- error("TODO: Implement SCN type BMP file parsing for %s", filename.c_str());
+ // Postpone parsing this until we have the offsets, which come after.
+ scnpos = fileStream->pos();
} else if (chunk.isSection(ID_OFF)) {
- if (vqtpos == -1)
- error("Expect VQT chunk before OFF chunk in BMP resource %s", filename.c_str());
+ if (vqtpos == -1 && scnpos == -1)
+ error("Expect VQT or SCN chunk before OFF chunk in BMP resource %s", filename.c_str());
// 2 possibilities: A set of offsets (find the one which we need and use it)
// or a single value of 0xffff. If it's only one tile the offset is always
// zero anyway. For subsequent images, round up to the next byte to start
// reading.
if (chunk.getSize() == 2) {
+ assert(scnpos == -1); // don't support this mode for SCN?
if (number != 0) {
uint16 val = stream->readUint16LE();
if (val != 0xffff)
@@ -183,11 +184,20 @@ void Image::loadBitmap(Common::String filename, int number) {
} else {
if (number)
stream->skip(4 * number);
- uint32 vqtOffset = stream->readUint32LE();
- // TODO: seek stream to end for tidiness?
- fileStream->seek(vqtpos + vqtOffset);
- loadVQT(_bmpData, tileWidths[number], tileHeights[number], 0, fileStream);
+
+ uint32 subImgOffset = stream->readUint32LE();
+ if (vqtpos != -1) {
+ fileStream->seek(vqtpos + subImgOffset);
+ loadVQT(_bmpData, tileWidths[number], tileHeights[number], 0, fileStream);
+ } else {
+ fileStream->seek(scnpos + subImgOffset);
+ loadSCN(_bmpData, tileWidths[number], tileHeights[number], fileStream);
+ }
}
+ // NOTE: This was proably the last chunk, but we don't check - should have
+ // the image data now. If we need to read another chunk we should fix up the
+ // offset of fileStream because we just broke it.
+ break;
}
}
@@ -384,6 +394,65 @@ uint32 Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toff
return state.offset;
}
+//
+// SCN file parsing - eg, "WILLCRED.BMP" from Willy Beamish
+// Ref: https://moddingwiki.shikadi.net/wiki/The_Incredible_Machine_Image_Format
+//
+bool Image::loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::SeekableReadStream *stream) {
+ surf.create(tw, th, Graphics::PixelFormat::createFormatCLUT8());
+ byte *dst = (byte *)surf.getPixels();
+
+ int32 y = 0;
+ int32 x = 0;
+
+ const byte addVal = stream->readByte();
+
+ byte lastcmd = 0xff;
+ while (y < th && !stream->eos()) {
+ byte val = stream->readByte();
+ byte cmd = val & 0xc0; // top 2 bits are the command
+ val &= 0x3f; // bottom 6 bits are the value
+ switch (cmd) {
+ case 0x00: // CMD 00 - move cursor down and back
+ if (lastcmd == 0x00 && val) {
+ x -= (val << 6);
+ } else {
+ y++;
+ x -= val;
+ }
+ if (x < 0)
+ error("Image::loadSCN: Moved x too far back on line %d", y);
+ break;
+ case 0x40: // CMD 01 - skip
+ if (!val)
+ y = th; // end of image.
+ else
+ x += val;
+ break;
+ case 0x80: { // CMD 10 - repeat val
+ byte color = stream->readByte();
+ for (uint16 i = 0; i < val; i++)
+ dst[y * tw + x + i] = color + addVal;
+ x += val;
+ break;
+ }
+ case 0xc0: { // CMD 11 - direct read of 4-bit values
+ for (uint16 i = 0; i < (val + 1) / 2; i++) {
+ byte color = stream->readByte();
+ dst[y * tw + x + i * 2] = (color >> 4) + addVal;
+ dst[y * tw + x + i * 2 + 1] = (color & 0xf) + addVal;
+ }
+ x += val;
+ break;
+ }
+ }
+ lastcmd = cmd;
+ if (x > tw)
+ error("Image::loadSCN: Invalid data, x went off the end of the row");
+ }
+ return !stream->err();
+}
+
void Image::loadPalette(Common::String filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream) {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index e7d926c591d..a6b51081334 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -55,6 +55,7 @@ private:
void loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
void loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
uint32 loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
+ bool loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::SeekableReadStream *stream);
Graphics::Surface _bmpData;
ResourceManager *_resourceMan;
Commit: 67ca71b91cb79874952cc2c112b22929a39fc3db
https://github.com/scummvm/scummvm/commit/67ca71b91cb79874952cc2c112b22929a39fc3db
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add a debug function to dump REQ contents after parsing
Changed paths:
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index d7d99a1417b..85c9d2871a2 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -30,23 +30,29 @@
namespace Dgds {
-Request::Request(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
+RequestParser::RequestParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
}
-bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
+bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
Common::SeekableReadStream *str = chunk.getContent();
uint16 numGadgets = str->readUint16LE();
data._gadgets.resize(numGadgets);
+ // Note: The original has some logic about loading single gadgets
+ // here, is only ever called with "num" of -1 (load all gadgets),
+ // so maybe just skip it?
+ if (num != -1)
+ error("Request::parseGADChunk: Implement handling of num other than -1");
+
for (Common::SharedPtr<Gadget> &gptr : data._gadgets) {
uint16 vals[12];
for (int i = 0; i < 12; i++)
vals[i] = str->readUint16LE();
uint16 gadgetTypeFlag = vals[5];
- if (num == 0 || num == vals[0]) {
+ if (num == -1 || num == vals[0]) {
if (gadgetTypeFlag == 1)
gptr.reset(new Gadget1());
else if (gadgetTypeFlag == 2)
@@ -96,8 +102,11 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num)
gptr->_sval2I = i;
}
- // FIXME: Where is this used?
- /*uint16 type3 = */str->readUint16LE();
+ uint16 val = str->readUint16LE();
+ if (gptr) {
+ gptr->_field20_0x28 = val;
+ gptr->_field21_0x2a = val >> 0xf;
+ }
// TODO: In each of these cases, work out the true offsets to these fields.
// and if they are shared between gadget types.
@@ -151,7 +160,7 @@ bool Request::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num)
}
-bool Request::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
+bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
Common::SeekableReadStream *str = chunk.getContent();
uint16 fileNum = str->readUint16LE();
@@ -188,7 +197,7 @@ bool Request::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num)
}
-bool Request::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
+bool RequestParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
RequestData &rdata = *(RequestData *)data;
int num = -1;
@@ -209,5 +218,54 @@ bool Request::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
}
-} // End of namespace Dgds
+Common::String Gadget::dump() const {
+ char buf1[6], buf2[6];
+ const char *sval1 = _sval1S.c_str();
+ const char *sval2 = _sval2S.c_str();
+ if (_sval1Type == 1) {
+ sval1 = buf1;
+ snprintf(buf1, 6, "%d", _sval1I);
+ }
+ if (_sval2Type == 1) {
+ sval2 = buf2;
+ snprintf(buf2, 6, "%d", _sval2I);
+ }
+
+ return Common::String::format(
+ "Gadget<num %d (%d,%d)-(%d,%d), typ %d, flgs %04x %04x svals %s, %s, '%s', parent (%d,%d)>",
+ _gadgetNo, _x, _y, _width, _height, _gadgetType, _flags2, _flags3, sval1, sval2,
+ _buttonName.c_str(), _parentX, _parentY);
+}
+
+Common::String Gadget1::dump() const {
+ const Common::String base = Gadget::dump();
+ return Common::String::format("Gadget1<%s, %d %d>", base.c_str(), _gadget1_i1, _gadget1_i2);
+}
+
+Common::String Gadget2::dump() const {
+ const Common::String base = Gadget::dump();
+ return Common::String::format("Gadget2<%s, %d %d %d %d>", base.c_str(), _gadget2_i1, _gadget2_i2, _gadget2_i3, _gadget2_i4);
+}
+
+Common::String Gadget8::dump() const {
+ const Common::String base = Gadget::dump();
+ return Common::String::format("Gadget8<%s, %d %d>", base.c_str(), _gadget8_i1, _gadget8_i2);
+}
+Common::String RequestData::dump() const {
+ Common::String ret = Common::String::format("RequestData<file %d (%d,%d) %d %d %d %d %d\n",
+ _fileNum, _x, _y, _vals[0], _vals[1], _vals[2], _vals[3], _vals[4]);
+ for (const auto &s1 : _struct1List)
+ ret += Common::String::format(" RequestStruct1<'%s' %d %d %d %d>\n", s1._str.c_str(),
+ s1._vals[0], s1._vals[1], s1._vals[2], s1._vals[3]);
+ for (const auto &s2 : _struct2List)
+ ret += Common::String::format(" RequestStruct2<%d %d %d %d %d %d>\n", s2._vals[0], s2._vals[1],
+ s2._vals[2], s2._vals[3], s2._vals[4], s2._vals[5]);
+ for (const auto &g : _gadgets)
+ ret += Common::String::format(" %s\n", g->dump().c_str());
+ ret += ">";
+
+ return ret;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 1d508c4b5af..58ea3ef8655 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -40,7 +40,8 @@ struct RequestStruct2 {
};
// basic gadget is 52 (0x34) bytes
-struct Gadget {
+class Gadget {
+public:
// NOTE: Most of these names are still guesses
uint16 _gadgetNo;
uint16 _x;
@@ -67,28 +68,42 @@ struct Gadget {
uint16 _field16_0x24;
uint16 _field17_0x26;
+ uint16 _field20_0x28;
+ uint16 _field21_0x2a;
+
uint16 _parentX;
uint16 _parentY;
+
+ virtual Common::String dump() const;
};
// extended gadget type 1 is 62 (0x3e) bytes
-struct Gadget1 : public Gadget {
+class Gadget1 : public Gadget {
+public:
uint16 _gadget1_i1;
uint16 _gadget1_i2;
+
+ Common::String dump() const override;
};
// extended gadget type 2 is 74 (0x4a) bytes
-struct Gadget2 : public Gadget {
+class Gadget2 : public Gadget {
+public:
uint16 _gadget2_i1;
uint16 _gadget2_i2;
uint16 _gadget2_i3;
uint16 _gadget2_i4;
+
+ Common::String dump() const override;
};
// extended gadget type 8 is 68 (0x44) bytes
-struct Gadget8 : public Gadget {
+class Gadget8 : public Gadget {
+public:
uint16 _gadget8_i1;
uint16 _gadget8_i2;
+
+ Common::String dump() const override;
};
class RequestData : public ParserData {
@@ -96,10 +111,12 @@ public:
uint16 _fileNum;
uint16 _x;
uint16 _y;
- uint16 _vals[7];
+ uint16 _vals[5];
Common::Array<RequestStruct1> _struct1List;
Common::Array<RequestStruct2> _struct2List;
Common::Array<Common::SharedPtr<Gadget>> _gadgets;
+
+ Common::String dump() const;
};
/**
@@ -108,17 +125,16 @@ public:
*
* Request files include REQ and GAD (Gadget) chunks.
*/
-class Request : public DgdsParser {
+class RequestParser : public DgdsParser {
public:
- Request(ResourceManager *resman, Decompressor *decompressor);
- virtual ~Request() {}
+ RequestParser(ResourceManager *resman, Decompressor *decompressor);
+ virtual ~RequestParser() {}
bool handleChunk(DgdsChunkReader &chunk, ParserData *data) override;
protected:
bool parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num);
bool parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num);
-
};
Commit: 6132d44e42aac7065876dc2b1661fc9785fd2127
https://github.com/scummvm/scummvm/commit/6132d44e42aac7065876dc2b1661fc9785fd2127
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Give request struct a better name
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 96536197fa2..e7c8cfb6458 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -136,12 +136,14 @@ Common::Error DgdsEngine::run() {
// Test parsing some things..
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
- RequestData invRequestData;
- RequestData vcrRequestData;
- Request invRequest(_resource, _decompressor);
- Request vcrRequest(_resource, _decompressor);
+ REQFileData invRequestData;
+ REQFileData vcrRequestData;
+ RequestParser invRequest(_resource, _decompressor);
+ RequestParser vcrRequest(_resource, _decompressor);
invRequest.parse(&invRequestData, "DINV.REQ");
vcrRequest.parse(&vcrRequestData, "DVCR.REQ");
+ debug("Parsed DINV.REQ:\n%s", invRequestData.dump().c_str());
+ debug("Parsed DVCR.REQ:\n%s", vcrRequestData.dump().c_str());
// Load the intro and play it for now.
interpIntro.load("TITLE1.ADS");
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 85c9d2871a2..44cd74bed3a 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -163,25 +163,30 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
Common::SeekableReadStream *str = chunk.getContent();
- uint16 fileNum = str->readUint16LE();
+ uint16 chunkNum = str->readUint16LE();
- if (num != 0 && num != fileNum)
- return true;
+ // Note: The original has some logic about loading single request blocks
+ // here, is only ever called with "num" of -1 (load all),
+ // so maybe just skip it?
+ if (num != -1)
+ error("Request::parseGADChunk: Implement handling of num other than -1");
- data._fileNum = fileNum;
+ data._fileNum = chunkNum;
data._x = str->readUint16LE();
data._y = str->readUint16LE();
for (int i = 0; i < 5; i++)
data._vals[i] = str->readUint16LE();
- uint16 numStruct1 = str->readUint16LE();
- data._struct1List.resize(numStruct1);
- for (int i = 0; i < numStruct1; i++) {
- RequestStruct1 &dst = data._struct1List[i];
- for (int j = 0; j < 4; j++) {
+ uint16 numTextItems = str->readUint16LE();
+ data._textItemList.resize(numTextItems);
+ for (int i = 0; i < numTextItems; i++) {
+ TextItem &dst = data._textItemList[i];
+ dst._x = str->readUint16LE();
+ dst._y = str->readUint16LE();
+ for (int j = 0; j < 2; j++) {
dst._vals[j] = str->readUint16LE();
}
- dst._str = str->readString();
+ dst._txt = str->readString();
}
uint16 numStruct2 = str->readUint16LE();
@@ -198,7 +203,9 @@ bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int
bool RequestParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
- RequestData &rdata = *(RequestData *)data;
+ REQFileData &rfdata = *static_cast<REQFileData *>(data);
+
+ // The game supports loading a particular item, but always passes -1?
int num = -1;
if (chunk.isContainer()) {
@@ -209,10 +216,14 @@ bool RequestParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
return false; // continue parsing
}
- if (chunk.getId() == ID_REQ)
- parseREQChunk(rdata, chunk, num);
- else if (chunk.getId() == ID_GAD)
- parseGADChunk(rdata, chunk, num);
+ if (chunk.getId() == ID_REQ) {
+ rfdata._requests.resize(rfdata._requests.size() + 1);
+ parseREQChunk(rfdata._requests.back(), chunk, num);
+ } else if (chunk.getId() == ID_GAD) {
+ if (rfdata._requests.empty())
+ error("GAD chunk before any REQ chunks in Reqeust file %s", _filename.c_str());
+ parseGADChunk(rfdata._requests.back(), chunk, num);
+ }
return chunk.getContent()->err();
}
@@ -232,7 +243,7 @@ Common::String Gadget::dump() const {
}
return Common::String::format(
- "Gadget<num %d (%d,%d)-(%d,%d), typ %d, flgs %04x %04x svals %s, %s, '%s', parent (%d,%d)>",
+ "Gadget<num %d pos (%d,%d) sz (%d,%d), typ %d, flgs %04x %04x svals %s, %s, '%s', parent (%d,%d)>",
_gadgetNo, _x, _y, _width, _height, _gadgetType, _flags2, _flags3, sval1, sval2,
_buttonName.c_str(), _parentX, _parentY);
}
@@ -253,11 +264,11 @@ Common::String Gadget8::dump() const {
}
Common::String RequestData::dump() const {
- Common::String ret = Common::String::format("RequestData<file %d (%d,%d) %d %d %d %d %d\n",
+ Common::String ret = Common::String::format("RequestData<file %d pos (%d,%d) size (%d, %d) %d %d %d\n",
_fileNum, _x, _y, _vals[0], _vals[1], _vals[2], _vals[3], _vals[4]);
- for (const auto &s1 : _struct1List)
- ret += Common::String::format(" RequestStruct1<'%s' %d %d %d %d>\n", s1._str.c_str(),
- s1._vals[0], s1._vals[1], s1._vals[2], s1._vals[3]);
+ for (const auto &s1 : _textItemList)
+ ret += Common::String::format(" TextItem<'%s' pos (%d,%d) %d %d>\n", s1._txt.c_str(),
+ s1._x, s1._y, s1._vals[0], s1._vals[1]);
for (const auto &s2 : _struct2List)
ret += Common::String::format(" RequestStruct2<%d %d %d %d %d %d>\n", s2._vals[0], s2._vals[1],
s2._vals[2], s2._vals[3], s2._vals[4], s2._vals[5]);
@@ -268,4 +279,15 @@ Common::String RequestData::dump() const {
return ret;
}
+Common::String REQFileData::dump() const {
+ Common::String ret("REQFileData<\n");
+ for (const auto &req : _requests) {
+ ret += req.dump().c_str();
+ ret += "\n";
+ }
+ ret += ">";
+
+ return ret;
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 58ea3ef8655..90a3b9f005c 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -30,9 +30,11 @@
namespace Dgds {
-struct RequestStruct1 {
- uint16 _vals[4];
- Common::String _str;
+struct TextItem {
+ uint16 _x;
+ uint16 _y;
+ uint16 _vals[2];
+ Common::String _txt;
};
struct RequestStruct2 {
@@ -106,19 +108,27 @@ public:
Common::String dump() const override;
};
-class RequestData : public ParserData {
+class RequestData {
public:
uint16 _fileNum;
uint16 _x;
uint16 _y;
uint16 _vals[5];
- Common::Array<RequestStruct1> _struct1List;
+ Common::Array<TextItem> _textItemList;
Common::Array<RequestStruct2> _struct2List;
Common::Array<Common::SharedPtr<Gadget>> _gadgets;
Common::String dump() const;
};
+// A REQ file contains a sequence of REQ and GAD block pairs.
+class REQFileData : public ParserData {
+public:
+ Common::Array<RequestData> _requests;
+
+ Common::String dump() const;
+};
+
/**
* A "Request" is described by a REQ file. Requests are things like menus,
* inventory items, etc.
Commit: 3d54a567cffe6e2efa2bbc4c0cb895fa9f42ad6d
https://github.com/scummvm/scummvm/commit/3d54a567cffe6e2efa2bbc4c0cb895fa9f42ad6d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Enhance filedump console command
Changed paths:
engines/dgds/console.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 2552effb907..2b7c8ab7c14 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -68,13 +68,15 @@ bool Console::cmdFileSearch(int argc, const char **argv) {
bool Console::cmdFileDump(int argc, const char **argv) {
if (argc < 2) {
- debugPrintf("Usage: %s <file> <ignore patches> <unpack>\n", argv[0]);
+ debugPrintf("Usage: %s <file> [ignore patches] [unpack] [outputpath] [chunktype]\n", argv[0]);
return true;
}
Common::String fileName = argv[1];
bool ignorePatches = (argc > 2) && (!scumm_stricmp(argv[2], "true") || !strcmp(argv[2], "1"));
bool unpack = (argc > 3) && (!scumm_stricmp(argv[3], "true") || !strcmp(argv[3], "1"));
+ Common::String dstPath = (argc > 4) ? argv[4] : "";
+ Common::String chunkType = (argc > 5) ? argv[5] : "";
Common::SeekableReadStream *resStream = _vm->getResource(fileName, ignorePatches);
if (resStream == nullptr) {
debugPrintf("Resource not found\n");
@@ -99,6 +101,9 @@ bool Console::cmdFileDump(int argc, const char **argv) {
DgdsChunkReader chunk(resStream);
while (chunk.readNextHeader(ex, fileName)) {
+ if (!chunkType.empty() && !chunkType.equals(chunk.getIdStr()))
+ continue;
+
chunk.readContent(_vm->getDecompressor());
memcpy(ptr, chunk.getIdStr(), 4);
@@ -115,7 +120,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
delete resStream;
Common::DumpFile out;
- out.open(Common::Path(fileName));
+ out.open(Common::Path(dstPath + fileName));
out.write(data, size);
out.flush();
out.close();
Commit: d2186d863d695be6db6975e4c0c1e52376e4a7a7
https://github.com/scummvm/scummvm/commit/d2186d863d695be6db6975e4c0c1e52376e4a7a7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Correct request parsing and test on more games
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/parser.cpp
engines/dgds/request.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index e7c8cfb6458..3c7fb9e8d55 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -131,19 +131,16 @@ Common::Error DgdsEngine::run() {
ADSInterpreter interpIntro(this);
bool creditsShown = false;
+ REQFileData invRequestData;
+ REQFileData vcrRequestData;
+ RequestParser reqParser(_resource, _decompressor);
if (getGameId() == GID_DRAGON) {
// Test parsing some things..
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
- REQFileData invRequestData;
- REQFileData vcrRequestData;
- RequestParser invRequest(_resource, _decompressor);
- RequestParser vcrRequest(_resource, _decompressor);
- invRequest.parse(&invRequestData, "DINV.REQ");
- vcrRequest.parse(&vcrRequestData, "DVCR.REQ");
- debug("Parsed DINV.REQ:\n%s", invRequestData.dump().c_str());
- debug("Parsed DVCR.REQ:\n%s", vcrRequestData.dump().c_str());
+ reqParser.parse(&invRequestData, "DINV.REQ");
+ reqParser.parse(&vcrRequestData, "DVCR.REQ");
// Load the intro and play it for now.
interpIntro.load("TITLE1.ADS");
@@ -151,17 +148,31 @@ Common::Error DgdsEngine::run() {
_fntP = (PFont *)Font::load("DRAGON.FNT", _resource, _decompressor);
} else if (getGameId() == GID_CHINA) {
+ _gdsScene->load("HOC.GDS", _resource, _decompressor);
+
+ reqParser.parse(&invRequestData, "HINV.REQ");
+ reqParser.parse(&vcrRequestData, "HVCR.REQ");
+
//_scene->load("S101.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
_fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
} else if (getGameId() == GID_BEAMISH) {
+ // TODO: This doesn't parse correctly yet.
+ //_gdsScene->load("WILLY.GDS", _resource, _decompressor);
+
+ reqParser.parse(&invRequestData, "WINV.REQ");
+ reqParser.parse(&vcrRequestData, "WVCR.REQ");
+
//_scene->load("S34.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
_fntP = (PFont *)Font::load("WILLY.FNT", _resource, _decompressor);
}
+ debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
+ debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
+
bool moveToNext = false;
while (!shouldQuit()) {
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index eb614bd5d73..9747e67c7a0 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -91,7 +91,7 @@ Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableRea
bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
- TTMData *scriptData = (TTMData *)data;
+ TTMData *scriptData = static_cast<TTMData *>(data);
switch (chunk.getId()) {
case ID_TTI: // Ignore containers
@@ -121,7 +121,7 @@ bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
}
bool ADSParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
- ADSData *scriptData = (ADSData *)data;
+ ADSData *scriptData = static_cast<ADSData *>(data);
Common::SeekableReadStream *chunkStream = chunk.getContent();
switch (chunk.getId()) {
case EX_ADS:
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 44cd74bed3a..5220c2bbf85 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -233,11 +233,11 @@ Common::String Gadget::dump() const {
char buf1[6], buf2[6];
const char *sval1 = _sval1S.c_str();
const char *sval2 = _sval2S.c_str();
- if (_sval1Type == 1) {
+ if (_sval1Type != 1) {
sval1 = buf1;
snprintf(buf1, 6, "%d", _sval1I);
}
- if (_sval2Type == 1) {
+ if (_sval2Type != 1) {
sval2 = buf2;
snprintf(buf2, 6, "%d", _sval2I);
}
Commit: d68d7348dcf8a4cab26dd353c1f6894e76783690
https://github.com/scummvm/scummvm/commit/d68d7348dcf8a4cab26dd353c1f6894e76783690
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Give gadget types meaningful names
Changed paths:
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 5220c2bbf85..ccc9dd706c9 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -51,14 +51,14 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
for (int i = 0; i < 12; i++)
vals[i] = str->readUint16LE();
- uint16 gadgetTypeFlag = vals[5];
+ GadgetType gadgetType = static_cast<GadgetType>(vals[5]);
if (num == -1 || num == vals[0]) {
- if (gadgetTypeFlag == 1)
- gptr.reset(new Gadget1());
- else if (gadgetTypeFlag == 2)
- gptr.reset(new Gadget2());
- else if (gadgetTypeFlag == 8)
- gptr.reset(new Gadget8());
+ if (gadgetType == kGadgetText)
+ gptr.reset(new TextAreaGadget());
+ else if (gadgetType == kGadgetSlider)
+ gptr.reset(new SliderGadget());
+ else if (gadgetType == kGadgetImage)
+ gptr.reset(new ImageGadget());
else
gptr.reset(new Gadget());
}
@@ -69,7 +69,7 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
gptr->_y = vals[2];
gptr->_width = vals[3];
gptr->_height = vals[4];
- gptr->_gadgetType = vals[5];
+ gptr->_gadgetType = gadgetType;
gptr->_flags2 = vals[6];
gptr->_flags3 = vals[7];
gptr->_field14_0x20 = vals[8];
@@ -110,25 +110,25 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
// TODO: In each of these cases, work out the true offsets to these fields.
// and if they are shared between gadget types.
- switch (gadgetTypeFlag) {
- case 1: {
+ switch (gadgetType) {
+ case kGadgetText: {
uint16 i1 = str->readUint16LE();
uint16 i2 = str->readUint16LE();
if (gptr) {
- Gadget1 *g1 = static_cast<Gadget1 *>(gptr.get());
- // TODO: These fields might are actually shared with other gadget types?
+ TextAreaGadget *g1 = static_cast<TextAreaGadget *>(gptr.get());
+ // TODO: These fields might actually be shared with other gadget types?
g1->_gadget1_i1 = i1;
g1->_gadget1_i2 = i2;
}
break;
}
- case 2: {
+ case kGadgetSlider: {
uint16 i1 = str->readUint16LE();
uint16 i2 = str->readUint16LE();
uint16 i3 = str->readUint16LE();
uint16 i4 = str->readUint16LE();
if (gptr) {
- Gadget2 *g2 = static_cast<Gadget2 *>(gptr.get());
+ SliderGadget *g2 = static_cast<SliderGadget *>(gptr.get());
g2->_gadget2_i1 = i1;
g2->_gadget2_i2 = i2;
g2->_gadget2_i3 = i3;
@@ -136,17 +136,17 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
}
break;
}
- case 4: {
+ case kGadgetButton: {
Common::String s = str->readString();
if (gptr)
gptr->_buttonName = s;
break;
}
- case 8: {
+ case kGadgetImage: {
uint16 i1 = str->readUint16LE();
uint16 i2 = str->readUint16LE();
if (gptr) {
- Gadget8 *g8 = static_cast<Gadget8 *>(gptr.get());
+ ImageGadget *g8 = static_cast<ImageGadget *>(gptr.get());
g8->_gadget8_i1 = i1;
g8->_gadget8_i2 = i2;
}
@@ -243,24 +243,25 @@ Common::String Gadget::dump() const {
}
return Common::String::format(
- "Gadget<num %d pos (%d,%d) sz (%d,%d), typ %d, flgs %04x %04x svals %s, %s, '%s', parent (%d,%d)>",
+ "%s<num %d pos (%d,%d) sz (%d,%d), typ %d, flgs %04x %04x svals %s, %s, '%s', parent (%d,%d)>",
+ _gadgetType == kGadgetButton ? "ButtonGadget" : "Gadget",
_gadgetNo, _x, _y, _width, _height, _gadgetType, _flags2, _flags3, sval1, sval2,
_buttonName.c_str(), _parentX, _parentY);
}
-Common::String Gadget1::dump() const {
+Common::String TextAreaGadget::dump() const {
const Common::String base = Gadget::dump();
- return Common::String::format("Gadget1<%s, %d %d>", base.c_str(), _gadget1_i1, _gadget1_i2);
+ return Common::String::format("TextArea<%s, %d %d>", base.c_str(), _gadget1_i1, _gadget1_i2);
}
-Common::String Gadget2::dump() const {
+Common::String SliderGadget::dump() const {
const Common::String base = Gadget::dump();
- return Common::String::format("Gadget2<%s, %d %d %d %d>", base.c_str(), _gadget2_i1, _gadget2_i2, _gadget2_i3, _gadget2_i4);
+ return Common::String::format("Slider<%s, %d %d %d %d>", base.c_str(), _gadget2_i1, _gadget2_i2, _gadget2_i3, _gadget2_i4);
}
-Common::String Gadget8::dump() const {
+Common::String ImageGadget::dump() const {
const Common::String base = Gadget::dump();
- return Common::String::format("Gadget8<%s, %d %d>", base.c_str(), _gadget8_i1, _gadget8_i2);
+ return Common::String::format("Image<%s, %d %d>", base.c_str(), _gadget8_i1, _gadget8_i2);
}
Common::String RequestData::dump() const {
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 90a3b9f005c..4193d4e10f7 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -41,6 +41,14 @@ struct RequestStruct2 {
uint16 _vals[6];
};
+enum GadgetType {
+ kGadgetNone = 0,
+ kGadgetText = 1,
+ kGadgetSlider = 2,
+ kGadgetButton = 4,
+ kGadgetImage = 8,
+};
+
// basic gadget is 52 (0x34) bytes
class Gadget {
public:
@@ -50,7 +58,7 @@ public:
uint16 _y;
uint16 _width;
uint16 _height;
- uint16 _gadgetType;
+ GadgetType _gadgetType;
uint16 _flags2;
uint16 _flags3;
@@ -80,7 +88,7 @@ public:
};
// extended gadget type 1 is 62 (0x3e) bytes
-class Gadget1 : public Gadget {
+class TextAreaGadget : public Gadget {
public:
uint16 _gadget1_i1;
uint16 _gadget1_i2;
@@ -89,7 +97,7 @@ public:
};
// extended gadget type 2 is 74 (0x4a) bytes
-class Gadget2 : public Gadget {
+class SliderGadget : public Gadget {
public:
uint16 _gadget2_i1;
uint16 _gadget2_i2;
@@ -100,7 +108,7 @@ public:
};
// extended gadget type 8 is 68 (0x44) bytes
-class Gadget8 : public Gadget {
+class ImageGadget : public Gadget {
public:
uint16 _gadget8_i1;
uint16 _gadget8_i2;
Commit: dab391f442f3fd40ef5b61284dbc591eb77f56c8
https://github.com/scummvm/scummvm/commit/dab391f442f3fd40ef5b61284dbc591eb77f56c8
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Cleaner font loading and eliminate memory leak
Changed paths:
engines/dgds/font.cpp
engines/dgds/font.h
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index e6fe8d3c048..21975a3db6d 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -54,8 +54,12 @@ Font *Font::load(const Common::String &filename, ResourceManager *resourceManage
debug(" magic: %u", magic);
if (magic != 0xFF)
- // font = FFont::load(*stream); // TODO: Where is this used?
- error("Font::load(): Attempted to load a font of type FFont");
+ // Fixed-width font. Do these get used in any game?
+#if DGDS_SUPPORT_FIXED_WIDTH
+ font = FFont::load(*stream);
+#else
+ error("Font::load(): Attempted to load FFont (fixed-width font)");
+#endif
else
font = PFont::load(*stream, decompressor);
}
@@ -66,6 +70,12 @@ Font *Font::load(const Common::String &filename, ResourceManager *resourceManage
return font;
}
+Font::Font(byte w, byte h, byte start, byte count, byte *data) : _w(w), _h(h), _start(start), _count(count), _data(data) { }
+
+Font::~Font() {
+ delete [] _data;
+}
+
bool Font::hasChar(byte chr) const {
return (chr >= _start && chr <= (_start + _count));
}
@@ -98,7 +108,10 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
}
}
-#if 0
+#if DGDS_SUPPORT_FIXED_WIDTH
+FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : Font(w, h, start, count, data) {
+}
+
void FFont::mapChar(byte chr, int &pos, int &bit) const {
pos = (chr - _start) * _h;
bit = 8 - _w;
@@ -124,18 +137,18 @@ FFont *FFont::load(Common::SeekableReadStream &input) {
debug(" w: %u, h: %u, start: 0x%x, count: %u", w, h, start, count);
- FFont *fnt = new FFont;
- fnt->_w = w;
- fnt->_h = h;
- fnt->_start = start;
- fnt->_count = count;
- fnt->_data = new byte[size];
+ byte *data = new byte[size];
input.read(fnt->_data, size);
- return fnt;
+ return new FFont(w, h, start, count, data);
}
#endif
+PFont::PFont(byte w, byte h, byte start, byte count, byte *data, const uint16 *offsets, const byte *widths)
+: Font(w, h, start, count, data), _offsets(offsets), _widths(widths)
+{
+}
+
void PFont::mapChar(byte chr, int& pos, int& bit) const {
pos = READ_LE_UINT16(&_offsets[chr - _start]);
bit = 0;
@@ -171,17 +184,9 @@ PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor
uint32 uncompressedSize;
byte *data = decompressor->decompress(&input, size, uncompressedSize);
- PFont *fnt = new PFont;
- fnt->_w = w;
- fnt->_h = h;
- fnt->_start = start;
- fnt->_count = count;
-
- fnt->_offsets = (uint16*)data;
- fnt->_widths = data + 2 * count;
- fnt->_data = data + 3 * count;
-
- return fnt;
+ return new PFont(w, h, start, count, data,
+ reinterpret_cast<const uint16 *>(data + 2 * count),
+ data + 3 * count);
}
} // End of namespace Dgds
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index cf187721c02..838c2749552 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -42,6 +42,8 @@ class Decompressor;
class Font : public Graphics::Font {
public:
+ Font(byte w, byte h, byte start, byte count, byte *data);
+ virtual ~Font();
int getFontHeight() const { return _h; }
int getMaxCharWidth() const { return _w; }
virtual int getCharWidth(uint32 chr) const = 0;
@@ -58,22 +60,26 @@ protected:
bool hasChar(byte chr) const;
};
+/* Proportional font (each char has its own width and so data is a different size) */
class PFont : public Font {
public:
+ PFont(byte w, byte h, byte start, byte count, byte *data, const uint16 *offsets, const byte *widths);
int getCharWidth(uint32 chr) const { return _widths[chr - _start]; }
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static PFont *load(Common::SeekableReadStream &input, Decompressor *decompressor);
protected:
- uint16 *_offsets;
- byte *_widths;
+ const uint16 *_offsets;
+ const byte *_widths;
void mapChar(byte chr, int &pos, int &bit) const;
};
-#if 0
+#if DGDS_SUPPORT_FIXED_WIDTH
+/* Fixed-width font */
class FFont : public Font {
public:
+ FFont(byte w, byte h, byte start, byte count, byte *data);
int getCharWidth(uint32 chr) const { return _w; }
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static FFont *load(Common::SeekableReadStream &input);
Commit: 41dba27e0f9fa3f5e77479f86fa3433cfae1020a
https://github.com/scummvm/scummvm/commit/41dba27e0f9fa3f5e77479f86fa3433cfae1020a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add font manager to keep multiple fonts
This may need some rework eventually, but the game holds a "current" or
"default" font, as well as a collection of others. Add similar handling.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/font.cpp
engines/dgds/font.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 3c7fb9e8d55..baccdeda624 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -61,7 +61,7 @@
namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
- : Engine(syst), _image(nullptr), /*_fntF(nullptr),*/ _fntP(nullptr), _console(nullptr),
+ : Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
_resource(nullptr) {
syncSoundSettings();
@@ -90,6 +90,7 @@ DgdsEngine::~DgdsEngine() {
delete _scene;
delete _gdsScene;
delete _soundPlayer;
+ delete _fontManager;
}
void readStrings(Common::SeekableReadStream *stream) {
@@ -117,6 +118,7 @@ Common::Error DgdsEngine::run() {
_soundPlayer = new Sound(_mixer, _resource, _decompressor);
_scene = new SDSScene();
_gdsScene = new GDSScene();
+ _fontManager = new FontManager();
setDebugger(_console);
@@ -135,6 +137,8 @@ Common::Error DgdsEngine::run() {
REQFileData vcrRequestData;
RequestParser reqParser(_resource, _decompressor);
+ _fontManager->loadFonts(getGameId(), _resource, _decompressor);
+
if (getGameId() == GID_DRAGON) {
// Test parsing some things..
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
@@ -146,7 +150,6 @@ Common::Error DgdsEngine::run() {
interpIntro.load("TITLE1.ADS");
//interpIntro.load("INTRO.ADS");
- _fntP = (PFont *)Font::load("DRAGON.FNT", _resource, _decompressor);
} else if (getGameId() == GID_CHINA) {
_gdsScene->load("HOC.GDS", _resource, _decompressor);
@@ -155,8 +158,6 @@ Common::Error DgdsEngine::run() {
//_scene->load("S101.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
-
- _fntP = (PFont *)Font::load("HOC.FNT", _resource, _decompressor);
} else if (getGameId() == GID_BEAMISH) {
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
@@ -166,8 +167,6 @@ Common::Error DgdsEngine::run() {
//_scene->load("S34.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
-
- _fntP = (PFont *)Font::load("WILLY.FNT", _resource, _decompressor);
}
debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 8de2f66822e..b77b02fa53d 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -42,8 +42,7 @@ class Console;
class ResourceManager;
class Decompressor;
class Image;
-class PFont;
-class FFont;
+class FontManager;
class SDSScene;
class GDSScene;
class Sound;
@@ -75,8 +74,7 @@ private:
SDSScene *_scene;
GDSScene *_gdsScene;
- PFont *_fntP;
- //FFont *_fntF;
+ FontManager *_fontManager;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -92,7 +90,7 @@ public:
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
- const PFont *getFntP() const { return _fntP; }
+ const FontManager *getFontMan() const { return _fontManager; }
};
} // End of namespace Dgds
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index 21975a3db6d..bff1f1cde1b 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -54,12 +54,7 @@ Font *Font::load(const Common::String &filename, ResourceManager *resourceManage
debug(" magic: %u", magic);
if (magic != 0xFF)
- // Fixed-width font. Do these get used in any game?
-#if DGDS_SUPPORT_FIXED_WIDTH
font = FFont::load(*stream);
-#else
- error("Font::load(): Attempted to load FFont (fixed-width font)");
-#endif
else
font = PFont::load(*stream, decompressor);
}
@@ -108,7 +103,6 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
}
}
-#if DGDS_SUPPORT_FIXED_WIDTH
FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : Font(w, h, start, count, data) {
}
@@ -138,11 +132,10 @@ FFont *FFont::load(Common::SeekableReadStream &input) {
debug(" w: %u, h: %u, start: 0x%x, count: %u", w, h, start, count);
byte *data = new byte[size];
- input.read(fnt->_data, size);
+ input.read(data, size);
return new FFont(w, h, start, count, data);
}
-#endif
PFont::PFont(byte w, byte h, byte start, byte count, byte *data, const uint16 *offsets, const byte *widths)
: Font(w, h, start, count, data), _offsets(offsets), _widths(widths)
@@ -189,4 +182,44 @@ PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor
data + 3 * count);
}
+FontManager::~FontManager() {
+ for (auto &entry : _fonts)
+ if (entry._key != kDefaultFont)
+ delete entry._value;
+}
+
+const Font *FontManager::getFont(FontType type) const {
+ return _fonts.getVal(type);
+}
+
+void FontManager::tryLoadFont(FontType ftype, const char *fname, ResourceManager *resMgr, Decompressor *decomp) {
+ Font *font = Font::load(fname, resMgr, decomp);
+ if (font)
+ _fonts.setVal(ftype, font);
+ else
+ error("Failed to load font %s", fname);
+}
+
+
+void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompressor *decomp) {
+ tryLoadFont(k8x8Font, "8X8.FNT", resMgr, decomp);
+ tryLoadFont(k6x6Font, "6X6.FNT", resMgr, decomp);
+ tryLoadFont(k4x5Font, "4x5.FNT", resMgr, decomp);
+ if (gameId == GID_DRAGON) {
+ tryLoadFont(kGameFont, "DRAGON.FNT", resMgr, decomp);
+ tryLoadFont(k7x8Font, "7X8.FNT", resMgr, decomp);
+ tryLoadFont(kP6x6Font, "P6X6.FNT", resMgr, decomp);
+ } else if (gameId == GID_CHINA) {
+ tryLoadFont(kGameFont, "HOC.FNT", resMgr, decomp);
+ tryLoadFont(kChinaFont, "CHINA.FNT", resMgr, decomp);
+ tryLoadFont(kChineseFont, "CHINESE.FNT", resMgr, decomp);
+ } else if (gameId == GID_BEAMISH) {
+ tryLoadFont(kGameFont, "WILLY.FNT", resMgr, decomp);
+ tryLoadFont(kWVCRFont, "WVCR.FNT", resMgr, decomp);
+ tryLoadFont(kComix16Font, "COMIX_16.FNT", resMgr, decomp);
+ }
+
+ _fonts.setVal(kDefaultFont, _fonts.getVal(kGameFont));
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index 838c2749552..6c53d40b7d6 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -24,8 +24,12 @@
#define DGDS_FONT_H
#include "common/scummsys.h"
+#include "common/hashmap.h"
+#include "common/func.h"
#include "graphics/font.h"
+#include "dgds/dgds.h"
+
namespace Graphics {
class Font;
struct Surface;
@@ -75,7 +79,6 @@ protected:
void mapChar(byte chr, int &pos, int &bit) const;
};
-#if DGDS_SUPPORT_FIXED_WIDTH
/* Fixed-width font */
class FFont : public Font {
public:
@@ -87,8 +90,44 @@ public:
protected:
void mapChar(byte chr, int &pos, int &bit) const;
};
-#endif
+
+class FontManager {
+public:
+ enum FontType {
+ kDefaultFont = 0,
+ k8x8Font,
+ k6x6Font,
+ k4x5Font,
+ kGameFont, // DRAGON for Rise of the Dragon, WILLY for Willy Beamish, HOC for Heart of China.
+ k7x8Font, // Rise of the Dragon only
+ kP6x6Font, // Rise of the Dragon only
+ kWVCRFont, // Willy Beamish only
+ kComix16Font, // Willy Beamish only
+ kChinaFont, // Heart of China only
+ kChineseFont, // Heart of China only
+ };
+
+ FontManager() {}
+ ~FontManager();
+
+ const Font *getFont(FontType) const;
+ void loadFonts(DgdsGameId gameId, ResourceManager *resourceManager, Decompressor *decompressor);
+private:
+
+ void tryLoadFont(FontType type, const char *filename, ResourceManager *resourceManager, Decompressor *decompressor);
+
+ struct FontTypeHash {
+ Common::Hash<const char *> hash;
+
+ uint operator()(FontType val) const {
+ return (uint)val;
+ }
+ };
+
+ Common::HashMap<FontType, Font*, FontTypeHash> _fonts;
+};
} // End of namespace Dgds
+
#endif // DGDS_FONT_H
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index c4bc00f2058..48d4c522851 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -195,15 +195,15 @@ bool TTMInterpreter::run() {
if (!_text.str.empty()) {
Common::StringArray lines;
- const PFont *fntP = _vm->getFntP();
- const int h = fntP->getFontHeight();
+ const Font *fnt = _vm->getFontMan()->getFont(FontManager::kGameFont);
+ const int h = fnt->getFontHeight();
- fntP->wordWrapText(_text.str, SCREEN_HEIGHT, lines);
+ fnt->wordWrapText(_text.str, SCREEN_HEIGHT, lines);
Common::Rect r(Common::Point(_text.rect.x, _text.rect.y), _text.rect.width, _text.rect.height);
_vm->_resData.fillRect(r, 15);
for (uint i = 0; i < lines.size(); i++) {
- const int w = fntP->getStringWidth(lines[i]);
- fntP->drawString(&_vm->_resData, lines[i], _text.rect.x, _text.rect.y + 1 + i * h, w, 0);
+ const int w = fnt->getStringWidth(lines[i]);
+ fnt->drawString(&_vm->_resData, lines[i], _text.rect.x, _text.rect.y + 1 + i * h, w, 0);
}
}
} break;
Commit: d17930218a1afd64a065542ca385c2e20eb149e7
https://github.com/scummvm/scummvm/commit/d17930218a1afd64a065542ca385c2e20eb149e7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix font data deallocation
Changed paths:
engines/dgds/font.cpp
engines/dgds/font.h
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index bff1f1cde1b..1bf5f0f083d 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -65,17 +65,16 @@ Font *Font::load(const Common::String &filename, ResourceManager *resourceManage
return font;
}
-Font::Font(byte w, byte h, byte start, byte count, byte *data) : _w(w), _h(h), _start(start), _count(count), _data(data) { }
+Font::Font(byte w, byte h, byte start, byte count, const byte *glyphs) : _w(w), _h(h), _start(start), _count(count), _glyphs(glyphs) { }
Font::~Font() {
- delete [] _data;
}
bool Font::hasChar(byte chr) const {
return (chr >= _start && chr <= (_start + _count));
}
-static inline uint isSet(byte *set, uint bit) {
+static inline uint isSet(const byte *set, uint bit) {
return (set[bit >> 3] & (1 << (bit & 7)));
}
@@ -90,7 +89,7 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
const int columns = clippedDestRect.width();
int idx = bit + croppedBy.x;
- byte *src = _data + pos + croppedBy.y;
+ const byte *src = _glyphs + pos + croppedBy.y;
byte *ptr = (byte *)dst->getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
@@ -103,9 +102,12 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
}
}
-FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : Font(w, h, start, count, data) {
+FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : Font(w, h, start, count, data), _rawData(data) {
}
+FFont::~FFont() {
+ delete [] _rawData;
+}
void FFont::mapChar(byte chr, int &pos, int &bit) const {
pos = (chr - _start) * _h;
bit = 8 - _w;
@@ -137,11 +139,15 @@ FFont *FFont::load(Common::SeekableReadStream &input) {
return new FFont(w, h, start, count, data);
}
-PFont::PFont(byte w, byte h, byte start, byte count, byte *data, const uint16 *offsets, const byte *widths)
-: Font(w, h, start, count, data), _offsets(offsets), _widths(widths)
+PFont::PFont(byte w, byte h, byte start, byte count, byte *data)
+: Font(w, h, start, count, data + 3 * count), _offsets(reinterpret_cast<const uint16 *>(data)), _widths(data + 2 * count), _rawData(data)
{
}
+PFont::~PFont() {
+ delete [] _rawData;
+}
+
void PFont::mapChar(byte chr, int& pos, int& bit) const {
pos = READ_LE_UINT16(&_offsets[chr - _start]);
bit = 0;
@@ -177,9 +183,7 @@ PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor
uint32 uncompressedSize;
byte *data = decompressor->decompress(&input, size, uncompressedSize);
- return new PFont(w, h, start, count, data,
- reinterpret_cast<const uint16 *>(data + 2 * count),
- data + 3 * count);
+ return new PFont(w, h, start, count, data);
}
FontManager::~FontManager() {
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index 6c53d40b7d6..c2d27a1b2d3 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -46,7 +46,7 @@ class Decompressor;
class Font : public Graphics::Font {
public:
- Font(byte w, byte h, byte start, byte count, byte *data);
+ Font(byte w, byte h, byte start, byte count, const byte *glyphs);
virtual ~Font();
int getFontHeight() const { return _h; }
int getMaxCharWidth() const { return _w; }
@@ -59,7 +59,7 @@ protected:
byte _h;
byte _start;
byte _count;
- byte *_data;
+ const byte *_glyphs;
bool hasChar(byte chr) const;
};
@@ -67,7 +67,8 @@ protected:
/* Proportional font (each char has its own width and so data is a different size) */
class PFont : public Font {
public:
- PFont(byte w, byte h, byte start, byte count, byte *data, const uint16 *offsets, const byte *widths);
+ PFont(byte w, byte h, byte start, byte count, byte *data);
+ ~PFont();
int getCharWidth(uint32 chr) const { return _widths[chr - _start]; }
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static PFont *load(Common::SeekableReadStream &input, Decompressor *decompressor);
@@ -75,6 +76,7 @@ public:
protected:
const uint16 *_offsets;
const byte *_widths;
+ byte *_rawData;
void mapChar(byte chr, int &pos, int &bit) const;
};
@@ -83,11 +85,14 @@ protected:
class FFont : public Font {
public:
FFont(byte w, byte h, byte start, byte count, byte *data);
+ ~FFont();
int getCharWidth(uint32 chr) const { return _w; }
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static FFont *load(Common::SeekableReadStream &input);
protected:
+ byte *_rawData;
+
void mapChar(byte chr, int &pos, int &bit) const;
};
Commit: 7923cac2ee357bbcbd17803d7d82d3e9d4142418
https://github.com/scummvm/scummvm/commit/7923cac2ee357bbcbd17803d7d82d3e9d4142418
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start adding gadget drawing code
This code is based off the button drawing in Rise of the Dragon. Others may
look slightly different.
Changed paths:
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index ccc9dd706c9..33d9c4740a1 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -23,13 +23,30 @@
#include "common/debug.h"
#include "common/endian.h"
#include "common/file.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+
+#include "dgds/dgds.h"
+#include "dgds/font.h"
#include "dgds/includes.h"
#include "dgds/request.h"
#include "dgds/resource.h"
namespace Dgds {
+// TODO: The following colors are from Rise of the Dragon. Will need to check
+// if the same ones are hard-coded in the other games.
+static const byte ButtonColors[] = {
+ 0x73, 0xF0, 0x7B, 0xDF, 0x5F, 0x5F, 0x7E, 0x27, 0x16, 0x73, 0x27, 0x16, 0xDF
+};
+
+static const byte SliderColors[] = {
+ 0x7B, 0x4D, 0xF4, 0x54, 0xDF, 0x74, 0x58
+ // TOOD: are these part of the list too?
+ // 0x7, 0x7, 0x8, 0x7, 0, 0xF, 0x7, 0xC, 0x4
+};
+
RequestParser::RequestParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
}
@@ -59,6 +76,8 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
gptr.reset(new SliderGadget());
else if (gadgetType == kGadgetImage)
gptr.reset(new ImageGadget());
+ else if (gadgetType == kGadgetButton)
+ gptr.reset(new ButtonGadget());
else
gptr.reset(new Gadget());
}
@@ -90,6 +109,8 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
if (gptr)
gptr->_sval1I = i;
}
+ if (gptr)
+ gptr->_sval1Type = type1;
uint16 type2 = str->readUint16LE();
if (type2 == 1) {
@@ -101,6 +122,8 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
if (gptr)
gptr->_sval2I = i;
}
+ if (gptr)
+ gptr->_sval2Type = type2;
uint16 val = str->readUint16LE();
if (gptr) {
@@ -249,21 +272,128 @@ Common::String Gadget::dump() const {
_buttonName.c_str(), _parentX, _parentY);
}
+void Gadget::draw(Graphics::Surface *dst) const {}
+
+/**
+ * A function to fill a rect from left to right *inclusive* of bottom/right coords,
+ * as that's how DGDS code specifies the rect and it's very confusing to try and
+ * RE it otherwise.
+ **/
+static void fillRectInc(Graphics::Surface *dst, uint16 left, uint16 top, uint16 right, uint16 bottom, byte fill) {
+ dst->fillRect(Common::Rect(left, top, right + 1, bottom + 1), fill);
+}
+
+void ButtonGadget::draw(Graphics::Surface *dst) const {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+
+ int16 x = _x + _parentX;
+ int16 y = _y + _parentY;
+
+ int16 right = x + _width;
+ int16 x2 = right - 1;
+ int16 bottom = (y + _height) - 1;
+
+ byte fill = ButtonColors[0];
+ fillRectInc(dst, x, y, x2, y, fill);
+ fillRectInc(dst, x + 2, y + 2, right - 3, y + 2, fill);
+ fillRectInc(dst, x + 1, bottom - 2, x + 1, bottom - 2, fill);
+ fillRectInc(dst, right - 2, bottom - 2, right - 2, bottom - 2, fill);
+ fillRectInc(dst, x + 1, bottom - 1, right - 2, bottom - 1, fill);
+
+ fill = ButtonColors[1];
+ fillRectInc(dst, x, y + 1, x, bottom, fill);
+ fillRectInc(dst, x2, y + 1, x2, bottom, fill);
+ fillRectInc(dst, x + 2, y + 3, x + 2, bottom - 2, fill);
+ fillRectInc(dst, right - 3, y + 3, right - 3, bottom - 2, fill);
+ fillRectInc(dst, x + 3,bottom - 2, right - 4, bottom - 2, fill);
+
+ fill = ButtonColors[2];
+ fillRectInc(dst, x + 1, y + 2, x + 1, bottom - 3, fill);
+ fillRectInc(dst, right - 2, y + 2, right - 2, bottom - 3, fill);
+ fillRectInc(dst, x + 1, bottom, right - 2, bottom, ButtonColors[3]);
+ fillRectInc(dst, x + 1, y + 1, right - 2, y + 1, ButtonColors[4]);
+
+ bool enabled = !(_flags3 & 9);
+ int colOffset;
+ if (!enabled) {
+ colOffset = 9;
+ } else {
+ colOffset = 5;
+ }
+
+ fillRectInc(dst, x + 3, y + 3, right - 4, y + 3, ButtonColors[colOffset + 1]);
+
+ // TODO: This is done with a different call in the game.. is there some reason for that?
+ dst->fillRect(Common::Rect(x + 3, y + 4, x + 3 + _width - 6, y + 4 + _height - 8), ButtonColors[colOffset + 2]);
+
+ fillRectInc(dst, x + 3, bottom - 3, right - 4, bottom - 3, ButtonColors[colOffset + 3]);
+
+ if (!_buttonName.empty()) {
+ const Font *font = fontman->getFont(FontManager::k6x6Font);
+
+ Common::String name = _buttonName;
+
+ int fontHeight = font->getFontHeight();
+
+ bool twoline;
+ int yoffset;
+ uint32 linebreak = name.find('&');
+
+ Common::String line1, line2;
+ if (linebreak != Common::String::npos) {
+ twoline = true;
+ name.setChar(' ', linebreak);
+ yoffset = _height + 1 - fontHeight * 2;
+ line1 = _buttonName.substr(0, linebreak);
+ line2 = _buttonName.substr(linebreak + 1);
+ } else {
+ twoline = false;
+ yoffset = _height - fontHeight;
+ line1 = _buttonName;
+ }
+
+ // TODO: Check me: had to subtract 1 here to get the right y offset.
+ // Some difference from drawing code of original?
+ yoffset = y + yoffset / 2 - 1;
+ int lineWidth = font->getStringWidth(line1);
+ font->drawString(dst, line1, x + (_width - lineWidth) / 2 + 1, yoffset + 2, lineWidth, ButtonColors[colOffset]);
+
+ if (linebreak != Common::String::npos) {
+ lineWidth = font->getStringWidth(line2);
+ font->drawString(dst, line2, x + (_width - lineWidth) / 2 + 1, yoffset + fontHeight, lineWidth, ButtonColors[colOffset]);
+ }
+ }
+
+}
+
Common::String TextAreaGadget::dump() const {
const Common::String base = Gadget::dump();
return Common::String::format("TextArea<%s, %d %d>", base.c_str(), _gadget1_i1, _gadget1_i2);
}
+void TextAreaGadget::draw(Graphics::Surface *dst) const {
+ error("TODO: Implement TextAreaGadget::draw");
+}
+
Common::String SliderGadget::dump() const {
const Common::String base = Gadget::dump();
return Common::String::format("Slider<%s, %d %d %d %d>", base.c_str(), _gadget2_i1, _gadget2_i2, _gadget2_i3, _gadget2_i4);
}
+void SliderGadget::draw(Graphics::Surface *dst) const {
+ error("TODO: Implement SliderGadget::draw");
+}
+
Common::String ImageGadget::dump() const {
const Common::String base = Gadget::dump();
return Common::String::format("Image<%s, %d %d>", base.c_str(), _gadget8_i1, _gadget8_i2);
}
+void ImageGadget::draw(Graphics::Surface *dst) const {
+ error("TODO: Implement ImageGadget::draw");
+}
+
Common::String RequestData::dump() const {
Common::String ret = Common::String::format("RequestData<file %d pos (%d,%d) size (%d, %d) %d %d %d\n",
_fileNum, _x, _y, _vals[0], _vals[1], _vals[2], _vals[3], _vals[4]);
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 4193d4e10f7..754a60c2550 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -37,6 +37,8 @@ struct TextItem {
Common::String _txt;
};
+// This struct is defined in the code, but seems
+// to not be used in any of the games?
struct RequestStruct2 {
uint16 _vals[6];
};
@@ -85,6 +87,13 @@ public:
uint16 _parentY;
virtual Common::String dump() const;
+ virtual void draw(Graphics::Surface *dst) const;
+};
+
+// Button gadget has no additional fields, but some behavior differences.
+class ButtonGadget : public Gadget {
+public:
+ void draw(Graphics::Surface *dst) const override;
};
// extended gadget type 1 is 62 (0x3e) bytes
@@ -94,6 +103,7 @@ public:
uint16 _gadget1_i2;
Common::String dump() const override;
+ void draw(Graphics::Surface *dst) const override;
};
// extended gadget type 2 is 74 (0x4a) bytes
@@ -105,6 +115,7 @@ public:
uint16 _gadget2_i4;
Common::String dump() const override;
+ void draw(Graphics::Surface *dst) const override;
};
// extended gadget type 8 is 68 (0x44) bytes
@@ -114,6 +125,7 @@ public:
uint16 _gadget8_i2;
Common::String dump() const override;
+ void draw(Graphics::Surface *dst) const override;
};
class RequestData {
Commit: a70d15bd6ce6268f865dee968c0c7553c5a4ef49
https://github.com/scummvm/scummvm/commit/a70d15bd6ce6268f865dee968c0c7553c5a4ef49
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Hook up VCR (main menu) drawing code to F5
This will aid with debugging
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index baccdeda624..afd628dc33c 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -107,6 +107,20 @@ void readStrings(Common::SeekableReadStream *stream) {
debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
}
}
+void DgdsEngine::drawVCR(REQFileData &vcrRequestData) {
+ // TODO: Hardcoded
+ Common::Array<Common::SharedPtr<Gadget>> gadgets = vcrRequestData._requests[0]._gadgets;
+ Graphics::Surface *dst = g_system->lockScreen();
+
+ for (Common::SharedPtr<Gadget> &gptr : gadgets) {
+ Gadget *gadget = gptr.get();
+ if (gadget->_gadgetType == kGadgetButton)
+ gadget->draw(dst);
+ }
+
+ g_system->unlockScreen();
+ g_system->updateScreen();
+}
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -173,6 +187,7 @@ Common::Error DgdsEngine::run() {
debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
+ bool vcrShown = false;
while (!shouldQuit()) {
if (eventMan->pollEvent(ev)) {
@@ -180,12 +195,22 @@ Common::Error DgdsEngine::run() {
switch (ev.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
moveToNext = true;
+ break;
+ case Common::KEYCODE_F5:
+ drawVCR(vcrRequestData);
+ vcrShown = !vcrShown;
+ break;
default:
break;
}
}
}
+ if (vcrShown) {
+ g_system->delayMillis(10);
+ continue;
+ }
+
if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
if (moveToNext || !interpIntro.run()) {
moveToNext = false;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index b77b02fa53d..9ee8a805323 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -46,7 +46,7 @@ class FontManager;
class SDSScene;
class GDSScene;
class Sound;
-
+class REQFileData;
struct DgdsADS;
enum DgdsGameId {
@@ -91,6 +91,7 @@ public:
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
const FontManager *getFontMan() const { return _fontManager; }
+ void drawVCR(REQFileData &vcrRequestData);
};
} // End of namespace Dgds
Commit: 0ea519cf4b62024a4987b62732e16ee8360bbd2f
https://github.com/scummvm/scummvm/commit/0ea519cf4b62024a4987b62732e16ee8360bbd2f
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Some renames and small changes to script parsing
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 48d4c522851..6a417727c48 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -103,7 +103,7 @@ bool TTMInterpreter::run() {
}
debug(" ");
- Common::Rect bmpWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
switch (op) {
case 0x0000:
@@ -152,19 +152,16 @@ bool TTMInterpreter::run() {
case 0x1090:
// SELECT SONG: id:int [0]
continue;
-
case 0x4120:
// FADE IN: ?,?,?,?:byte
_vm->_image->setPalette();
continue;
-
case 0x4110:
// FADE OUT: ?,?,?,?:byte
g_system->delayMillis(_state.delay);
_vm->_image->clearPalette();
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
continue;
-
// these 3 ops do interaction between the topBuffer (imgData) and the bottomBuffer (scrData) but... it might turn out this uses z values!
case 0xa050: { //GFX? i,j,k,l:int [i<k,j<l] // HAPPENS IN INTRO.TTM:INTRO9
// it works like a bitblit, but it doesn't write if there's something already at the destination?
@@ -176,22 +173,20 @@ bool TTMInterpreter::run() {
case 0x0020: //SAVE BG?: void // OR PERHAPS SWAPBUFFERS ; it makes bmpData persist in the next frames.
_vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
continue;
-
case 0x4200: {
// STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
_vm->_resData.blitFrom(_vm->getBottomBuffer());
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
_vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
- }
continue;
-
+ }
case 0x0ff0: {
// REFRESH: void
_vm->_resData.blitFrom(_vm->getBottomBuffer());
- Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpWin);
- _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpWin.left, bmpWin.top));
- _vm->getTopBuffer().fillRect(bmpWin, 0);
+ Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
+ _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
+ _vm->getTopBuffer().fillRect(bmpArea, 0);
if (!_text.str.empty()) {
Common::StringArray lines;
@@ -210,16 +205,20 @@ bool TTMInterpreter::run() {
case 0xa520:
//DRAW BMP: x,y:int ; happens once in INTRO.TTM
+ case 0xa530:
+ // CHINA
+ // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
case 0xa500:
debug("DRAW \"%s\"", _state.bmpNames[_state._currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
- int bk = ivals[2];
+ int tileId = ivals[2];
_state._currentBmpId = ivals[3];
- if (bk != -1) {
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], bk);
+ if (tileId != -1) {
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], tileId);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
@@ -234,15 +233,18 @@ bool TTMInterpreter::run() {
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
continue;
- case 0x1110: { //SET SCENE?: i:int [1..n]
+ case 0x1110: { //SHOW SCENE TEXT?: i:int [1..n]
// DESCRIPTION IN TTM TAGS.
- debug("SET SCENE: %u", ivals[0]);
+ debug("SHOW SCENE TEXT: %u", ivals[0]);
_state.scene = ivals[0];
const Common::Array<Dialogue> dialogues = _vm->getScene()->getLines();
_text.str.clear();
for (const Dialogue &dialogue: dialogues) {
- if (dialogue.num == ivals[0])
+ if (dialogue.num == _state.scene)
+ _text = dialogue;
+ // HACK to get Dragon intro working
+ if (_text.str.empty() && dialogue.num == _state.scene + 14)
_text = dialogue;
}
if (!_text.str.empty())
@@ -251,13 +253,13 @@ bool TTMInterpreter::run() {
}
case 0x4000:
- //SET WINDOW? x,y,w,h:int [0..320,0..200]
+ //SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
_state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
continue;
case 0xa100:
- //SET WINDOW? x,y,w,h:int [0..320,0..200]
- bmpWin = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ //SET BMP AREA? x,y,w,h:int [0..320,0..200]
+ bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
continue;
case 0x1020: //DELAY?: i:int [0..n]
@@ -265,12 +267,11 @@ bool TTMInterpreter::run() {
continue;
case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
+ debug("SET SCENE: %u", ivals[0]);
+ break;
case 0x2000: //SET FRAME1?: i,j:int [0..255]
- case 0xa530: // CHINA
- // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
case 0x0110: //PURGE IMGS? void
case 0x0080: //DRAW BG: void
case 0x1100: //? i:int [9]
Commit: dab1edd2344f8e7f9f32c2c7199525ec472d7f6f
https://github.com/scummvm/scummvm/commit/dab1edd2344f8e7f9f32c2c7199525ec472d7f6f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add drawing code for more gadgets
Changed paths:
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 33d9c4740a1..5901143dc0e 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -43,8 +43,30 @@ static const byte ButtonColors[] = {
static const byte SliderColors[] = {
0x7B, 0x4D, 0xF4, 0x54, 0xDF, 0x74, 0x58
- // TOOD: are these part of the list too?
- // 0x7, 0x7, 0x8, 0x7, 0, 0xF, 0x7, 0xC, 0x4
+};
+
+static const byte FallbackColors[] = {
+ 0x7, 0x7, 0x8, 0x7, 0x0, 0xF, 0x7, 0xC,
+ 0x4, 0x0, 0xF, 0xF, 0xC, 0x4, 0x7, 0xF,
+ 0x8, 0x7, 0x0, 0x7, 0x7
+};
+
+static const byte MenuBackgroundColors[] {
+ 0x71, 0x71, 0x71, 0x71, 0x71, 0x7B, 0x71, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B,
+ 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7B, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A,
+ 0x7A, 0x7A, 0x7A, 0x46, 0x7A, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x58, 0x46, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+ 0x58, 0x52, 0x58, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,
+ 0x59, 0x52, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5C,
+ 0x59, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x0F, 0x5C,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x5C, 0x0F, 0x5C, 0x5C, 0x5C,
+ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x59, 0x5C, 0x59, 0x59, 0x59, 0x59,
+ 0x59, 0x59, 0x59, 0x59, 0x59, 0x52, 0x59, 0x52, 0x52, 0x52, 0x52, 0x52,
+ 0x52, 0x52, 0x52, 0x52, 0x58, 0x52, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+ 0x58, 0x58, 0x58, 0x46, 0x58, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
+ 0x46, 0x46, 0x7A, 0x46, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A,
+ 0x7A, 0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B,
+ 0x71, 0x7B, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71
};
RequestParser::RequestParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
@@ -197,7 +219,9 @@ bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int
data._fileNum = chunkNum;
data._x = str->readUint16LE();
data._y = str->readUint16LE();
- for (int i = 0; i < 5; i++)
+ data._width = str->readUint16LE();
+ data._height = str->readUint16LE();
+ for (int i = 0; i < 3; i++)
data._vals[i] = str->readUint16LE();
uint16 numTextItems = str->readUint16LE();
@@ -274,19 +298,12 @@ Common::String Gadget::dump() const {
void Gadget::draw(Graphics::Surface *dst) const {}
-/**
- * A function to fill a rect from left to right *inclusive* of bottom/right coords,
- * as that's how DGDS code specifies the rect and it's very confusing to try and
- * RE it otherwise.
- **/
-static void fillRectInc(Graphics::Surface *dst, uint16 left, uint16 top, uint16 right, uint16 bottom, byte fill) {
- dst->fillRect(Common::Rect(left, top, right + 1, bottom + 1), fill);
-}
-
void ButtonGadget::draw(Graphics::Surface *dst) const {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const FontManager *fontman = engine->getFontMan();
+ // TODO: Bounds calculation here might depend on parent.
+
int16 x = _x + _parentX;
int16 y = _y + _parentY;
@@ -295,24 +312,24 @@ void ButtonGadget::draw(Graphics::Surface *dst) const {
int16 bottom = (y + _height) - 1;
byte fill = ButtonColors[0];
- fillRectInc(dst, x, y, x2, y, fill);
- fillRectInc(dst, x + 2, y + 2, right - 3, y + 2, fill);
- fillRectInc(dst, x + 1, bottom - 2, x + 1, bottom - 2, fill);
- fillRectInc(dst, right - 2, bottom - 2, right - 2, bottom - 2, fill);
- fillRectInc(dst, x + 1, bottom - 1, right - 2, bottom - 1, fill);
+ dst->drawLine(x, y, x2, y, fill);
+ dst->drawLine(x + 2, y + 2, right - 3, y + 2, fill);
+ dst->drawLine(x + 1, bottom - 2, x + 1, bottom - 2, fill);
+ dst->drawLine(right - 2, bottom - 2, right - 2, bottom - 2, fill);
+ dst->drawLine(x + 1, bottom - 1, right - 2, bottom - 1, fill);
fill = ButtonColors[1];
- fillRectInc(dst, x, y + 1, x, bottom, fill);
- fillRectInc(dst, x2, y + 1, x2, bottom, fill);
- fillRectInc(dst, x + 2, y + 3, x + 2, bottom - 2, fill);
- fillRectInc(dst, right - 3, y + 3, right - 3, bottom - 2, fill);
- fillRectInc(dst, x + 3,bottom - 2, right - 4, bottom - 2, fill);
+ dst->drawLine(x, y + 1, x, bottom, fill);
+ dst->drawLine(x2, y + 1, x2, bottom, fill);
+ dst->drawLine(x + 2, y + 3, x + 2, bottom - 2, fill);
+ dst->drawLine(right - 3, y + 3, right - 3, bottom - 2, fill);
+ dst->drawLine(x + 3,bottom - 2, right - 4, bottom - 2, fill);
fill = ButtonColors[2];
- fillRectInc(dst, x + 1, y + 2, x + 1, bottom - 3, fill);
- fillRectInc(dst, right - 2, y + 2, right - 2, bottom - 3, fill);
- fillRectInc(dst, x + 1, bottom, right - 2, bottom, ButtonColors[3]);
- fillRectInc(dst, x + 1, y + 1, right - 2, y + 1, ButtonColors[4]);
+ dst->drawLine(x + 1, y + 2, x + 1, bottom - 3, fill);
+ dst->drawLine(right - 2, y + 2, right - 2, bottom - 3, fill);
+ dst->drawLine(x + 1, bottom, right - 2, bottom, ButtonColors[3]);
+ dst->drawLine(x + 1, y + 1, right - 2, y + 1, ButtonColors[4]);
bool enabled = !(_flags3 & 9);
int colOffset;
@@ -322,16 +339,18 @@ void ButtonGadget::draw(Graphics::Surface *dst) const {
colOffset = 5;
}
- fillRectInc(dst, x + 3, y + 3, right - 4, y + 3, ButtonColors[colOffset + 1]);
+ dst->drawLine(x + 3, y + 3, right - 4, y + 3, ButtonColors[colOffset + 1]);
// TODO: This is done with a different call in the game.. is there some reason for that?
dst->fillRect(Common::Rect(x + 3, y + 4, x + 3 + _width - 6, y + 4 + _height - 8), ButtonColors[colOffset + 2]);
- fillRectInc(dst, x + 3, bottom - 3, right - 4, bottom - 3, ButtonColors[colOffset + 3]);
+ dst->drawLine(x + 3, bottom - 3, right - 4, bottom - 3, ButtonColors[colOffset + 3]);
if (!_buttonName.empty()) {
const Font *font = fontman->getFont(FontManager::k6x6Font);
+ // TODO: Depending on some flags, the game toggles " ON " to " OFF" at the
+ // end of the string.
Common::String name = _buttonName;
int fontHeight = font->getFontHeight();
@@ -373,7 +392,10 @@ Common::String TextAreaGadget::dump() const {
}
void TextAreaGadget::draw(Graphics::Surface *dst) const {
- error("TODO: Implement TextAreaGadget::draw");
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+ const Font *font = fontman->getFont(FontManager::k6x6Font);
+ font->drawString(dst, _buttonName, _x + _parentX, _y + _parentY, 0, 0);
}
Common::String SliderGadget::dump() const {
@@ -381,8 +403,58 @@ Common::String SliderGadget::dump() const {
return Common::String::format("Slider<%s, %d %d %d %d>", base.c_str(), _gadget2_i1, _gadget2_i2, _gadget2_i3, _gadget2_i4);
}
+// Slider labels and title are hard-coded in game, not part of data files.
+static const char *_sliderTitleForGadget(uint16 num) {
+ switch (num) {
+ case 0x7B: return "DIFFICULTY";
+ case 0x7D: return "TEXT SPEED";
+ case 0x83: return "DETAIL LEVEL";
+ case 0x98: return "MOUSE SPEED";
+ case 0x9C: return "BUTTON THRESHOLD";
+ default: return "SLIDER";
+ }
+}
+
+static const char *_sliderLabelsForGadget(uint16 num) {
+ switch (num) {
+ case 0x7B: return "EASY HARD";
+ case 0x7D: return "SLOW FAST";
+ case 0x83: return "LOW HIGH";
+ case 0x98: return "SLOW FAST";
+ case 0x9C: return "LONG SHORT";
+ default: return "MIN MAX";
+ }
+}
+
void SliderGadget::draw(Graphics::Surface *dst) const {
- error("TODO: Implement SliderGadget::draw");
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+ const Font *font = fontman->getFont(FontManager::k6x6Font);
+
+ int16 x = _x + _parentX;
+ int16 y = _y + _parentY;
+ int16 x2 = x + _width;
+ int16 y2 = (y + _height) - 1;
+
+ int16 titley = (y - font->getFontHeight()) + 1;
+ const char *title = _sliderTitleForGadget(_gadgetNo);
+ const char *labels = _sliderLabelsForGadget(_gadgetNo);
+ int16 titleWidth = font->getStringWidth(title);
+
+ // TODO: Get the right color for this text?
+ font->drawString(dst, title, x + (_width - titleWidth) / 2, titley, titleWidth, 0);
+ int16 labelWidth = font->getStringWidth(labels);
+ font->drawString(dst, labels, x + (_width - labelWidth) / 2, y + 7, labelWidth, 0);
+ int16 y1 = y - 1;
+ dst->drawLine(x - 2, y - 1, x - 2, y2, SliderColors[0]);
+ dst->drawLine(x - 1, y1, x - 1, y2, SliderColors[1]);
+ dst->drawLine(x, y2, x2 - 1, y2, SliderColors[1]);
+ dst->drawLine(x, y1, x2, y1, SliderColors[2]);
+ dst->drawLine(x2, y1, x2, y2, SliderColors[2]);
+ dst->drawLine(x2 + 1, y1, x2 + 1, y2, SliderColors[3]);
+ dst->drawLine(x, y, x2 - 1, y, SliderColors[4]);
+ dst->drawLine(x2 - 1, y + 1, x2 - 1, (y + _height) - 2, SliderColors[4]);
+ dst->fillRect(Common::Rect(x, y + 1, x + _width - 1, y + _height - 2), SliderColors[5]);
}
Common::String ImageGadget::dump() const {
@@ -396,7 +468,7 @@ void ImageGadget::draw(Graphics::Surface *dst) const {
Common::String RequestData::dump() const {
Common::String ret = Common::String::format("RequestData<file %d pos (%d,%d) size (%d, %d) %d %d %d\n",
- _fileNum, _x, _y, _vals[0], _vals[1], _vals[2], _vals[3], _vals[4]);
+ _fileNum, _x, _y, _width, _height, _vals[0], _vals[1], _vals[2]);
for (const auto &s1 : _textItemList)
ret += Common::String::format(" TextItem<'%s' pos (%d,%d) %d %d>\n", s1._txt.c_str(),
s1._x, s1._y, s1._vals[0], s1._vals[1]);
@@ -410,6 +482,44 @@ Common::String RequestData::dump() const {
return ret;
}
+void RequestData::draw(Graphics::Surface *dst) const {
+ drawBackground(dst);
+}
+
+void RequestData::drawBackground(Graphics::Surface *dst) const {
+ bool detailHigh = true;
+ int startoffset = 0;
+ if (detailHigh) {
+ //g_videoMaskEnabled = true;
+ //g_vidMaskXMax = (x + width) - 1;
+ //g_vidMaskYMax = (y + height) - 1;
+ while (startoffset < 0)
+ startoffset += ARRAYSIZE(MenuBackgroundColors);
+ startoffset = startoffset % ARRAYSIZE(MenuBackgroundColors);
+
+ int coloffset = startoffset;
+ for (int yoff = _x; yoff < (_x + _width); yoff++) {
+ dst->drawLine(yoff, _y, yoff + _height, _y + _height, MenuBackgroundColors[coloffset]);
+ coloffset++;
+ if (coloffset >= ARRAYSIZE(MenuBackgroundColors))
+ coloffset = 0;
+ }
+ // TODO: Game positions mouse in middle of menu here?
+ coloffset = startoffset;
+ for (int yoff = _y; yoff < (_y + _height); yoff++) {
+ dst->drawLine(_x, yoff, _x + _height, yoff + _height, MenuBackgroundColors[coloffset]);
+ coloffset--;
+ if (coloffset < 0)
+ coloffset = ARRAYSIZE(MenuBackgroundColors) - 1;
+ }
+ //g_vidMaskYMax = g_screenHeight - 1;
+ //g_vidMaskXMax = g_screenWidth - 1;
+ } else {
+ dst->fillRect(Common::Rect(_x, _y, _width, _height), FallbackColors[0]);
+ }
+}
+
+
Common::String REQFileData::dump() const {
Common::String ret("REQFileData<\n");
for (const auto &req : _requests) {
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 754a60c2550..d8286b7f067 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -133,12 +133,18 @@ public:
uint16 _fileNum;
uint16 _x;
uint16 _y;
- uint16 _vals[5];
+ uint16 _width;
+ uint16 _height;
+ uint16 _vals[3];
Common::Array<TextItem> _textItemList;
Common::Array<RequestStruct2> _struct2List;
Common::Array<Common::SharedPtr<Gadget>> _gadgets;
Common::String dump() const;
+ void draw(Graphics::Surface *dst) const;
+private:
+
+ void drawBackground(Graphics::Surface *dst) const;
};
// A REQ file contains a sequence of REQ and GAD block pairs.
Commit: 10debcef1eab2cee93cd0f81f715a40173a3893f
https://github.com/scummvm/scummvm/commit/10debcef1eab2cee93cd0f81f715a40173a3893f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement most of menu drawing
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index afd628dc33c..e9d5d0a105c 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -109,12 +109,15 @@ void readStrings(Common::SeekableReadStream *stream) {
}
void DgdsEngine::drawVCR(REQFileData &vcrRequestData) {
// TODO: Hardcoded
- Common::Array<Common::SharedPtr<Gadget>> gadgets = vcrRequestData._requests[0]._gadgets;
+
+ Common::Array<Common::SharedPtr<Gadget>> gadgets = vcrRequestData._requests[1]._gadgets;
Graphics::Surface *dst = g_system->lockScreen();
+ vcrRequestData._requests[1].draw(dst);
+
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
- if (gadget->_gadgetType == kGadgetButton)
+ if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider)
gadget->draw(dst);
}
@@ -122,6 +125,15 @@ void DgdsEngine::drawVCR(REQFileData &vcrRequestData) {
g_system->updateScreen();
}
+void DgdsEngine::loadCorners(const Common::String &filename, int numImgs) {
+ _corners.resize(numImgs);
+ for (int i = 0; i < numImgs; i++) {
+ Image *img = new Image(_resource, _decompressor);
+ img->loadBitmap(filename, i);
+ _corners[i].reset(img);
+ }
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -163,6 +175,7 @@ Common::Error DgdsEngine::run() {
// Load the intro and play it for now.
interpIntro.load("TITLE1.ADS");
//interpIntro.load("INTRO.ADS");
+ loadCorners("DCORNERS.BMP", 29);
} else if (getGameId() == GID_CHINA) {
_gdsScene->load("HOC.GDS", _resource, _decompressor);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 9ee8a805323..afdb8111b1c 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -75,6 +75,7 @@ private:
GDSScene *_gdsScene;
FontManager *_fontManager;
+ Common::Array<Common::SharedPtr<Image>> _corners;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -92,6 +93,10 @@ public:
const SDSScene *getScene() const { return _scene; }
const FontManager *getFontMan() const { return _fontManager; }
void drawVCR(REQFileData &vcrRequestData);
+ const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
+
+private:
+ void loadCorners(const Common::String &filename, int numImgs);
};
} // End of namespace Dgds
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 46f162e537d..19c08c2e52e 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -204,7 +204,7 @@ void Image::loadBitmap(Common::String filename, int number) {
delete fileStream;
}
-void Image::drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &surface) {
+void Image::drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surface &surface) {
const Common::Rect destRect(x, y, x + _bmpData.w, y + _bmpData.h);
Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
clippedDestRect.clip(destRect);
@@ -488,6 +488,15 @@ void Image::clearPalette() {
g_system->getPaletteManager()->setPalette(_blacks, 0, 256);
}
+int16 Image::width() const {
+ return _bmpData.w;
+}
+
+int16 Image::height() const {
+ return _bmpData.h;
+}
+
+
// grayscale palette.
/*
for (uint i=0; i<256; i++) {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index a6b51081334..d3ada319abe 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -44,12 +44,14 @@ public:
void drawScreen(Common::String filename, Graphics::Surface &surface);
void loadBitmap(Common::String filename, int number);
- void drawBitmap(int x, int y, Common::Rect &drawWin, Graphics::Surface &surface);
+ void drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surface &surface);
void loadPalette(Common::String filename);
void setPalette();
void clearPalette();
bool isLoaded() const { return _bmpData.getPixels() != nullptr; }
+ int16 width() const;
+ int16 height() const;
private:
void loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 5901143dc0e..ab41f307317 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -29,6 +29,7 @@
#include "dgds/dgds.h"
#include "dgds/font.h"
+#include "dgds/image.h"
#include "dgds/includes.h"
#include "dgds/request.h"
#include "dgds/resource.h"
@@ -69,6 +70,7 @@ static const byte MenuBackgroundColors[] {
0x71, 0x7B, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71
};
+
RequestParser::RequestParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
}
@@ -299,9 +301,6 @@ Common::String Gadget::dump() const {
void Gadget::draw(Graphics::Surface *dst) const {}
void ButtonGadget::draw(Graphics::Surface *dst) const {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
-
// TODO: Bounds calculation here might depend on parent.
int16 x = _x + _parentX;
@@ -347,7 +346,7 @@ void ButtonGadget::draw(Graphics::Surface *dst) const {
dst->drawLine(x + 3, bottom - 3, right - 4, bottom - 3, ButtonColors[colOffset + 3]);
if (!_buttonName.empty()) {
- const Font *font = fontman->getFont(FontManager::k6x6Font);
+ const Font *font = RequestData::getMenuFont();
// TODO: Depending on some flags, the game toggles " ON " to " OFF" at the
// end of the string.
@@ -372,9 +371,7 @@ void ButtonGadget::draw(Graphics::Surface *dst) const {
line1 = _buttonName;
}
- // TODO: Check me: had to subtract 1 here to get the right y offset.
- // Some difference from drawing code of original?
- yoffset = y + yoffset / 2 - 1;
+ yoffset = y + yoffset / 2;
int lineWidth = font->getStringWidth(line1);
font->drawString(dst, line1, x + (_width - lineWidth) / 2 + 1, yoffset + 2, lineWidth, ButtonColors[colOffset]);
@@ -392,9 +389,7 @@ Common::String TextAreaGadget::dump() const {
}
void TextAreaGadget::draw(Graphics::Surface *dst) const {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
- const Font *font = fontman->getFont(FontManager::k6x6Font);
+ const Font *font = RequestData::getMenuFont();
font->drawString(dst, _buttonName, _x + _parentX, _y + _parentY, 0, 0);
}
@@ -427,9 +422,7 @@ static const char *_sliderLabelsForGadget(uint16 num) {
}
void SliderGadget::draw(Graphics::Surface *dst) const {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
- const Font *font = fontman->getFont(FontManager::k6x6Font);
+ const Font *font = RequestData::getMenuFont();
int16 x = _x + _parentX;
int16 y = _y + _parentY;
@@ -441,7 +434,6 @@ void SliderGadget::draw(Graphics::Surface *dst) const {
const char *labels = _sliderLabelsForGadget(_gadgetNo);
int16 titleWidth = font->getStringWidth(title);
- // TODO: Get the right color for this text?
font->drawString(dst, title, x + (_width - titleWidth) / 2, titley, titleWidth, 0);
int16 labelWidth = font->getStringWidth(labels);
font->drawString(dst, labels, x + (_width - labelWidth) / 2, y + 7, labelWidth, 0);
@@ -454,7 +446,11 @@ void SliderGadget::draw(Graphics::Surface *dst) const {
dst->drawLine(x2 + 1, y1, x2 + 1, y2, SliderColors[3]);
dst->drawLine(x, y, x2 - 1, y, SliderColors[4]);
dst->drawLine(x2 - 1, y + 1, x2 - 1, (y + _height) - 2, SliderColors[4]);
- dst->fillRect(Common::Rect(x, y + 1, x + _width - 1, y + _height - 2), SliderColors[5]);
+ // This is not exactly what happens in the original, but gets the same result
+ Common::Rect fillrect = Common::Rect(x, y + 1, x + _width - 1, y + _height - 1);
+ dst->fillRect(fillrect, SliderColors[5]);
+ fillrect.grow(-1);
+ dst->fillRect(fillrect, SliderColors[6]);
}
Common::String ImageGadget::dump() const {
@@ -483,39 +479,156 @@ Common::String RequestData::dump() const {
}
void RequestData::draw(Graphics::Surface *dst) const {
- drawBackground(dst);
+ int slidery = 0;
+ for (const auto &gadget : _gadgets) {
+ const SliderGadget *slider = dynamic_cast<const SliderGadget *>(gadget.get());
+ if (slider) {
+ slidery = MAX(slidery, slider->_y + slider->_height);
+ }
+ }
+
+ Common::String header;
+ if (!_textItemList.empty())
+ header = _textItemList[0]._txt.substr(1);
+
+ if (slidery)
+ drawBackgroundWithSliderArea(dst, slidery, header);
+ else
+ drawBackgroundNoSliders(dst, header);
+}
+
+/*static*/
+const Font *RequestData::getMenuFont() {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ return engine->getFontMan()->getFont(FontManager::kGameFont);
+}
+
+/*static*/
+const Image *RequestData::getCorner(int cornerNum) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ return engine->getUICorners()[cornerNum].get();
+}
+
+/*static*/
+void RequestData::drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::Array<Common::SharedPtr<Image>> &allCorners = engine->getUICorners();
+
+ assert(allCorners.size() > startNum + 7);
+
+ const Common::SharedPtr<Image> *corners = allCorners.data() + startNum;
+ const Common::Rect screenRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ for (int xoff = x + corners[0]->width(); xoff < (x + width) - corners[2]->width(); xoff += corners[1]->width())
+ corners[1]->drawBitmap(xoff, y, screenRect, *dst);
+
+ for (int xoff = x + corners[6]->width(); xoff < (x + width) - corners[7]->width(); xoff += corners[6]->width())
+ corners[6]->drawBitmap(xoff, (y + height) - corners[6]->height(), screenRect, *dst);
+
+ for (int yoff = y + corners[0]->height(); yoff < (y + height) - corners[5]->height(); yoff += corners[3]->height()) {
+ corners[3]->drawBitmap(x, yoff, screenRect, *dst);
+ }
+
+ for (int yoff = y + corners[2]->height(); yoff < (y + height) - corners[7]->height(); yoff += corners[4]->height()) {
+ corners[4]->drawBitmap((x + width) - corners[4]->width(), yoff, screenRect, *dst);
+ }
+
+ corners[0]->drawBitmap(x, y, screenRect, *dst);
+ corners[2]->drawBitmap((x + width) - corners[2]->width(), y, screenRect, *dst);
+ corners[5]->drawBitmap(x, (y + height) - corners[5]->height(), screenRect, *dst);
+ corners[7]->drawBitmap((x + width) - corners[7]->width(), (y + height) - corners[7]->height(), screenRect, *dst);
+}
+
+void RequestData::drawHeader(Graphics::Surface *dst, int16 yoffset, const Common::String &header) const {
+ if (!header.empty()) {
+ const Font *font = getMenuFont();
+ int hwidth = font->getStringWidth(header);
+ int hheight = font->getFontHeight();
+ int hleft = _x + (_width - hwidth) / 2;
+ int hright = hleft + hwidth + 3;
+ int htop = _y + yoffset;
+ int hbottom = htop + hheight;
+
+ font->drawString(dst, header, hleft + 1, htop + 2, hwidth, 0);
+ dst->drawLine(hleft - 3, htop, hright, htop, 0);
+ dst->drawLine(hright, htop + 1, hright, hbottom, 0);
+ dst->drawLine(hleft - 3, htop + 1, hleft - 3, hbottom, 15);
+ dst->drawLine(hleft - 2, hbottom, hleft + hwidth, hbottom, 15);
+ }
+}
+
+void RequestData::drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sliderHeight, const Common::String &header) const {
+ uint16 sliderBgHeight = sliderHeight + 18;
+ fillBackground(dst, _x, _y, _width, sliderBgHeight, 0);
+ fillBackground(dst, _x + 8, _y + sliderBgHeight, _width - 16, _height - sliderBgHeight, 8 - sliderBgHeight);
+ fillBackground(dst, _x + 9, _y + 8, _width - 18, sliderHeight + 2, 8);
+ fillBackground(dst, _x + 17, _y + 8 + sliderHeight + 2, _width - 34, _height - sliderBgHeight, 32 - sliderBgHeight);
+
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::Array<Common::SharedPtr<Image>> &corners = engine->getUICorners();
+ const Common::Rect screenRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ for (int xoff = _x + corners[0]->width(); xoff < (_x + _width) - corners[3]->width(); xoff += corners[2]->width()) {
+ corners[2]->drawBitmap(xoff, _y, screenRect, *dst);
+ }
+ for (int xoff = _x + 8 + corners[6]->width(); xoff < (_x + 8 + _width - 16) - corners[8]->width(); xoff += corners[7]->width()) {
+ corners[7]->drawBitmap(xoff, (_y + _height) - corners[7]->height(), screenRect, *dst);
+ }
+ for (int yoff = _y + corners[3]->height(); yoff < (_y + sliderBgHeight) - corners[10]->height(); yoff += corners[5]->height()) {
+ corners[5]->drawBitmap((_x + _width) - corners[5]->width(), yoff, screenRect, *dst);
+ }
+ for (int yoff = _y + corners[1]->height(); yoff < (_y + sliderBgHeight) - corners[9]->height(); yoff += corners[4]->height()) {
+ corners[4]->drawBitmap(_x, yoff, screenRect, *dst);
+ }
+ for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[6]->height(); yoff += corners[4]->height()) {
+ corners[4]->drawBitmap(_x + 8, yoff, screenRect, *dst);
+ }
+ for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[8]->height(); yoff += corners[5]->height()) {
+ corners[5]->drawBitmap((_x + 8 + _width - 16) - corners[5]->width(), yoff, screenRect, *dst);
+ }
+ corners[1]->drawBitmap(_x, _y, screenRect, *dst);
+ corners[3]->drawBitmap((_x + _width) - corners[3]->width(), _y, screenRect, *dst);
+ corners[6]->drawBitmap(_x + 8, (_y + _height) - corners[6]->height(), screenRect, *dst);
+ corners[8]->drawBitmap((_x + _width - 8) - corners[8]->width(), (_y + _height) - corners[8]->height(), screenRect, *dst);
+ corners[9]->drawBitmap(_x, (_y + sliderBgHeight) - corners[9]->height(), screenRect, *dst);
+ corners[10]->drawBitmap((_x + _width) - corners[10]->width(), (_y + sliderBgHeight) - corners[10]->height(), screenRect, *dst);
+
+ drawHeader(dst, 9, header);
+}
+
+
+void RequestData::drawBackgroundNoSliders(Graphics::Surface *dst, const Common::String &header) const {
+ fillBackground(dst, _x, _y, _width, _height, 0);
+ drawCorners(dst, 11, _x, _y, _width, _height);
+ drawHeader(dst, 4, header);
}
-void RequestData::drawBackground(Graphics::Surface *dst) const {
+/*static*/
+void RequestData::fillBackground(Graphics::Surface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset) {
bool detailHigh = true;
- int startoffset = 0;
if (detailHigh) {
- //g_videoMaskEnabled = true;
- //g_vidMaskXMax = (x + width) - 1;
- //g_vidMaskYMax = (y + height) - 1;
+ Graphics::Surface area = dst->getSubArea(Common::Rect(x, y, x + width, y + height));
while (startoffset < 0)
startoffset += ARRAYSIZE(MenuBackgroundColors);
startoffset = startoffset % ARRAYSIZE(MenuBackgroundColors);
int coloffset = startoffset;
- for (int yoff = _x; yoff < (_x + _width); yoff++) {
- dst->drawLine(yoff, _y, yoff + _height, _y + _height, MenuBackgroundColors[coloffset]);
+ for (int xoff = 0; xoff < width; xoff++) {
+ area.drawLine(xoff, 0, xoff + height, height, MenuBackgroundColors[coloffset]);
coloffset++;
if (coloffset >= ARRAYSIZE(MenuBackgroundColors))
coloffset = 0;
}
// TODO: Game positions mouse in middle of menu here?
coloffset = startoffset;
- for (int yoff = _y; yoff < (_y + _height); yoff++) {
- dst->drawLine(_x, yoff, _x + _height, yoff + _height, MenuBackgroundColors[coloffset]);
+ for (int yoff = 0; yoff < height; yoff++) {
+ area.drawLine(0, yoff, height, yoff + height, MenuBackgroundColors[coloffset]);
coloffset--;
if (coloffset < 0)
coloffset = ARRAYSIZE(MenuBackgroundColors) - 1;
}
- //g_vidMaskYMax = g_screenHeight - 1;
- //g_vidMaskXMax = g_screenWidth - 1;
} else {
- dst->fillRect(Common::Rect(_x, _y, _width, _height), FallbackColors[0]);
+ dst->fillRect(Common::Rect(x, y, width, height), FallbackColors[0]);
}
}
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index d8286b7f067..bab9a0ac08b 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -142,9 +142,19 @@ public:
Common::String dump() const;
void draw(Graphics::Surface *dst) const;
+
+ static const Font *getMenuFont();
+ static const Image *getCorner(int cornerNum);
+
private:
- void drawBackground(Graphics::Surface *dst) const;
+ void drawBackgroundNoSliders(Graphics::Surface *dst, const Common::String &header) const;
+ void drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sliderHeight, const Common::String &header) const;
+
+ void drawHeader(Graphics::Surface *dst, int16 yoffset, const Common::String &header) const;
+
+ static void fillBackground(Graphics::Surface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
+ static void drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
};
// A REQ file contains a sequence of REQ and GAD block pairs.
Commit: 9ee23154204d191fda58f8e0942da8b18d9980f3
https://github.com/scummvm/scummvm/commit/9ee23154204d191fda58f8e0942da8b18d9980f3
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start to implement dialogue rendering
Changed paths:
engines/dgds/dgds.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index afdb8111b1c..8c71f8cc866 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -91,6 +91,7 @@ public:
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
+ SDSScene *getScene() { return _scene; }
const FontManager *getFontMan() const { return _fontManager; }
void drawVCR(REQFileData &vcrRequestData);
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index d2eaa5f217b..06a431ea639 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -23,13 +23,150 @@
#include "common/debug.h"
#include "common/endian.h"
#include "common/file.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+#include "graphics/primitives.h"
+
+#include "dgds/dgds.h"
#include "dgds/includes.h"
#include "dgds/resource.h"
#include "dgds/scene.h"
+#include "dgds/font.h"
namespace Dgds {
+
+void Dialogue::draw(Graphics::Surface *dst, int mode) {
+ switch (_frameType) {
+ case 1: return drawType1(dst, mode);
+ case 2: return drawType2(dst, mode);
+ case 3: return drawType3(dst, mode);
+ case 4: return drawType4(dst, mode);
+ default: error("unexpected frame type %d for dialog %d", _frameType, _num);
+ }
+}
+
+static void _drawPixel(int x, int y, int color, void *data) {
+ Graphics::Surface *surface = (Graphics::Surface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
+ *((byte *)surface->getBasePtr(x, y)) = (byte)color;
+}
+
+
+// box with simple frame
+void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
+ //if (!_field15_0x22)
+ // return;
+ if (stage == 1) {
+ int x = _rect.x;
+ int y = _rect.y;
+ int w = _rect.width;
+ int h = _rect.height;
+
+ // TODO: Is this right?
+ dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
+ dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
+ /*
+ int uVar1 = _field15_0x22;
+ *(int *)(uVar1 + 2) = x + 3;
+ *(int *)(uVar1 + 4) = y + 3;
+ *(int *)(uVar1 + 6) = width + -6;
+ *(int *)(uVar1 + 8) = height + -6; */
+ } else if (stage == 2) {
+ drawStage2(dst);
+ } else if (stage == 2) {
+ drawStage2(dst);
+ } else {
+ drawStage4(dst);
+ }
+}
+
+// box with fancy frame and optional title (everything before ":")
+void Dialogue::drawType2(Graphics::Surface *dst, int stage) {
+ // TODO: Implement me properly.
+ Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
+ dst->fillRect(drawRect, _bgColor);
+}
+
+// comic baloon style box
+void Dialogue::drawType3(Graphics::Surface *dst, int stage) {
+ // TODO: Implement me properly.
+ Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
+ dst->fillRect(drawRect, _bgColor);
+}
+
+// ellipse
+void Dialogue::drawType4(Graphics::Surface *dst, int stage) {
+ if (stage == 1) {
+ int x = _rect.x;
+ int y = _rect.y;
+ int w = _rect.width;
+ int h = _rect.height;
+
+ int midy = (h - 1) / 2;
+ //int radius = (midy * 5) / 4;
+
+ byte fillcolor;
+ byte fillbgcolor;
+ if (!(_flags & 1)) {
+ fillcolor = 0;
+ fillbgcolor = 15;
+ } else {
+ fillcolor = _fontColor;
+ fillbgcolor = _bgColor;
+ }
+
+ // This is not exactly the same as the original - might need some work to get pixel-perfect
+ Common::Rect drawRect(x, y, x + w, y + h);
+ Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, _drawPixel, dst);
+ Graphics::drawRoundRect(drawRect, midy, fillcolor, false, _drawPixel, dst);
+ } else if (stage == 2) {
+ drawStage2(dst);
+ } else if (stage == 2) {
+ drawStage2(dst);
+ } else {
+ drawStage4(dst);
+ }
+}
+
+void Dialogue::drawStage2(Graphics::Surface *dst) {
+ // TODO: various text wrapping and alignment calculations happen here.
+}
+
+void Dialogue::drawStage3(Graphics::Surface *dst) {
+ // TODO: various text wrapping and alignment calculations happen here.
+}
+
+void Dialogue::drawStage4(Graphics::Surface *dst) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+ FontManager::FontType fontType = FontManager::k6x6Font;
+ if (_fontSize == 1)
+ fontType = FontManager::k8x8Font;
+ else if (_fontSize == 3)
+ fontType = FontManager::k4x5Font;
+ const Font *font = fontman->getFont(fontType);
+
+ // TODO: some more text calcuations happen here.
+ // This is where we actually draw the text.
+ // For now do the simplest wrapping.
+ Common::StringArray lines;
+ const int h = font->getFontHeight();
+ font->wordWrapText(_str, _rect.width, lines);
+
+ int ystart = _rect.y + (_rect.height - lines.size() * h) / 2;
+ for (uint i = 0; i < lines.size(); i++) {
+ //const int w = font->getStringWidth(lines[i]);
+ font->drawString(dst, lines[i], _rect.x, ystart + i * h, _rect.width, _fontColor, Graphics::kTextAlignCenter);
+ }
+
+}
+
+
+// //////////////////////////////////// //
+
Scene::Scene() : _magic(0) {
}
@@ -142,52 +279,54 @@ bool Scene::readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneSt
bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const {
+ // Some data on this format here https://www.oldgamesitalia.net/forum/index.php?showtopic=24055&st=25&p=359214&#entry359214
+
list.resize(s->readUint16LE());
for (Dialogue &dst : list) {
- dst.num = s->readUint16LE();
- dst.rect.x = s->readUint16LE();
- dst.rect.y = s->readUint16LE();
- dst.rect.width = s->readUint16LE();
- dst.rect.height = s->readUint16LE();
- dst.bgColor = s->readUint16LE();
- dst.fontColor = s->readUint16LE(); // 0 = black, 0xf = white
+ dst._num = s->readUint16LE();
+ dst._rect.x = s->readUint16LE();
+ dst._rect.y = s->readUint16LE();
+ dst._rect.width = s->readUint16LE();
+ dst._rect.height = s->readUint16LE();
+ dst._bgColor = s->readUint16LE();
+ dst._fontColor = s->readUint16LE(); // 0 = black, 0xf = white
if (isVersionUnder(" 1.209")) {
- dst.field7_0xe = dst.bgColor;
- dst.field8_0x10 = dst.fontColor;
+ dst._field7_0xe = dst._bgColor;
+ dst._field8_0x10 = dst._fontColor;
} else {
- dst.field7_0xe = s->readUint16LE();
- dst.field8_0x10 = s->readUint16LE();
+ dst._field7_0xe = s->readUint16LE();
+ dst._field8_0x10 = s->readUint16LE();
}
- dst.fontSize = s->readUint16LE(); // 01 = 8x8, 02 = 6x6, 03 = 4x5
+ dst._fontSize = s->readUint16LE(); // 01 = 8x8, 02 = 6x6, 03 = 4x5
if (isVersionUnder(" 1.210")) {
- dst.flags = s->readUint16LE();
+ dst._flags = s->readUint16LE();
} else {
// Game reads a 32 bit int but then truncates anyway..
// probably never used the full thing.
- dst.flags = (s->readUint32LE() & 0xffff);
+ dst._flags = (s->readUint32LE() & 0xffff);
}
-
- dst.frametype = s->readUint16LE(); // 01 =simple frame, 02 = with title w/ text before :, 03 = baloon, 04 = eliptical
- dst.field12_0x1a = s->readUint16LE();
+
+ dst._frameType = s->readUint16LE(); // 01 =simple frame, 02 = with title w/ text before :, 03 = baloon, 04 = eliptical
+ dst._field12_0x1a = s->readUint16LE();
if (isVersionOver(" 1.207")) {
- dst.maybeNextDialogNum = s->readUint16LE();
+ dst._maybeNextDialogNum = s->readUint16LE();
}
-
+
uint16 nbytes = s->readUint16LE();
if (nbytes > 0) {
- dst.str = s->readString('\0', nbytes);
+ dst._str = s->readString('\0', nbytes);
} else {
- dst.str.clear();
+ dst._str.clear();
}
- readDialogSubstringList(s, dst.subStrings);
-
- if (isVersionUnder(" 1.209") && !dst.subStrings.empty()) {
- if (dst.fontColor == 0)
- dst.field8_0x10 = 4;
- else if (dst.fontColor == 0xff)
- dst.fontColor = 7;
+ readDialogSubstringList(s, dst._subStrings);
+
+ if (isVersionUnder(" 1.209") && !dst._subStrings.empty()) {
+ if (dst._fontColor == 0)
+ dst._field8_0x10 = 4;
+ else if (dst._fontColor == 0xff)
+ dst._fontColor = 7;
else
- dst.fontColor = dst.fontColor ^ 8;
+ dst._fontColor = dst._fontColor ^ 8;
}
}
@@ -209,10 +348,10 @@ bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneSt
bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) const {
list.resize(s->readUint16LE());
-
+
if (!list.empty())
list[0].val = 1;
-
+
for (DialogueSubstring &dst : list) {
dst.strOff1 = s->readUint16LE();
dst.strOff2 = s->readUint16LE();
@@ -342,7 +481,7 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
readStruct4List(stream, _struct4List2);
if (isVersionOver(" 1.205"))
readStruct4List(stream, _struct4List1);
-
+
return !stream->err();
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index e7af16891fd..8708fd7c4be 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -30,88 +30,100 @@ namespace Dgds {
// TODO: Use Common::Rect instead.
struct Rect {
- int x;
- int y;
- int width;
- int height;
+ int x;
+ int y;
+ int width;
+ int height;
};
struct SceneStruct1 {
- uint16 val1;
- uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
- uint16 val3;
+ uint16 val1;
+ uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
+ uint16 val3;
};
struct SceneStruct2 {
- struct Rect rect;
- uint16 field1_0x8;
- uint16 field2_0xa;
- Common::Array<struct SceneStruct1> struct1List;
- Common::Array<struct SceneStruct5> struct5List1;
- Common::Array<struct SceneStruct5> struct5List2;
- Common::Array<struct SceneStruct5> struct5List3;
+ struct Rect rect;
+ uint16 field1_0x8;
+ uint16 field2_0xa;
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneStruct5> struct5List1;
+ Common::Array<struct SceneStruct5> struct5List2;
+ Common::Array<struct SceneStruct5> struct5List3;
};
struct SceneStruct5 {
- Common::Array<struct SceneStruct1> struct1List;
- Common::Array<uint16> uintList;
- uint16 val;
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<uint16> uintList;
+ uint16 val;
};
struct SceneStruct2_Extended : public SceneStruct2 {
- Common::Array<struct SceneStruct5> struct5List5;
- Common::Array<struct SceneStruct5> struct5List6;
- uint16 field10_0x24;
- uint16 field11_0x26;
- uint16 field12_0x28;
- uint16 field13_0x2a;
- uint16 field14_0x2c;
+ Common::Array<struct SceneStruct5> struct5List5;
+ Common::Array<struct SceneStruct5> struct5List6;
+ uint16 field10_0x24;
+ uint16 field11_0x26;
+ uint16 field12_0x28;
+ uint16 field13_0x2a;
+ uint16 field14_0x2c;
};
struct SceneStruct3 {
- uint16 val1;
- uint16 val2;
- uint16 val3; /* Not set in loader? */
+ uint16 val1;
+ uint16 val2;
+ uint16 val3; /* Not set in loader? */
};
struct SceneStruct4 {
- uint16 val1;
- uint16 val2;
- Common::Array<struct SceneStruct5> struct5List;
+ uint16 val1;
+ uint16 val2;
+ Common::Array<struct SceneStruct5> struct5List;
};
-struct Dialogue {
- uint16 num;
- Rect rect;
- uint16 bgColor;
- uint16 fontColor;
- uint16 field7_0xe;
- uint16 field8_0x10;
- uint16 fontSize;
- uint32 flags; // includes justify
- uint16 frametype;
- uint16 field12_0x1a;
- uint16 maybeNextDialogNum;
- Common::Array<struct DialogueSubstring> subStrings;
- uint16 field15_0x22;
- Common::String str;
- uint16 field18_0x28;
+class Dialogue {
+public:
+ uint16 _num;
+ Rect _rect;
+ uint16 _bgColor;
+ uint16 _fontColor;
+ uint16 _field7_0xe;
+ uint16 _field8_0x10;
+ uint16 _fontSize;
+ uint32 _flags; // includes justify
+ uint16 _frameType;
+ uint16 _field12_0x1a;
+ uint16 _maybeNextDialogNum;
+ Common::Array<struct DialogueSubstring> _subStrings;
+ uint16 _field15_0x22;
+ Common::String _str;
+ uint16 _field18_0x28;
+
+ void draw(Graphics::Surface *dst, int mode);
+private:
+ void drawType1(Graphics::Surface *dst, int mode);
+ void drawType2(Graphics::Surface *dst, int mode);
+ void drawType3(Graphics::Surface *dst, int mode);
+ void drawType4(Graphics::Surface *dst, int mode);
+
+ void drawStage2(Graphics::Surface *dst);
+ void drawStage3(Graphics::Surface *dst);
+ void drawStage4(Graphics::Surface *dst);
};
struct SceneStruct7 {
- uint16 val;
- int16 field1_0x2;
- Common::Array<struct SceneStruct1> struct1List;
- Common::Array<struct SceneStruct5> struct5List;
+ uint16 val;
+ int16 field1_0x2;
+ Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneStruct5> struct5List;
};
struct DialogueSubstring {
- uint16 strOff1; // The game initializes these to pointers, but let's be a bit nicer.
- uint16 strOff2;
- byte unk[8]; /* Not initialized in loader */
- Common::Array<struct SceneStruct5> struct5List;
- uint val; /* First entry initialized to 1 in loader */
+ uint16 strOff1; // The game initializes these to pointers, but let's be a bit nicer.
+ uint16 strOff2;
+ byte unk[8]; /* Not initialized in loader */
+ Common::Array<struct SceneStruct5> struct5List;
+ uint val; /* First entry initialized to 1 in loader */
};
@@ -176,25 +188,25 @@ public:
bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
- const Common::Array<struct Dialogue> &getLines() const { return _dialogues; }
+ Common::Array<struct Dialogue> &getLines() { return _dialogues; }
private:
int _num;
- Common::Array<struct SceneStruct5> _struct5List1;
- Common::Array<struct SceneStruct5> _struct5List2;
- Common::Array<struct SceneStruct5> _struct5List3;
- Common::Array<struct SceneStruct5> _struct5List4;
- //uint _field5_0x12;
- uint _field6_0x14;
- Common::String _adsFile;
- //uint _field8_0x23;
- Common::Array<struct SceneStruct2> _struct2List;
- Common::Array<struct SceneStruct4> _struct4List1;
- Common::Array<struct SceneStruct4> _struct4List2;
- //uint _field12_0x2b;
- Common::Array<struct Dialogue> _dialogues;
- Common::Array<struct SceneStruct7> _struct7List;
- //uint _field15_0x33;
+ Common::Array<struct SceneStruct5> _struct5List1;
+ Common::Array<struct SceneStruct5> _struct5List2;
+ Common::Array<struct SceneStruct5> _struct5List3;
+ Common::Array<struct SceneStruct5> _struct5List4;
+ //uint _field5_0x12;
+ uint _field6_0x14;
+ Common::String _adsFile;
+ //uint _field8_0x23;
+ Common::Array<struct SceneStruct2> _struct2List;
+ Common::Array<struct SceneStruct4> _struct4List1;
+ Common::Array<struct SceneStruct4> _struct4List2;
+ //uint _field12_0x2b;
+ Common::Array<struct Dialogue> _dialogues;
+ Common::Array<struct SceneStruct7> _struct7List;
+ //uint _field15_0x33;
};
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 6a417727c48..efef62788e8 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -42,7 +42,7 @@
namespace Dgds {
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _text(nullptr) {}
bool TTMInterpreter::load(const Common::String &filename) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
@@ -188,18 +188,9 @@ bool TTMInterpreter::run() {
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
_vm->getTopBuffer().fillRect(bmpArea, 0);
- if (!_text.str.empty()) {
- Common::StringArray lines;
- const Font *fnt = _vm->getFontMan()->getFont(FontManager::kGameFont);
- const int h = fnt->getFontHeight();
-
- fnt->wordWrapText(_text.str, SCREEN_HEIGHT, lines);
- Common::Rect r(Common::Point(_text.rect.x, _text.rect.y), _text.rect.width, _text.rect.height);
- _vm->_resData.fillRect(r, 15);
- for (uint i = 0; i < lines.size(); i++) {
- const int w = fnt->getStringWidth(lines[i]);
- fnt->drawString(&_vm->_resData, lines[i], _text.rect.x, _text.rect.y + 1 + i * h, w, 0);
- }
+ if (_text) {
+ _text->draw(_vm->_resData.surfacePtr(), 1);
+ _text->draw(_vm->_resData.surfacePtr(), 4);
}
} break;
@@ -238,16 +229,16 @@ bool TTMInterpreter::run() {
debug("SHOW SCENE TEXT: %u", ivals[0]);
_state.scene = ivals[0];
- const Common::Array<Dialogue> dialogues = _vm->getScene()->getLines();
- _text.str.clear();
- for (const Dialogue &dialogue: dialogues) {
- if (dialogue.num == _state.scene)
- _text = dialogue;
+ Common::Array<Dialogue> &dialogues = _vm->getScene()->getLines();
+ _text = nullptr;
+ for (Dialogue &dialogue: dialogues) {
+ if (dialogue._num == _state.scene)
+ _text = &dialogue;
// HACK to get Dragon intro working
- if (_text.str.empty() && dialogue.num == _state.scene + 14)
- _text = dialogue;
+ if (!_text && dialogue._num == _state.scene + 14)
+ _text = &dialogue;
}
- if (!_text.str.empty())
+ if (_text && !_text->_str.empty())
_state.delay += 1500;
continue;
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index ff0817eb98b..548eb4593e4 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -80,7 +80,7 @@ public:
protected:
DgdsEngine *_vm;
- Dialogue _text;
+ Dialogue *_text;
TTMData _scriptData;
TTMState _state;
};
Commit: 006a38b3388923874fc8863061ae5e05998c20d9
https://github.com/scummvm/scummvm/commit/006a38b3388923874fc8863061ae5e05998c20d9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Dialogue is a class - fix forward declaration
Changed paths:
engines/dgds/scene.h
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 8708fd7c4be..144b622a44a 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -188,7 +188,7 @@ public:
bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
- Common::Array<struct Dialogue> &getLines() { return _dialogues; }
+ Common::Array<class Dialogue> &getLines() { return _dialogues; }
private:
int _num;
@@ -204,7 +204,7 @@ private:
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
//uint _field12_0x2b;
- Common::Array<struct Dialogue> _dialogues;
+ Common::Array<class Dialogue> _dialogues;
Common::Array<struct SceneStruct7> _struct7List;
//uint _field15_0x33;
};
Commit: 09529edb052529e39fd8daa4882fd2c901fb9fa8
https://github.com/scummvm/scummvm/commit/09529edb052529e39fd8daa4882fd2c901fb9fa8
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start implementing menus
The cursor used is a temporary placeholder for debugging purposes
Also, some minor fixes:
- Free screen buffers on engine destruction
- Added menu corners for HoC (the colors still look wrong)
- Added menu corners for Beamish (currently not loading correctly)
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index e9d5d0a105c..d258926496d 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -35,6 +35,7 @@
#include "common/formats/iff_container.h"
+#include "graphics/cursorman.h"
#include "graphics/font.h"
#include "graphics/fontman.h"
#include "graphics/managed_surface.h"
@@ -60,6 +61,81 @@
namespace Dgds {
+enum MenuIds {
+ kMenuNone = -1,
+ kMenuMain = 0,
+ kMenuControls = 1,
+ kMenuOptions = 2,
+ kMenuCalibrate = 3,
+ kMenuRestart = 4,
+ // 5: you cannot save your game right now
+ // 6: game over
+ kMenuFiles = 7,
+ // 8: save game not saved because disk is full
+ // 9: all game entries are full
+ kMenuSave = 10,
+ // 11: change directory - create directory
+ // 12: change directory - invalid directory specified
+ kMenuChangeDirectory = 13,
+ kMenuJoystick = 14,
+ kMenuMouse = 15,
+ kMenuQuit = 16
+ // 17: I'm frustrated - keep trying / win arcade
+ // 18: skip introduction / play introduction
+ // 19: save game before arcade
+ // 20: replay arcade
+};
+
+enum MenuButtonIds {
+ kMenuMainPlay = 120,
+ kMenuMainControls = 20,
+ kMenuMainOptions = 121,
+ kMenuMainCalibrate = 118,
+ kMenuMainFiles = 119,
+ kMenuMainQuit = 122,
+
+ kMenuControlsVCR = 127,
+ kMenuControlsPlay = 128,
+
+ kMenuOptionsJoystickOnOff = 139,
+ kMenuOptionsMouseOnOff = 138,
+ kMenuOptionsSoundsOnOff = 137,
+ kMenuOptionsMusicOnOff = 140,
+ kMenuOptionsVCR = 135,
+ kMenuOptionsPlay = 136,
+
+ kMenuCalibrateJoystick = 145,
+ kMenuCalibrateMouse = 146,
+ kMenuCalibrateVCR = 144,
+ kMenuCalibratePlay = 147,
+
+ kMenuFilesSave = 107,
+ kMenuFilesRestore = 106,
+ kMenuFilesRestart = 105,
+ kMenuFilesVCR = 103,
+ kMenuFilesPlay = 130,
+
+ kMenuSavePrevious = 58,
+ kMenuSaveNext = 59,
+ kMenuSaveSave = 53,
+ kMenuSaveCancel = 54,
+ kMenuSaveChangeDirectory = 55,
+
+ kMenuChangeDirectoryOK = 95,
+ kMenuChangeDirectoryCancel = 96,
+
+ kMenuMouseCalibrationCalibrate = 157,
+ kMenuMouseCalibrationPlay = 155,
+
+ kMenuJoystickCalibrationOK = 132,
+
+ kMenuQuitYes = 134,
+ kMenuQuitNo = 133,
+
+ kMenuRestartYes = 163,
+ kMenuRestartNo = 164
+};
+
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
@@ -91,6 +167,11 @@ DgdsEngine::~DgdsEngine() {
delete _gdsScene;
delete _soundPlayer;
delete _fontManager;
+
+ _screenBuffer.free();
+ _resData.free();
+ _topBuffer.free();
+ _bottomBuffer.free();
}
void readStrings(Common::SeekableReadStream *stream) {
@@ -107,13 +188,17 @@ void readStrings(Common::SeekableReadStream *stream) {
debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
}
}
-void DgdsEngine::drawVCR(REQFileData &vcrRequestData) {
- // TODO: Hardcoded
- Common::Array<Common::SharedPtr<Gadget>> gadgets = vcrRequestData._requests[1]._gadgets;
+void DgdsEngine::drawMenu(REQFileData &vcrRequestData, int16 menu) {
+ _curMenu = menu;
+
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
Graphics::Surface *dst = g_system->lockScreen();
- vcrRequestData._requests[1].draw(dst);
+ // Restore background when drawing submenus
+ dst->copyFrom(_screenBuffer);
+
+ vcrRequestData._requests[_curMenu].draw(dst);
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
@@ -125,6 +210,113 @@ void DgdsEngine::drawVCR(REQFileData &vcrRequestData) {
g_system->updateScreen();
}
+int16 DgdsEngine::getClickedMenuItem(REQFileData& vcrRequestData, Common::Point mouseClick) {
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+
+ for (Common::SharedPtr<Gadget> &gptr : gadgets) {
+ Gadget *gadget = gptr.get();
+ if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider) {
+ int16 x = gadget->_x + gadget->_parentX;
+ int16 y = gadget->_y + gadget->_parentY;
+ int16 right = x + gadget->_width;
+ int16 bottom = (y + gadget->_height) - 1;
+ Common::Rect gadgetRect(x, y, right, bottom);
+ if (gadgetRect.contains(mouseClick))
+ return (int16)gadget->_gadgetNo;
+ }
+ }
+
+ return -1;
+}
+
+void DgdsEngine::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
+ const int16 clickedMenuItem = getClickedMenuItem(vcrRequestData, mouse);
+ switch (clickedMenuItem) {
+ case kMenuMainPlay:
+ case kMenuControlsPlay:
+ case kMenuOptionsPlay:
+ case kMenuCalibratePlay:
+ case kMenuFilesPlay:
+ case kMenuMouseCalibrationPlay:
+ _curMenu = kMenuNone;
+ CursorMan.showMouse(false);
+ break;
+ case kMenuMainControls:
+ drawMenu(vcrRequestData, kMenuControls);
+ break;
+ case kMenuMainOptions:
+ drawMenu(vcrRequestData, kMenuOptions);
+ break;
+ case kMenuMainCalibrate:
+ case kMenuJoystickCalibrationOK:
+ case kMenuMouseCalibrationCalibrate:
+ drawMenu(vcrRequestData, kMenuCalibrate);
+ break;
+ case kMenuMainFiles:
+ case kMenuSaveCancel:
+ drawMenu(vcrRequestData, kMenuFiles);
+ break;
+ case kMenuMainQuit:
+ drawMenu(vcrRequestData, kMenuQuit);
+ break;
+ case kMenuControlsVCR:
+ case kMenuOptionsVCR:
+ case kMenuCalibrateVCR:
+ case kMenuFilesVCR:
+ case kMenuQuitNo:
+ case kMenuRestartNo:
+ drawMenu(vcrRequestData, kMenuMain);
+ break;
+ case kMenuOptionsJoystickOnOff:
+ case kMenuOptionsMouseOnOff:
+ case kMenuOptionsSoundsOnOff:
+ case kMenuOptionsMusicOnOff:
+ // TODO
+ debug("Clicked option with ID %d", clickedMenuItem);
+ break;
+ case kMenuCalibrateJoystick:
+ drawMenu(vcrRequestData, kMenuJoystick);
+ break;
+ case kMenuCalibrateMouse:
+ drawMenu(vcrRequestData, kMenuMouse);
+ break;
+ case kMenuFilesSave:
+ case kMenuChangeDirectoryCancel:
+ drawMenu(vcrRequestData, kMenuSave);
+ break;
+ case kMenuFilesRestore:
+ // TODO
+ debug("Clicked Files - Restore %d", clickedMenuItem);
+ break;
+ case kMenuFilesRestart:
+ drawMenu(vcrRequestData, kMenuRestart);
+ break;
+ case kMenuSavePrevious:
+ case kMenuSaveNext:
+ case kMenuSaveSave:
+ // TODO
+ debug("Clicked Save - %d", clickedMenuItem);
+ break;
+ case kMenuSaveChangeDirectory:
+ drawMenu(vcrRequestData, kMenuChangeDirectory);
+ break;
+ case kMenuChangeDirectoryOK:
+ // TODO
+ debug("Clicked change directory - %d", clickedMenuItem);
+ break;
+ case kMenuQuitYes:
+ g_engine->quitGame();
+ break;
+ case kMenuRestartYes:
+ // TODO
+ debug("Clicked Restart - Yes %d", clickedMenuItem);
+ break;
+ default:
+ debug("Clicked ID %d", clickedMenuItem);
+ break;
+ }
+}
+
void DgdsEngine::loadCorners(const Common::String &filename, int numImgs) {
_corners.resize(numImgs);
for (int i = 0; i < numImgs; i++) {
@@ -134,6 +326,25 @@ void DgdsEngine::loadCorners(const Common::String &filename, int numImgs) {
}
}
+// TODO: Temporary placeholder cursor - replace!
+static const byte mouseData[] = {
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 7, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 7, 7, 1, 0, 0, 0, 0, 0, 0,
+ 1, 7, 7, 7, 1, 0, 0, 0, 0, 0,
+ 1, 7, 7, 7, 7, 1, 0, 0, 0, 0,
+ 1, 7, 7, 7, 7, 7, 1, 0, 0, 0,
+ 1, 7, 7, 7, 7, 7, 7, 1, 0, 0,
+ 1, 7, 7, 7, 7, 7, 7, 7, 1, 0,
+ 1, 7, 7, 7, 7, 7, 1, 1, 1, 1,
+ 1, 7, 7, 1, 7, 7, 1, 0, 0, 0,
+ 1, 7, 1, 0, 1, 7, 7, 1, 0, 0,
+ 1, 1, 0, 0, 1, 7, 7, 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
+ 0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
+};
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -146,11 +357,14 @@ Common::Error DgdsEngine::run() {
_gdsScene = new GDSScene();
_fontManager = new FontManager();
+ CursorMan.pushCursor(mouseData, 10, 15, 0, 0, 0);
+
setDebugger(_console);
_bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _screenBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
g_system->fillScreen(0);
@@ -166,17 +380,13 @@ Common::Error DgdsEngine::run() {
_fontManager->loadFonts(getGameId(), _resource, _decompressor);
if (getGameId() == GID_DRAGON) {
- // Test parsing some things..
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
reqParser.parse(&invRequestData, "DINV.REQ");
reqParser.parse(&vcrRequestData, "DVCR.REQ");
- // Load the intro and play it for now.
interpIntro.load("TITLE1.ADS");
- //interpIntro.load("INTRO.ADS");
loadCorners("DCORNERS.BMP", 29);
-
} else if (getGameId() == GID_CHINA) {
_gdsScene->load("HOC.GDS", _resource, _decompressor);
@@ -185,6 +395,7 @@ Common::Error DgdsEngine::run() {
//_scene->load("S101.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
+ loadCorners("HCORNERS.BMP", 29);
} else if (getGameId() == GID_BEAMISH) {
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
@@ -194,32 +405,60 @@ Common::Error DgdsEngine::run() {
//_scene->load("S34.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
+ //loadCorners("WCORNERS.BMP", 29); // TODO: Currently crashes
}
debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
- bool vcrShown = false;
+ bool triggerMenu = false;
+ bool mouseEvent = false;
while (!shouldQuit()) {
- if (eventMan->pollEvent(ev)) {
+ while (eventMan->pollEvent(ev)) {
if (ev.type == Common::EVENT_KEYDOWN) {
switch (ev.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
- moveToNext = true;
+ if (_curMenu >= 0)
+ triggerMenu = true;
+ else
+ moveToNext = true;
break;
case Common::KEYCODE_F5:
- drawVCR(vcrRequestData);
- vcrShown = !vcrShown;
+ triggerMenu = true;
break;
default:
break;
}
+ } else if (ev.type == Common::EVENT_LBUTTONUP) {
+ mouseEvent = true;
}
}
- if (vcrShown) {
+ if (triggerMenu) {
+ if (_curMenu == kMenuNone) {
+ Graphics::Surface *dst = g_system->lockScreen();
+ _screenBuffer.copyFrom(*dst);
+ g_system->unlockScreen();
+
+ CursorMan.showMouse(true);
+ drawMenu(vcrRequestData, 0);
+ } else {
+ _curMenu = kMenuNone;
+ CursorMan.showMouse(false);
+ }
+
+ triggerMenu = false;
+ }
+
+ if (mouseEvent) {
+ handleMenu(vcrRequestData, ev.mouse);
+ mouseEvent = false;
+ }
+
+ if (_curMenu != kMenuNone) {
+ g_system->updateScreen();
g_system->delayMillis(10);
continue;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 8c71f8cc866..f559d2e8419 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -24,6 +24,7 @@
#define DGDS_DGDS_H
#include "common/error.h"
+#include "common/events.h"
#include "common/platform.h"
#include "graphics/surface.h"
@@ -71,11 +72,13 @@ private:
DgdsGameId _gameId;
Graphics::Surface _bottomBuffer;
Graphics::Surface _topBuffer;
+ Graphics::Surface _screenBuffer;
SDSScene *_scene;
GDSScene *_gdsScene;
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
+ int16 _curMenu = -1;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -93,7 +96,9 @@ public:
const SDSScene *getScene() const { return _scene; }
SDSScene *getScene() { return _scene; }
const FontManager *getFontMan() const { return _fontManager; }
- void drawVCR(REQFileData &vcrRequestData);
+ void drawMenu(REQFileData &vcrRequestData, int16 menu);
+ int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
+ void handleMenu(REQFileData &vcrRequestData, Common::Point &mouse);
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
private:
Commit: 7576860102e90f81f9c3edc21bbc54784fd6c0a0
https://github.com/scummvm/scummvm/commit/7576860102e90f81f9c3edc21bbc54784fd6c0a0
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add debug command to dump bitmap frames
Changed paths:
engines/dgds/console.cpp
engines/dgds/console.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/resource.cpp
engines/dgds/resource.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 2b7c8ab7c14..3e808b1bfc5 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -21,10 +21,17 @@
*/
#include "common/memstream.h"
+#include "common/system.h"
+
+#include "graphics/palette.h"
+
+#include "image/png.h"
+
#include "dgds/console.h"
#include "dgds/decompress.h"
#include "dgds/dgds.h"
#include "dgds/includes.h"
+#include "dgds/image.h"
#include "dgds/parser.h"
#include "dgds/resource.h"
#include "gui/debugger.h"
@@ -35,6 +42,7 @@ Console::Console(DgdsEngine *vm) : _vm(vm) {
registerCmd("fileinfo", WRAP_METHOD(Console, cmdFileInfo));
registerCmd("filesearch", WRAP_METHOD(Console, cmdFileSearch));
registerCmd("filedump", WRAP_METHOD(Console, cmdFileDump));
+ registerCmd("imagedump", WRAP_METHOD(Console, cmdImageDump));
}
bool Console::cmdFileInfo(int argc, const char **argv) {
@@ -101,8 +109,11 @@ bool Console::cmdFileDump(int argc, const char **argv) {
DgdsChunkReader chunk(resStream);
while (chunk.readNextHeader(ex, fileName)) {
- if (!chunkType.empty() && !chunkType.equals(chunk.getIdStr()))
+ if (!chunkType.empty() && !chunkType.equals(chunk.getIdStr())) {
+ if (!chunk.isContainer())
+ chunk.skipContent();
continue;
+ }
chunk.readContent(_vm->getDecompressor());
@@ -129,4 +140,68 @@ bool Console::cmdFileDump(int argc, const char **argv) {
return true;
}
+bool Console::cmdImageDump(int argc, const char **argv) {
+#if USE_PNG
+ if (argc < 3) {
+ debugPrintf("Usage: %s <imagefilename> <frameno> [outputpath]\n", argv[0]);
+ return true;
+ }
+
+ const char *fname = argv[1];
+ int frameno = atoi(argv[2]);
+
+ if (!_vm->getResourceManager()->hasResource(fname)) {
+ debugPrintf("Resource %s not found\n", fname);
+ return true;
+ }
+
+ Image img(_vm->getResourceManager(), _vm->getDecompressor());
+
+ int maxframe = img.frameCount(fname);
+ if (frameno > maxframe) {
+ debugPrintf("Image only has %d frames\n", maxframe);
+ return true;
+ }
+ img.loadPalette("DYNAMIX.PAL");
+ img.setPalette();
+ img.loadBitmap(fname, frameno);
+ int width = img.width();
+ int height = img.height();
+ if (!width || !height) {
+ debugPrintf("Image %s:%d not valid\n", fname, frameno);
+ return true;
+ }
+
+ Graphics::Surface surf;
+ surf.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+ img.drawBitmap(0, 0, Common::Rect(0, 0, width, height), surf);
+
+ Common::DumpFile outf;
+ Common::String outfname = Common::String::format("%s-%d.png", fname, frameno);
+
+ if (argc == 4) {
+ Common::Path path(argv[3]);
+ path.joinInPlace(outfname);
+ outf.open(path);
+ } else {
+ outf.open(Common::Path(outfname));
+ }
+ if (!outf.isOpen()) {
+ debugPrintf("Couldn't open %s\n", outfname.c_str());
+ return true;
+ }
+
+ byte palbuf[768];
+ g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
+ ::Image::writePNG(outf, surf, palbuf);
+ outf.close();
+ surf.free();
+ debugPrintf("wrote %dx%d png to %s\n", width, height, outfname.c_str());
+
+#else
+ warning("dumpimage needs png support");
+#endif
+ return true;
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/console.h b/engines/dgds/console.h
index f96c53ecc03..f3c75638082 100644
--- a/engines/dgds/console.h
+++ b/engines/dgds/console.h
@@ -38,6 +38,7 @@ private:
bool cmdFileInfo(int argc, const char **argv);
bool cmdFileSearch(int argc, const char **argv);
bool cmdFileDump(int argc, const char **argv);
+ bool cmdImageDump(int argc, const char **argv);
DgdsEngine *_vm;
};
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 19c08c2e52e..059c0351318 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -87,7 +87,23 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
delete fileStream;
}
-void Image::loadBitmap(Common::String filename, int number) {
+int Image::frameCount(const Common::String &filename) {
+ Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ if (!fileStream)
+ error("Couldn't get bitmap resource %s", filename.c_str());
+
+ int tileCount = -1;
+ DgdsChunkReader chunk(fileStream);
+ while (chunk.readNextHeader(EX_BMP, filename)) {
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
+ if (chunk.isSection(ID_INF)) {
+ tileCount = stream->readUint16LE();
+ }
+ }
+}
+
+void Image::loadBitmap(const Common::String &filename, int number) {
const char *dot;
DGDS_EX ex;
uint16 *mtx;
@@ -111,8 +127,8 @@ void Image::loadBitmap(Common::String filename, int number) {
int64 vqtpos = -1;
int64 scnpos = -1;
- uint16 tileWidths[64];
- uint16 tileHeights[64];
+ uint16 tileWidths[128];
+ uint16 tileHeights[128];
int32 tileOffset = 0;
DgdsChunkReader chunk(fileStream);
@@ -121,8 +137,12 @@ void Image::loadBitmap(Common::String filename, int number) {
Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
- if (tileCount > 64)
+ if (tileCount > ARRAYSIZE(tileWidths))
error("Image::loadBitmap: Unexpectedly large number of tiles in image (%d)", tileCount);
+ if (tileCount < number) {
+ warning("Request for frame %d from %s that only has %d frames", number, filename.c_str(), tileCount);
+ return;
+ }
for (uint16 k = 0; k < tileCount; k++) {
tileWidths[k] = stream->readUint16LE();
}
@@ -388,7 +408,7 @@ uint32 Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toff
state.srcPtr = buf;
for (uint i = 0; i < th; i++)
state.rowStarts[i] = tw * i;
-
+
_doVqtDecode(&state, 0, 0, tw, th);
free(buf);
return state.offset;
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index d3ada319abe..44add4381a4 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -43,7 +43,8 @@ public:
virtual ~Image();
void drawScreen(Common::String filename, Graphics::Surface &surface);
- void loadBitmap(Common::String filename, int number);
+ void loadBitmap(const Common::String &filename, int number);
+ int frameCount(const Common::String &filename);
void drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surface &surface);
void loadPalette(Common::String filename);
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index ebbe51c6dec..5bde5cb50e9 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -122,6 +122,11 @@ Resource ResourceManager::getResourceInfo(Common::String name) {
return _resources[name];
}
+bool ResourceManager::hasResource(Common::String name) const {
+ name.toLowercase();
+ return _resources.contains(name);
+}
+
DgdsChunkReader::~DgdsChunkReader() {
if (_contentStream)
delete _contentStream;
diff --git a/engines/dgds/resource.h b/engines/dgds/resource.h
index 2affffff710..ea6c0a20f9a 100644
--- a/engines/dgds/resource.h
+++ b/engines/dgds/resource.h
@@ -54,6 +54,7 @@ public:
Common::SeekableReadStream *getResource(Common::String name, bool ignorePatches = false);
Resource getResourceInfo(Common::String name);
+ bool hasResource(Common::String name) const;
const ResourceList &getResources() const { return _resources; }
Commit: 8523a24e4b53f27f63b211f1cc77bb22884d970f
https://github.com/scummvm/scummvm/commit/8523a24e4b53f27f63b211f1cc77bb22884d970f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add loading of game icons (mouse cursors etc)
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index d258926496d..4d679b2527d 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -211,6 +211,9 @@ void DgdsEngine::drawMenu(REQFileData &vcrRequestData, int16 menu) {
}
int16 DgdsEngine::getClickedMenuItem(REQFileData& vcrRequestData, Common::Point mouseClick) {
+ if (_curMenu < 0)
+ return -1;
+
Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
@@ -317,7 +320,9 @@ void DgdsEngine::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
}
}
-void DgdsEngine::loadCorners(const Common::String &filename, int numImgs) {
+void DgdsEngine::loadCorners(const Common::String &filename) {
+ Image i(_resource, _decompressor);
+ int numImgs = i.frameCount(filename);
_corners.resize(numImgs);
for (int i = 0; i < numImgs; i++) {
Image *img = new Image(_resource, _decompressor);
@@ -345,6 +350,22 @@ static const byte mouseData[] = {
0, 0, 0, 0, 0, 0, 1, 1, 0, 0
};
+void DgdsEngine::loadIcons() {
+ const Common::String &iconFileName = _gdsScene->getIconFile();
+
+ if (iconFileName.empty())
+ return;
+
+ Image i(_resource, _decompressor);
+ int numImgs = i.frameCount(iconFileName);
+ _icons.resize(numImgs);
+ for (int i = 0; i < numImgs; i++) {
+ Image *img = new Image(_resource, _decompressor);
+ img->loadBitmap(iconFileName, i);
+ _icons[i].reset(img);
+ }
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -386,7 +407,7 @@ Common::Error DgdsEngine::run() {
reqParser.parse(&vcrRequestData, "DVCR.REQ");
interpIntro.load("TITLE1.ADS");
- loadCorners("DCORNERS.BMP", 29);
+ loadCorners("DCORNERS.BMP");
} else if (getGameId() == GID_CHINA) {
_gdsScene->load("HOC.GDS", _resource, _decompressor);
@@ -395,7 +416,7 @@ Common::Error DgdsEngine::run() {
//_scene->load("S101.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
- loadCorners("HCORNERS.BMP", 29);
+ loadCorners("HCORNERS.BMP");
} else if (getGameId() == GID_BEAMISH) {
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
@@ -405,9 +426,13 @@ Common::Error DgdsEngine::run() {
//_scene->load("S34.SDS", _resource, _decompressor);
interpIntro.load("TITLE.ADS");
- //loadCorners("WCORNERS.BMP", 29); // TODO: Currently crashes
+ loadCorners("WCORNERS.BMP");
}
+ loadIcons();
+
+ //getDebugger()->attach();
+
debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index f559d2e8419..6473087cfc1 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -78,6 +78,7 @@ private:
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
+ Common::Array<Common::SharedPtr<Image>> _icons;
int16 _curMenu = -1;
public:
@@ -102,7 +103,8 @@ public:
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
private:
- void loadCorners(const Common::String &filename, int numImgs);
+ void loadCorners(const Common::String &filename);
+ void loadIcons();
};
} // End of namespace Dgds
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 059c0351318..adc3830fb57 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -101,6 +101,7 @@ int Image::frameCount(const Common::String &filename) {
tileCount = stream->readUint16LE();
}
}
+ return tileCount;
}
void Image::loadBitmap(const Common::String &filename, int number) {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 44add4381a4..fc4a3da2bc3 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -54,6 +54,8 @@ public:
int16 width() const;
int16 height() const;
+ const Graphics::Surface &getSurface() { return _bmpData; }
+
private:
void loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
void loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 144b622a44a..0c15823ea8c 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -167,6 +167,7 @@ public:
bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
bool parseInf(Common::SeekableReadStream *s);
+ const Common::String &getIconFile() const { return _iconFile; }
private:
//byte _unk[32];
Commit: 78f23ed1c80a1d64c14fb4bbd37a921acbd7169b
https://github.com/scummvm/scummvm/commit/78f23ed1c80a1d64c14fb4bbd37a921acbd7169b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Use default mouse cursor from icons file
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 3e808b1bfc5..df579932fd5 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -172,10 +172,6 @@ bool Console::cmdImageDump(int argc, const char **argv) {
return true;
}
- Graphics::Surface surf;
- surf.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
- img.drawBitmap(0, 0, Common::Rect(0, 0, width, height), surf);
-
Common::DumpFile outf;
Common::String outfname = Common::String::format("%s-%d.png", fname, frameno);
@@ -193,9 +189,8 @@ bool Console::cmdImageDump(int argc, const char **argv) {
byte palbuf[768];
g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
- ::Image::writePNG(outf, surf, palbuf);
+ ::Image::writePNG(outf, img.getSurface(), palbuf);
outf.close();
- surf.free();
debugPrintf("wrote %dx%d png to %s\n", width, height, outfname.c_str());
#else
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 4d679b2527d..d471b7c5e36 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -323,6 +323,8 @@ void DgdsEngine::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
void DgdsEngine::loadCorners(const Common::String &filename) {
Image i(_resource, _decompressor);
int numImgs = i.frameCount(filename);
+ if (numImgs <= 0)
+ error("Corner file %s didn't have any frames?", filename.c_str());
_corners.resize(numImgs);
for (int i = 0; i < numImgs; i++) {
Image *img = new Image(_resource, _decompressor);
@@ -331,25 +333,6 @@ void DgdsEngine::loadCorners(const Common::String &filename) {
}
}
-// TODO: Temporary placeholder cursor - replace!
-static const byte mouseData[] = {
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 7, 1, 0, 0, 0, 0, 0, 0, 0,
- 1, 7, 7, 1, 0, 0, 0, 0, 0, 0,
- 1, 7, 7, 7, 1, 0, 0, 0, 0, 0,
- 1, 7, 7, 7, 7, 1, 0, 0, 0, 0,
- 1, 7, 7, 7, 7, 7, 1, 0, 0, 0,
- 1, 7, 7, 7, 7, 7, 7, 1, 0, 0,
- 1, 7, 7, 7, 7, 7, 7, 7, 1, 0,
- 1, 7, 7, 7, 7, 7, 1, 1, 1, 1,
- 1, 7, 7, 1, 7, 7, 1, 0, 0, 0,
- 1, 7, 1, 0, 1, 7, 7, 1, 0, 0,
- 1, 1, 0, 0, 1, 7, 7, 1, 0, 0,
- 0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
- 0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
-};
-
void DgdsEngine::loadIcons() {
const Common::String &iconFileName = _gdsScene->getIconFile();
@@ -358,6 +341,8 @@ void DgdsEngine::loadIcons() {
Image i(_resource, _decompressor);
int numImgs = i.frameCount(iconFileName);
+ if (numImgs <= 0)
+ error("Icon file %s didn't have any frames?", iconFileName.c_str());
_icons.resize(numImgs);
for (int i = 0; i < numImgs; i++) {
Image *img = new Image(_resource, _decompressor);
@@ -378,8 +363,6 @@ Common::Error DgdsEngine::run() {
_gdsScene = new GDSScene();
_fontManager = new FontManager();
- CursorMan.pushCursor(mouseData, 10, 15, 0, 0, 0);
-
setDebugger(_console);
_bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
@@ -430,6 +413,9 @@ Common::Error DgdsEngine::run() {
}
loadIcons();
+ if (!_icons.empty()) {
+ CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
+ }
//getDebugger()->attach();
Commit: 086f896a43ea604df455e070df287677da1634da
https://github.com/scummvm/scummvm/commit/086f896a43ea604df455e070df287677da1634da
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Name mouse cursor struct correctly
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index d471b7c5e36..e51d040c974 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -196,7 +196,7 @@ void DgdsEngine::drawMenu(REQFileData &vcrRequestData, int16 menu) {
Graphics::Surface *dst = g_system->lockScreen();
// Restore background when drawing submenus
- dst->copyFrom(_screenBuffer);
+ //dst->copyFrom(_screenBuffer);
vcrRequestData._requests[_curMenu].draw(dst);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 06a431ea639..12678d1ddde 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -236,11 +236,11 @@ bool Scene::readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array
}
-bool Scene::readStruct3List(Common::SeekableReadStream *s, Common::Array<SceneStruct3> &list) const {
+bool Scene::readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct3 &dst : list) {
- dst.val1 = s->readUint16LE();
- dst.val2 = s->readUint16LE();
+ for (MouseCursor &dst : list) {
+ dst._hotX = s->readUint16LE();
+ dst._hotY = s->readUint16LE();
}
return !s->err();
}
@@ -474,9 +474,9 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
readStruct5List(stream, _struct5List5);
Common::Array<struct SceneStruct1> struct1List;
readStruct1List(stream, struct1List);
- Common::Array<struct SceneStruct3> struct3List;
+ Common::Array<struct MouseCursor> struct3List;
_iconFile = stream->readString();
- readStruct3List(stream, struct3List);
+ readMouseHotspotList(stream, struct3List);
readStruct2ExtendedList(stream, _struct2ExtList);
readStruct4List(stream, _struct4List2);
if (isVersionOver(" 1.205"))
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 0c15823ea8c..bb8b6008819 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -68,10 +68,11 @@ struct SceneStruct2_Extended : public SceneStruct2 {
uint16 field14_0x2c;
};
-struct SceneStruct3 {
- uint16 val1;
- uint16 val2;
- uint16 val3; /* Not set in loader? */
+struct MouseCursor {
+ uint16 _hotX;
+ uint16 _hotY;
+ // pointer to cursor image
+ //Common::SharedPtr<Image> _img;
};
struct SceneStruct4 {
@@ -146,7 +147,7 @@ protected:
bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const;
bool readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<SceneStruct2_Extended> &list) const;
- bool readStruct3List(Common::SeekableReadStream *s, Common::Array<SceneStruct3> &list) const;
+ bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
bool readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) const;
bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const;
Commit: bec24c36db29a2e7e30c968f080f58734cacc41d
https://github.com/scummvm/scummvm/commit/bec24c36db29a2e7e30c968f080f58734cacc41d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix background buffer handling
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index e51d040c974..98c2ccf40a6 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -193,10 +193,10 @@ void DgdsEngine::drawMenu(REQFileData &vcrRequestData, int16 menu) {
_curMenu = menu;
Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
- Graphics::Surface *dst = g_system->lockScreen();
-
// Restore background when drawing submenus
- //dst->copyFrom(_screenBuffer);
+ g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
+
+ Graphics::Surface *dst = g_system->lockScreen();
vcrRequestData._requests[_curMenu].draw(dst);
Commit: 423dd1f26791d0508caae3dbaa002bbf840282db
https://github.com/scummvm/scummvm/commit/423dd1f26791d0508caae3dbaa002bbf840282db
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix shadowed variables
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 98c2ccf40a6..191f190783a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -321,8 +321,8 @@ void DgdsEngine::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
}
void DgdsEngine::loadCorners(const Common::String &filename) {
- Image i(_resource, _decompressor);
- int numImgs = i.frameCount(filename);
+ Image imgRes(_resource, _decompressor);
+ int numImgs = imgRes.frameCount(filename);
if (numImgs <= 0)
error("Corner file %s didn't have any frames?", filename.c_str());
_corners.resize(numImgs);
@@ -339,8 +339,8 @@ void DgdsEngine::loadIcons() {
if (iconFileName.empty())
return;
- Image i(_resource, _decompressor);
- int numImgs = i.frameCount(iconFileName);
+ Image imgRes(_resource, _decompressor);
+ int numImgs = imgRes.frameCount(iconFileName);
if (numImgs <= 0)
error("Icon file %s didn't have any frames?", iconFileName.c_str());
_icons.resize(numImgs);
Commit: 25bbabb6b2ed3641cec0002f00c1bf140e15e60c
https://github.com/scummvm/scummvm/commit/25bbabb6b2ed3641cec0002f00c1bf140e15e60c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start moving menu-related functionality in a separate class
Changed paths:
A engines/dgds/menu.cpp
A engines/dgds/menu.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/module.mk
engines/dgds/request.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 191f190783a..acca69420c9 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -53,6 +53,7 @@
#include "dgds/font.h"
#include "dgds/image.h"
#include "dgds/includes.h"
+#include "dgds/menu.h"
#include "dgds/parser.h"
#include "dgds/request.h"
#include "dgds/resource.h"
@@ -61,81 +62,6 @@
namespace Dgds {
-enum MenuIds {
- kMenuNone = -1,
- kMenuMain = 0,
- kMenuControls = 1,
- kMenuOptions = 2,
- kMenuCalibrate = 3,
- kMenuRestart = 4,
- // 5: you cannot save your game right now
- // 6: game over
- kMenuFiles = 7,
- // 8: save game not saved because disk is full
- // 9: all game entries are full
- kMenuSave = 10,
- // 11: change directory - create directory
- // 12: change directory - invalid directory specified
- kMenuChangeDirectory = 13,
- kMenuJoystick = 14,
- kMenuMouse = 15,
- kMenuQuit = 16
- // 17: I'm frustrated - keep trying / win arcade
- // 18: skip introduction / play introduction
- // 19: save game before arcade
- // 20: replay arcade
-};
-
-enum MenuButtonIds {
- kMenuMainPlay = 120,
- kMenuMainControls = 20,
- kMenuMainOptions = 121,
- kMenuMainCalibrate = 118,
- kMenuMainFiles = 119,
- kMenuMainQuit = 122,
-
- kMenuControlsVCR = 127,
- kMenuControlsPlay = 128,
-
- kMenuOptionsJoystickOnOff = 139,
- kMenuOptionsMouseOnOff = 138,
- kMenuOptionsSoundsOnOff = 137,
- kMenuOptionsMusicOnOff = 140,
- kMenuOptionsVCR = 135,
- kMenuOptionsPlay = 136,
-
- kMenuCalibrateJoystick = 145,
- kMenuCalibrateMouse = 146,
- kMenuCalibrateVCR = 144,
- kMenuCalibratePlay = 147,
-
- kMenuFilesSave = 107,
- kMenuFilesRestore = 106,
- kMenuFilesRestart = 105,
- kMenuFilesVCR = 103,
- kMenuFilesPlay = 130,
-
- kMenuSavePrevious = 58,
- kMenuSaveNext = 59,
- kMenuSaveSave = 53,
- kMenuSaveCancel = 54,
- kMenuSaveChangeDirectory = 55,
-
- kMenuChangeDirectoryOK = 95,
- kMenuChangeDirectoryCancel = 96,
-
- kMenuMouseCalibrationCalibrate = 157,
- kMenuMouseCalibrationPlay = 155,
-
- kMenuJoystickCalibrationOK = 132,
-
- kMenuQuitYes = 134,
- kMenuQuitNo = 133,
-
- kMenuRestartYes = 163,
- kMenuRestartNo = 164
-};
-
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
@@ -167,8 +93,8 @@ DgdsEngine::~DgdsEngine() {
delete _gdsScene;
delete _soundPlayer;
delete _fontManager;
+ delete _menu;
- _screenBuffer.free();
_resData.free();
_topBuffer.free();
_bottomBuffer.free();
@@ -189,137 +115,6 @@ void readStrings(Common::SeekableReadStream *stream) {
}
}
-void DgdsEngine::drawMenu(REQFileData &vcrRequestData, int16 menu) {
- _curMenu = menu;
-
- Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
- // Restore background when drawing submenus
- g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
-
- Graphics::Surface *dst = g_system->lockScreen();
-
- vcrRequestData._requests[_curMenu].draw(dst);
-
- for (Common::SharedPtr<Gadget> &gptr : gadgets) {
- Gadget *gadget = gptr.get();
- if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider)
- gadget->draw(dst);
- }
-
- g_system->unlockScreen();
- g_system->updateScreen();
-}
-
-int16 DgdsEngine::getClickedMenuItem(REQFileData& vcrRequestData, Common::Point mouseClick) {
- if (_curMenu < 0)
- return -1;
-
- Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
-
- for (Common::SharedPtr<Gadget> &gptr : gadgets) {
- Gadget *gadget = gptr.get();
- if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider) {
- int16 x = gadget->_x + gadget->_parentX;
- int16 y = gadget->_y + gadget->_parentY;
- int16 right = x + gadget->_width;
- int16 bottom = (y + gadget->_height) - 1;
- Common::Rect gadgetRect(x, y, right, bottom);
- if (gadgetRect.contains(mouseClick))
- return (int16)gadget->_gadgetNo;
- }
- }
-
- return -1;
-}
-
-void DgdsEngine::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
- const int16 clickedMenuItem = getClickedMenuItem(vcrRequestData, mouse);
- switch (clickedMenuItem) {
- case kMenuMainPlay:
- case kMenuControlsPlay:
- case kMenuOptionsPlay:
- case kMenuCalibratePlay:
- case kMenuFilesPlay:
- case kMenuMouseCalibrationPlay:
- _curMenu = kMenuNone;
- CursorMan.showMouse(false);
- break;
- case kMenuMainControls:
- drawMenu(vcrRequestData, kMenuControls);
- break;
- case kMenuMainOptions:
- drawMenu(vcrRequestData, kMenuOptions);
- break;
- case kMenuMainCalibrate:
- case kMenuJoystickCalibrationOK:
- case kMenuMouseCalibrationCalibrate:
- drawMenu(vcrRequestData, kMenuCalibrate);
- break;
- case kMenuMainFiles:
- case kMenuSaveCancel:
- drawMenu(vcrRequestData, kMenuFiles);
- break;
- case kMenuMainQuit:
- drawMenu(vcrRequestData, kMenuQuit);
- break;
- case kMenuControlsVCR:
- case kMenuOptionsVCR:
- case kMenuCalibrateVCR:
- case kMenuFilesVCR:
- case kMenuQuitNo:
- case kMenuRestartNo:
- drawMenu(vcrRequestData, kMenuMain);
- break;
- case kMenuOptionsJoystickOnOff:
- case kMenuOptionsMouseOnOff:
- case kMenuOptionsSoundsOnOff:
- case kMenuOptionsMusicOnOff:
- // TODO
- debug("Clicked option with ID %d", clickedMenuItem);
- break;
- case kMenuCalibrateJoystick:
- drawMenu(vcrRequestData, kMenuJoystick);
- break;
- case kMenuCalibrateMouse:
- drawMenu(vcrRequestData, kMenuMouse);
- break;
- case kMenuFilesSave:
- case kMenuChangeDirectoryCancel:
- drawMenu(vcrRequestData, kMenuSave);
- break;
- case kMenuFilesRestore:
- // TODO
- debug("Clicked Files - Restore %d", clickedMenuItem);
- break;
- case kMenuFilesRestart:
- drawMenu(vcrRequestData, kMenuRestart);
- break;
- case kMenuSavePrevious:
- case kMenuSaveNext:
- case kMenuSaveSave:
- // TODO
- debug("Clicked Save - %d", clickedMenuItem);
- break;
- case kMenuSaveChangeDirectory:
- drawMenu(vcrRequestData, kMenuChangeDirectory);
- break;
- case kMenuChangeDirectoryOK:
- // TODO
- debug("Clicked change directory - %d", clickedMenuItem);
- break;
- case kMenuQuitYes:
- g_engine->quitGame();
- break;
- case kMenuRestartYes:
- // TODO
- debug("Clicked Restart - Yes %d", clickedMenuItem);
- break;
- default:
- debug("Clicked ID %d", clickedMenuItem);
- break;
- }
-}
-
void DgdsEngine::loadCorners(const Common::String &filename) {
Image imgRes(_resource, _decompressor);
int numImgs = imgRes.frameCount(filename);
@@ -362,13 +157,13 @@ Common::Error DgdsEngine::run() {
_scene = new SDSScene();
_gdsScene = new GDSScene();
_fontManager = new FontManager();
+ _menu = new Menu();
setDebugger(_console);
_bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- _screenBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
g_system->fillScreen(0);
@@ -431,7 +226,7 @@ Common::Error DgdsEngine::run() {
if (ev.type == Common::EVENT_KEYDOWN) {
switch (ev.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
- if (_curMenu >= 0)
+ if (_menu->menuShown())
triggerMenu = true;
else
moveToNext = true;
@@ -448,15 +243,13 @@ Common::Error DgdsEngine::run() {
}
if (triggerMenu) {
- if (_curMenu == kMenuNone) {
- Graphics::Surface *dst = g_system->lockScreen();
- _screenBuffer.copyFrom(*dst);
- g_system->unlockScreen();
+ if (!_menu->menuShown()) {
+ _menu->setScreenBuffer();
CursorMan.showMouse(true);
- drawMenu(vcrRequestData, 0);
+ _menu->drawMenu(vcrRequestData);
} else {
- _curMenu = kMenuNone;
+ _menu->hideMenu();
CursorMan.showMouse(false);
}
@@ -464,11 +257,11 @@ Common::Error DgdsEngine::run() {
}
if (mouseEvent) {
- handleMenu(vcrRequestData, ev.mouse);
+ _menu->handleMenu(vcrRequestData, ev.mouse);
mouseEvent = false;
}
- if (_curMenu != kMenuNone) {
+ if (_menu->menuShown()) {
g_system->updateScreen();
g_system->delayMillis(10);
continue;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 6473087cfc1..0f5e75cc9cf 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -48,6 +48,7 @@ class SDSScene;
class GDSScene;
class Sound;
class REQFileData;
+class Menu;
struct DgdsADS;
enum DgdsGameId {
@@ -72,14 +73,13 @@ private:
DgdsGameId _gameId;
Graphics::Surface _bottomBuffer;
Graphics::Surface _topBuffer;
- Graphics::Surface _screenBuffer;
SDSScene *_scene;
GDSScene *_gdsScene;
+ Menu *_menu;
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
Common::Array<Common::SharedPtr<Image>> _icons;
- int16 _curMenu = -1;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -97,9 +97,6 @@ public:
const SDSScene *getScene() const { return _scene; }
SDSScene *getScene() { return _scene; }
const FontManager *getFontMan() const { return _fontManager; }
- void drawMenu(REQFileData &vcrRequestData, int16 menu);
- int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
- void handleMenu(REQFileData &vcrRequestData, Common::Point &mouse);
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
private:
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
new file mode 100644
index 00000000000..acc7d278725
--- /dev/null
+++ b/engines/dgds/menu.cpp
@@ -0,0 +1,258 @@
+/* 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/system.h"
+
+#include "graphics/cursorman.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+#include "dgds/includes.h"
+#include "dgds/menu.h"
+#include "dgds/request.h"
+
+namespace Dgds {
+
+enum MenuIds {
+ kMenuNone = -1,
+ kMenuMain = 0,
+ kMenuControls = 1,
+ kMenuOptions = 2,
+ kMenuCalibrate = 3,
+ kMenuRestart = 4,
+ // 5: you cannot save your game right now
+ // 6: game over
+ kMenuFiles = 7,
+ // 8: save game not saved because disk is full
+ // 9: all game entries are full
+ kMenuSave = 10,
+ // 11: change directory - create directory
+ // 12: change directory - invalid directory specified
+ kMenuChangeDirectory = 13,
+ kMenuJoystick = 14,
+ kMenuMouse = 15,
+ kMenuQuit = 16
+ // 17: I'm frustrated - keep trying / win arcade
+ // 18: skip introduction / play introduction
+ // 19: save game before arcade
+ // 20: replay arcade
+};
+
+enum MenuButtonIds {
+ kMenuMainPlay = 120,
+ kMenuMainControls = 20,
+ kMenuMainOptions = 121,
+ kMenuMainCalibrate = 118,
+ kMenuMainFiles = 119,
+ kMenuMainQuit = 122,
+
+ kMenuControlsVCR = 127,
+ kMenuControlsPlay = 128,
+
+ kMenuOptionsJoystickOnOff = 139,
+ kMenuOptionsMouseOnOff = 138,
+ kMenuOptionsSoundsOnOff = 137,
+ kMenuOptionsMusicOnOff = 140,
+ kMenuOptionsVCR = 135,
+ kMenuOptionsPlay = 136,
+
+ kMenuCalibrateJoystick = 145,
+ kMenuCalibrateMouse = 146,
+ kMenuCalibrateVCR = 144,
+ kMenuCalibratePlay = 147,
+
+ kMenuFilesSave = 107,
+ kMenuFilesRestore = 106,
+ kMenuFilesRestart = 105,
+ kMenuFilesVCR = 103,
+ kMenuFilesPlay = 130,
+
+ kMenuSavePrevious = 58,
+ kMenuSaveNext = 59,
+ kMenuSaveSave = 53,
+ kMenuSaveCancel = 54,
+ kMenuSaveChangeDirectory = 55,
+
+ kMenuChangeDirectoryOK = 95,
+ kMenuChangeDirectoryCancel = 96,
+
+ kMenuMouseCalibrationCalibrate = 157,
+ kMenuMouseCalibrationPlay = 155,
+
+ kMenuJoystickCalibrationOK = 132,
+
+ kMenuQuitYes = 134,
+ kMenuQuitNo = 133,
+
+ kMenuRestartYes = 163,
+ kMenuRestartNo = 164
+};
+
+Menu::Menu() {
+ _screenBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+Menu::~Menu() {
+ _screenBuffer.free();
+}
+
+void Menu::setScreenBuffer() {
+ Graphics::Surface *dst = g_system->lockScreen();
+ _screenBuffer.copyFrom(*dst);
+ g_system->unlockScreen();
+}
+
+void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
+ _curMenu = menu;
+
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+ // Restore background when drawing submenus
+ g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
+
+ Graphics::Surface *dst = g_system->lockScreen();
+
+ vcrRequestData._requests[_curMenu].draw(dst);
+
+ for (Common::SharedPtr<Gadget> &gptr : gadgets) {
+ Gadget *gadget = gptr.get();
+ if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider)
+ gadget->draw(dst);
+ }
+
+ g_system->unlockScreen();
+ g_system->updateScreen();
+}
+
+int16 Menu::getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick) {
+ if (_curMenu < 0)
+ return -1;
+
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+
+ for (Common::SharedPtr<Gadget> &gptr : gadgets) {
+ Gadget *gadget = gptr.get();
+ if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider) {
+ int16 x = gadget->_x + gadget->_parentX;
+ int16 y = gadget->_y + gadget->_parentY;
+ int16 right = x + gadget->_width;
+ int16 bottom = (y + gadget->_height) - 1;
+ Common::Rect gadgetRect(x, y, right, bottom);
+ if (gadgetRect.contains(mouseClick))
+ return (int16)gadget->_gadgetNo;
+ }
+ }
+
+ return -1;
+}
+
+void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
+ const int16 clickedMenuItem = getClickedMenuItem(vcrRequestData, mouse);
+ switch (clickedMenuItem) {
+ case kMenuMainPlay:
+ case kMenuControlsPlay:
+ case kMenuOptionsPlay:
+ case kMenuCalibratePlay:
+ case kMenuFilesPlay:
+ case kMenuMouseCalibrationPlay:
+ _curMenu = kMenuNone;
+ CursorMan.showMouse(false);
+ break;
+ case kMenuMainControls:
+ drawMenu(vcrRequestData, kMenuControls);
+ break;
+ case kMenuMainOptions:
+ drawMenu(vcrRequestData, kMenuOptions);
+ break;
+ case kMenuMainCalibrate:
+ case kMenuJoystickCalibrationOK:
+ case kMenuMouseCalibrationCalibrate:
+ drawMenu(vcrRequestData, kMenuCalibrate);
+ break;
+ case kMenuMainFiles:
+ case kMenuSaveCancel:
+ drawMenu(vcrRequestData, kMenuFiles);
+ break;
+ case kMenuMainQuit:
+ drawMenu(vcrRequestData, kMenuQuit);
+ break;
+ case kMenuControlsVCR:
+ case kMenuOptionsVCR:
+ case kMenuCalibrateVCR:
+ case kMenuFilesVCR:
+ case kMenuQuitNo:
+ case kMenuRestartNo:
+ drawMenu(vcrRequestData, kMenuMain);
+ break;
+ case kMenuOptionsJoystickOnOff:
+ case kMenuOptionsMouseOnOff:
+ case kMenuOptionsSoundsOnOff:
+ case kMenuOptionsMusicOnOff:
+ // TODO
+ debug("Clicked option with ID %d", clickedMenuItem);
+ break;
+ case kMenuCalibrateJoystick:
+ drawMenu(vcrRequestData, kMenuJoystick);
+ break;
+ case kMenuCalibrateMouse:
+ drawMenu(vcrRequestData, kMenuMouse);
+ break;
+ case kMenuFilesSave:
+ case kMenuChangeDirectoryCancel:
+ drawMenu(vcrRequestData, kMenuSave);
+ break;
+ case kMenuFilesRestore:
+ // TODO
+ debug("Clicked Files - Restore %d", clickedMenuItem);
+ break;
+ case kMenuFilesRestart:
+ drawMenu(vcrRequestData, kMenuRestart);
+ break;
+ case kMenuSavePrevious:
+ case kMenuSaveNext:
+ case kMenuSaveSave:
+ // TODO
+ debug("Clicked Save - %d", clickedMenuItem);
+ break;
+ case kMenuSaveChangeDirectory:
+ drawMenu(vcrRequestData, kMenuChangeDirectory);
+ break;
+ case kMenuChangeDirectoryOK:
+ // TODO
+ debug("Clicked change directory - %d", clickedMenuItem);
+ break;
+ case kMenuQuitYes:
+ g_engine->quitGame();
+ break;
+ case kMenuRestartYes:
+ // TODO
+ debug("Clicked Restart - Yes %d", clickedMenuItem);
+ break;
+ default:
+ debug("Clicked ID %d", clickedMenuItem);
+ break;
+ }
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
new file mode 100644
index 00000000000..19e3f8b59ae
--- /dev/null
+++ b/engines/dgds/menu.h
@@ -0,0 +1,63 @@
+/* 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 DGDS_MENU_H
+#define DGDS_MENU_H
+
+#include "common/error.h"
+#include "common/events.h"
+#include "common/platform.h"
+
+#include "graphics/surface.h"
+#include "graphics/managed_surface.h"
+
+#include "engines/advancedDetector.h"
+#include "engines/engine.h"
+
+#include "gui/debugger.h"
+
+#include "dgds/resource.h"
+
+namespace Dgds {
+
+class REQFileData;
+
+class Menu {
+private:
+ Graphics::Surface _screenBuffer;
+ int16 _curMenu = -1;
+
+public:
+ Menu();
+ virtual ~Menu();
+
+ void setScreenBuffer();
+ void drawMenu(REQFileData &vcrRequestData, int16 menu = 0);
+ int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
+ void handleMenu(REQFileData &vcrRequestData, Common::Point &mouse);
+ bool menuShown() const { return _curMenu >= 0; }
+ void hideMenu() { _curMenu = -1; }
+};
+
+} // End of namespace Dgds
+
+#endif // DGDS_DGDS_H
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index a207572876c..51839b97076 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
dgds.o \
font.o \
image.o \
+ menu.o \
metaengine.o \
music.o \
parser.o \
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index bab9a0ac08b..31d23aaa913 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -30,6 +30,9 @@
namespace Dgds {
+class Font;
+class Image;
+
struct TextItem {
uint16 _x;
uint16 _y;
Commit: fa18dd02b8cda259bf1c4ee5f253de8e9f4b18b3
https://github.com/scummvm/scummvm/commit/fa18dd02b8cda259bf1c4ee5f253de8e9f4b18b3
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Draw menu text - WIP
Changed paths:
engines/dgds/menu.cpp
engines/dgds/menu.h
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index acc7d278725..999d20f79d7 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -30,6 +30,7 @@
#include "graphics/surface.h"
#include "dgds/includes.h"
+#include "dgds/font.h"
#include "dgds/menu.h"
#include "dgds/request.h"
@@ -128,6 +129,7 @@ void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
_curMenu = menu;
Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+
// Restore background when drawing submenus
g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
@@ -141,10 +143,35 @@ void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
gadget->draw(dst);
}
+ drawMenuText(vcrRequestData, dst);
+
g_system->unlockScreen();
g_system->updateScreen();
}
+void Menu::drawMenuText(REQFileData &vcrRequestData, Graphics::Surface *dst) {
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+ Common::Array<TextItem> textItems = vcrRequestData._requests[_curMenu]._textItemList;
+
+ // TODO: Get the parent coordinates properly
+ uint16 parentX = gadgets[0].get()->_parentX;
+ uint16 parentY = gadgets[0].get()->_parentY;
+ uint16 pos = 0;
+
+ for (TextItem &textItem : textItems) {
+ // HACK: Skip the first entry, which corresponds to the header
+ if (pos == 0) {
+ pos++;
+ continue;
+ }
+
+ const Font *font = RequestData::getMenuFont();
+ int w = font->getStringWidth(textItem._txt);
+ font->drawString(dst, textItem._txt, parentX + textItem._x, parentY + textItem._y, w, 0);
+ pos++;
+ }
+}
+
int16 Menu::getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick) {
if (_curMenu < 0)
return -1;
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 19e3f8b59ae..42f06aa3a10 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -52,10 +52,13 @@ public:
void setScreenBuffer();
void drawMenu(REQFileData &vcrRequestData, int16 menu = 0);
- int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
void handleMenu(REQFileData &vcrRequestData, Common::Point &mouse);
bool menuShown() const { return _curMenu >= 0; }
void hideMenu() { _curMenu = -1; }
+
+private:
+ int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
+ void drawMenuText(REQFileData &vcrRequestData, Graphics::Surface *dst);
};
} // End of namespace Dgds
Commit: abcc5c81048a5199d3ad51dd62c19071d1ad650d
https://github.com/scummvm/scummvm/commit/abcc5c81048a5199d3ad51dd62c19071d1ad650d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add menu button click animations
Changed paths:
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 999d20f79d7..cf316931b5e 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -196,6 +196,16 @@ int16 Menu::getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseC
void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
const int16 clickedMenuItem = getClickedMenuItem(vcrRequestData, mouse);
+
+ // Click animation
+ // TODO: Handle on/off buttons
+ if (clickedMenuItem >= 0) {
+ toggleGadget(vcrRequestData, clickedMenuItem, false);
+ drawMenu(vcrRequestData, _curMenu);
+ g_system->delayMillis(500);
+ toggleGadget(vcrRequestData, clickedMenuItem, true);
+ }
+
switch (clickedMenuItem) {
case kMenuMainPlay:
case kMenuControlsPlay:
@@ -282,4 +292,16 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
}
}
+void Menu::toggleGadget(REQFileData &vcrRequestData, int16 gadgetId, bool enable) {
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+
+ for (Common::SharedPtr<Gadget> &gptr : gadgets) {
+ Gadget *gadget = gptr.get();
+ if (gadget->_gadgetNo == gadgetId) {
+ gadget->toggle(enable);
+ return;
+ }
+ }
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 42f06aa3a10..937a64d478e 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -59,6 +59,7 @@ public:
private:
int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
void drawMenuText(REQFileData &vcrRequestData, Graphics::Surface *dst);
+ void toggleGadget(REQFileData &vcrRequestData, int16 gadgetId, bool enable);
};
} // End of namespace Dgds
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index ab41f307317..bb70e83aac9 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -383,6 +383,13 @@ void ButtonGadget::draw(Graphics::Surface *dst) const {
}
+void ButtonGadget::toggle(bool enable) {
+ if (!enable)
+ _flags3 |= 9; // 0x1001
+ else
+ _flags3 &= 6; // 0x0110
+}
+
Common::String TextAreaGadget::dump() const {
const Common::String base = Gadget::dump();
return Common::String::format("TextArea<%s, %d %d>", base.c_str(), _gadget1_i1, _gadget1_i2);
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 31d23aaa913..12a0b8580c4 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -91,12 +91,14 @@ public:
virtual Common::String dump() const;
virtual void draw(Graphics::Surface *dst) const;
+ virtual void toggle(bool enable) {}
};
// Button gadget has no additional fields, but some behavior differences.
class ButtonGadget : public Gadget {
public:
void draw(Graphics::Surface *dst) const override;
+ void toggle(bool enable) override;
};
// extended gadget type 1 is 62 (0x3e) bytes
Commit: 650062dcc738711d7477c44896d82ec2e52b3e74
https://github.com/scummvm/scummvm/commit/650062dcc738711d7477c44896d82ec2e52b3e74
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix some compile warnings
Changed paths:
engines/dgds/console.cpp
engines/dgds/request.h
engines/dgds/resource.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index df579932fd5..d4ce96bf45a 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -141,7 +141,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
}
bool Console::cmdImageDump(int argc, const char **argv) {
-#if USE_PNG
+#ifdef USE_PNG
if (argc < 3) {
debugPrintf("Usage: %s <imagefilename> <frameno> [outputpath]\n", argv[0]);
return true;
@@ -195,7 +195,7 @@ bool Console::cmdImageDump(int argc, const char **argv) {
#else
warning("dumpimage needs png support");
-#endif
+#endif // USE_PNG
return true;
}
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 12a0b8580c4..1496a7a5440 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -57,6 +57,8 @@ enum GadgetType {
// basic gadget is 52 (0x34) bytes
class Gadget {
public:
+ virtual ~Gadget() {}
+
// NOTE: Most of these names are still guesses
uint16 _gadgetNo;
uint16 _x;
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 5bde5cb50e9..8f19c7f46ac 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -62,7 +62,6 @@ ResourceManager::ResourceManager() {
indexFile.skip(1); // unknown
int entries = indexFile.readUint16LE();
- //debug("File %s has %d entries", volumeName.c_str(), entries);
for (int j = 0; j < entries; j++) {
Resource res;
@@ -84,7 +83,6 @@ ResourceManager::ResourceManager() {
if (fileName == "" || res.size == 0)
continue;
- debug(" - %s at %d, size: %d", fileName.c_str(), res.pos, res.size);
}
}
@@ -266,7 +264,6 @@ bool DgdsChunkReader::readNextHeader(DGDS_EX ex, const Common::String &filename)
}
-
bool DgdsChunkReader::readContent(Decompressor* decompressor) {
assert(_sourceStream && !_contentStream);
_contentStream = isPacked() ? decodeStream(decompressor) : readStream();
@@ -304,7 +301,7 @@ Common::SeekableReadStream *DgdsChunkReader::readStream() {
Common::SeekableReadStream *DgdsChunkReader::makeMemoryStream() {
assert(_contentStream);
assert(_contentStream->pos() == 0);
-
+
int64 startPos = _contentStream->pos();
int16 dataSize = _contentStream->size() - startPos;
byte *data = (byte *)malloc(dataSize);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index efef62788e8..5c16d4fd316 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -271,7 +271,7 @@ bool TTMInterpreter::run() {
case 0x1310: //? i:int [107]
default:
- warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[1], ivals[2], ivals[3], ivals[4]);
+ warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
continue;
}
break;
Commit: 0c629728b1aede5c0b2e7ea6dbac3f9fc4294452
https://github.com/scummvm/scummvm/commit/0c629728b1aede5c0b2e7ea6dbac3f9fc4294452
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add dump code for SDS and GDS scene data
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index acca69420c9..0ef3c80208d 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -181,10 +181,13 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
+ //debug("%s", _gdsScene->dump("").c_str());
+
reqParser.parse(&invRequestData, "DINV.REQ");
reqParser.parse(&vcrRequestData, "DVCR.REQ");
interpIntro.load("TITLE1.ADS");
+
loadCorners("DCORNERS.BMP");
} else if (getGameId() == GID_CHINA) {
_gdsScene->load("HOC.GDS", _resource, _decompressor);
@@ -273,8 +276,10 @@ Common::Error DgdsEngine::run() {
if (!creditsShown) {
creditsShown = true;
- if (getGameId() == GID_DRAGON)
+ if (getGameId() == GID_DRAGON) {
_scene->load("S55.SDS", _resource, _decompressor); // FIXME: Removing this breaks the Bahumat scene dialog
+ //debug("%s", _scene->dump("").c_str());
+ }
interpIntro.load("INTRO.ADS");
} else {
return Common::kNoError;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 12678d1ddde..7f6a7fa3cf9 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -36,6 +36,100 @@
namespace Dgds {
+template<class S> Common::String _dumpStructList(const Common::String &indent, const Common::String &name, const Common::Array<S> &list) {
+ if (list.empty())
+ return "";
+
+ const Common::String nextind = indent + " ";
+ Common::String str = Common::String::format("\n%s%s=", Common::String(indent + " ").c_str(), name.c_str());
+ for (const auto &s : list) {
+ str += "\n";
+ str += s.dump(nextind);
+ }
+ return str;
+}
+
+
+Common::String Rect::dump(const Common::String &indent) const {
+ return Common::String::format("%sRect<%d,%d %d,%d>", indent.c_str(), x, y, width, height);
+}
+
+
+Common::String SceneStruct1::dump(const Common::String &indent) const {
+ return Common::String::format("%sSceneStruct1<%d flg 0x%02x %d>", indent.c_str(), val1, flags, val3);
+}
+
+
+Common::String SceneStruct2::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sSceneStruct2<%s %d %d", indent.c_str(), rect.dump("").c_str(), field1_0x8, field2_0xa);
+ str += _dumpStructList(indent, "struct1list", struct1List);
+ str += _dumpStructList(indent, "struct5list1", struct5List1);
+ str += _dumpStructList(indent, "struct5list2", struct5List2);
+ str += _dumpStructList(indent, "struct5list3", struct5List3);
+ str += "\n";
+ str += indent + ">";
+ return str;
+}
+
+
+Common::String SceneStruct5::dump(const Common::String &indent) const {
+ Common::String uints;
+ if (uintList.empty()) {
+ uints = "[]";
+ } else {
+ uints = "[";
+ for (uint i : uintList)
+ uints += Common::String::format("%d ", i);
+ uints.setChar(']', uints.size() - 1);
+ }
+ Common::String str = Common::String::format("%sSceneStruct5<%d uints: %s", indent.c_str(), val, uints.c_str());
+
+ str += _dumpStructList(indent, "struct1list", struct1List);
+ if (!struct1List.empty()) {
+ str += "\n";
+ str += indent;
+ }
+ str += ">";
+ return str;
+}
+
+
+Common::String SceneStruct2_Extended::dump(const Common::String &indent) const {
+ Common::String super = SceneStruct2::dump(indent + " ");
+
+ Common::String str = Common::String::format("%sSceneStruct2_Ext<\n%s\n unk10 %d cursor %d unk12 %d unk13 %d unk14 %d", indent.c_str(), super.c_str(), field10_0x24, _mouseCursorNum, field12_0x28, field13_0x2a, field14_0x2c);
+ str += _dumpStructList(indent, "struct5list5", struct5List5);
+ str += _dumpStructList(indent, "struct5list6", struct5List6);
+ str += "\n";
+ str += indent + ">";
+ return str;
+}
+
+
+Common::String MouseCursor::dump(const Common::String &indent) const {
+ return Common::String::format("%sMouseCursor<%d %d>", indent.c_str(), _hotX, _hotY);
+}
+
+
+Common::String SceneStruct4::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sSceneStruct4<%d %d", indent.c_str(), val1, val2);
+
+ str += _dumpStructList(indent, "struct5list", struct5List);
+ str += "\n";
+ str += indent + ">";
+ return str;
+}
+
+
+Common::String SceneStruct7::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sSceneStruct7<%d %d", indent.c_str(), val, field1_0x2);
+ str += _dumpStructList(indent, "struct1list", struct1List);
+ str += _dumpStructList(indent, "struct5list", struct5List);
+ str += "\n";
+ str += indent + ">";
+ return str;
+}
+
void Dialogue::draw(Graphics::Surface *dst, int mode) {
switch (_frameType) {
@@ -164,6 +258,24 @@ void Dialogue::drawStage4(Graphics::Surface *dst) {
}
+Common::String Dialogue::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d", indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize, _flags, _frameType, _time, _nextDialogNum, _field15_0x22, _field18_0x28);
+ str += _dumpStructList(indent, "subStrings", _subStrings);
+ str += "\n";
+ str += indent + " str='" + _str + "'>";
+ return str;
+}
+
+Common::String DialogueSubstring::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sSubDialogue<%d %d-%d", indent.c_str(), val, strOff1, strOff2);
+ str += _dumpStructList(indent, "struct5list", struct5List);
+ if (!struct5List.empty()) {
+ str += "\n";
+ str += indent;
+ }
+ str += ">";
+ return str;
+}
// //////////////////////////////////// //
@@ -220,7 +332,7 @@ bool Scene::readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array
readStruct2(s, dst);
}
for (SceneStruct2_Extended &dst : list) {
- dst.field11_0x26 = s->readUint16LE();
+ dst._mouseCursorNum = s->readUint16LE();
dst.field12_0x28 = s->readUint16LE();
dst.field14_0x2c = s->readUint16LE();
if (!isVersionUnder(" 1.211"))
@@ -307,9 +419,9 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
}
dst._frameType = s->readUint16LE(); // 01 =simple frame, 02 = with title w/ text before :, 03 = baloon, 04 = eliptical
- dst._field12_0x1a = s->readUint16LE();
+ dst._time = s->readUint16LE();
if (isVersionOver(" 1.207")) {
- dst._maybeNextDialogNum = s->readUint16LE();
+ dst._nextDialogNum = s->readUint16LE();
}
uint16 nbytes = s->readUint16LE();
@@ -422,6 +534,24 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
return !stream->err();
}
+Common::String SDSScene::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sSDSScene<num %d %d ads %s", indent.c_str(), _num, _field6_0x14, _adsFile.c_str());
+ str += _dumpStructList(indent, "struct5List1", _struct5List1);
+ str += _dumpStructList(indent, "struct5List2", _struct5List2);
+ str += _dumpStructList(indent, "struct5List3", _struct5List3);
+ str += _dumpStructList(indent, "struct5List4", _struct5List4);
+ str += _dumpStructList(indent, "struct2List", _struct2List);
+ str += _dumpStructList(indent, "struct4List1", _struct4List1);
+ str += _dumpStructList(indent, "struct4List2", _struct4List2);
+ str += _dumpStructList(indent, "dialogues", _dialogues);
+ str += _dumpStructList(indent, "struct7List", _struct7List);
+
+ str += "\n";
+ str += indent + ">";
+ return str;
+}
+
+
GDSScene::GDSScene() {
}
@@ -485,6 +615,22 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
return !stream->err();
}
+Common::String GDSScene::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sGDSScene<icons %s", indent.c_str(), _iconFile.c_str());
+ str += _dumpStructList(indent, "struct2ExtList", _struct2ExtList);
+ str += _dumpStructList(indent, "struct5List1", _struct5List1);
+ str += _dumpStructList(indent, "struct5List2", _struct5List2);
+ str += _dumpStructList(indent, "struct5List3", _struct5List3);
+ str += _dumpStructList(indent, "struct5List4", _struct5List4);
+ str += _dumpStructList(indent, "struct5List5", _struct5List5);
+ str += _dumpStructList(indent, "struct4List1", _struct4List1);
+ str += _dumpStructList(indent, "struct4List2", _struct4List2);
+
+ str += "\n";
+ str += indent + ">";
+ return str;
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index bb8b6008819..49398fdc4a4 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -34,12 +34,16 @@ struct Rect {
int y;
int width;
int height;
+
+ Common::String dump(const Common::String &indent) const;
};
struct SceneStruct1 {
uint16 val1;
uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
uint16 val3;
+
+ Common::String dump(const Common::String &indent) const;
};
struct SceneStruct2 {
@@ -50,22 +54,28 @@ struct SceneStruct2 {
Common::Array<struct SceneStruct5> struct5List1;
Common::Array<struct SceneStruct5> struct5List2;
Common::Array<struct SceneStruct5> struct5List3;
+
+ virtual Common::String dump(const Common::String &indent) const;
};
struct SceneStruct5 {
Common::Array<struct SceneStruct1> struct1List;
Common::Array<uint16> uintList;
uint16 val;
+
+ Common::String dump(const Common::String &indent) const;
};
struct SceneStruct2_Extended : public SceneStruct2 {
Common::Array<struct SceneStruct5> struct5List5;
Common::Array<struct SceneStruct5> struct5List6;
uint16 field10_0x24;
- uint16 field11_0x26;
+ uint16 _mouseCursorNum;
uint16 field12_0x28;
uint16 field13_0x2a;
uint16 field14_0x2c;
+
+ Common::String dump(const Common::String &indent) const override;
};
struct MouseCursor {
@@ -73,12 +83,16 @@ struct MouseCursor {
uint16 _hotY;
// pointer to cursor image
//Common::SharedPtr<Image> _img;
+
+ Common::String dump(const Common::String &indent) const;
};
struct SceneStruct4 {
uint16 val1;
uint16 val2;
Common::Array<struct SceneStruct5> struct5List;
+
+ Common::String dump(const Common::String &indent) const;
};
@@ -93,14 +107,17 @@ public:
uint16 _fontSize;
uint32 _flags; // includes justify
uint16 _frameType;
- uint16 _field12_0x1a;
- uint16 _maybeNextDialogNum;
+ uint16 _time;
+ uint16 _nextDialogNum;
Common::Array<struct DialogueSubstring> _subStrings;
uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
void draw(Graphics::Surface *dst, int mode);
+
+ Common::String dump(const Common::String &indent) const;
+
private:
void drawType1(Graphics::Surface *dst, int mode);
void drawType2(Graphics::Surface *dst, int mode);
@@ -117,6 +134,8 @@ struct SceneStruct7 {
int16 field1_0x2;
Common::Array<struct SceneStruct1> struct1List;
Common::Array<struct SceneStruct5> struct5List;
+
+ Common::String dump(const Common::String &indent) const;
};
struct DialogueSubstring {
@@ -125,6 +144,8 @@ struct DialogueSubstring {
byte unk[8]; /* Not initialized in loader */
Common::Array<struct SceneStruct5> struct5List;
uint val; /* First entry initialized to 1 in loader */
+
+ Common::String dump(const Common::String &indent) const;
};
@@ -170,6 +191,7 @@ public:
bool parseInf(Common::SeekableReadStream *s);
const Common::String &getIconFile() const { return _iconFile; }
+ Common::String dump(const Common::String &indent) const;
private:
//byte _unk[32];
Common::String _iconFile;
@@ -192,6 +214,8 @@ public:
Common::Array<class Dialogue> &getLines() { return _dialogues; }
+ Common::String dump(const Common::String &indent) const;
+
private:
int _num;
Common::Array<struct SceneStruct5> _struct5List1;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 5c16d4fd316..64fff2831f4 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -60,6 +60,20 @@ void TTMInterpreter::unload() {
_scriptData.scr = nullptr;
}
+void TTMInterpreter::setActiveDialogue(uint16 num) {
+ Common::Array<Dialogue> &dialogues = _vm->getScene()->getLines();
+ _text = nullptr;
+ for (Dialogue &dialogue: dialogues) {
+ if (dialogue._num == num)
+ _text = &dialogue;
+ // HACK to get Dragon intro working
+ if (!_text && dialogue._num == num + 14)
+ _text = &dialogue;
+ }
+ if (_text && !_text->_str.empty())
+ _state.delay += _text->_time * 9; // More correctly, 9 - text-speed-setting
+}
+
bool TTMInterpreter::run() {
Common::SeekableReadStream *scr = _scriptData.scr;
if (!scr)
@@ -228,18 +242,7 @@ bool TTMInterpreter::run() {
// DESCRIPTION IN TTM TAGS.
debug("SHOW SCENE TEXT: %u", ivals[0]);
_state.scene = ivals[0];
-
- Common::Array<Dialogue> &dialogues = _vm->getScene()->getLines();
- _text = nullptr;
- for (Dialogue &dialogue: dialogues) {
- if (dialogue._num == _state.scene)
- _text = &dialogue;
- // HACK to get Dragon intro working
- if (!_text && dialogue._num == _state.scene + 14)
- _text = &dialogue;
- }
- if (_text && !_text->_str.empty())
- _state.delay += 1500;
+ setActiveDialogue(_state.scene);
continue;
}
@@ -282,6 +285,7 @@ bool TTMInterpreter::run() {
g_system->unlockScreen();
g_system->updateScreen();
g_system->delayMillis(_state.delay);
+
return true;
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 548eb4593e4..f3d1fe3dba7 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -78,6 +78,8 @@ public:
uint16 getScene() const { return _state.scene; }
protected:
+ void setActiveDialogue(uint16 num);
+
DgdsEngine *_vm;
Dialogue *_text;
Commit: c2c9e0e040fb57f7a2147786d54731ba71e7f75f
https://github.com/scummvm/scummvm/commit/c2c9e0e040fb57f7a2147786d54731ba71e7f75f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Name some structures and members of scene data
Starting to understand what these things are.
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 7f6a7fa3cf9..19a0db56808 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -61,28 +61,40 @@ Common::String SceneStruct1::dump(const Common::String &indent) const {
Common::String SceneStruct2::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sSceneStruct2<%s %d %d", indent.c_str(), rect.dump("").c_str(), field1_0x8, field2_0xa);
+ Common::String str = Common::String::format("%sSceneStruct2<%s %d %d",
+ indent.c_str(), rect.dump("").c_str(), field1_0x8, field2_0xa);
str += _dumpStructList(indent, "struct1list", struct1List);
- str += _dumpStructList(indent, "struct5list1", struct5List1);
- str += _dumpStructList(indent, "struct5list2", struct5List2);
- str += _dumpStructList(indent, "struct5list3", struct5List3);
+ str += _dumpStructList(indent, "oplist1", opList1);
+ str += _dumpStructList(indent, "oplist2", opList2);
+ str += _dumpStructList(indent, "oplist3", opList3);
str += "\n";
str += indent + ">";
return str;
}
-Common::String SceneStruct5::dump(const Common::String &indent) const {
- Common::String uints;
- if (uintList.empty()) {
- uints = "[]";
+static Common::String _sceneOpCodeName(SceneOpCode code) {
+ switch (code) {
+ case kSceneOpNone: return "none";
+ case kSceneOpChangeScene: return "changeScene";
+ case kSceneOpNoop: return "noop";
+ case kSceneOpMeanwhile: return "meanwhile";
+ default:
+ return Common::String::format("sceneOp%d", (int)code);
+ }
+}
+
+Common::String SceneOp::dump(const Common::String &indent) const {
+ Common::String argsStr;
+ if (_args.empty()) {
+ argsStr = "[]";
} else {
- uints = "[";
- for (uint i : uintList)
- uints += Common::String::format("%d ", i);
- uints.setChar(']', uints.size() - 1);
+ argsStr = "[";
+ for (uint i : _args)
+ argsStr += Common::String::format("%d ", i);
+ argsStr.setChar(']', argsStr.size() - 1);
}
- Common::String str = Common::String::format("%sSceneStruct5<%d uints: %s", indent.c_str(), val, uints.c_str());
+ Common::String str = Common::String::format("%sSceneOp<op: %s args: %s", indent.c_str(), _sceneOpCodeName(_opCode).c_str(), argsStr.c_str());
str += _dumpStructList(indent, "struct1list", struct1List);
if (!struct1List.empty()) {
@@ -94,12 +106,15 @@ Common::String SceneStruct5::dump(const Common::String &indent) const {
}
-Common::String SceneStruct2_Extended::dump(const Common::String &indent) const {
+Common::String GameItem::dump(const Common::String &indent) const {
Common::String super = SceneStruct2::dump(indent + " ");
- Common::String str = Common::String::format("%sSceneStruct2_Ext<\n%s\n unk10 %d cursor %d unk12 %d unk13 %d unk14 %d", indent.c_str(), super.c_str(), field10_0x24, _mouseCursorNum, field12_0x28, field13_0x2a, field14_0x2c);
- str += _dumpStructList(indent, "struct5list5", struct5List5);
- str += _dumpStructList(indent, "struct5list6", struct5List6);
+ Common::String str = Common::String::format(
+ "%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d unk13 %d unk14 %d",
+ indent.c_str(), super.c_str(), indent.c_str(), field10_0x24,
+ _iconNum, field12_0x28, field13_0x2a, field14_0x2c);
+ str += _dumpStructList(indent, "oplist5", opList5);
+ str += _dumpStructList(indent, "oplist6", opList6);
str += "\n";
str += indent + ">";
return str;
@@ -114,7 +129,7 @@ Common::String MouseCursor::dump(const Common::String &indent) const {
Common::String SceneStruct4::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSceneStruct4<%d %d", indent.c_str(), val1, val2);
- str += _dumpStructList(indent, "struct5list", struct5List);
+ str += _dumpStructList(indent, "oplist", opList);
str += "\n";
str += indent + ">";
return str;
@@ -124,7 +139,7 @@ Common::String SceneStruct4::dump(const Common::String &indent) const {
Common::String SceneStruct7::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSceneStruct7<%d %d", indent.c_str(), val, field1_0x2);
str += _dumpStructList(indent, "struct1list", struct1List);
- str += _dumpStructList(indent, "struct5list", struct5List);
+ str += _dumpStructList(indent, "opList", sceneOpList);
str += "\n";
str += indent + ">";
return str;
@@ -259,17 +274,20 @@ void Dialogue::drawStage4(Graphics::Surface *dst) {
}
Common::String Dialogue::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d", indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize, _flags, _frameType, _time, _nextDialogNum, _field15_0x22, _field18_0x28);
+ Common::String str = Common::String::format(
+ "%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d",
+ indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize,
+ _flags, _frameType, _time, _nextDialogNum, _field15_0x22, _field18_0x28);
str += _dumpStructList(indent, "subStrings", _subStrings);
str += "\n";
str += indent + " str='" + _str + "'>";
return str;
}
-Common::String DialogueSubstring::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sSubDialogue<%d %d-%d", indent.c_str(), val, strOff1, strOff2);
- str += _dumpStructList(indent, "struct5list", struct5List);
- if (!struct5List.empty()) {
+Common::String DialogueAction::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
+ str += _dumpStructList(indent, "oplist", sceneOpList);
+ if (!sceneOpList.empty()) {
str += "\n";
str += indent;
}
@@ -310,9 +328,9 @@ bool Scene::readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const
dst.field1_0x8 = s->readUint16LE();
dst.field2_0xa = s->readUint16LE();
readStruct1List(s, dst.struct1List);
- readStruct5List(s, dst.struct5List1);
- readStruct5List(s, dst.struct5List2);
- readStruct5List(s, dst.struct5List3);
+ readOpList(s, dst.opList1);
+ readOpList(s, dst.opList2);
+ readOpList(s, dst.opList3);
return !s->err();
}
@@ -326,21 +344,21 @@ bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneSt
}
-bool Scene::readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<SceneStruct2_Extended> &list) const {
+bool Scene::readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct2_Extended &dst : list) {
+ for (GameItem &dst : list) {
readStruct2(s, dst);
}
- for (SceneStruct2_Extended &dst : list) {
- dst._mouseCursorNum = s->readUint16LE();
+ for (GameItem &dst : list) {
+ dst._iconNum = s->readUint16LE();
dst.field12_0x28 = s->readUint16LE();
dst.field14_0x2c = s->readUint16LE();
if (!isVersionUnder(" 1.211"))
dst.field13_0x2a = s->readUint16LE() & 0xfffe;
if (!isVersionUnder(" 1.204")) {
dst.field10_0x24 = s->readUint16LE();
- readStruct5List(s, dst.struct5List5);
- readStruct5List(s, dst.struct5List6);
+ readOpList(s, dst.opList5);
+ readOpList(s, dst.opList6);
}
}
return !s->err();
@@ -369,20 +387,20 @@ bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneSt
dst.val1 = s->readUint16LE();
dst.val2 = s->readUint16LE();
}
- readStruct5List(s, dst.struct5List);
+ readOpList(s, dst.opList);
}
return !s->err();
}
-bool Scene::readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) const {
+bool Scene::readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct5 &dst : list) {
+ for (SceneOp &dst : list) {
readStruct1List(s, dst.struct1List);
- dst.val = s->readUint16LE();
+ dst._opCode = static_cast<SceneOpCode>(s->readUint16LE());
int nvals = s->readUint16LE();
for (int i = 0; i < nvals / 2; i++) {
- dst.uintList.push_back(s->readUint16LE());
+ dst._args.push_back(s->readUint16LE());
}
}
@@ -451,23 +469,23 @@ bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneSt
for (SceneStruct7 &dst : list) {
dst.val = s->readUint16LE();
readStruct1List(s, dst.struct1List);
- readStruct5List(s, dst.struct5List);
+ readOpList(s, dst.sceneOpList);
}
return !s->err();
}
-bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) const {
+bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const {
list.resize(s->readUint16LE());
if (!list.empty())
list[0].val = 1;
- for (DialogueSubstring &dst : list) {
- dst.strOff1 = s->readUint16LE();
- dst.strOff2 = s->readUint16LE();
- readStruct5List(s, dst.struct5List);
+ for (DialogueAction &dst : list) {
+ dst.strStart = s->readUint16LE();
+ dst.strEnd = s->readUint16LE();
+ readOpList(s, dst.sceneOpList);
}
return !s->err();
@@ -513,12 +531,12 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
error("Unsupported scene version '%s'", _version.c_str());
}
_num = stream->readUint16LE();
- readStruct5List(stream, _struct5List1);
- readStruct5List(stream, _struct5List2);
+ readOpList(stream, _enterSceneOps);
+ readOpList(stream, _leaveSceneOps);
if (isVersionOver(" 1.206")) {
- readStruct5List(stream, _struct5List3);
+ readOpList(stream, _opList3);
}
- readStruct5List(stream, _struct5List4);
+ readOpList(stream, _opList4);
_field6_0x14 = stream->readUint16LE();
_adsFile = stream->readString();
readStruct2List(stream, _struct2List);
@@ -536,10 +554,10 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
Common::String SDSScene::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSDSScene<num %d %d ads %s", indent.c_str(), _num, _field6_0x14, _adsFile.c_str());
- str += _dumpStructList(indent, "struct5List1", _struct5List1);
- str += _dumpStructList(indent, "struct5List2", _struct5List2);
- str += _dumpStructList(indent, "struct5List3", _struct5List3);
- str += _dumpStructList(indent, "struct5List4", _struct5List4);
+ str += _dumpStructList(indent, "enterSceneOps", _enterSceneOps);
+ str += _dumpStructList(indent, "leaveSceneOps", _leaveSceneOps);
+ str += _dumpStructList(indent, "opList3", _opList3);
+ str += _dumpStructList(indent, "opList4", _opList4);
str += _dumpStructList(indent, "struct2List", _struct2List);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
@@ -595,19 +613,19 @@ bool GDSScene::parseInf(Common::SeekableReadStream *s) {
}
bool GDSScene::parse(Common::SeekableReadStream *stream) {
- readStruct5List(stream, _struct5List1);
- readStruct5List(stream, _struct5List2);
+ readOpList(stream, _startGameOps);
+ readOpList(stream, _opList2);
if (isVersionOver(" 1.206"))
- readStruct5List(stream, _struct5List3);
- readStruct5List(stream, _struct5List4);
+ readOpList(stream, _opList3);
+ readOpList(stream, _opList4);
if (isVersionOver(" 1.208"))
- readStruct5List(stream, _struct5List5);
+ readOpList(stream, _opList5);
Common::Array<struct SceneStruct1> struct1List;
readStruct1List(stream, struct1List);
Common::Array<struct MouseCursor> struct3List;
_iconFile = stream->readString();
readMouseHotspotList(stream, struct3List);
- readStruct2ExtendedList(stream, _struct2ExtList);
+ readStruct2ExtendedList(stream, _gameItems);
readStruct4List(stream, _struct4List2);
if (isVersionOver(" 1.205"))
readStruct4List(stream, _struct4List1);
@@ -617,12 +635,12 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
Common::String GDSScene::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sGDSScene<icons %s", indent.c_str(), _iconFile.c_str());
- str += _dumpStructList(indent, "struct2ExtList", _struct2ExtList);
- str += _dumpStructList(indent, "struct5List1", _struct5List1);
- str += _dumpStructList(indent, "struct5List2", _struct5List2);
- str += _dumpStructList(indent, "struct5List3", _struct5List3);
- str += _dumpStructList(indent, "struct5List4", _struct5List4);
- str += _dumpStructList(indent, "struct5List5", _struct5List5);
+ str += _dumpStructList(indent, "gameItems", _gameItems);
+ str += _dumpStructList(indent, "opList1", _startGameOps);
+ str += _dumpStructList(indent, "opList2", _opList2);
+ str += _dumpStructList(indent, "opList3", _opList3);
+ str += _dumpStructList(indent, "opList4", _opList4);
+ str += _dumpStructList(indent, "opList5", _opList5);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 49398fdc4a4..09e58804fea 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -51,26 +51,58 @@ struct SceneStruct2 {
uint16 field1_0x8;
uint16 field2_0xa;
Common::Array<struct SceneStruct1> struct1List;
- Common::Array<struct SceneStruct5> struct5List1;
- Common::Array<struct SceneStruct5> struct5List2;
- Common::Array<struct SceneStruct5> struct5List3;
+ Common::Array<struct SceneOp> opList1;
+ Common::Array<struct SceneOp> opList2;
+ Common::Array<struct SceneOp> opList3;
virtual Common::String dump(const Common::String &indent) const;
};
-struct SceneStruct5 {
+enum SceneOpCode {
+ kSceneOpNone = 0,
+ kSceneOpChangeScene = 1, // args: scene num
+ kSceneOpNoop = 2, // args: none.
+ kSceneOp3 = 3, // args: array of uints
+ kSceneOp4 = 4, // args: array of uint pairs [op arg, op arg], term with 0,0. a script within a script (see disasm at 1f1a:4b51)
+ kSceneOp5 = 5, // args: [item num, ??, ??]. give item?
+ kSceneOp6 = 6, // args: item num?
+ kSceneOp7 = 7, // args: none.
+ kSceneOp8 = 8, // args: dialogue number. show dialogue?
+ kSceneOp9 = 9, // args: none.
+ kSceneOp10 = 10, // args: none. Looks through the struct2 list for something.
+ kSceneOp11 = 11, // args: ? Takes a struct 7 number and finds it, then sets its field2 to 1.
+ kSceneOp12 = 12, // args: none. Change scene to stored number (previous?)
+ kSceneOp13 = 13, // args: none.
+ kSceneOp14 = 14, // args: none.
+ kSceneOp15 = 15, // args: none.
+ kSceneOp16 = 16, // args: none.
+ kSceneOp17 = 17, // args: none.
+ kSceneOp18 = 18, // args: none.
+ kSceneOp19 = 19, // args: none.
+ kSceneOp100 = 100, // args: none.
+ kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
+ kSceneOp102 = 102, // args: none.
+ kSceneOp103 = 103, // args: none.
+ kSceneOp104 = 104, // args: none.
+ kSceneOp105 = 105, // args: none. Draw some number at 141, 56
+ kSceneOp106 = 106, // args: none. Draw some number at 42, 250
+ kSceneOp107 = 107, // args: none.
+ kSceneOp108 = 108, // args: none.
+};
+
+struct SceneOp {
Common::Array<struct SceneStruct1> struct1List;
- Common::Array<uint16> uintList;
- uint16 val;
+ Common::Array<uint16> _args;
+ SceneOpCode _opCode;
Common::String dump(const Common::String &indent) const;
};
-struct SceneStruct2_Extended : public SceneStruct2 {
- Common::Array<struct SceneStruct5> struct5List5;
- Common::Array<struct SceneStruct5> struct5List6;
+struct GameItem : public SceneStruct2 {
+ Common::Array<struct SceneOp> opList5;
+ Common::Array<struct SceneOp> opList6;
uint16 field10_0x24;
- uint16 _mouseCursorNum;
+ uint16 _iconNum;
uint16 field12_0x28;
uint16 field13_0x2a;
uint16 field14_0x2c;
@@ -90,7 +122,7 @@ struct MouseCursor {
struct SceneStruct4 {
uint16 val1;
uint16 val2;
- Common::Array<struct SceneStruct5> struct5List;
+ Common::Array<struct SceneOp> opList;
Common::String dump(const Common::String &indent) const;
};
@@ -109,7 +141,7 @@ public:
uint16 _frameType;
uint16 _time;
uint16 _nextDialogNum;
- Common::Array<struct DialogueSubstring> _subStrings;
+ Common::Array<struct DialogueAction> _subStrings;
uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
@@ -133,16 +165,17 @@ struct SceneStruct7 {
uint16 val;
int16 field1_0x2;
Common::Array<struct SceneStruct1> struct1List;
- Common::Array<struct SceneStruct5> struct5List;
+ Common::Array<struct SceneOp> sceneOpList;
Common::String dump(const Common::String &indent) const;
};
-struct DialogueSubstring {
- uint16 strOff1; // The game initializes these to pointers, but let's be a bit nicer.
- uint16 strOff2;
+struct DialogueAction {
+ // The game initializes str offsets to pointers, but let's be a bit nicer.
+ uint16 strStart; /// The start of the clickable text for this action
+ uint16 strEnd; /// End of clickable text for this action
byte unk[8]; /* Not initialized in loader */
- Common::Array<struct SceneStruct5> struct5List;
+ Common::Array<struct SceneOp> sceneOpList;
uint val; /* First entry initialized to 1 in loader */
Common::String dump(const Common::String &indent) const;
@@ -167,13 +200,13 @@ protected:
bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const;
bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const;
- bool readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<SceneStruct2_Extended> &list) const;
+ bool readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
- bool readStruct5List(Common::SeekableReadStream *s, Common::Array<SceneStruct5> &list) const;
+ bool readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const;
bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const;
bool readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) const;
- bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueSubstring> &list) const;
+ bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
uint32 _magic;
Common::String _version;
@@ -195,12 +228,12 @@ public:
private:
//byte _unk[32];
Common::String _iconFile;
- Common::Array<struct SceneStruct2_Extended> _struct2ExtList;
- Common::Array<struct SceneStruct5> _struct5List1;
- Common::Array<struct SceneStruct5> _struct5List2;
- Common::Array<struct SceneStruct5> _struct5List3;
- Common::Array<struct SceneStruct5> _struct5List4;
- Common::Array<struct SceneStruct5> _struct5List5;
+ Common::Array<struct GameItem> _gameItems;
+ Common::Array<struct SceneOp> _startGameOps;
+ Common::Array<struct SceneOp> _opList2;
+ Common::Array<struct SceneOp> _opList3;
+ Common::Array<struct SceneOp> _opList4;
+ Common::Array<struct SceneOp> _opList5;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
};
@@ -218,10 +251,10 @@ public:
private:
int _num;
- Common::Array<struct SceneStruct5> _struct5List1;
- Common::Array<struct SceneStruct5> _struct5List2;
- Common::Array<struct SceneStruct5> _struct5List3;
- Common::Array<struct SceneStruct5> _struct5List4;
+ Common::Array<struct SceneOp> _enterSceneOps;
+ Common::Array<struct SceneOp> _leaveSceneOps;
+ Common::Array<struct SceneOp> _opList3;
+ Common::Array<struct SceneOp> _opList4;
//uint _field5_0x12;
uint _field6_0x14;
Common::String _adsFile;
Commit: 481c286597fcba02e6aed6c46c729e418fba7804
https://github.com/scummvm/scummvm/commit/481c286597fcba02e6aed6c46c729e418fba7804
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Rename scene trigger type now I understand it a bit
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 19a0db56808..fc9406357aa 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -78,6 +78,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpNone: return "none";
case kSceneOpChangeScene: return "changeScene";
case kSceneOpNoop: return "noop";
+ case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpMeanwhile: return "meanwhile";
default:
return Common::String::format("sceneOp%d", (int)code);
@@ -105,7 +106,6 @@ Common::String SceneOp::dump(const Common::String &indent) const {
return str;
}
-
Common::String GameItem::dump(const Common::String &indent) const {
Common::String super = SceneStruct2::dump(indent + " ");
@@ -136,8 +136,8 @@ Common::String SceneStruct4::dump(const Common::String &indent) const {
}
-Common::String SceneStruct7::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sSceneStruct7<%d %d", indent.c_str(), val, field1_0x2);
+Common::String SceneTrigger::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sSceneTrigger<num %d %s", indent.c_str(), _num, _enabled ? "enabled" : "disabled");
str += _dumpStructList(indent, "struct1list", struct1List);
str += _dumpStructList(indent, "opList", sceneOpList);
str += "\n";
@@ -344,7 +344,7 @@ bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneSt
}
-bool Scene::readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const {
+bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const {
list.resize(s->readUint16LE());
for (GameItem &dst : list) {
readStruct2(s, dst);
@@ -464,10 +464,11 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
}
-bool Scene::readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) const {
+bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct7 &dst : list) {
- dst.val = s->readUint16LE();
+ for (SceneTrigger &dst : list) {
+ dst._num = s->readUint16LE();
+ dst._enabled = false;
readStruct1List(s, dst.struct1List);
readOpList(s, dst.sceneOpList);
}
@@ -492,6 +493,36 @@ bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array
}
+void SDSScene::enableTrigger(uint16 num) {
+ for (auto &trigger : _triggers) {
+ if (trigger._num == num)
+ trigger._enabled = true;
+ }
+}
+
+
+void Scene::runOps(const Common::Array<SceneOp> &ops) {
+ for (const SceneOp &op : ops) {
+ switch(op._opCode) {
+ case kSceneOpChangeScene:
+ warning("TODO: Change scene no to %d", op._args[0]);
+ break;
+ case kSceneOpNoop:
+ break;
+ case kSceneOpEnableTrigger:
+ enableTrigger(op._args[0]);
+ break;
+ case kSceneOpMeanwhile:
+ error("TODO: Implement meanwhile screen");
+ break;
+ default:
+ warning("TODO: Implement scene op %d", op._opCode);
+ break;
+ }
+ }
+}
+
+
SDSScene::SDSScene() : _num(-1) {
}
@@ -546,7 +577,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
}
readDialogueList(stream, _dialogues);
if (isVersionOver(" 1.203")) {
- readStruct7List(stream, _struct7List);
+ readTriggerList(stream, _triggers);
}
return !stream->err();
@@ -562,7 +593,7 @@ Common::String SDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
str += _dumpStructList(indent, "dialogues", _dialogues);
- str += _dumpStructList(indent, "struct7List", _struct7List);
+ str += _dumpStructList(indent, "triggers", _triggers);
str += "\n";
str += indent + ">";
@@ -625,7 +656,7 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
Common::Array<struct MouseCursor> struct3List;
_iconFile = stream->readString();
readMouseHotspotList(stream, struct3List);
- readStruct2ExtendedList(stream, _gameItems);
+ readGameItemList(stream, _gameItems);
readStruct4List(stream, _struct4List2);
if (isVersionOver(" 1.205"))
readStruct4List(stream, _struct4List1);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 09e58804fea..974babf5583 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -61,7 +61,7 @@ struct SceneStruct2 {
enum SceneOpCode {
kSceneOpNone = 0,
kSceneOpChangeScene = 1, // args: scene num
- kSceneOpNoop = 2, // args: none.
+ kSceneOpNoop = 2, // args: none. Maybe should close dialogue?
kSceneOp3 = 3, // args: array of uints
kSceneOp4 = 4, // args: array of uint pairs [op arg, op arg], term with 0,0. a script within a script (see disasm at 1f1a:4b51)
kSceneOp5 = 5, // args: [item num, ??, ??]. give item?
@@ -70,7 +70,7 @@ enum SceneOpCode {
kSceneOp8 = 8, // args: dialogue number. show dialogue?
kSceneOp9 = 9, // args: none.
kSceneOp10 = 10, // args: none. Looks through the struct2 list for something.
- kSceneOp11 = 11, // args: ? Takes a struct 7 number and finds it, then sets its field2 to 1.
+ kSceneOpEnableTrigger = 11, // args: trigger num
kSceneOp12 = 12, // args: none. Change scene to stored number (previous?)
kSceneOp13 = 13, // args: none.
kSceneOp14 = 14, // args: none.
@@ -161,9 +161,9 @@ private:
void drawStage4(Graphics::Surface *dst);
};
-struct SceneStruct7 {
- uint16 val;
- int16 field1_0x2;
+struct SceneTrigger {
+ uint16 _num;
+ bool _enabled;
Common::Array<struct SceneStruct1> struct1List;
Common::Array<struct SceneOp> sceneOpList;
@@ -200,14 +200,18 @@ protected:
bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const;
bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const;
- bool readStruct2ExtendedList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
+ bool readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
bool readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const;
bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const;
- bool readStruct7List(Common::SeekableReadStream *s, Common::Array<SceneStruct7> &list) const;
+ bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
+ void runOps(const Common::Array<SceneOp> &ops);
+
+ virtual void enableTrigger(uint16 num) {};
+
uint32 _magic;
Common::String _version;
};
@@ -250,6 +254,8 @@ public:
Common::String dump(const Common::String &indent) const;
private:
+ void enableTrigger(uint16 num) override;
+
int _num;
Common::Array<struct SceneOp> _enterSceneOps;
Common::Array<struct SceneOp> _leaveSceneOps;
@@ -264,7 +270,7 @@ private:
Common::Array<struct SceneStruct4> _struct4List2;
//uint _field12_0x2b;
Common::Array<class Dialogue> _dialogues;
- Common::Array<struct SceneStruct7> _struct7List;
+ Common::Array<struct SceneTrigger> _triggers;
//uint _field15_0x33;
};
Commit: a0355e18b588dce49df3a673c0b2b19a8109db7d
https://github.com/scummvm/scummvm/commit/a0355e18b588dce49df3a673c0b2b19a8109db7d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement some scene operations
Started to implement scene triggers and conditions.
Also implemented rendering for dialogs of type 2 (frame with title).
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 0ef3c80208d..c3d50009bfc 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -146,6 +146,35 @@ void DgdsEngine::loadIcons() {
}
}
+void DgdsEngine::changeScene(int sceneNum) {
+ assert(_scene && _adsInterp);
+
+ if (sceneNum == _scene->getNum()) {
+ warning("Tried to change from scene %d to itself, doing nothing.", sceneNum);
+ return;
+ }
+
+ _adsInterp->unload();
+ _scene->runLeaveSceneOps();
+ _scene->unload();
+
+ if (!_icons.empty()) {
+ CursorMan.popAllCursors();
+ CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
+ }
+
+ const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
+ if (!_resource->hasResource(sceneFile))
+ error("Tried to switch to non-existant scene %d", sceneNum);
+
+ _scene->load(sceneFile, _resource, _decompressor);
+ if (!_scene->getAdsFile().empty())
+ _adsInterp->load(_scene->getAdsFile());
+
+ _scene->runEnterSceneOps();
+ debug("%s", _scene->dump("").c_str());
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -158,6 +187,7 @@ Common::Error DgdsEngine::run() {
_gdsScene = new GDSScene();
_fontManager = new FontManager();
_menu = new Menu();
+ _adsInterp = new ADSInterpreter(this);
setDebugger(_console);
@@ -170,7 +200,6 @@ Common::Error DgdsEngine::run() {
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
- ADSInterpreter interpIntro(this);
bool creditsShown = false;
REQFileData invRequestData;
REQFileData vcrRequestData;
@@ -183,20 +212,22 @@ Common::Error DgdsEngine::run() {
//debug("%s", _gdsScene->dump("").c_str());
+ loadCorners("DCORNERS.BMP");
reqParser.parse(&invRequestData, "DINV.REQ");
reqParser.parse(&vcrRequestData, "DVCR.REQ");
- interpIntro.load("TITLE1.ADS");
+ _gdsScene->runStartGameOps();
- loadCorners("DCORNERS.BMP");
} else if (getGameId() == GID_CHINA) {
_gdsScene->load("HOC.GDS", _resource, _decompressor);
+ //debug("%s", _gdsScene->dump("").c_str());
+
reqParser.parse(&invRequestData, "HINV.REQ");
reqParser.parse(&vcrRequestData, "HVCR.REQ");
//_scene->load("S101.SDS", _resource, _decompressor);
- interpIntro.load("TITLE.ADS");
+ _adsInterp->load("TITLE.ADS");
loadCorners("HCORNERS.BMP");
} else if (getGameId() == GID_BEAMISH) {
// TODO: This doesn't parse correctly yet.
@@ -206,14 +237,13 @@ Common::Error DgdsEngine::run() {
reqParser.parse(&vcrRequestData, "WVCR.REQ");
//_scene->load("S34.SDS", _resource, _decompressor);
- interpIntro.load("TITLE.ADS");
+ _adsInterp->load("TITLE.ADS");
loadCorners("WCORNERS.BMP");
}
loadIcons();
- if (!_icons.empty()) {
+ if (!_icons.empty())
CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
- }
//getDebugger()->attach();
@@ -271,22 +301,23 @@ Common::Error DgdsEngine::run() {
}
if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
- if (moveToNext || !interpIntro.run()) {
+ if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
if (!creditsShown) {
creditsShown = true;
if (getGameId() == GID_DRAGON) {
- _scene->load("S55.SDS", _resource, _decompressor); // FIXME: Removing this breaks the Bahumat scene dialog
- //debug("%s", _scene->dump("").c_str());
+ // TODO: This will be done by the trigger once we know how to do it.
+ // It's trigger number 3 in scene 3.
+ changeScene(55);
}
- interpIntro.load("INTRO.ADS");
} else {
return Common::kNoError;
}
}
+ _scene->checkTriggers();
} else if (getGameId() == GID_BEAMISH) {
- if (!interpIntro.run())
+ if (_adsInterp->run())
return Common::kNoError;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 0f5e75cc9cf..dbd7b82b75a 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -50,6 +50,7 @@ class Sound;
class REQFileData;
class Menu;
struct DgdsADS;
+class ADSInterpreter;
enum DgdsGameId {
GID_DRAGON,
@@ -57,6 +58,11 @@ enum DgdsGameId {
GID_BEAMISH
};
+enum DgdsDetailLevel {
+ kDgdsDetailLow,
+ kDgdsDetailHigh
+};
+
class DgdsEngine : public Engine {
public:
Common::Platform _platform;
@@ -76,6 +82,7 @@ private:
SDSScene *_scene;
GDSScene *_gdsScene;
Menu *_menu;
+ ADSInterpreter *_adsInterp;
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
@@ -98,10 +105,14 @@ public:
SDSScene *getScene() { return _scene; }
const FontManager *getFontMan() const { return _fontManager; }
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
+ void changeScene(int sceneNum);
+
+ DgdsDetailLevel getDetailLevel() const { return kDgdsDetailHigh; }
private:
void loadCorners(const Common::String &filename);
void loadIcons();
+
};
} // End of namespace Dgds
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index bb70e83aac9..1a951877ea3 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -546,14 +546,15 @@ void RequestData::drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x,
corners[7]->drawBitmap((x + width) - corners[7]->width(), (y + height) - corners[7]->height(), screenRect, *dst);
}
-void RequestData::drawHeader(Graphics::Surface *dst, int16 yoffset, const Common::String &header) const {
+/*static*/
+void RequestData::drawHeader(Graphics::Surface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header) {
if (!header.empty()) {
const Font *font = getMenuFont();
int hwidth = font->getStringWidth(header);
int hheight = font->getFontHeight();
- int hleft = _x + (_width - hwidth) / 2;
+ int hleft = x + (width - hwidth) / 2;
int hright = hleft + hwidth + 3;
- int htop = _y + yoffset;
+ int htop = y + yoffset;
int hbottom = htop + hheight;
font->drawString(dst, header, hleft + 1, htop + 2, hwidth, 0);
@@ -600,14 +601,14 @@ void RequestData::drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sli
corners[9]->drawBitmap(_x, (_y + sliderBgHeight) - corners[9]->height(), screenRect, *dst);
corners[10]->drawBitmap((_x + _width) - corners[10]->width(), (_y + sliderBgHeight) - corners[10]->height(), screenRect, *dst);
- drawHeader(dst, 9, header);
+ drawHeader(dst, _x, _y, _width, 9, header);
}
void RequestData::drawBackgroundNoSliders(Graphics::Surface *dst, const Common::String &header) const {
fillBackground(dst, _x, _y, _width, _height, 0);
drawCorners(dst, 11, _x, _y, _width, _height);
- drawHeader(dst, 4, header);
+ drawHeader(dst, _x, _y, _width, 4, header);
}
/*static*/
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 1496a7a5440..0881a0c3aea 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -153,15 +153,15 @@ public:
static const Font *getMenuFont();
static const Image *getCorner(int cornerNum);
+ static void fillBackground(Graphics::Surface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
+ static void drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
+ static void drawHeader(Graphics::Surface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header);
+
private:
void drawBackgroundNoSliders(Graphics::Surface *dst, const Common::String &header) const;
void drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sliderHeight, const Common::String &header) const;
- void drawHeader(Graphics::Surface *dst, int16 yoffset, const Common::String &header) const;
-
- static void fillBackground(Graphics::Surface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
- static void drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
};
// A REQ file contains a sequence of REQ and GAD block pairs.
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index fc9406357aa..705a315df7f 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -31,6 +31,7 @@
#include "dgds/dgds.h"
#include "dgds/includes.h"
#include "dgds/resource.h"
+#include "dgds/request.h"
#include "dgds/scene.h"
#include "dgds/font.h"
@@ -56,7 +57,7 @@ Common::String Rect::dump(const Common::String &indent) const {
Common::String SceneStruct1::dump(const Common::String &indent) const {
- return Common::String::format("%sSceneStruct1<%d flg 0x%02x %d>", indent.c_str(), val1, flags, val3);
+ return Common::String::format("%sSceneStruct1<%d flg 0x%02x %d>", indent.c_str(), _num, _flags, _val);
}
@@ -146,12 +147,12 @@ Common::String SceneTrigger::dump(const Common::String &indent) const {
}
-void Dialogue::draw(Graphics::Surface *dst, int mode) {
+void Dialogue::draw(Graphics::Surface *dst, int stage) {
switch (_frameType) {
- case 1: return drawType1(dst, mode);
- case 2: return drawType2(dst, mode);
- case 3: return drawType3(dst, mode);
- case 4: return drawType4(dst, mode);
+ case 1: return drawType1(dst, stage);
+ case 2: return drawType2(dst, stage);
+ case 3: return drawType3(dst, stage);
+ case 4: return drawType4(dst, stage);
default: error("unexpected frame type %d for dialog %d", _frameType, _num);
}
}
@@ -168,12 +169,12 @@ static void _drawPixel(int x, int y, int color, void *data) {
void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
//if (!_field15_0x22)
// return;
- if (stage == 1) {
- int x = _rect.x;
- int y = _rect.y;
- int w = _rect.width;
- int h = _rect.height;
+ int x = _rect.x;
+ int y = _rect.y;
+ int w = _rect.width;
+ int h = _rect.height;
+ if (stage == 1) {
// TODO: Is this right?
dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
@@ -185,48 +186,92 @@ void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
*(int *)(uVar1 + 8) = height + -6; */
} else if (stage == 2) {
drawStage2(dst);
- } else if (stage == 2) {
- drawStage2(dst);
+ } else if (stage == 3) {
+ drawStage3(dst);
} else {
- drawStage4(dst);
+ drawStage4(dst, Common::Rect(x + 2, y + 2, x + w - 2, y + h - 2), _bgColor, _str);
}
}
// box with fancy frame and optional title (everything before ":")
void Dialogue::drawType2(Graphics::Surface *dst, int stage) {
- // TODO: Implement me properly.
- Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
- dst->fillRect(drawRect, _bgColor);
+ Common::String title;
+ Common::String txt;
+ uint32 colonpos = _str.find(':');
+ if (colonpos != Common::String::npos) {
+ title = _str.substr(0, colonpos);
+ txt = _str.substr(colonpos + 1);
+ } else {
+ txt = _str;
+ }
+
+ Common::Rect fillArea(_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
+ if (stage == 1) {
+ bool flatfill = _flags & 1; // TODO: make this an enum
+ Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
+ RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
+ RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
+ if (!title.empty()) {
+ // TODO: Maybe should measure the font?
+ fillArea.top += 10;
+ RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
+ }
+ if (flatfill)
+ dst->fillRect(fillArea, 0);
+ else
+ RequestData::fillBackground(dst, fillArea.left, fillArea.top, fillArea.width(), fillArea.height(), 6);
+
+ RequestData::drawCorners(dst, 19, fillArea.left - 2, fillArea.top - 2, fillArea.width() + 4, fillArea.height() + 4);
+
+ } else if (stage == 2) {
+ drawStage2(dst);
+ } else if (stage == 3) {
+ drawStage3(dst);
+ } else {
+ Common::Rect textRect = fillArea;
+ textRect.left += 8;
+ textRect.right -= 8;
+ drawStage4(dst, textRect, _fontColor, txt);
+ }
}
// comic baloon style box
void Dialogue::drawType3(Graphics::Surface *dst, int stage) {
- // TODO: Implement me properly.
- Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
- dst->fillRect(drawRect, _bgColor);
+ // TODO: Implement me properly. Draw some circles and a bubble.
+ if (stage == 1) {
+ Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
+ dst->fillRect(drawRect, _bgColor);
+ } else if (stage == 2) {
+ drawStage2(dst);
+ } else if (stage == 3) {
+ drawStage3(dst);
+ } else {
+ Common::Rect drawRect(_rect.x + 5, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height - 5);
+ drawStage4(dst, drawRect, _fontColor, _str);
+ }
}
// ellipse
void Dialogue::drawType4(Graphics::Surface *dst, int stage) {
- if (stage == 1) {
- int x = _rect.x;
- int y = _rect.y;
- int w = _rect.width;
- int h = _rect.height;
+ int x = _rect.x;
+ int y = _rect.y;
+ int w = _rect.width;
+ int h = _rect.height;
+
+ int midy = (h - 1) / 2;
+ byte fillcolor;
+ byte fillbgcolor;
+ if (!(_flags & 1)) {
+ fillcolor = 0;
+ fillbgcolor = 15;
+ } else {
+ fillcolor = _fontColor;
+ fillbgcolor = _bgColor;
+ }
- int midy = (h - 1) / 2;
+ if (stage == 1) {
//int radius = (midy * 5) / 4;
- byte fillcolor;
- byte fillbgcolor;
- if (!(_flags & 1)) {
- fillcolor = 0;
- fillbgcolor = 15;
- } else {
- fillcolor = _fontColor;
- fillbgcolor = _bgColor;
- }
-
// This is not exactly the same as the original - might need some work to get pixel-perfect
Common::Rect drawRect(x, y, x + w, y + h);
Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, _drawPixel, dst);
@@ -236,7 +281,8 @@ void Dialogue::drawType4(Graphics::Surface *dst, int stage) {
} else if (stage == 2) {
drawStage2(dst);
} else {
- drawStage4(dst);
+ Common::Rect textRect(x + midy, y + 1, x + w - midy, y + h - 1);
+ drawStage4(dst, textRect, fillcolor, _str);
}
}
@@ -248,7 +294,7 @@ void Dialogue::drawStage3(Graphics::Surface *dst) {
// TODO: various text wrapping and alignment calculations happen here.
}
-void Dialogue::drawStage4(Graphics::Surface *dst) {
+void Dialogue::drawStage4(Graphics::Surface *dst, const Common::Rect &textArea, uint16 fontcol, const Common::String &txt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const FontManager *fontman = engine->getFontMan();
FontManager::FontType fontType = FontManager::k6x6Font;
@@ -263,12 +309,12 @@ void Dialogue::drawStage4(Graphics::Surface *dst) {
// For now do the simplest wrapping.
Common::StringArray lines;
const int h = font->getFontHeight();
- font->wordWrapText(_str, _rect.width, lines);
+ font->wordWrapText(txt, textArea.width(), lines);
- int ystart = _rect.y + (_rect.height - lines.size() * h) / 2;
+ int ystart = textArea.top + (textArea.height() - lines.size() * h) / 2;
for (uint i = 0; i < lines.size(); i++) {
//const int w = font->getStringWidth(lines[i]);
- font->drawString(dst, lines[i], _rect.x, ystart + i * h, _rect.width, _fontColor, Graphics::kTextAlignCenter);
+ font->drawString(dst, lines[i], textArea.left, ystart + i * h, textArea.width(), fontcol, Graphics::kTextAlignCenter);
}
}
@@ -312,9 +358,9 @@ bool Scene::isVersionUnder(const char *version) const {
bool Scene::readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const {
list.resize(s->readUint16LE());
for (SceneStruct1 &dst : list) {
- dst.val1 = s->readUint16LE();
- dst.flags = s->readUint16LE();
- dst.val3 = s->readUint16LE();
+ dst._num = s->readUint16LE();
+ dst._flags = static_cast<SceneCondition>(s->readUint16LE());
+ dst._val = s->readUint16LE();
}
return !s->err();
}
@@ -502,10 +548,11 @@ void SDSScene::enableTrigger(uint16 num) {
void Scene::runOps(const Common::Array<SceneOp> &ops) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
switch(op._opCode) {
case kSceneOpChangeScene:
- warning("TODO: Change scene no to %d", op._args[0]);
+ engine->changeScene(op._args[0]);
break;
case kSceneOpNoop:
break;
@@ -522,6 +569,17 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
}
}
+bool Scene::checkConditions(const Common::Array<struct SceneStruct1> &conds) {
+ for (const auto & c : conds) {
+ if (c._flags & kSceneCondAlwaysTrue)
+ return true;
+ // TODO: Finish this.
+ // 0x80 seems to check some value set
+ return false;
+ }
+ return true;
+}
+
SDSScene::SDSScene() : _num(-1) {
}
@@ -583,6 +641,22 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
return !stream->err();
}
+void SDSScene::unload() {
+ _num = 0;
+ _enterSceneOps.clear();
+ _leaveSceneOps.clear();
+ _opList3.clear();
+ _opList4.clear();
+ _field6_0x14 = 0;
+ _adsFile.clear();
+ _struct2List.clear();
+ _struct4List1.clear();
+ _struct4List2.clear();
+ _dialogues.clear();
+ _triggers.clear();
+}
+
+
Common::String SDSScene::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSDSScene<num %d %d ads %s", indent.c_str(), _num, _field6_0x14, _adsFile.c_str());
str += _dumpStructList(indent, "enterSceneOps", _enterSceneOps);
@@ -600,7 +674,26 @@ Common::String SDSScene::dump(const Common::String &indent) const {
return str;
}
+void SDSScene::checkTriggers() {
+ // scene can change on these triggers. if that happens we stop.
+ int startSceneNum = _num;
+
+ for (struct SceneTrigger &trigger : _triggers) {
+ if (!trigger._enabled)
+ continue;
+
+ if (!checkConditions(trigger.struct1List))
+ continue;
+
+ runOps(trigger.sceneOpList);
+
+ // If the scene changed, the list is no longer valid. Abort!
+ if (_num != startSceneNum)
+ return;
+ trigger._enabled = false;
+ }
+}
GDSScene::GDSScene() {
}
@@ -667,7 +760,7 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
Common::String GDSScene::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sGDSScene<icons %s", indent.c_str(), _iconFile.c_str());
str += _dumpStructList(indent, "gameItems", _gameItems);
- str += _dumpStructList(indent, "opList1", _startGameOps);
+ str += _dumpStructList(indent, "startGameOps", _startGameOps);
str += _dumpStructList(indent, "opList2", _opList2);
str += _dumpStructList(indent, "opList3", _opList3);
str += _dumpStructList(indent, "opList4", _opList4);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 974babf5583..f2889bd5238 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -38,10 +38,21 @@ struct Rect {
Common::String dump(const Common::String &indent) const;
};
+enum SceneCondition {
+ kSceneCondNone = 0,
+ kSceneCond1 = 1,
+ kSceneCond2 = 2,
+ kSceneCond4 = 4,
+ kSceneCondAlwaysTrue = 0x10,
+ kSceneCond20 = 0x20,
+ kSceneCondNeedItemField12 = 0x40,
+ kSceneCond80 = 0x80
+};
+
struct SceneStruct1 {
- uint16 val1;
- uint16 flags; /* eg, see usage in FUN_1f1a_2106 */
- uint16 val3;
+ uint16 _num;
+ SceneCondition _flags; /* eg, see usage in FUN_1f1a_2106 */
+ uint16 _val;
Common::String dump(const Common::String &indent) const;
};
@@ -158,7 +169,7 @@ private:
void drawStage2(Graphics::Surface *dst);
void drawStage3(Graphics::Surface *dst);
- void drawStage4(Graphics::Surface *dst);
+ void drawStage4(Graphics::Surface *dst, const Common::Rect &textArea, uint16 fontcol, const Common::String &txt);
};
struct SceneTrigger {
@@ -209,6 +220,7 @@ protected:
bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
void runOps(const Common::Array<SceneOp> &ops);
+ bool checkConditions(const Common::Array<struct SceneStruct1> &cond);
virtual void enableTrigger(uint16 num) {};
@@ -229,6 +241,9 @@ public:
const Common::String &getIconFile() const { return _iconFile; }
Common::String dump(const Common::String &indent) const;
+
+ void runStartGameOps() { runOps(_startGameOps); }
+
private:
//byte _unk[32];
Common::String _iconFile;
@@ -248,9 +263,15 @@ public:
bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
+ void unload();
Common::Array<class Dialogue> &getLines() { return _dialogues; }
+ const Common::String &getAdsFile() const { return _adsFile; }
+ void runEnterSceneOps() { runOps(_enterSceneOps); }
+ void runLeaveSceneOps() { runOps(_leaveSceneOps); }
+ void checkTriggers();
+ int getNum() const { return _num; }
Common::String dump(const Common::String &indent) const;
private:
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 64fff2831f4..2181d041499 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -301,8 +301,18 @@ ADSInterpreter::~ADSInterpreter() {
bool ADSInterpreter::load(const Common::String &filename) {
unload();
+ // For high detail, replace extension ADS with ADH. Low detail is ADL.
+ Common::String detailfile = filename.substr(0, filename.size() - 1);
+ if (_vm->getDetailLevel() == kDgdsDetailLow)
+ detailfile += "L";
+ else
+ detailfile += "H";
+
+ if (!_vm->getResourceManager()->hasResource(detailfile))
+ detailfile = filename;
+
ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- dgds.parse(&_scriptData, filename);
+ dgds.parse(&_scriptData, detailfile);
_state.scene = 0;
_state.subIdx = 0;
@@ -317,6 +327,7 @@ void ADSInterpreter::unload() {
_scriptData.names.clear();
delete _scriptData.scr;
_scriptData.scr = nullptr;
+ _state = ADSState();
}
bool ADSInterpreter::run() {
Commit: d12688f1564fb884c60963c7a4c705645530269f
https://github.com/scummvm/scummvm/commit/d12688f1564fb884c60963c7a4c705645530269f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement thought-bubble style dialogues and text alignment
Changed paths:
engines/dgds/font.cpp
engines/dgds/font.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index 1bf5f0f083d..cc22671f1d4 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -162,6 +162,12 @@ void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 co
Font::drawChar(dst, pos, bit, x, y, color);
}
+int PFont::getCharWidth(uint32 chr) const {
+ if (!hasChar(chr))
+ return 0;
+ return _widths[chr - _start];
+}
+
PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor) {
byte magic = input.readByte();
byte w = input.readByte();
@@ -212,15 +218,15 @@ void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompre
if (gameId == GID_DRAGON) {
tryLoadFont(kGameFont, "DRAGON.FNT", resMgr, decomp);
tryLoadFont(k7x8Font, "7X8.FNT", resMgr, decomp);
- tryLoadFont(kP6x6Font, "P6X6.FNT", resMgr, decomp);
+ tryLoadFont(kGameDlgFont, "P6X6.FNT", resMgr, decomp);
} else if (gameId == GID_CHINA) {
tryLoadFont(kGameFont, "HOC.FNT", resMgr, decomp);
tryLoadFont(kChinaFont, "CHINA.FNT", resMgr, decomp);
- tryLoadFont(kChineseFont, "CHINESE.FNT", resMgr, decomp);
+ tryLoadFont(kGameDlgFont, "CHINESE.FNT", resMgr, decomp);
} else if (gameId == GID_BEAMISH) {
tryLoadFont(kGameFont, "WILLY.FNT", resMgr, decomp);
tryLoadFont(kWVCRFont, "WVCR.FNT", resMgr, decomp);
- tryLoadFont(kComix16Font, "COMIX_16.FNT", resMgr, decomp);
+ tryLoadFont(kGameDlgFont, "COMIX_16.FNT", resMgr, decomp);
}
_fonts.setVal(kDefaultFont, _fonts.getVal(kGameFont));
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index c2d27a1b2d3..411467083e5 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -69,7 +69,7 @@ class PFont : public Font {
public:
PFont(byte w, byte h, byte start, byte count, byte *data);
~PFont();
- int getCharWidth(uint32 chr) const { return _widths[chr - _start]; }
+ int getCharWidth(uint32 chr) const;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static PFont *load(Common::SeekableReadStream &input, Decompressor *decompressor);
@@ -104,12 +104,10 @@ public:
k6x6Font,
k4x5Font,
kGameFont, // DRAGON for Rise of the Dragon, WILLY for Willy Beamish, HOC for Heart of China.
+ kGameDlgFont, // P6x6 for Rise of the Dragon, COMIX_16 for Willy Beamish, CHINESE for Heart of China
k7x8Font, // Rise of the Dragon only
- kP6x6Font, // Rise of the Dragon only
kWVCRFont, // Willy Beamish only
- kComix16Font, // Willy Beamish only
kChinaFont, // Heart of China only
- kChineseFont, // Heart of China only
};
FontManager() {}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 705a315df7f..d170a053f60 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -149,10 +149,10 @@ Common::String SceneTrigger::dump(const Common::String &indent) const {
void Dialogue::draw(Graphics::Surface *dst, int stage) {
switch (_frameType) {
- case 1: return drawType1(dst, stage);
- case 2: return drawType2(dst, stage);
- case 3: return drawType3(dst, stage);
- case 4: return drawType4(dst, stage);
+ case kDlgFramePlain: return drawType1(dst, stage);
+ case kDlgFrameBorder: return drawType2(dst, stage);
+ case kDlgFrameThought: return drawType3(dst, stage);
+ case kDlgFrameRounded: return drawType4(dst, stage);
default: error("unexpected frame type %d for dialog %d", _frameType, _num);
}
}
@@ -189,7 +189,8 @@ void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
} else if (stage == 3) {
drawStage3(dst);
} else {
- drawStage4(dst, Common::Rect(x + 2, y + 2, x + w - 2, y + h - 2), _bgColor, _str);
+ _textDrawRect = Common::Rect(x + 2, y + 2, x + w - 2, y + h - 2);
+ drawStage4(dst, _bgColor, _str);
}
}
@@ -205,49 +206,124 @@ void Dialogue::drawType2(Graphics::Surface *dst, int stage) {
txt = _str;
}
- Common::Rect fillArea(_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
if (stage == 1) {
- bool flatfill = _flags & 1; // TODO: make this an enum
+ _textDrawRect = Common::Rect (_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
if (!title.empty()) {
// TODO: Maybe should measure the font?
- fillArea.top += 10;
+ _textDrawRect.top += 10;
RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
}
- if (flatfill)
- dst->fillRect(fillArea, 0);
+ if (_flags & kDlgFlagFlatBg)
+ dst->fillRect(_textDrawRect, 0);
else
- RequestData::fillBackground(dst, fillArea.left, fillArea.top, fillArea.width(), fillArea.height(), 6);
+ RequestData::fillBackground(dst, _textDrawRect.left, _textDrawRect.top, _textDrawRect.width(), _textDrawRect.height(), 6);
- RequestData::drawCorners(dst, 19, fillArea.left - 2, fillArea.top - 2, fillArea.width() + 4, fillArea.height() + 4);
+ RequestData::drawCorners(dst, 19, _textDrawRect.left - 2, _textDrawRect.top - 2, _textDrawRect.width() + 4, _textDrawRect.height() + 4);
+ _textDrawRect.left += 8;
+ _textDrawRect.right -= 8;
} else if (stage == 2) {
drawStage2(dst);
} else if (stage == 3) {
drawStage3(dst);
} else {
- Common::Rect textRect = fillArea;
- textRect.left += 8;
- textRect.right -= 8;
- drawStage4(dst, textRect, _fontColor, txt);
+ drawStage4(dst, _fontColor, txt);
}
}
-// comic baloon style box
+static void _filledCircle(int x, int y, int xr, int yr, Graphics::Surface *dst, byte fgcol, byte bgcol) {
+ Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, bgcol, true, _drawPixel, dst);
+ Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, _drawPixel, dst);
+}
+
+// Comic tought box made up of circles with 2 circles going up to it.
+// Draw circles with 5/4 more pixels in x because the pixels are not square.
void Dialogue::drawType3(Graphics::Surface *dst, int stage) {
- // TODO: Implement me properly. Draw some circles and a bubble.
if (stage == 1) {
- Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
- dst->fillRect(drawRect, _bgColor);
+ uint16 xradius = 9999;
+ uint16 yradius = 40;
+ const int16 usabley = _rect.height - 31;
+ const int16 usablex = _rect.width - 30;
+ for (uint16 testyradius = 40; testyradius != 0; testyradius--) {
+ int16 testxradius = (testyradius * 5) / 4;
+ if ((usablex / testxradius > 2) && (usabley / testyradius > 2)) {
+ testxradius = usablex % testxradius + usabley % testyradius;
+ if (testxradius < xradius) {
+ yradius = testyradius;
+ xradius = testxradius;
+ }
+ }
+ if (testyradius < 20 && xradius != 9999)
+ break;
+ }
+
+ xradius = (yradius * 5) / 4;
+ const int16 circlesAcross = usablex / xradius - 1;
+ const int16 circlesDown = usabley / yradius - 1;
+
+ uint16 x = _rect.x + xradius;
+ uint16 y = _rect.y + yradius;
+
+ bool isbig = _rect.x + _rect.width / 2 > 160;
+ if (isbig)
+ x = x + 30;
+
+ byte fgcol = 0;
+ byte bgcol = 15;
+ if (_flags & kDlgFlagFlatBg) {
+ bgcol = _bgColor;
+ fgcol = _fontColor;
+ }
+
+ for (int i = 1; i < circlesDown; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ y += yradius;
+ }
+ for (int i = 1; i < circlesAcross; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ x += xradius;
+ }
+ for (int i = 1; i < circlesDown; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ y -= yradius;
+ }
+ for (int i = 1; i < circlesAcross; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ x -= xradius;
+ }
+
+ uint16 smallCircleX;
+ if (isbig) {
+ _filledCircle((x - xradius) - 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
+ smallCircleX = (x - xradius) - 20;
+ } else {
+ _filledCircle(x + circlesAcross * xradius + 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
+ smallCircleX = x + circlesAcross * xradius + 20;
+ }
+
+ _filledCircle(smallCircleX, y + circlesDown * yradius + 25, 5, 4, dst, fgcol, bgcol);
+
+ int16 yoff = (yradius * 27) / 32;
+ dst->fillRect(Common::Rect(x, y - yoff,
+ x + (circlesAcross - 1) * xradius + 1,
+ y + (circlesDown - 1) * yradius + yoff + 1), bgcol);
+ int16 xoff = (xradius * 27) / 32;
+ dst->fillRect(Common::Rect(x - xoff, y,
+ x + (circlesAcross - 1) * xradius + xoff + 1,
+ y + (circlesDown - 1) * yradius + 1), bgcol);
+
+ int16 textRectX = x - xradius / 2;
+ int16 textRectY = y - yradius / 2;
+ _textDrawRect = Common::Rect(textRectX, textRectY, textRectX + circlesAcross * xradius , textRectY + circlesDown * yradius);
} else if (stage == 2) {
drawStage2(dst);
} else if (stage == 3) {
drawStage3(dst);
} else {
- Common::Rect drawRect(_rect.x + 5, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height - 5);
- drawStage4(dst, drawRect, _fontColor, _str);
+ drawStage4(dst, _fontColor, _str);
}
}
@@ -281,8 +357,8 @@ void Dialogue::drawType4(Graphics::Surface *dst, int stage) {
} else if (stage == 2) {
drawStage2(dst);
} else {
- Common::Rect textRect(x + midy, y + 1, x + w - midy, y + h - 1);
- drawStage4(dst, textRect, fillcolor, _str);
+ _textDrawRect = Common::Rect(x + midy, y + 1, x + w - midy, y + h - 1);
+ drawStage4(dst, fillcolor, _str);
}
}
@@ -294,10 +370,10 @@ void Dialogue::drawStage3(Graphics::Surface *dst) {
// TODO: various text wrapping and alignment calculations happen here.
}
-void Dialogue::drawStage4(Graphics::Surface *dst, const Common::Rect &textArea, uint16 fontcol, const Common::String &txt) {
+void Dialogue::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const FontManager *fontman = engine->getFontMan();
- FontManager::FontType fontType = FontManager::k6x6Font;
+ FontManager::FontType fontType = FontManager::kGameDlgFont;
if (_fontSize == 1)
fontType = FontManager::k8x8Font;
else if (_fontSize == 3)
@@ -309,14 +385,28 @@ void Dialogue::drawStage4(Graphics::Surface *dst, const Common::Rect &textArea,
// For now do the simplest wrapping.
Common::StringArray lines;
const int h = font->getFontHeight();
- font->wordWrapText(txt, textArea.width(), lines);
+ font->wordWrapText(txt, _textDrawRect.width(), lines);
+
+ int ystart = _textDrawRect.top + (_textDrawRect.height() - lines.size() * h) / 2;
+
+ int x = _textDrawRect.left;
+ if (_flags & kDlgFlagLeftJust) {
+ // each line left-aligned, but overall block is still centered
+ int maxlen = -1;
+ for (const auto &line : lines)
+ maxlen = MAX(maxlen, font->getStringWidth(line));
- int ystart = textArea.top + (textArea.height() - lines.size() * h) / 2;
- for (uint i = 0; i < lines.size(); i++) {
- //const int w = font->getStringWidth(lines[i]);
- font->drawString(dst, lines[i], textArea.left, ystart + i * h, textArea.width(), fontcol, Graphics::kTextAlignCenter);
+ x += (_textDrawRect.width() - maxlen) / 2;
+
+ for (uint i = 0; i < lines.size(); i++)
+ font->drawString(dst, lines[i], x, ystart + i * h, maxlen, fontcol, Graphics::kTextAlignLeft);
+ } else {
+ // center each line
+ for (uint i = 0; i < lines.size(); i++)
+ font->drawString(dst, lines[i], x, ystart + i * h, _textDrawRect.width(), fontcol, Graphics::kTextAlignCenter);
}
+
}
Common::String Dialogue::dump(const Common::String &indent) const {
@@ -475,14 +565,14 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
}
dst._fontSize = s->readUint16LE(); // 01 = 8x8, 02 = 6x6, 03 = 4x5
if (isVersionUnder(" 1.210")) {
- dst._flags = s->readUint16LE();
+ dst._flags = static_cast<DialogueFlags>(s->readUint16LE());
} else {
// Game reads a 32 bit int but then truncates anyway..
// probably never used the full thing.
- dst._flags = (s->readUint32LE() & 0xffff);
+ dst._flags = static_cast<DialogueFlags>(s->readUint32LE() & 0xffff);
}
- dst._frameType = s->readUint16LE(); // 01 =simple frame, 02 = with title w/ text before :, 03 = baloon, 04 = eliptical
+ dst._frameType = static_cast<DialogueFrameType>(s->readUint16LE());
dst._time = s->readUint16LE();
if (isVersionOver(" 1.207")) {
dst._nextDialogNum = s->readUint16LE();
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index f2889bd5238..ed0c3ed6c08 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -138,6 +138,18 @@ struct SceneStruct4 {
Common::String dump(const Common::String &indent) const;
};
+enum DialogueFlags {
+ kDlgFlagNone = 0,
+ kDlgFlagFlatBg = 1,
+ kDlgFlagLeftJust = 2,
+};
+
+enum DialogueFrameType {
+ kDlgFramePlain = 1,
+ kDlgFrameBorder = 2,
+ kDlgFrameThought = 3,
+ kDlgFrameRounded = 4
+};
class Dialogue {
public:
@@ -148,8 +160,8 @@ public:
uint16 _field7_0xe;
uint16 _field8_0x10;
uint16 _fontSize;
- uint32 _flags; // includes justify
- uint16 _frameType;
+ DialogueFlags _flags;
+ DialogueFrameType _frameType;
uint16 _time;
uint16 _nextDialogNum;
Common::Array<struct DialogueAction> _subStrings;
@@ -162,6 +174,8 @@ public:
Common::String dump(const Common::String &indent) const;
private:
+ Common::Rect _textDrawRect; // Calculated while drawing the background.
+
void drawType1(Graphics::Surface *dst, int mode);
void drawType2(Graphics::Surface *dst, int mode);
void drawType3(Graphics::Surface *dst, int mode);
@@ -169,7 +183,7 @@ private:
void drawStage2(Graphics::Surface *dst);
void drawStage3(Graphics::Surface *dst);
- void drawStage4(Graphics::Surface *dst, const Common::Rect &textArea, uint16 fontcol, const Common::String &txt);
+ void drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt);
};
struct SceneTrigger {
Commit: 064585c48c8fe9cc8b1960480e0d6b327f7f1850
https://github.com/scummvm/scummvm/commit/064585c48c8fe9cc8b1960480e0d6b327f7f1850
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add more script ops and unsupported items
Started looking at the original more closely and discovered some improvements.
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 2181d041499..cb566d565a7 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -89,7 +89,7 @@ bool TTMInterpreter::run() {
uint op = code & 0xFFF0;
int16 ivals[8];
Common::String sval;
-
+
if (count > 8 && count != 0x0f)
error("Invalid TTM opcode %04x requires %d locals", code, count);
@@ -123,29 +123,28 @@ bool TTMInterpreter::run() {
case 0x0000:
// FINISH: void
break;
- case 0xf010:
- // LOAD SCR: filename:str
- _vm->_image->drawScreen(sval, _vm->getBottomBuffer());
- continue;
- case 0xf020:
- // LOAD BMP: filename:str
- _state.bmpNames[_state._currentBmpId] = sval;
+ case 0x0020: //SAVE BACKGROUND
+ _vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
continue;
- case 0xf050:
- // LOAD PAL: filename:str
- _vm->_image->loadPalette(sval);
+ case 0x0110: //PURGE void
+ // .. shouldn't actually clear the bmps, what should it do?
+ _state._currentBmpId = 0;
continue;
- case 0xf060:
- // LOAD SONG: filename:str
- if (_vm->_platform == Common::kPlatformAmiga) {
- _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
- } else if (_vm->_platform == Common::kPlatformMacintosh) {
- _vm->_soundPlayer->playMacMusic(sval.c_str());
- } else {
- _vm->_soundPlayer->playMusic(sval.c_str());
+ case 0x0ff0: {
+ // REFRESH: void
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
+ _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
+ _vm->getTopBuffer().fillRect(bmpArea, 0);
+
+ if (_text) {
+ _text->draw(_vm->_resData.surfacePtr(), 1);
+ _text->draw(_vm->_resData.surfacePtr(), 4);
}
+ } break;
+ case 0x1020: // SET DELAY: i:int [0..n]
+ _state.delay += ivals[0] * 10;
continue;
-
case 0x1030: {
// SET BMP: id:int [-1:n]
int bk = ivals[0];
@@ -159,33 +158,43 @@ bool TTMInterpreter::run() {
_state._currentBmpId = ivals[0];
continue;
case 0x1060:
- // SELECT SCR|PAL: id:int [0]
- warning("Switching scene %d -> %d for opcode 0x1060 .. is that right?", _state.scene, ivals[0]);
- _state.scene = ivals[0];
+ // SELECT PAL: id:int [0]
+ warning("TTM: Switching palette to %d for opcode 0x1060, but we don't use it yet", ivals[0]);
+ _state._currentPalId = ivals[0];
continue;
case 0x1090:
// SELECT SONG: id:int [0]
continue;
- case 0x4120:
- // FADE IN: ?,?,?,?:byte
- _vm->_image->setPalette();
+ case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
+ debug("SET SCENE: %u", ivals[0]);
+ break;
+ case 0x1110: { //SHOW SCENE TEXT?: i:int [1..n]
+ // DESCRIPTION IN TTM TAGS.
+ debug("SHOW SCENE TEXT: %u", ivals[0]);
+ _state.scene = ivals[0];
+ setActiveDialogue(_state.scene);
+ continue;
+ }
+
+ case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
+ _state._drawColFG = static_cast<byte>(ivals[0]);
+ _state._drawColBG = static_cast<byte>(ivals[1]);
+ continue;
+
+ case 0x4000:
+ //SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
+ _state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
continue;
case 0x4110:
- // FADE OUT: ?,?,?,?:byte
+ // FADE OUT: colorno,ncolors,coloffset,speed:byte
g_system->delayMillis(_state.delay);
_vm->_image->clearPalette();
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
continue;
- // these 3 ops do interaction between the topBuffer (imgData) and the bottomBuffer (scrData) but... it might turn out this uses z values!
- case 0xa050: { //GFX? i,j,k,l:int [i<k,j<l] // HAPPENS IN INTRO.TTM:INTRO9
- // it works like a bitblit, but it doesn't write if there's something already at the destination?
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- _vm->getTopBuffer().copyFrom(_vm->_resData);
- continue;
- }
- case 0x0020: //SAVE BG?: void // OR PERHAPS SWAPBUFFERS ; it makes bmpData persist in the next frames.
- _vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
+ case 0x4120:
+ // FADE IN: colorno,ncolors,coloffset,speed:byte
+ warning("TTM: FADE IN, implement me");
+ _vm->_image->setPalette();
continue;
case 0x4200: {
// STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
@@ -195,25 +204,28 @@ bool TTMInterpreter::run() {
_vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
continue;
}
- case 0x0ff0: {
- // REFRESH: void
+ case 0xa000: // DRAW PIXEL x,y:int
+ _vm->getTopBuffer().setPixel(ivals[0], ivals[1], _state._drawColFG);
+ continue;
+ case 0xa050: //SAVE REGION i,j,k,l:int [i<k,j<l]
+ // it works like a bitblit, but it doesn't write if there's something already at the destination?
_vm->_resData.blitFrom(_vm->getBottomBuffer());
- Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
- _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
- _vm->getTopBuffer().fillRect(bmpArea, 0);
-
- if (_text) {
- _text->draw(_vm->_resData.surfacePtr(), 1);
- _text->draw(_vm->_resData.surfacePtr(), 4);
- }
- } break;
-
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ _vm->getTopBuffer().copyFrom(_vm->_resData);
+ continue;
+ case 0xa100:
+ //DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
+ bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ _vm->getTopBuffer().fillRect(bmpArea, _state._drawColFG);
+ continue;
case 0xa520:
- //DRAW BMP: x,y:int ; happens once in INTRO.TTM
+ // DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
+ // FALL THROUGH
case 0xa530:
// CHINA
// DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
+ // FALL THROUGH
case 0xa500:
debug("DRAW \"%s\"", _state.bmpNames[_state._currentBmpId].c_str());
@@ -237,41 +249,53 @@ bool TTMInterpreter::run() {
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
continue;
-
- case 0x1110: { //SHOW SCENE TEXT?: i:int [1..n]
- // DESCRIPTION IN TTM TAGS.
- debug("SHOW SCENE TEXT: %u", ivals[0]);
- _state.scene = ivals[0];
- setActiveDialogue(_state.scene);
+ case 0xf010:
+ // LOAD SCR: filename:str
+ _vm->_image->drawScreen(sval, _vm->getBottomBuffer());
continue;
- }
-
- case 0x4000:
- //SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
- _state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ case 0xf020:
+ // LOAD BMP: filename:str
+ _state.bmpNames[_state._currentBmpId] = sval;
continue;
-
- case 0xa100:
- //SET BMP AREA? x,y,w,h:int [0..320,0..200]
- bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ case 0xf050:
+ // LOAD PAL: filename:str
+ _vm->_image->loadPalette(sval);
continue;
-
- case 0x1020: //DELAY?: i:int [0..n]
- _state.delay += ivals[0] * 10;
+ case 0xf060:
+ // LOAD SONG: filename:str
+ if (_vm->_platform == Common::kPlatformAmiga) {
+ _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
+ } else if (_vm->_platform == Common::kPlatformMacintosh) {
+ _vm->_soundPlayer->playMacMusic(sval.c_str());
+ } else {
+ _vm->_soundPlayer->playMusic(sval.c_str());
+ }
continue;
- case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
- debug("SET SCENE: %u", ivals[0]);
- break;
-
- case 0x2000: //SET FRAME1?: i,j:int [0..255]
-
- case 0x0110: //PURGE IMGS? void
- case 0x0080: //DRAW BG: void
- case 0x1100: //? i:int [9]
- case 0x1300: //? i:int [72,98,99,100,107]
-
- case 0x1310: //? i:int [107]
+ // Unimplemented / unknown
+ case 0x0080: // DRAW BG: void
+ case 0x1100: // ? i:int [9]
+ case 0x1120: // SET_BACKGROUND
+ case 0x1200: // GOTO
+ case 0x1300: // ? i:int [72,98,99,100,107]
+ case 0x1310: // ? i:int [107]
+ case 0x2010: // SET FRAME
+ case 0x2020: // SET TIMER
+ case 0x4210: // SAVE IMAGE REGION
+ case 0xA0A0: // DRAW LINE x1,y1,x2,y2:int
+ //case 0xA100: // DRAW FILLED RECT x1,y1,x2,y2:int
+ case 0xA110: // DRAW EMPTY RECT x1,y1,x2,y2:int
+ case 0xA300: // DRAW some string? x,y,w,h:int
+ case 0xA400: // DRAW FILLED CIRCLE
+ case 0xA424: // DRAW EMPTY CIRCLE
+ case 0xA510: // DRAW SPRITE1
+ case 0xA600: // CLEAR SCREEN
+ case 0xB600: // DRAW SCREEN
+ case 0xC020: // LOAD_SAMPLE
+ case 0xC030: // SELECT_SAMPLE
+ case 0xC040: // DESELECT_SAMPLE
+ case 0xC050: // PLAY_SAMPLE
+ case 0xC060: // STOP_SAMPLE
default:
warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
@@ -344,7 +368,7 @@ bool ADSInterpreter::run() {
return false;
}
}
-
+
return true;
}
@@ -356,7 +380,6 @@ bool ADSInterpreter::run() {
do {
uint16 code = scr->readUint16LE();
- byte count = code & 0x000F;
//uint op = code & 0xFFF0;
if ((code & 0xFF00) == 0) {
@@ -365,45 +388,55 @@ bool ADSInterpreter::run() {
switch (code) {
case 0x2005: {
- // play scene.
+ // ADD SCENE
_state.subIdx = scr->readUint16LE();
_state.subMax = scr->readUint16LE();
uint16 unk1 = scr->readUint16LE();
uint16 unk2 = scr->readUint16LE();
_ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
- debug("ADSInterpreter play scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", _state.subIdx, _state.subMax, unk1, unk2);
+ debug("ADSInterpreter add scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", _state.subIdx, _state.subMax, unk1, unk2);
return true;
}
-
- case 0xF010:
- case 0xF200:
- case 0xFDA8:
- case 0xFE98:
- case 0xFF88:
- case 0xFF10:
case 0xFFFF:
+ // END
+ return false;
+
+ case 0x1330: { // IF_NOT_PLAYED, 2 params
+ uint16 unk1 = scr->readUint16LE();
+ uint16 unk2 = scr->readUint16LE();
+ warning("Unimplemented ADS opcode: IF_NOT_PLAYED %02x %02x", unk1, unk2);
+ continue;
+ }
+
+ //// unknown / to-be-implemented
case 0x0190:
- case 0x1070:
- case 0x1330:
+ case 0x1070: // unknown, 2 params
case 0x1340:
- case 0x1350:
- case 0x1360:
- case 0x1370:
- case 0x1420:
- case 0x1430:
+ case 0x1350: // IF_PLAYED, 2 params
+ case 0x1360: // IF_NOT_RUNNING, 2 params
+ case 0x1370: // IF_RUNNING, 2 params
+ case 0x1420: // AND, 0 params
+ case 0x1430: // OR, 0 params
case 0x1500:
- case 0x1510:
- case 0x1520:
+ case 0x1510: // PLAY_SCENE, 0 params
+ case 0x1520: // PLAY_SCENE_2, 5 params
case 0x2000:
- case 0x2010:
+ case 0x2010: // STOP_SCENE, 3 params
case 0x2020:
- case 0x3010:
- case 0x3020:
- case 0x30FF:
- case 0x4000:
+ case 0x3010: // RANDOM_START, 0 params
+ case 0x3020: // RANDOM_??, 1 param
+ case 0x30FF: // RANDOM_END, 0 params
+ case 0x4000: // unknown, 3 params
case 0x4010:
+ case 0xF010: // FADE_OUT, 0 params
+ case 0xF200: // RUN_SCRIPT, 1 param
+ case 0xFDA8:
+ case 0xFE98:
+ case 0xFF88:
+ case 0xFF10:
+ case 0xFFF0: // END_IF, 0 params
default:
- warning("Unimplemented ADS opcode: 0x%04X (count %d)", code, count);
+ warning("Unimplemented ADS opcode: 0x%04X", code);
continue;
}
break;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index f3d1fe3dba7..500940b8526 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -47,11 +47,14 @@ public:
};
struct TTMState {
- TTMState() : scene(0), delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0) {}
+ TTMState() : scene(0), delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0), _currentPalId(0), _drawColFG(0), _drawColBG(0) {}
uint16 scene;
int delay;
Common::Rect _drawWin;
int _currentBmpId;
+ int _currentPalId;
+ byte _drawColFG;
+ byte _drawColBG;
Common::String bmpNames[16];
};
Commit: 8a6bb5e0315022fd32f312c9b33962aa7d07ee8a
https://github.com/scummvm/scummvm/commit/8a6bb5e0315022fd32f312c9b33962aa7d07ee8a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Check magic on scene load like original
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index c3d50009bfc..11487175141 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -168,6 +168,10 @@ void DgdsEngine::changeScene(int sceneNum) {
error("Tried to switch to non-existant scene %d", sceneNum);
_scene->load(sceneFile, _resource, _decompressor);
+
+ if (_scene->getMagic() != _gdsScene->getMagic())
+ error("Scene %s magic does (0x%08x) not match GDS magic (0x%08x)", sceneFile.c_str(), _scene->getMagic(), _gdsScene->getMagic());
+
if (!_scene->getAdsFile().empty())
_adsInterp->load(_scene->getAdsFile());
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index d170a053f60..ea916dbd2d3 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -828,7 +828,7 @@ bool GDSScene::parseInf(Common::SeekableReadStream *s) {
bool GDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _startGameOps);
- readOpList(stream, _opList2);
+ readOpList(stream, _quitGameOps);
if (isVersionOver(" 1.206"))
readOpList(stream, _opList3);
readOpList(stream, _opList4);
@@ -851,7 +851,7 @@ Common::String GDSScene::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sGDSScene<icons %s", indent.c_str(), _iconFile.c_str());
str += _dumpStructList(indent, "gameItems", _gameItems);
str += _dumpStructList(indent, "startGameOps", _startGameOps);
- str += _dumpStructList(indent, "opList2", _opList2);
+ str += _dumpStructList(indent, "quitGameOps", _quitGameOps);
str += _dumpStructList(indent, "opList3", _opList3);
str += _dumpStructList(indent, "opList4", _opList4);
str += _dumpStructList(indent, "opList5", _opList5);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index ed0c3ed6c08..646de6429f0 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -221,6 +221,9 @@ public:
bool isVersionOver(const char *version) const;
bool isVersionUnder(const char *version) const;
+ uint32 getMagic() const { return _magic; }
+ const Common::String &getVersion() const { return _version; }
+
protected:
bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const;
bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
@@ -257,13 +260,14 @@ public:
Common::String dump(const Common::String &indent) const;
void runStartGameOps() { runOps(_startGameOps); }
+ void runQuitGameOps() { runOps(_quitGameOps); }
private:
//byte _unk[32];
Common::String _iconFile;
Common::Array<struct GameItem> _gameItems;
Common::Array<struct SceneOp> _startGameOps;
- Common::Array<struct SceneOp> _opList2;
+ Common::Array<struct SceneOp> _quitGameOps;
Common::Array<struct SceneOp> _opList3;
Common::Array<struct SceneOp> _opList4;
Common::Array<struct SceneOp> _opList5;
Commit: c2d36517828731f0fcf4db838768c66d0b02114b
https://github.com/scummvm/scummvm/commit/c2d36517828731f0fcf4db838768c66d0b02114b
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add some more menu button IDs used in HoC
Changed paths:
engines/dgds/menu.cpp
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index cf316931b5e..9d62ae091df 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -83,6 +83,8 @@ enum MenuButtonIds {
kMenuCalibrateMouse = 146,
kMenuCalibrateVCR = 144,
kMenuCalibratePlay = 147,
+ kMenuCalibrateVCRHoC = 159,
+ kMenuCalibratePlayHoC = 158,
kMenuFilesSave = 107,
kMenuFilesRestore = 106,
@@ -211,6 +213,7 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
case kMenuControlsPlay:
case kMenuOptionsPlay:
case kMenuCalibratePlay:
+ case kMenuCalibratePlayHoC:
case kMenuFilesPlay:
case kMenuMouseCalibrationPlay:
_curMenu = kMenuNone;
@@ -237,6 +240,7 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
case kMenuControlsVCR:
case kMenuOptionsVCR:
case kMenuCalibrateVCR:
+ case kMenuCalibrateVCRHoC:
case kMenuFilesVCR:
case kMenuQuitNo:
case kMenuRestartNo:
Commit: 925290ff9e415c6f028ef443815b061ea7cd92d3
https://github.com/scummvm/scummvm/commit/925290ff9e415c6f028ef443815b061ea7cd92d3
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Silence some noisy debug console output
This helps to read the running script output a bit better
Changed paths:
engines/dgds/resource.cpp
engines/dgds/sound.cpp
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 8f19c7f46ac..2b1408a299d 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -294,7 +294,7 @@ Common::SeekableReadStream *DgdsChunkReader::readStream() {
output = new Common::SeekableSubReadStream(_sourceStream, _startPos, _startPos + _size, DisposeAfterUse::NO);
}
- debug(" %s %u%c", _idStr, _size, (_container ? '+' : ' '));
+ //debug(" %s %u%c", _idStr, _size, (_container ? '+' : ' '));
return output;
}
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 1ce432d8bdf..e8c30222cbd 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -216,10 +216,10 @@ void Sound::playMusic(const Common::String &filename) {
stream->read(_musicData, _musicSize);
} else if (chunk.isSection(ID_INF)) {
uint32 count = stream->size() / 2;
- debug(" [%u]", count);
+ //debug(" [%u]", count);
for (uint32 k = 0; k < count; k++) {
- uint16 idx = stream->readUint16LE();
- debug(" %2u: %u", k, idx);
+ /*uint16 idx = */stream->readUint16LE();
+ //debug(" %2u: %u", k, idx);
}
}
}
@@ -274,19 +274,19 @@ uint32 availableSndTracks(const byte *data, uint32 size) {
while (pos[0] != 0xFF) {
byte drv = *pos++;
- debug("(%d)", drv);
+ //debug("(%d)", drv);
while (pos[0] != 0xFF) {
uint16 off, siz;
readPartHeader(pos, off, siz);
off += sci_header;
- debug("%06d:%d ", off, siz);
+ //debug("%06d:%d ", off, siz);
- debug("Header bytes");
- debug("[%06X] ", data[off]);
- debug("[%02X] ", data[off+0]);
- debug("[%02X] ", data[off+1]);
+ //debug("Header bytes");
+ //debug("[%06X] ", data[off]);
+ //debug("[%02X] ", data[off+0]);
+ //debug("[%02X] ", data[off+1]);
bool digital_pcm = false;
if (READ_LE_UINT16(&data[off]) == 0x00FE) {
@@ -295,20 +295,34 @@ uint32 availableSndTracks(const byte *data, uint32 size) {
switch (drv) {
case 0: if (digital_pcm) {
- debug("- Soundblaster");
+ //debug("- Soundblaster");
tracks |= DIGITAL_PCM;
} else {
- debug("- Adlib");
+ //debug("- Adlib");
tracks |= TRACK_ADLIB;
- } break;
- case 7: debug("- General MIDI");
- tracks |= TRACK_GM; break;
- case 9: debug("- CMS"); break;
- case 12: debug("- MT-32");
- tracks |= TRACK_MT32; break;
- case 18: debug("- PC Speaker"); break;
- case 19: debug("- Tandy 1000"); break;
- default: debug("- Unknown %d", drv); break;
+ }
+ break;
+ case 7:
+ //debug("- General MIDI");
+ tracks |= TRACK_GM;
+ break;
+ case 9:
+ //debug("- CMS");
+ break;
+ case 12:
+ //debug("- MT-32");
+ tracks |= TRACK_MT32;
+ break;
+ case 18:
+ //debug("- PC Speaker");
+ break;
+ case 19:
+ //debug("- Tandy 1000");
+ break;
+ default:
+ //debug("- Unknown %d", drv);
+ warning("Unknown music type %d", drv);
+ break;
}
}
Commit: f437ad7e8480a93697997aa8a1d5547f9443385c
https://github.com/scummvm/scummvm/commit/f437ad7e8480a93697997aa8a1d5547f9443385c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement some more TTM opcodes
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index cb566d565a7..63c6ea82b3d 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -123,9 +123,12 @@ bool TTMInterpreter::run() {
case 0x0000:
// FINISH: void
break;
- case 0x0020: //SAVE BACKGROUND
+ case 0x0020: // SAVE BACKGROUND
_vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
continue;
+ case 0x0080: // DRAW BACKGROUND
+ _vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
+ continue;
case 0x0110: //PURGE void
// .. shouldn't actually clear the bmps, what should it do?
_state._currentBmpId = 0;
@@ -167,7 +170,7 @@ bool TTMInterpreter::run() {
continue;
case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
debug("SET SCENE: %u", ivals[0]);
- break;
+ continue;
case 0x1110: { //SHOW SCENE TEXT?: i:int [1..n]
// DESCRIPTION IN TTM TAGS.
debug("SHOW SCENE TEXT: %u", ivals[0]);
@@ -175,12 +178,14 @@ bool TTMInterpreter::run() {
setActiveDialogue(_state.scene);
continue;
}
-
+ case 0x1200: // GOTO
+ debug("GOTO SCENE: %u", ivals[0]);
+ _state.scene = ivals[0];
+ continue;
case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
_state._drawColFG = static_cast<byte>(ivals[0]);
_state._drawColBG = static_cast<byte>(ivals[1]);
continue;
-
case 0x4000:
//SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
_state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
@@ -213,6 +218,9 @@ bool TTMInterpreter::run() {
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
_vm->getTopBuffer().copyFrom(_vm->_resData);
continue;
+ case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
+ _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], _state._drawColFG);
+ continue;
case 0xa100:
//DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
@@ -273,29 +281,30 @@ bool TTMInterpreter::run() {
continue;
// Unimplemented / unknown
- case 0x0080: // DRAW BG: void
+ case 0x0070: // ? (0 args)
+ case 0x0230: // ? (0 args) - found in HoC intro
case 0x1100: // ? i:int [9]
case 0x1120: // SET_BACKGROUND
- case 0x1200: // GOTO
- case 0x1300: // ? i:int [72,98,99,100,107]
+ case 0x1300: // ? (1 args) - found in Dragon + HoC intro
case 0x1310: // ? i:int [107]
case 0x2010: // SET FRAME
case 0x2020: // SET TIMER
case 0x4210: // SAVE IMAGE REGION
- case 0xA0A0: // DRAW LINE x1,y1,x2,y2:int
- //case 0xA100: // DRAW FILLED RECT x1,y1,x2,y2:int
- case 0xA110: // DRAW EMPTY RECT x1,y1,x2,y2:int
- case 0xA300: // DRAW some string? x,y,w,h:int
- case 0xA400: // DRAW FILLED CIRCLE
- case 0xA424: // DRAW EMPTY CIRCLE
- case 0xA510: // DRAW SPRITE1
- case 0xA600: // CLEAR SCREEN
- case 0xB600: // DRAW SCREEN
- case 0xC020: // LOAD_SAMPLE
- case 0xC030: // SELECT_SAMPLE
- case 0xC040: // DESELECT_SAMPLE
- case 0xC050: // PLAY_SAMPLE
- case 0xC060: // STOP_SAMPLE
+ //case 0xa100: // DRAW FILLED RECT x1,y1,x2,y2:int
+ case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
+ case 0xa300: // DRAW some string? x,y,w,h:int
+ case 0xa400: // DRAW FILLED CIRCLE
+ case 0xa424: // DRAW EMPTY CIRCLE
+ case 0xa510: // DRAW SPRITE1
+ case 0xa600: // CLEAR SCREEN
+ case 0xb000: // ? (0 args) - found in HoC intro
+ case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
+ case 0xb600: // DRAW SCREEN
+ case 0xc020: // LOAD_SAMPLE
+ case 0xc030: // SELECT_SAMPLE
+ case 0xc040: // DESELECT_SAMPLE
+ case 0xc050: // PLAY_SAMPLE
+ case 0xc060: // STOP_SAMPLE
default:
warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
Commit: 67547e0ed1709832ed63f8cbfe6ede1569966877
https://github.com/scummvm/scummvm/commit/67547e0ed1709832ed63f8cbfe6ede1569966877
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactor TTM opcode handling
- Split opcode handling in a separate function
- Remove the do...while loop: it's never used, as only a single opcode is processed per cycle
- Use copyRectToScreen() to refresh the screen contents
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 63c6ea82b3d..ca3c3872a6e 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -74,6 +74,202 @@ void TTMInterpreter::setActiveDialogue(uint16 num) {
_state.delay += _text->_time * 9; // More correctly, 9 - text-speed-setting
}
+void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval) {
+ Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ switch (op) {
+ case 0x0000:
+ // FINISH: void
+ break;
+ case 0x0020: // SAVE BACKGROUND
+ _vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
+ break;
+ case 0x0080: // DRAW BACKGROUND
+ _vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
+ break;
+ case 0x0110: // PURGE void
+ // .. shouldn't actually clear the bmps, what should it do?
+ _state._currentBmpId = 0;
+ break;
+ case 0x0ff0: {
+ // REFRESH: void
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
+ _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
+ _vm->getTopBuffer().fillRect(bmpArea, 0);
+
+ if (_text) {
+ _text->draw(_vm->_resData.surfacePtr(), 1);
+ _text->draw(_vm->_resData.surfacePtr(), 4);
+ }
+ } break;
+ case 0x1020: // SET DELAY: i:int [0..n]
+ _state.delay += ivals[0] * 10;
+ break;
+ case 0x1030: {
+ // SET BMP: id:int [-1:n]
+ int bk = ivals[0];
+ if (bk != -1) {
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], bk);
+ }
+ break;
+ }
+ case 0x1050:
+ // SELECT BMP: id:int [0:n]
+ _state._currentBmpId = ivals[0];
+ break;
+ case 0x1060:
+ // SELECT PAL: id:int [0]
+ warning("TTM: Switching palette to %d for opcode 0x1060, but we don't use it yet", ivals[0]);
+ _state._currentPalId = ivals[0];
+ break;
+ case 0x1090:
+ // SELECT SONG: id:int [0]
+ break;
+ case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
+ debug("SET SCENE: %u", ivals[0]);
+ break;
+ case 0x1110: { // SHOW SCENE TEXT?: i:int [1..n]
+ // DESCRIPTION IN TTM TAGS.
+ debug("SHOW SCENE TEXT: %u", ivals[0]);
+ _state.scene = ivals[0];
+ setActiveDialogue(_state.scene);
+ break;
+ }
+ case 0x1200: // GOTO
+ debug("GOTO SCENE: %u", ivals[0]);
+ _state.scene = ivals[0];
+ break;
+ case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
+ _state._drawColFG = static_cast<byte>(ivals[0]);
+ _state._drawColBG = static_cast<byte>(ivals[1]);
+ break;
+ case 0x4000:
+ // SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
+ _state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ break;
+ case 0x4110:
+ // FADE OUT: colorno,ncolors,coloffset,speed:byte
+ g_system->delayMillis(_state.delay);
+ _vm->_image->clearPalette();
+ _vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ break;
+ case 0x4120:
+ // FADE IN: colorno,ncolors,coloffset,speed:byte
+ warning("TTM: FADE IN, implement me");
+ _vm->_image->setPalette();
+ break;
+ case 0x4200: {
+ // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
+ const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ _vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
+ break;
+ }
+ case 0xa000: // DRAW PIXEL x,y:int
+ _vm->getTopBuffer().setPixel(ivals[0], ivals[1], _state._drawColFG);
+ break;
+ case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l]
+ // it works like a bitblit, but it doesn't write if there's something already at the destination?
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ _vm->getTopBuffer().copyFrom(_vm->_resData);
+ break;
+ case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
+ _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], _state._drawColFG);
+ break;
+ case 0xa100:
+ // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
+ bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ _vm->getTopBuffer().fillRect(bmpArea, _state._drawColFG);
+ break;
+ case 0xa520:
+ // DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
+ // FALL THROUGH
+ case 0xa530:
+ // CHINA
+ // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
+ // FALL THROUGH
+ case 0xa500:
+ debug("DRAW \"%s\"", _state.bmpNames[_state._currentBmpId].c_str());
+
+ // DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // This is kind of file system intensive, will likely have to change to store all the BMPs.
+ if (count == 4) {
+ int tileId = ivals[2];
+ _state._currentBmpId = ivals[3];
+ if (tileId != -1) {
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], tileId);
+ }
+ } else if (!_vm->_image->isLoaded()) {
+ // load on demand?
+ warning("trying to load bmp %d (%s) on demand", _state._currentBmpId, _state.bmpNames[_state._currentBmpId].c_str());
+ _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], 0);
+ }
+
+ // DRAW BMP: x,y:int [-n,+n] (RISE)
+ if (_vm->_image->isLoaded())
+ _vm->_image->drawBitmap(ivals[0], ivals[1], _state._drawWin, _vm->getTopBuffer());
+ else
+ warning("request to draw null img at %d %d", ivals[0], ivals[1]);
+ break;
+ case 0xf010:
+ // LOAD SCR: filename:str
+ _vm->_image->drawScreen(sval, _vm->getBottomBuffer());
+ break;
+ case 0xf020:
+ // LOAD BMP: filename:str
+ _state.bmpNames[_state._currentBmpId] = sval;
+ break;
+ case 0xf050:
+ // LOAD PAL: filename:str
+ _vm->_image->loadPalette(sval);
+ break;
+ case 0xf060:
+ // LOAD SONG: filename:str
+ if (_vm->_platform == Common::kPlatformAmiga) {
+ _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
+ } else if (_vm->_platform == Common::kPlatformMacintosh) {
+ _vm->_soundPlayer->playMacMusic(sval.c_str());
+ } else {
+ _vm->_soundPlayer->playMusic(sval.c_str());
+ }
+ break;
+
+ // Unimplemented / unknown
+ case 0x0070: // ? (0 args)
+ case 0x0230: // ? (0 args) - found in HoC intro
+ case 0x1100: // ? i:int [9]
+ case 0x1120: // SET_BACKGROUND
+ case 0x1300: // ? (1 args) - found in Dragon + HoC intro
+ case 0x1310: // ? i:int [107]
+ case 0x2010: // SET FRAME
+ case 0x2020: // SET TIMER
+ case 0x4210: // SAVE IMAGE REGION
+ // case 0xa100: // DRAW FILLED RECT x1,y1,x2,y2:int
+ case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
+ case 0xa300: // DRAW some string? x,y,w,h:int
+ case 0xa400: // DRAW FILLED CIRCLE
+ case 0xa424: // DRAW EMPTY CIRCLE
+ case 0xa510: // DRAW SPRITE1
+ case 0xa600: // CLEAR SCREEN
+ case 0xb000: // ? (0 args) - found in HoC intro
+ case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
+ case 0xb600: // DRAW SCREEN
+ case 0xc020: // LOAD_SAMPLE
+ case 0xc030: // SELECT_SAMPLE
+ case 0xc040: // DESELECT_SAMPLE
+ case 0xc050: // PLAY_SAMPLE
+ case 0xc060: // STOP_SAMPLE
+
+ default:
+ warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
+ break;
+ }
+}
+
bool TTMInterpreter::run() {
Common::SeekableReadStream *scr = _scriptData.scr;
if (!scr)
@@ -83,239 +279,42 @@ bool TTMInterpreter::run() {
_state.delay = 0;
- do {
- uint16 code = scr->readUint16LE();
- byte count = code & 0x000F;
- uint op = code & 0xFFF0;
- int16 ivals[8];
- Common::String sval;
-
- if (count > 8 && count != 0x0f)
- error("Invalid TTM opcode %04x requires %d locals", code, count);
-
- debugN("\tOP: 0x%4.4x %2u ", op, count);
- if (count == 0x0F) {
- byte ch[2];
-
- do {
- ch[0] = scr->readByte();
- ch[1] = scr->readByte();
- if (ch[0])
- sval += ch[0];
- if (ch[1])
- sval += ch[1];
- } while (ch[0] != 0 && ch[1] != 0);
-
- debugN("\"%s\"", sval.c_str());
- } else {
- for (byte i = 0; i < count; i++) {
- ivals[i] = scr->readSint16LE();
- if (i > 0)
- debugN(", ");
- debugN("%d", ivals[i]);
- }
- }
- debug(" ");
-
- Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-
- switch (op) {
- case 0x0000:
- // FINISH: void
- break;
- case 0x0020: // SAVE BACKGROUND
- _vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
- continue;
- case 0x0080: // DRAW BACKGROUND
- _vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
- continue;
- case 0x0110: //PURGE void
- // .. shouldn't actually clear the bmps, what should it do?
- _state._currentBmpId = 0;
- continue;
- case 0x0ff0: {
- // REFRESH: void
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
- _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
- _vm->getTopBuffer().fillRect(bmpArea, 0);
-
- if (_text) {
- _text->draw(_vm->_resData.surfacePtr(), 1);
- _text->draw(_vm->_resData.surfacePtr(), 4);
- }
- } break;
- case 0x1020: // SET DELAY: i:int [0..n]
- _state.delay += ivals[0] * 10;
- continue;
- case 0x1030: {
- // SET BMP: id:int [-1:n]
- int bk = ivals[0];
- if (bk != -1) {
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], bk);
- }
- continue;
- }
- case 0x1050:
- // SELECT BMP: id:int [0:n]
- _state._currentBmpId = ivals[0];
- continue;
- case 0x1060:
- // SELECT PAL: id:int [0]
- warning("TTM: Switching palette to %d for opcode 0x1060, but we don't use it yet", ivals[0]);
- _state._currentPalId = ivals[0];
- continue;
- case 0x1090:
- // SELECT SONG: id:int [0]
- continue;
- case 0x10a0: //SET SCENE?: i:int [0..n], often 0, called on scene change?
- debug("SET SCENE: %u", ivals[0]);
- continue;
- case 0x1110: { //SHOW SCENE TEXT?: i:int [1..n]
- // DESCRIPTION IN TTM TAGS.
- debug("SHOW SCENE TEXT: %u", ivals[0]);
- _state.scene = ivals[0];
- setActiveDialogue(_state.scene);
- continue;
- }
- case 0x1200: // GOTO
- debug("GOTO SCENE: %u", ivals[0]);
- _state.scene = ivals[0];
- continue;
- case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
- _state._drawColFG = static_cast<byte>(ivals[0]);
- _state._drawColBG = static_cast<byte>(ivals[1]);
- continue;
- case 0x4000:
- //SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
- _state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
- continue;
- case 0x4110:
- // FADE OUT: colorno,ncolors,coloffset,speed:byte
- g_system->delayMillis(_state.delay);
- _vm->_image->clearPalette();
- _vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- continue;
- case 0x4120:
- // FADE IN: colorno,ncolors,coloffset,speed:byte
- warning("TTM: FADE IN, implement me");
- _vm->_image->setPalette();
- continue;
- case 0x4200: {
- // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
- const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- _vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
- continue;
+ uint16 code = scr->readUint16LE();
+ uint16 op = code & 0xFFF0;
+ byte count = code & 0x000F;
+ int16 ivals[8];
+ Common::String sval;
+
+ if (count > 8 && count != 0x0f)
+ error("Invalid TTM opcode %04x requires %d locals", code, count);
+
+ debugN("\tOP: 0x%4.4x %2u ", op, count);
+ if (count == 0x0F) {
+ byte ch[2];
+
+ do {
+ ch[0] = scr->readByte();
+ ch[1] = scr->readByte();
+ if (ch[0])
+ sval += ch[0];
+ if (ch[1])
+ sval += ch[1];
+ } while (ch[0] != 0 && ch[1] != 0);
+
+ debugN("\"%s\"", sval.c_str());
+ } else {
+ for (byte i = 0; i < count; i++) {
+ ivals[i] = scr->readSint16LE();
+ if (i > 0)
+ debugN(", ");
+ debugN("%d", ivals[i]);
}
- case 0xa000: // DRAW PIXEL x,y:int
- _vm->getTopBuffer().setPixel(ivals[0], ivals[1], _state._drawColFG);
- continue;
- case 0xa050: //SAVE REGION i,j,k,l:int [i<k,j<l]
- // it works like a bitblit, but it doesn't write if there's something already at the destination?
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- _vm->getTopBuffer().copyFrom(_vm->_resData);
- continue;
- case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], _state._drawColFG);
- continue;
- case 0xa100:
- //DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
- bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- _vm->getTopBuffer().fillRect(bmpArea, _state._drawColFG);
- continue;
- case 0xa520:
- // DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
- // FALL THROUGH
- case 0xa530:
- // CHINA
- // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
- // FALL THROUGH
- case 0xa500:
- debug("DRAW \"%s\"", _state.bmpNames[_state._currentBmpId].c_str());
-
- // DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // This is kind of file system intensive, will likely have to change to store all the BMPs.
- if (count == 4) {
- int tileId = ivals[2];
- _state._currentBmpId = ivals[3];
- if (tileId != -1) {
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], tileId);
- }
- } else if (!_vm->_image->isLoaded()) {
- // load on demand?
- warning("trying to load bmp %d (%s) on demand", _state._currentBmpId, _state.bmpNames[_state._currentBmpId].c_str());
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], 0);
- }
-
- // DRAW BMP: x,y:int [-n,+n] (RISE)
- if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], _state._drawWin, _vm->getTopBuffer());
- else
- warning("request to draw null img at %d %d", ivals[0], ivals[1]);
- continue;
- case 0xf010:
- // LOAD SCR: filename:str
- _vm->_image->drawScreen(sval, _vm->getBottomBuffer());
- continue;
- case 0xf020:
- // LOAD BMP: filename:str
- _state.bmpNames[_state._currentBmpId] = sval;
- continue;
- case 0xf050:
- // LOAD PAL: filename:str
- _vm->_image->loadPalette(sval);
- continue;
- case 0xf060:
- // LOAD SONG: filename:str
- if (_vm->_platform == Common::kPlatformAmiga) {
- _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
- } else if (_vm->_platform == Common::kPlatformMacintosh) {
- _vm->_soundPlayer->playMacMusic(sval.c_str());
- } else {
- _vm->_soundPlayer->playMusic(sval.c_str());
- }
- continue;
-
- // Unimplemented / unknown
- case 0x0070: // ? (0 args)
- case 0x0230: // ? (0 args) - found in HoC intro
- case 0x1100: // ? i:int [9]
- case 0x1120: // SET_BACKGROUND
- case 0x1300: // ? (1 args) - found in Dragon + HoC intro
- case 0x1310: // ? i:int [107]
- case 0x2010: // SET FRAME
- case 0x2020: // SET TIMER
- case 0x4210: // SAVE IMAGE REGION
- //case 0xa100: // DRAW FILLED RECT x1,y1,x2,y2:int
- case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
- case 0xa300: // DRAW some string? x,y,w,h:int
- case 0xa400: // DRAW FILLED CIRCLE
- case 0xa424: // DRAW EMPTY CIRCLE
- case 0xa510: // DRAW SPRITE1
- case 0xa600: // CLEAR SCREEN
- case 0xb000: // ? (0 args) - found in HoC intro
- case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
- case 0xb600: // DRAW SCREEN
- case 0xc020: // LOAD_SAMPLE
- case 0xc030: // SELECT_SAMPLE
- case 0xc040: // DESELECT_SAMPLE
- case 0xc050: // PLAY_SAMPLE
- case 0xc060: // STOP_SAMPLE
+ }
+ debug(" ");
- default:
- warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
- continue;
- }
- break;
- } while (scr->pos() < scr->size());
+ handleOperation(op, count, ivals, sval);
- Graphics::Surface *dst = g_system->lockScreen();
- dst->copyRectToSurface(_vm->_resData, 0, 0, Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
- g_system->unlockScreen();
+ g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g_system->updateScreen();
g_system->delayMillis(_state.delay);
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 500940b8526..ca3ad3db8cd 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -82,6 +82,7 @@ public:
protected:
void setActiveDialogue(uint16 num);
+ void handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval);
DgdsEngine *_vm;
Commit: afede5326fa07830447d6ca515a74c4352ec0c9e
https://github.com/scummvm/scummvm/commit/afede5326fa07830447d6ca515a74c4352ec0c9e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactor the ADS script parser, and add stubs for some opcodes
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index ca3c3872a6e..91da4eb76c0 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -362,7 +362,7 @@ void ADSInterpreter::unload() {
_state = ADSState();
}
-bool ADSInterpreter::run() {
+void ADSInterpreter::playScene() {
// This is the main scene player loop, which will run
// after the first time the ADS script is loaded below
// TODO/FIXME: Rewrite this
@@ -373,10 +373,94 @@ bool ADSInterpreter::run() {
_state.subIdx++;
_ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
} else {
- return false;
+ _state.subMax = 0; // continue ADS script execution
}
}
+ }
+}
+
+void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
+ uint16 subIdx, subMax;
+
+ switch (code) {
+ case 0x2005: { // ADD SCENE TO QUEUE
+ subIdx = scr->readUint16LE();
+ subMax = scr->readUint16LE();
+ // TODO: We only add the first scene here, ignoring the rest
+ if (_state.subMax == 0) {
+ _state.scene = subIdx;
+ _state.subIdx = subIdx;
+ _state.subMax = subMax;
+ _ttmInterpreter->load(_scriptData.names[subIdx - 1]);
+ }
+ uint16 unk1 = scr->readUint16LE();
+ uint16 unk2 = scr->readUint16LE();
+ debug("ADSInterpreter add scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", subIdx, subMax, unk1, unk2);
+ break;
+ }
+ case 0x1330: { // IF_NOT_PLAYED, 2 params
+ subIdx = scr->readUint16LE();
+ subMax = scr->readUint16LE();
+ warning("Unimplemented ADS opcode: IF_NOT_PLAYED subIdx: %d, subMax: %d", subIdx, subMax);
+ break;
+ }
+ case 0x1350: { // IF_PLAYED, 2 params
+ subIdx = scr->readUint16LE();
+ subMax = scr->readUint16LE();
+ warning("Unimplemented ADS opcode: IF_PLAYED subIdx: %d, subMax: %d", subIdx, subMax);
+ break;
+ }
+ case 0x1360: { // IF_NOT_RUNNING, 2 params
+ subIdx = scr->readUint16LE();
+ subMax = scr->readUint16LE();
+ warning("Unimplemented ADS opcode: IF_NOT_RUNNING subIdx: %d, subMax: %d", subIdx, subMax);
+ break;
+ }
+ case 0x1370: { // IF_RUNNING, 2 params
+ subIdx = scr->readUint16LE();
+ subMax = scr->readUint16LE();
+ warning("Unimplemented ADS opcode: IF_RUNNING subIdx: %d, subMax: %d", subIdx, subMax);
+ break;
+ }
+ case 0x1510: // PLAY_SCENE, 0 params
+ debug("PLAY SCENE");
+ // TODO
+ break;
+ case 0xffff: // END
+ break;
+
+ //// unknown / to-be-implemented
+ case 0x0190:
+ case 0x1070: // unknown, 2 params
+ case 0x1340:
+ case 0x1420: // AND, 0 params
+ case 0x1430: // OR, 0 params
+ case 0x1500:
+ case 0x1520: // PLAY_SCENE_2, 5 params
+ case 0x2000:
+ case 0x2010: // STOP_SCENE, 3 params
+ case 0x2020:
+ case 0x3010: // RANDOM_START, 0 params
+ case 0x3020: // RANDOM_??, 1 param
+ case 0x30FF: // RANDOM_END, 0 params
+ case 0x4000: // unknown, 3 params
+ case 0x4010:
+ case 0xF010: // FADE_OUT, 0 params
+ case 0xF200: // RUN_SCRIPT, 1 param
+ case 0xFDA8:
+ case 0xFE98:
+ case 0xFF88:
+ case 0xFF10:
+ case 0xFFF0: // END_IF, 0 params
+ default:
+ warning("Unimplemented ADS opcode: 0x%04X", code);
+ break;
+ }
+}
+bool ADSInterpreter::run() {
+ if (_state.subMax > 0) {
+ playScene();
return true;
}
@@ -390,67 +474,13 @@ bool ADSInterpreter::run() {
uint16 code = scr->readUint16LE();
//uint op = code & 0xFFF0;
- if ((code & 0xFF00) == 0) {
- continue;
- }
-
- switch (code) {
- case 0x2005: {
- // ADD SCENE
- _state.subIdx = scr->readUint16LE();
- _state.subMax = scr->readUint16LE();
- uint16 unk1 = scr->readUint16LE();
- uint16 unk2 = scr->readUint16LE();
- _ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
- debug("ADSInterpreter add scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", _state.subIdx, _state.subMax, unk1, unk2);
- return true;
- }
- case 0xFFFF:
- // END
- return false;
-
- case 0x1330: { // IF_NOT_PLAYED, 2 params
- uint16 unk1 = scr->readUint16LE();
- uint16 unk2 = scr->readUint16LE();
- warning("Unimplemented ADS opcode: IF_NOT_PLAYED %02x %02x", unk1, unk2);
+ if ((code & 0xFF00) == 0)
continue;
- }
- //// unknown / to-be-implemented
- case 0x0190:
- case 0x1070: // unknown, 2 params
- case 0x1340:
- case 0x1350: // IF_PLAYED, 2 params
- case 0x1360: // IF_NOT_RUNNING, 2 params
- case 0x1370: // IF_RUNNING, 2 params
- case 0x1420: // AND, 0 params
- case 0x1430: // OR, 0 params
- case 0x1500:
- case 0x1510: // PLAY_SCENE, 0 params
- case 0x1520: // PLAY_SCENE_2, 5 params
- case 0x2000:
- case 0x2010: // STOP_SCENE, 3 params
- case 0x2020:
- case 0x3010: // RANDOM_START, 0 params
- case 0x3020: // RANDOM_??, 1 param
- case 0x30FF: // RANDOM_END, 0 params
- case 0x4000: // unknown, 3 params
- case 0x4010:
- case 0xF010: // FADE_OUT, 0 params
- case 0xF200: // RUN_SCRIPT, 1 param
- case 0xFDA8:
- case 0xFE98:
- case 0xFF88:
- case 0xFF10:
- case 0xFFF0: // END_IF, 0 params
- default:
- warning("Unimplemented ADS opcode: 0x%04X", code);
- continue;
- }
- break;
+ handleOperation(code, scr);
} while (scr->pos() < scr->size());
- return false;
+ return true;
}
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index ca3ad3db8cd..de91a5cbb98 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -101,6 +101,9 @@ public:
bool run();
protected:
+ void handleOperation(uint16 code, Common::SeekableReadStream *scr);
+ void playScene();
+
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
Commit: b3e7422bc008be16114b4d1de9d0496d7fd881f1
https://github.com/scummvm/scummvm/commit/b3e7422bc008be16114b4d1de9d0496d7fd881f1
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement multi-palette management and fades
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index d4ce96bf45a..f7600a00fab 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -162,8 +162,9 @@ bool Console::cmdImageDump(int argc, const char **argv) {
debugPrintf("Image only has %d frames\n", maxframe);
return true;
}
- img.loadPalette("DYNAMIX.PAL");
- img.setPalette();
+ GamePalettes pal(_vm->getResourceManager(), _vm->getDecompressor());
+ pal.loadPalette("DYNAMIX.PAL");
+ pal.setPalette();
img.loadBitmap(fname, frameno);
int width = img.width();
int height = img.height();
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 11487175141..bebe656969f 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -65,7 +65,7 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
- _resource(nullptr) {
+ _resource(nullptr), _gamePals(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -87,6 +87,7 @@ DgdsEngine::~DgdsEngine() {
DebugMan.removeAllDebugChannels();
delete _image;
+ delete _gamePals;
delete _decompressor;
delete _resource;
delete _scene;
@@ -186,6 +187,7 @@ Common::Error DgdsEngine::run() {
_resource = new ResourceManager();
_decompressor = new Decompressor();
_image = new Image(_resource, _decompressor);
+ _gamePals = new GamePalettes(_resource, _decompressor);
_soundPlayer = new Sound(_mixer, _resource, _decompressor);
_scene = new SDSScene();
_gdsScene = new GDSScene();
@@ -212,6 +214,7 @@ Common::Error DgdsEngine::run() {
_fontManager->loadFonts(getGameId(), _resource, _decompressor);
if (getGameId() == GID_DRAGON) {
+ _gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
//debug("%s", _gdsScene->dump("").c_str());
@@ -223,6 +226,7 @@ Common::Error DgdsEngine::run() {
_gdsScene->runStartGameOps();
} else if (getGameId() == GID_CHINA) {
+ _gamePals->loadPalette("HOC.PAL");
_gdsScene->load("HOC.GDS", _resource, _decompressor);
//debug("%s", _gdsScene->dump("").c_str());
@@ -234,6 +238,7 @@ Common::Error DgdsEngine::run() {
_adsInterp->load("TITLE.ADS");
loadCorners("HCORNERS.BMP");
} else if (getGameId() == GID_BEAMISH) {
+ _gamePals->loadPalette("WILLY.PAL");
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
@@ -325,7 +330,7 @@ Common::Error DgdsEngine::run() {
return Common::kNoError;
}
- g_system->delayMillis(40);
+ g_system->delayMillis(10);
}
return Common::kNoError;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index dbd7b82b75a..846c265b1db 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -43,6 +43,7 @@ class Console;
class ResourceManager;
class Decompressor;
class Image;
+class GamePalettes;
class FontManager;
class SDSScene;
class GDSScene;
@@ -83,6 +84,7 @@ private:
GDSScene *_gdsScene;
Menu *_menu;
ADSInterpreter *_adsInterp;
+ GamePalettes *_gamePals;
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
@@ -106,6 +108,7 @@ public:
const FontManager *getFontMan() const { return _fontManager; }
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
void changeScene(int sceneNum);
+ GamePalettes *getGamePals() { return _gamePals; }
DgdsDetailLevel getDetailLevel() const { return kDgdsDetailHigh; }
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index adc3830fb57..7d831492156 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -39,9 +39,89 @@
namespace Dgds {
-Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor) {
+Palette::Palette() {
memset(_palette, 0, 256 * 3);
- memset(_blacks, 0, 256 * 3);
+}
+
+GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor) : _curPalNum(0),
+_resourceMan(resourceMan), _decompressor(decompressor) {
+}
+
+void GamePalettes::loadPalette(Common::String filename) {
+ Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ if (!fileStream) {
+ // Happens in the Amiga version of Dragon
+ warning("Couldn't load palette resource %s", filename.c_str());
+ return;
+ }
+
+ _palettes.resize(_palettes.size() + 1);
+
+ Palette &pal = _palettes.back();
+
+ DgdsChunkReader chunk(fileStream);
+ while (chunk.readNextHeader(EX_PAL, filename)) {
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *chunkStream = chunk.getContent();
+ if (chunk.isSection(ID_VGA)) {
+ chunkStream->read(pal._palette, 256 * 3);
+
+ for (uint k = 0; k < 256 * 3; k += 3) {
+ pal._palette[k + 0] <<= 2;
+ pal._palette[k + 1] <<= 2;
+ pal._palette[k + 2] <<= 2;
+ }
+ }
+ }
+
+ delete fileStream;
+
+ selectPalNum(0);
+}
+
+void GamePalettes::selectPalNum(int num) {
+ _curPalNum = num;
+ setPalette();
+}
+
+void GamePalettes::setPalette() {
+ if (_curPalNum >= _palettes.size())
+ error("request to set pal %d but only have %d pals", _curPalNum, _palettes.size());
+
+ _curPal = _palettes[_palettes.size() - _curPalNum - 1];
+ g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
+}
+
+void GamePalettes::clearPalette() {
+ _curPal = _blacks;
+ g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
+}
+
+void GamePalettes::setFade(int col, int ncols, int coloff, int fade) {
+ if (coloff)
+ warning("TODO: Handle non-zero coloff in GamePalettes::setFade");
+
+ if (_curPalNum >= _palettes.size())
+ error("GamePalettes::setFade: invalid curPalNum %d, only have %d pals", _curPalNum, _palettes.size());
+
+ if (col + ncols > 256)
+ error("GamePalettes::setFade: request to fade past the end of the palette");
+
+ Palette &pal = _palettes[_palettes.size() - _curPalNum - 1];
+
+ for (int c = col; c < col + ncols; c++) {
+ byte r = pal._palette[c * 3 + 0];
+ byte g = pal._palette[c * 3 + 1];
+ byte b = pal._palette[c * 3 + 2];
+
+ _curPal._palette[c * 3 + 0] = r - (r * fade) / 255;
+ _curPal._palette[c * 3 + 1] = g - (g * fade) / 255;
+ _curPal._palette[c * 3 + 2] = b - (b * fade) / 255;
+ }
+ g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
+}
+
+Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor) {
}
Image::~Image() {
@@ -474,41 +554,6 @@ bool Image::loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::Seeka
return !stream->err();
}
-void Image::loadPalette(Common::String filename) {
- Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
- if (!fileStream) {
- // Happens in the Amiga version of Dragon
- warning("Couldn't load palette resource %s", filename.c_str());
- return;
- }
-
-
- DgdsChunkReader chunk(fileStream);
- while (chunk.readNextHeader(EX_PAL, filename)) {
- chunk.readContent(_decompressor);
- Common::SeekableReadStream *chunkStream = chunk.getContent();
- if (chunk.isSection(ID_VGA)) {
- chunkStream->read(_palette, 256 * 3);
-
- for (uint k = 0; k < 256 * 3; k += 3) {
- _palette[k + 0] <<= 2;
- _palette[k + 1] <<= 2;
- _palette[k + 2] <<= 2;
- }
- }
- }
-
- delete fileStream;
-}
-
-void Image::setPalette() {
- g_system->getPaletteManager()->setPalette(_palette, 0, 256);
-}
-
-void Image::clearPalette() {
- g_system->getPaletteManager()->setPalette(_blacks, 0, 256);
-}
-
int16 Image::width() const {
return _bmpData.w;
}
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index fc4a3da2bc3..98383c0995b 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -37,6 +37,34 @@ class Decompressor;
class DgdsChunkReader;
class ResourceManager;
+class Palette {
+public:
+ Palette();
+ byte _palette[256 * 3];
+};
+
+class GamePalettes {
+public:
+ GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor);
+ void loadPalette(Common::String filename);
+ void selectPalNum(int num);
+ void setPalette();
+ void clearPalette();
+
+ // Fade the colors in the current palette toward black. Start at col, and fade ncols of the palette.
+ // Add coloff to the result to move toward white.
+ void setFade(int col, int ncols, int coloff, int fade);
+
+private:
+ ResourceManager *_resourceMan;
+ Decompressor *_decompressor;
+
+ Palette _curPal;
+ uint _curPalNum;
+ Common::Array<Palette> _palettes;
+ Palette _blacks;
+};
+
class Image {
public:
Image(ResourceManager *resourceMan, Decompressor *decompressor);
@@ -47,9 +75,6 @@ public:
int frameCount(const Common::String &filename);
void drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surface &surface);
- void loadPalette(Common::String filename);
- void setPalette();
- void clearPalette();
bool isLoaded() const { return _bmpData.getPixels() != nullptr; }
int16 width() const;
int16 height() const;
@@ -65,9 +90,6 @@ private:
Graphics::Surface _bmpData;
ResourceManager *_resourceMan;
Decompressor *_decompressor;
-
- byte _palette[256 * 3];
- byte _blacks[256 * 3];
};
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 91da4eb76c0..46d201f1ed0 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -48,7 +48,7 @@ bool TTMInterpreter::load(const Common::String &filename) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
bool parseResult = dgds.parse(&_scriptData, filename);
- _state.delay = 0;
+ _state._delay = 0;
_state.scene = 0;
_scriptData.scr->seek(0);
@@ -71,7 +71,12 @@ void TTMInterpreter::setActiveDialogue(uint16 num) {
_text = &dialogue;
}
if (_text && !_text->_str.empty())
- _state.delay += _text->_time * 9; // More correctly, 9 - text-speed-setting
+ _state._delay += _text->_time * 9; // More correctly, 9 - text-speed-setting
+}
+
+void TTMInterpreter::updateScreen() {
+ g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ g_system->updateScreen();
}
void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval) {
@@ -104,7 +109,8 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
}
} break;
case 0x1020: // SET DELAY: i:int [0..n]
- _state.delay += ivals[0] * 10;
+ _state._delay += ivals[0] * 10;
+ _state._delayStart = g_system->getMillis();
break;
case 0x1030: {
// SET BMP: id:int [-1:n]
@@ -120,8 +126,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
case 0x1060:
// SELECT PAL: id:int [0]
- warning("TTM: Switching palette to %d for opcode 0x1060, but we don't use it yet", ivals[0]);
- _state._currentPalId = ivals[0];
+ _vm->getGamePals()->selectPalNum(ivals[0]);
break;
case 0x1090:
// SELECT SONG: id:int [0]
@@ -150,14 +155,32 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
case 0x4110:
// FADE OUT: colorno,ncolors,coloffset,speed:byte
- g_system->delayMillis(_state.delay);
- _vm->_image->clearPalette();
+ if (ivals[3] == 0) {
+ _vm->getGamePals()->clearPalette();
+ } else {
+ // The original tight-loops here with 640 steps and i/10 as the fade level..
+ // bring that down a bit to use less cpu.
+ for (int i = 0; i < 320; i += ivals[3]) {
+ int fade = MIN(i / 5, 63);
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2] * 4, fade * 4);
+ updateScreen();
+ g_system->delayMillis(5);
+ }
+ }
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x4120:
// FADE IN: colorno,ncolors,coloffset,speed:byte
- warning("TTM: FADE IN, implement me");
- _vm->_image->setPalette();
+ if (ivals[3] == 0) {
+ _vm->getGamePals()->setPalette();
+ } else {
+ for (int i = 320; i != 0; i -= ivals[3]) {
+ int fade = MIN(i / 5, 63);
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2] * 4, fade * 4);
+ updateScreen();
+ g_system->delayMillis(5);
+ }
+ }
break;
case 0x4200: {
// STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
@@ -184,6 +207,13 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
_vm->getTopBuffer().fillRect(bmpArea, _state._drawColFG);
break;
+ case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
+ bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, _state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, _state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, _state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, _state._drawColFG);
+ break;
case 0xa520:
// DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
// FALL THROUGH
@@ -225,7 +255,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
case 0xf050:
// LOAD PAL: filename:str
- _vm->_image->loadPalette(sval);
+ _vm->getGamePals()->loadPalette(sval);
break;
case 0xf060:
// LOAD SONG: filename:str
@@ -249,7 +279,6 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
case 0x2020: // SET TIMER
case 0x4210: // SAVE IMAGE REGION
// case 0xa100: // DRAW FILLED RECT x1,y1,x2,y2:int
- case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
case 0xa300: // DRAW some string? x,y,w,h:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa424: // DRAW EMPTY CIRCLE
@@ -277,7 +306,11 @@ bool TTMInterpreter::run() {
if (scr->pos() >= scr->size())
return false;
- _state.delay = 0;
+ if (_state._delayStart + _state._delay > g_system->getMillis()) {
+ return true;
+ }
+ _state._delay = 0;
+ _state._delayStart = 0;
uint16 code = scr->readUint16LE();
uint16 op = code & 0xFFF0;
@@ -313,10 +346,7 @@ bool TTMInterpreter::run() {
debug(" ");
handleOperation(op, count, ivals, sval);
-
- g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- g_system->updateScreen();
- g_system->delayMillis(_state.delay);
+ updateScreen();
return true;
}
@@ -383,6 +413,10 @@ void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
uint16 subIdx, subMax;
switch (code) {
+ case 0x0001:
+ case 0x0005:
+ // Seems to be "enter" or "label", does nothing. 0x0005 can be used for searching..
+ break;
case 0x2005: { // ADD SCENE TO QUEUE
subIdx = scr->readUint16LE();
subMax = scr->readUint16LE();
@@ -452,10 +486,14 @@ void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xFF88:
case 0xFF10:
case 0xFFF0: // END_IF, 0 params
- default:
- warning("Unimplemented ADS opcode: 0x%04X", code);
+ default: {
+ int nops = numArgs(code);
+ warning("Unimplemented ADS opcode: 0x%04X (skip %d args)", code, nops);
+ for (int i = 0; i < nops; i++)
+ scr->readUint16LE();
break;
}
+ }
}
bool ADSInterpreter::run() {
@@ -472,15 +510,53 @@ bool ADSInterpreter::run() {
do {
uint16 code = scr->readUint16LE();
- //uint op = code & 0xFFF0;
-
- if ((code & 0xFF00) == 0)
- continue;
-
handleOperation(code, scr);
} while (scr->pos() < scr->size());
return true;
}
+int ADSInterpreter::numArgs(uint16 opcode) const {
+ // TODO: This list is from DRAGON, there may be more entries in newer games.
+ switch (opcode) {
+ case 0x1080:
+ case 0x3020:
+ case 0xF010:
+ case 0xF200:
+ case 0xF210:
+ return 1;
+
+ case 0x1010:
+ case 0x1020:
+ case 0x1030:
+ case 0x1040:
+ case 0x1050:
+ case 0x1060:
+ case 0x1070:
+ case 0x1310:
+ case 0x1320:
+ case 0x1330:
+ case 0x1340:
+ case 0x1350:
+ case 0x1360:
+ case 0x1370:
+ return 2;
+
+ case 0x2010:
+ case 0x2015:
+ case 0x2020:
+ case 0x4000:
+ case 0x4010:
+ return 3;
+
+ case 0x2000:
+ case 0x2005:
+ return 4;
+
+ default:
+ return 0;
+ }
+}
+
+
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index de91a5cbb98..3eb687c43f5 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -47,9 +47,10 @@ public:
};
struct TTMState {
- TTMState() : scene(0), delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0), _currentPalId(0), _drawColFG(0), _drawColBG(0) {}
+ TTMState() : scene(0), _delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0), _currentPalId(0), _drawColFG(0), _drawColBG(0), _delayStart(0) {}
uint16 scene;
- int delay;
+ int _delay;
+ uint32 _delayStart;
Common::Rect _drawWin;
int _currentBmpId;
int _currentPalId;
@@ -83,6 +84,7 @@ public:
protected:
void setActiveDialogue(uint16 num);
void handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval);
+ void updateScreen();
DgdsEngine *_vm;
@@ -99,6 +101,7 @@ public:
bool load(const Common::String &filename);
void unload();
bool run();
+ int numArgs(uint16 opcode) const;
protected:
void handleOperation(uint16 code, Common::SeekableReadStream *scr);
Commit: 8ea13cb86c56e5029c09a1344d73f0ea694335eb
https://github.com/scummvm/scummvm/commit/8ea13cb86c56e5029c09a1344d73f0ea694335eb
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix fades a bit - still not quite right.
Changed paths:
engines/dgds/image.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 7d831492156..23a1d7e57c9 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -97,10 +97,7 @@ void GamePalettes::clearPalette() {
g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
}
-void GamePalettes::setFade(int col, int ncols, int coloff, int fade) {
- if (coloff)
- warning("TODO: Handle non-zero coloff in GamePalettes::setFade");
-
+void GamePalettes::setFade(int col, int ncols, int targetcol, int fade) {
if (_curPalNum >= _palettes.size())
error("GamePalettes::setFade: invalid curPalNum %d, only have %d pals", _curPalNum, _palettes.size());
@@ -109,14 +106,18 @@ void GamePalettes::setFade(int col, int ncols, int coloff, int fade) {
Palette &pal = _palettes[_palettes.size() - _curPalNum - 1];
+ byte r2 = pal._palette[targetcol * 3 + 0];
+ byte g2 = pal._palette[targetcol * 3 + 1];
+ byte b2 = pal._palette[targetcol * 3 + 2];
+
for (int c = col; c < col + ncols; c++) {
byte r = pal._palette[c * 3 + 0];
byte g = pal._palette[c * 3 + 1];
byte b = pal._palette[c * 3 + 2];
- _curPal._palette[c * 3 + 0] = r - (r * fade) / 255;
- _curPal._palette[c * 3 + 1] = g - (g * fade) / 255;
- _curPal._palette[c * 3 + 2] = b - (b * fade) / 255;
+ _curPal._palette[c * 3 + 0] = r2 * fade / 255 + r * (255 - fade) / 255;
+ _curPal._palette[c * 3 + 1] = g2 * fade / 255 + g * (255 - fade) / 255;
+ _curPal._palette[c * 3 + 2] = b2 * fade / 255 + b * (255 - fade) / 255;
}
g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
}
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 46d201f1ed0..8aa1bd95f2c 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -154,7 +154,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
_state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
case 0x4110:
- // FADE OUT: colorno,ncolors,coloffset,speed:byte
+ // FADE OUT: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->clearPalette();
} else {
@@ -162,7 +162,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
// bring that down a bit to use less cpu.
for (int i = 0; i < 320; i += ivals[3]) {
int fade = MIN(i / 5, 63);
- _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2] * 4, fade * 4);
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
updateScreen();
g_system->delayMillis(5);
}
@@ -170,13 +170,13 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x4120:
- // FADE IN: colorno,ncolors,coloffset,speed:byte
+ // FADE IN: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
} else {
- for (int i = 320; i != 0; i -= ivals[3]) {
- int fade = MIN(i / 5, 63);
- _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2] * 4, fade * 4);
+ for (int i = 320; i > 0; i -= ivals[3]) {
+ int fade = MAX(0, MIN(i / 5, 63));
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
updateScreen();
g_system->delayMillis(5);
}
@@ -270,20 +270,21 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
// Unimplemented / unknown
case 0x0070: // ? (0 args)
- case 0x0230: // ? (0 args) - found in HoC intro
+ case 0x0220: // STOP CURRENT MUSIC
+ case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1100: // ? i:int [9]
case 0x1120: // SET_BACKGROUND
- case 0x1300: // ? (1 args) - found in Dragon + HoC intro
- case 0x1310: // ? i:int [107]
+ case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
+ case 0x1310: // STOP SFX i:int eg [107]
case 0x2010: // SET FRAME
case 0x2020: // SET TIMER
case 0x4210: // SAVE IMAGE REGION
- // case 0xa100: // DRAW FILLED RECT x1,y1,x2,y2:int
case 0xa300: // DRAW some string? x,y,w,h:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa424: // DRAW EMPTY CIRCLE
case 0xa510: // DRAW SPRITE1
case 0xa600: // CLEAR SCREEN
+ // From here on are not implemented in DRAGON
case 0xb000: // ? (0 args) - found in HoC intro
case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
case 0xb600: // DRAW SCREEN
Commit: 7f0a1aad5ac6a28a57f4db725dc8776b7d9fc6da
https://github.com/scummvm/scummvm/commit/7f0a1aad5ac6a28a57f4db725dc8776b7d9fc6da
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Control dialogues more like the original.
This actually breaks quite a bit of dialog stuff, but it's a necessary step to
get there.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index bebe656969f..c2641590b8a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -330,7 +330,9 @@ Common::Error DgdsEngine::run() {
return Common::kNoError;
}
+ g_system->updateScreen();
g_system->delayMillis(10);
+
}
return Common::kNoError;
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index ea916dbd2d3..e445b181b53 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -24,6 +24,7 @@
#include "common/endian.h"
#include "common/file.h"
#include "common/rect.h"
+#include "common/system.h"
#include "graphics/surface.h"
#include "graphics/primitives.h"
@@ -56,8 +57,8 @@ Common::String Rect::dump(const Common::String &indent) const {
}
-Common::String SceneStruct1::dump(const Common::String &indent) const {
- return Common::String::format("%sSceneStruct1<%d flg 0x%02x %d>", indent.c_str(), _num, _flags, _val);
+Common::String SceneConditions::dump(const Common::String &indent) const {
+ return Common::String::format("%sSceneCondition<%d flg 0x%02x %d>", indent.c_str(), _num, _flags, _val);
}
@@ -79,6 +80,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpNone: return "none";
case kSceneOpChangeScene: return "changeScene";
case kSceneOpNoop: return "noop";
+ case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpMeanwhile: return "meanwhile";
default:
@@ -98,8 +100,8 @@ Common::String SceneOp::dump(const Common::String &indent) const {
}
Common::String str = Common::String::format("%sSceneOp<op: %s args: %s", indent.c_str(), _sceneOpCodeName(_opCode).c_str(), argsStr.c_str());
- str += _dumpStructList(indent, "struct1list", struct1List);
- if (!struct1List.empty()) {
+ str += _dumpStructList(indent, "conditionList", _conditionList);
+ if (!_conditionList.empty()) {
str += "\n";
str += indent;
}
@@ -139,7 +141,7 @@ Common::String SceneStruct4::dump(const Common::String &indent) const {
Common::String SceneTrigger::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSceneTrigger<num %d %s", indent.c_str(), _num, _enabled ? "enabled" : "disabled");
- str += _dumpStructList(indent, "struct1list", struct1List);
+ str += _dumpStructList(indent, "struct1list", conditionList);
str += _dumpStructList(indent, "opList", sceneOpList);
str += "\n";
str += indent + ">";
@@ -147,6 +149,12 @@ Common::String SceneTrigger::dump(const Common::String &indent) const {
}
+Dialogue::Dialogue() : _num(0), _bgColor(0), _fontColor(0), _field7_0xe(0), _field8_0x10(0),
+ _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
+ _field15_0x22(0), _field18_0x28(0), _hideTime(0)
+{}
+
+
void Dialogue::draw(Graphics::Surface *dst, int stage) {
switch (_frameType) {
case kDlgFramePlain: return drawType1(dst, stage);
@@ -175,21 +183,14 @@ void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
int h = _rect.height;
if (stage == 1) {
- // TODO: Is this right?
dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
- /*
- int uVar1 = _field15_0x22;
- *(int *)(uVar1 + 2) = x + 3;
- *(int *)(uVar1 + 4) = y + 3;
- *(int *)(uVar1 + 6) = width + -6;
- *(int *)(uVar1 + 8) = height + -6; */
} else if (stage == 2) {
drawStage2(dst);
} else if (stage == 3) {
drawStage3(dst);
} else {
- _textDrawRect = Common::Rect(x + 2, y + 2, x + w - 2, y + h - 2);
+ _textDrawRect = Common::Rect(x + 3, y + 3, x + w - 3, y + h - 3);
drawStage4(dst, _bgColor, _str);
}
}
@@ -409,6 +410,18 @@ void Dialogue::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::
}
+void Dialogue::addFlag(DialogueFlags flg) {
+ _flags = static_cast<DialogueFlags>(_flags | flg);
+}
+
+void Dialogue::clearFlag(DialogueFlags flg) {
+ _flags = static_cast<DialogueFlags>(_flags & ~flg);
+}
+
+bool Dialogue::hasFlag(DialogueFlags flg) const {
+ return _flags & flg;
+}
+
Common::String Dialogue::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
"%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d",
@@ -445,9 +458,9 @@ bool Scene::isVersionUnder(const char *version) const {
}
-bool Scene::readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const {
+bool Scene::readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct1 &dst : list) {
+ for (SceneConditions &dst : list) {
dst._num = s->readUint16LE();
dst._flags = static_cast<SceneCondition>(s->readUint16LE());
dst._val = s->readUint16LE();
@@ -463,7 +476,7 @@ bool Scene::readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const
dst.rect.height = s->readUint16LE();
dst.field1_0x8 = s->readUint16LE();
dst.field2_0xa = s->readUint16LE();
- readStruct1List(s, dst.struct1List);
+ readConditionList(s, dst.struct1List);
readOpList(s, dst.opList1);
readOpList(s, dst.opList2);
readOpList(s, dst.opList3);
@@ -532,7 +545,7 @@ bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneSt
bool Scene::readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const {
list.resize(s->readUint16LE());
for (SceneOp &dst : list) {
- readStruct1List(s, dst.struct1List);
+ readConditionList(s, dst._conditionList);
dst._opCode = static_cast<SceneOpCode>(s->readUint16LE());
int nvals = s->readUint16LE();
for (int i = 0; i < nvals / 2; i++) {
@@ -605,7 +618,7 @@ bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTr
for (SceneTrigger &dst : list) {
dst._num = s->readUint16LE();
dst._enabled = false;
- readStruct1List(s, dst.struct1List);
+ readConditionList(s, dst.conditionList);
readOpList(s, dst.sceneOpList);
}
@@ -646,6 +659,9 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
break;
case kSceneOpNoop:
break;
+ case kSceneOpShowDlg:
+ showDialog(op._args[0]);
+ break;
case kSceneOpEnableTrigger:
enableTrigger(op._args[0]);
break;
@@ -659,15 +675,48 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
}
}
-bool Scene::checkConditions(const Common::Array<struct SceneStruct1> &conds) {
+bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds) {
+ if (conds.empty())
+ return true;
+ uint truecount = 0;
for (const auto & c : conds) {
- if (c._flags & kSceneCondAlwaysTrue)
+ uint16 refval = c._val;
+ uint16 checkval;
+ SceneCondition cflag = c._flags;
+ if (cflag & kSceneCondAlwaysTrue)
return true;
- // TODO: Finish this.
- // 0x80 seems to check some value set
- return false;
+
+ if (cflag & kSceneCond80) {
+ refval = 1;
+ // TODO: check something about current ADS script?
+ checkval = 0;
+
+ SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
+ if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
+ refval = 0;
+ } else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemField12) {
+ // TODO: Get game object c._num and check value from object table
+ checkval = 0;
+ } else {
+ // TODO: Check something about current SDS scene??
+ checkval = 0;
+ }
+
+ bool result = false;
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCond80 | kSceneCondNeedItemField12 | kSceneCondNeedItemField14));
+ if (cflag == kSceneCondNone)
+ cflag = static_cast<SceneCondition>(kSceneCondEqual | kSceneCondNegate);
+ if ((cflag & kSceneCondLessThan) && checkval < refval)
+ result = true;
+ if ((cflag & kSceneCondEqual) && checkval == refval)
+ result = true;
+ if (cflag & kSceneCondNegate)
+ result = !result;
+
+ if (result)
+ truecount++;
}
- return true;
+ return truecount == conds.size();
}
@@ -723,7 +772,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
if (isVersionOver(" 1.205")) {
readStruct4List(stream, _struct4List2);
}
- readDialogueList(stream, _dialogues);
+ readDialogueList(stream, _dialogs);
if (isVersionOver(" 1.203")) {
readTriggerList(stream, _triggers);
}
@@ -742,7 +791,7 @@ void SDSScene::unload() {
_struct2List.clear();
_struct4List1.clear();
_struct4List2.clear();
- _dialogues.clear();
+ _dialogs.clear();
_triggers.clear();
}
@@ -756,7 +805,7 @@ Common::String SDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "struct2List", _struct2List);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
- str += _dumpStructList(indent, "dialogues", _dialogues);
+ str += _dumpStructList(indent, "dialogues", _dialogs);
str += _dumpStructList(indent, "triggers", _triggers);
str += "\n";
@@ -772,7 +821,7 @@ void SDSScene::checkTriggers() {
if (!trigger._enabled)
continue;
- if (!checkConditions(trigger.struct1List))
+ if (!checkConditions(trigger.conditionList))
continue;
runOps(trigger.sceneOpList);
@@ -785,6 +834,51 @@ void SDSScene::checkTriggers() {
}
}
+void SDSScene::showDialog(uint16 num) {
+ for (auto &dialog : _dialogs) {
+ if (dialog._num == num) {
+ dialog.addFlag(kDlgFlagVisible);
+ // hide time gets set the first time it's drawn.
+ }
+ }
+}
+
+bool SDSScene::checkDialogActive() {
+ uint32 timeNow = g_system->getMillis();
+ bool retval = false;
+ for (auto &dialog : _dialogs) {
+ if (dialog.hasFlag(kDlgFlagVisible)) {
+ if (dialog._hideTime > 0 && dialog._hideTime < timeNow) {
+ dialog.clearFlag(kDlgFlagVisible);
+ dialog._hideTime = 0;
+ if (dialog._nextDialogNum) {
+ showDialog(dialog._nextDialogNum);
+ retval = true;
+ }
+ } else {
+ retval = true;
+ }
+ }
+ }
+ return retval;
+}
+
+bool SDSScene::drawActiveDialog(Graphics::Surface *dst, int mode) {
+ bool retval = false;
+ for (auto &dialog : _dialogs) {
+ if (dialog.hasFlag(kDlgFlagVisible)) {
+ if (dialog._hideTime == 0 && dialog._time > 0) {
+ // TOOD: This should be (9 - text-speed-slider-setting)
+ dialog._hideTime = g_system->getMillis() + dialog._time * 9;
+ }
+ dialog.draw(dst, mode);
+ retval = true;
+ }
+ }
+ return retval;
+}
+
+
GDSScene::GDSScene() {
}
@@ -834,11 +928,11 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _opList4);
if (isVersionOver(" 1.208"))
readOpList(stream, _opList5);
- Common::Array<struct SceneStruct1> struct1List;
- readStruct1List(stream, struct1List);
- Common::Array<struct MouseCursor> struct3List;
+ Common::Array<struct SceneConditions> conditionList;
+ readConditionList(stream, conditionList);
+ Common::Array<struct MouseCursor> cursorList;
_iconFile = stream->readString();
- readMouseHotspotList(stream, struct3List);
+ readMouseHotspotList(stream, cursorList);
readGameItemList(stream, _gameItems);
readStruct4List(stream, _struct4List2);
if (isVersionOver(" 1.205"))
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 646de6429f0..4111040e42d 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -40,16 +40,17 @@ struct Rect {
enum SceneCondition {
kSceneCondNone = 0,
- kSceneCond1 = 1,
- kSceneCond2 = 2,
- kSceneCond4 = 4,
+ kSceneCondLessThan = 1,
+ kSceneCondEqual = 2,
+ kSceneCondNegate = 4,
+ kSceneCondSceneAbsVal = 8,
kSceneCondAlwaysTrue = 0x10,
- kSceneCond20 = 0x20,
+ kSceneCondNeedItemField14 = 0x20,
kSceneCondNeedItemField12 = 0x40,
kSceneCond80 = 0x80
};
-struct SceneStruct1 {
+struct SceneConditions {
uint16 _num;
SceneCondition _flags; /* eg, see usage in FUN_1f1a_2106 */
uint16 _val;
@@ -61,7 +62,7 @@ struct SceneStruct2 {
struct Rect rect;
uint16 field1_0x8;
uint16 field2_0xa;
- Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneConditions> struct1List;
Common::Array<struct SceneOp> opList1;
Common::Array<struct SceneOp> opList2;
Common::Array<struct SceneOp> opList3;
@@ -78,7 +79,7 @@ enum SceneOpCode {
kSceneOp5 = 5, // args: [item num, ??, ??]. give item?
kSceneOp6 = 6, // args: item num?
kSceneOp7 = 7, // args: none.
- kSceneOp8 = 8, // args: dialogue number. show dialogue?
+ kSceneOpShowDlg = 8, // args: dialogue number. show dialogue?
kSceneOp9 = 9, // args: none.
kSceneOp10 = 10, // args: none. Looks through the struct2 list for something.
kSceneOpEnableTrigger = 11, // args: trigger num
@@ -102,7 +103,7 @@ enum SceneOpCode {
};
struct SceneOp {
- Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneConditions> _conditionList;
Common::Array<uint16> _args;
SceneOpCode _opCode;
@@ -142,6 +143,7 @@ enum DialogueFlags {
kDlgFlagNone = 0,
kDlgFlagFlatBg = 1,
kDlgFlagLeftJust = 2,
+ kDlgFlagVisible = 0x8000,
};
enum DialogueFrameType {
@@ -153,6 +155,7 @@ enum DialogueFrameType {
class Dialogue {
public:
+ Dialogue();
uint16 _num;
Rect _rect;
uint16 _bgColor;
@@ -168,8 +171,13 @@ public:
uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
+
+ uint _hideTime;
void draw(Graphics::Surface *dst, int mode);
+ void addFlag(DialogueFlags flg);
+ void clearFlag(DialogueFlags flg);
+ bool hasFlag(DialogueFlags flg) const;
Common::String dump(const Common::String &indent) const;
@@ -189,7 +197,7 @@ private:
struct SceneTrigger {
uint16 _num;
bool _enabled;
- Common::Array<struct SceneStruct1> struct1List;
+ Common::Array<struct SceneConditions> conditionList;
Common::Array<struct SceneOp> sceneOpList;
Common::String dump(const Common::String &indent) const;
@@ -225,7 +233,7 @@ public:
const Common::String &getVersion() const { return _version; }
protected:
- bool readStruct1List(Common::SeekableReadStream *s, Common::Array<SceneStruct1> &list) const;
+ bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const;
bool readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
@@ -237,9 +245,10 @@ protected:
bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
void runOps(const Common::Array<SceneOp> &ops);
- bool checkConditions(const Common::Array<struct SceneStruct1> &cond);
+ bool checkConditions(const Common::Array<struct SceneConditions> &cond);
- virtual void enableTrigger(uint16 num) {};
+ virtual void enableTrigger(uint16 num) {}
+ virtual void showDialog(uint16 num) {}
uint32 _magic;
Common::String _version;
@@ -283,7 +292,6 @@ public:
bool parse(Common::SeekableReadStream *s) override;
void unload();
- Common::Array<class Dialogue> &getLines() { return _dialogues; }
const Common::String &getAdsFile() const { return _adsFile; }
void runEnterSceneOps() { runOps(_enterSceneOps); }
void runLeaveSceneOps() { runOps(_leaveSceneOps); }
@@ -292,8 +300,12 @@ public:
int getNum() const { return _num; }
Common::String dump(const Common::String &indent) const;
+ bool checkDialogActive();
+ bool drawActiveDialog(Graphics::Surface *dst, int mode);
+
private:
void enableTrigger(uint16 num) override;
+ void showDialog(uint16 num) override;
int _num;
Common::Array<struct SceneOp> _enterSceneOps;
@@ -308,7 +320,7 @@ private:
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
//uint _field12_0x2b;
- Common::Array<class Dialogue> _dialogues;
+ Common::Array<class Dialogue> _dialogs;
Common::Array<struct SceneTrigger> _triggers;
//uint _field15_0x33;
};
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 8aa1bd95f2c..9ab570462e9 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -42,7 +42,7 @@
namespace Dgds {
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _text(nullptr) {}
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
bool TTMInterpreter::load(const Common::String &filename) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
@@ -60,22 +60,16 @@ void TTMInterpreter::unload() {
_scriptData.scr = nullptr;
}
-void TTMInterpreter::setActiveDialogue(uint16 num) {
- Common::Array<Dialogue> &dialogues = _vm->getScene()->getLines();
- _text = nullptr;
- for (Dialogue &dialogue: dialogues) {
- if (dialogue._num == num)
- _text = &dialogue;
- // HACK to get Dragon intro working
- if (!_text && dialogue._num == num + 14)
- _text = &dialogue;
- }
- if (_text && !_text->_str.empty())
- _state._delay += _text->_time * 9; // More correctly, 9 - text-speed-setting
-}
-
void TTMInterpreter::updateScreen() {
g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ if (_state._setupFinished && _vm->getScene()->checkDialogActive()) {
+ Graphics::Surface *screen = g_system->lockScreen();
+ _vm->getScene()->drawActiveDialog(screen, 1);
+ _vm->getScene()->drawActiveDialog(screen, 4);
+ g_system->unlockScreen();
+ }
+
g_system->updateScreen();
}
@@ -102,11 +96,6 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
_vm->getTopBuffer().fillRect(bmpArea, 0);
-
- if (_text) {
- _text->draw(_vm->_resData.surfacePtr(), 1);
- _text->draw(_vm->_resData.surfacePtr(), 4);
- }
} break;
case 0x1020: // SET DELAY: i:int [0..n]
_state._delay += ivals[0] * 10;
@@ -132,16 +121,17 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
// SELECT SONG: id:int [0]
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
- debug("SET SCENE: %u", ivals[0]);
+ debug("SCENE SETUP DONE: %u", ivals[0]);
+ _state._setupFinished = true;
break;
- case 0x1110: { // SHOW SCENE TEXT?: i:int [1..n]
+ case 0x1110: { // SET_SCENE: i:int [1..n]
// DESCRIPTION IN TTM TAGS.
- debug("SHOW SCENE TEXT: %u", ivals[0]);
+ debug("SET SCENE: %u", ivals[0]);
_state.scene = ivals[0];
- setActiveDialogue(_state.scene);
+ _state._setupFinished = false;
break;
}
- case 0x1200: // GOTO
+ case 0x1200: // GOTO? How different to SET SCENE??
debug("GOTO SCENE: %u", ivals[0]);
_state.scene = ivals[0];
break;
@@ -169,7 +159,14 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
}
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
- case 0x4120:
+ case 0x4120: {
+ // blt first?
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
+ _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
+ _vm->getTopBuffer().fillRect(bmpArea, 0);
+
+
// FADE IN: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -182,6 +179,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
}
}
break;
+ }
case 0x4200: {
// STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
@@ -272,6 +270,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
case 0x0070: // ? (0 args)
case 0x0220: // STOP CURRENT MUSIC
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
+ case 0x1070: // SELECT FONT i:int
case 0x1100: // ? i:int [9]
case 0x1120: // SET_BACKGROUND
case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
@@ -347,6 +346,7 @@ bool TTMInterpreter::run() {
debug(" ");
handleOperation(op, count, ivals, sval);
+
updateScreen();
return true;
@@ -383,6 +383,8 @@ bool ADSInterpreter::load(const Common::String &filename) {
_scriptData.scr->seek(0);
_scriptData.filename = filename;
+ _state._subsPlayed.resize(_scriptData.names.size());
+ _state._subsRunning.resize(_scriptData.names.size());
return true;
}
@@ -399,10 +401,13 @@ void ADSInterpreter::playScene() {
// TODO/FIXME: Rewrite this
if (_state.subMax != 0) {
if (!_ttmInterpreter->run()) {
+ _state._subsRunning[_state.subIdx - 1] = false;
+ _state._subsPlayed[_state.subIdx - 1] = true;
const uint16 id = _state.subIdx - 1;
if (id + 1 < _scriptData.names.size()) {
_state.subIdx++;
_ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
+ _state._subsRunning[_state.subIdx - 1] = true;
} else {
_state.subMax = 0; // continue ADS script execution
}
@@ -410,7 +415,21 @@ void ADSInterpreter::playScene() {
}
}
-void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
+void ADSInterpreter::skipToEndIf(Common::SeekableReadStream *scr) {
+ while (scr->pos() < scr->size()) {
+ uint16 op = scr->readUint16LE();
+ if (op == 0x1520)
+ scr->seek(-2);
+ if (op == 0 || op == 0x1520)
+ return;
+ int nargs = numArgs(op);
+ for (int i = 0; i < nargs; i++)
+ scr->readUint16LE();
+ }
+}
+
+
+bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 subIdx, subMax;
switch (code) {
@@ -437,32 +456,40 @@ void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
subIdx = scr->readUint16LE();
subMax = scr->readUint16LE();
warning("Unimplemented ADS opcode: IF_NOT_PLAYED subIdx: %d, subMax: %d", subIdx, subMax);
+ if (_state._subsPlayed[subIdx - 1])
+ skipToEndIf(scr);
break;
}
case 0x1350: { // IF_PLAYED, 2 params
subIdx = scr->readUint16LE();
subMax = scr->readUint16LE();
warning("Unimplemented ADS opcode: IF_PLAYED subIdx: %d, subMax: %d", subIdx, subMax);
+ if (!_state._subsPlayed[subIdx - 1])
+ skipToEndIf(scr);
break;
}
case 0x1360: { // IF_NOT_RUNNING, 2 params
subIdx = scr->readUint16LE();
subMax = scr->readUint16LE();
warning("Unimplemented ADS opcode: IF_NOT_RUNNING subIdx: %d, subMax: %d", subIdx, subMax);
+ if (_state._subsRunning[subIdx - 1])
+ skipToEndIf(scr);
break;
}
case 0x1370: { // IF_RUNNING, 2 params
subIdx = scr->readUint16LE();
subMax = scr->readUint16LE();
warning("Unimplemented ADS opcode: IF_RUNNING subIdx: %d, subMax: %d", subIdx, subMax);
+ if (!_state._subsRunning[subIdx - 1])
+ skipToEndIf(scr);
break;
}
case 0x1510: // PLAY_SCENE, 0 params
- debug("PLAY SCENE");
- // TODO
- break;
+ debug("ADS PLAY SCENE");
+ return false;
+
case 0xffff: // END
- break;
+ return false;
//// unknown / to-be-implemented
case 0x0190:
@@ -471,10 +498,10 @@ void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
case 0x1500:
- case 0x1520: // PLAY_SCENE_2, 5 params
+ case 0x1520: // PLAY_SCENE_ENDIF, 5 params
case 0x2000:
case 0x2010: // STOP_SCENE, 3 params
- case 0x2020:
+ case 0x2020: // RESET SCENE?
case 0x3010: // RANDOM_START, 0 params
case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
@@ -495,6 +522,8 @@ void ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
break;
}
}
+
+ return true;
}
bool ADSInterpreter::run() {
@@ -509,10 +538,11 @@ bool ADSInterpreter::run() {
if (scr->pos() >= scr->size())
return false;
+ bool more = true;
do {
uint16 code = scr->readUint16LE();
- handleOperation(code, scr);
- } while (scr->pos() < scr->size());
+ more = handleOperation(code, scr);
+ } while (more && scr->pos() < scr->size());
return true;
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 3eb687c43f5..c5c527d93fd 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -47,7 +47,7 @@ public:
};
struct TTMState {
- TTMState() : scene(0), _delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0), _currentPalId(0), _drawColFG(0), _drawColBG(0), _delayStart(0) {}
+ TTMState() : scene(0), _delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0), _currentPalId(0), _drawColFG(0), _drawColBG(0), _delayStart(0), _setupFinished(false) {}
uint16 scene;
int _delay;
uint32 _delayStart;
@@ -56,6 +56,7 @@ struct TTMState {
int _currentPalId;
byte _drawColFG;
byte _drawColBG;
+ bool _setupFinished;
Common::String bmpNames[16];
};
@@ -69,6 +70,8 @@ struct ADSState {
ADSState() : scene(0), subIdx(0), subMax(0) {}
uint16 scene;
uint16 subIdx, subMax;
+ Common::Array<bool> _subsPlayed;
+ Common::Array<bool> _subsRunning;
};
class TTMInterpreter {
@@ -82,13 +85,10 @@ public:
uint16 getScene() const { return _state.scene; }
protected:
- void setActiveDialogue(uint16 num);
void handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval);
void updateScreen();
DgdsEngine *_vm;
-
- Dialogue *_text;
TTMData _scriptData;
TTMState _state;
};
@@ -104,8 +104,9 @@ public:
int numArgs(uint16 opcode) const;
protected:
- void handleOperation(uint16 code, Common::SeekableReadStream *scr);
+ bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
void playScene();
+ void skipToEndIf(Common::SeekableReadStream *scr);
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
Commit: 6112d70c1bdca7dbb3cbc03fd44fefed526f84e2
https://github.com/scummvm/scummvm/commit/6112d70c1bdca7dbb3cbc03fd44fefed526f84e2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add handling for game globals
Changed paths:
A engines/dgds/globals.cpp
A engines/dgds/globals.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/module.mk
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index c2641590b8a..4c93337b845 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -51,6 +51,7 @@
#include "dgds/detection_tables.h"
#include "dgds/dgds.h"
#include "dgds/font.h"
+#include "dgds/globals.h"
#include "dgds/image.h"
#include "dgds/includes.h"
#include "dgds/menu.h"
@@ -65,7 +66,7 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
- _resource(nullptr), _gamePals(nullptr) {
+ _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr), _detailLevel(kDgdsDetailHigh) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -214,10 +215,11 @@ Common::Error DgdsEngine::run() {
_fontManager->loadFonts(getGameId(), _resource, _decompressor);
if (getGameId() == GID_DRAGON) {
+ _gameGlobals = new DragonGlobals();
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
- //debug("%s", _gdsScene->dump("").c_str());
+ debug("%s", _gdsScene->dump("").c_str());
loadCorners("DCORNERS.BMP");
reqParser.parse(&invRequestData, "DINV.REQ");
@@ -226,6 +228,7 @@ Common::Error DgdsEngine::run() {
_gdsScene->runStartGameOps();
} else if (getGameId() == GID_CHINA) {
+ _gameGlobals = new Globals();
_gamePals->loadPalette("HOC.PAL");
_gdsScene->load("HOC.GDS", _resource, _decompressor);
@@ -238,6 +241,7 @@ Common::Error DgdsEngine::run() {
_adsInterp->load("TITLE.ADS");
loadCorners("HCORNERS.BMP");
} else if (getGameId() == GID_BEAMISH) {
+ _gameGlobals = new Globals();
_gamePals->loadPalette("WILLY.PAL");
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 846c265b1db..71e5ba50de5 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -52,6 +52,7 @@ class REQFileData;
class Menu;
struct DgdsADS;
class ADSInterpreter;
+class Globals;
enum DgdsGameId {
GID_DRAGON,
@@ -60,8 +61,8 @@ enum DgdsGameId {
};
enum DgdsDetailLevel {
- kDgdsDetailLow,
- kDgdsDetailHigh
+ kDgdsDetailLow = 0,
+ kDgdsDetailHigh = 1
};
class DgdsEngine : public Engine {
@@ -83,12 +84,15 @@ private:
SDSScene *_scene;
GDSScene *_gdsScene;
Menu *_menu;
+
ADSInterpreter *_adsInterp;
GamePalettes *_gamePals;
+ Globals *_gameGlobals;
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
Common::Array<Common::SharedPtr<Image>> _icons;
+ DgdsDetailLevel _detailLevel;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -105,12 +109,14 @@ public:
Decompressor *getDecompressor() { return _decompressor; }
const SDSScene *getScene() const { return _scene; }
SDSScene *getScene() { return _scene; }
+ GDSScene *getGDSScene() { return _gdsScene; }
const FontManager *getFontMan() const { return _fontManager; }
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
void changeScene(int sceneNum);
GamePalettes *getGamePals() { return _gamePals; }
+ Globals *getGameGlobals() { return _gameGlobals; }
- DgdsDetailLevel getDetailLevel() const { return kDgdsDetailHigh; }
+ DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
private:
void loadCorners(const Common::String &filename);
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
new file mode 100644
index 00000000000..dbe64b94b65
--- /dev/null
+++ b/engines/dgds/globals.cpp
@@ -0,0 +1,218 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dgds/globals.h"
+#include "dgds/dgds.h"
+
+namespace Dgds {
+
+template<typename T> class ReadOnlyGlobal : public Global {
+public:
+ ReadOnlyGlobal(uint16 num, const T *val) : Global(num), _val(val) {}
+ uint16 get() override { return *_val; }
+ uint16 set(uint16 val) override { return *_val; }
+private:
+ const T *_val;
+};
+
+template<typename T> class ReadWriteGlobal : public Global {
+public:
+ ReadWriteGlobal(uint16 num, T *val) : Global(num), _val(val) {}
+ uint16 get() override { return *_val; }
+ uint16 set(uint16 val) override { *_val = val; return *_val; }
+private:
+ T *_val;
+};
+
+typedef ReadOnlyGlobal<uint16> ROU16Global;
+typedef ReadWriteGlobal<uint16> RWU16Global;
+
+////////////////////////////////
+
+Globals::Globals() {
+}
+
+Globals::~Globals() {
+ for (auto &g : _globals) {
+ delete g;
+ }
+}
+
+uint16 Globals::getGlobal(uint16 num) {
+ for (auto &global : _globals) {
+ if (global->_num == num) {
+ return global->get();
+ }
+ }
+ return 0;
+}
+
+uint16 Globals::setGlobal(uint16 num, uint16 val) {
+ for (auto &global : _globals) {
+ if (global->_num == num) {
+ return global->set(val);
+ }
+ }
+ return 0;
+}
+
+////////////////////////////////
+
+class DetailLevelROGlobal : public Global {
+public:
+ DetailLevelROGlobal(uint16 num) : Global(num) {}
+ uint16 get() override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
+ uint16 set(uint16 val) override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
+};
+
+////////////////////////////////
+
+static byte dragonDataTableOffsets[] = {0x9, 0x29, 0xF, 0x15, 0x5C, 0x19, 0x28, 0x1F};
+
+static byte dragonDataTable[] = {
+ 0x4, 0x8, 0x16, 0xE, 0x8, 0xE, 0x17, 0x1C,
+ 0x8, 0x2, 0x18, 0x8, 0x10, 0x10, 0x17, 0x15,
+ 0x16, 0x18, 0x3, 0x20, 0x1E, 0x24, 0x32, 0x30,
+ 0xE, 0x8, 0x20, 0x3, 0x13, 0xE, 0x14, 0x12,
+ 0x8, 0x10, 0x1E, 0x13, 0x3, 0x8, 0x12, 0x22,
+ 0xE, 0x10, 0x24, 0xE, 0x8, 0x3, 0xB, 0x20,
+ 0x17, 0x17, 0x32, 0x14, 0x12, 0xB, 0x4, 0x24,
+ 0x1C, 0x15, 0x30, 0x12, 0x22, 0x20, 0x24, 0x4
+};
+
+DragonDataTable::DragonDataTable() : _row(0), _col(0), _divBy4(0), _output(0) {}
+
+int DragonDataTable::getOffsetForVal(uint16 val) {
+ for (int i = 0; i < ARRAYSIZE(dragonDataTableOffsets); i++) {
+ if (dragonDataTableOffsets[i] == val)
+ return i;
+ }
+ return 0;
+}
+
+uint16 DragonDataTable::getValueFromTable() {
+ int row = getOffsetForVal(_row);
+ int col = getOffsetForVal(_col);
+ _output = dragonDataTable[row * 8 + col];
+ if (_divBy4)
+ _output /= 4;
+ if (_output == 0)
+ _output = 1;
+ return _output;
+}
+
+class DragonDataTableGlobal : public Global {
+public:
+ DragonDataTableGlobal(uint16 num, DragonDataTable &table) : Global(num), _table(table) {}
+ uint16 get() override { return _table.getValueFromTable(); }
+ uint16 set(uint16 val) override { return _table.getValueFromTable(); }
+private:
+ DragonDataTable &_table;
+};
+
+////////////////////////////////
+
+class DragonTimeGlobal : public ReadWriteGlobal<int> {
+public:
+ DragonTimeGlobal(uint16 num, int *val, DragonGameTime &time) : ReadWriteGlobal<int>(num, val), _time(time) {}
+ uint16 set(uint16 val) override {
+ if (val != ReadWriteGlobal::get()) {
+ ReadWriteGlobal::set(val);
+ _time.addGameTime(0);
+ }
+ return val;
+ }
+
+private:
+ DragonGameTime &_time;
+};
+
+DragonGameTime::DragonGameTime() : _gameTimeDays(0), _gameTimeMins(0), _gameTimeHours(0), _gameMinsAdded(0) {}
+
+Global *DragonGameTime::getDaysGlobal(uint16 num) {
+ return new DragonTimeGlobal(num, &_gameTimeDays, *this);
+}
+
+Global *DragonGameTime::getHoursGlobal(uint16 num) {
+ return new DragonTimeGlobal(num, &_gameTimeHours, *this);
+}
+
+Global *DragonGameTime::getMinsGlobal(uint16 num) {
+ return new DragonTimeGlobal(num, &_gameTimeMins, *this);
+}
+
+void DragonGameTime::addGameTime(int mins) {
+ _gameMinsAdded += mins;
+ int nhours = (_gameTimeMins + mins) / 60;
+ _gameTimeMins = (_gameTimeMins + mins) % 60;
+ if (_gameTimeMins < 0) {
+ _gameTimeMins += 0x3c;
+ nhours--;
+ }
+ int ndays = (_gameTimeHours + nhours) / 24;
+ _gameTimeHours = (_gameTimeHours + nhours) % 24;
+ if (_gameTimeHours < 0) {
+ _gameTimeHours += 24;
+ _gameTimeDays -= 1;
+ }
+ _gameTimeDays += ndays;
+ // TODO: if any change was made to days/hours/mins..
+ //if (plusmins + nhours + ndays != 0)
+ // UINT_39e5_0ffa = 0;
+}
+
+////////////////////////////////
+
+DragonGlobals::DragonGlobals() : Globals(),
+_gameCounterTicksUp(0), _gameCounterTicksDown(0), _lastOpcode1SceneChageNum(0),
+_sceneOp12SceneNum(0), _currentSelectedItem(0), _gameMinsToAdd_1(0), _gameMinsToAdd_2(0),
+_gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0), _gameDays2(0),
+_sceneOpcode15Flag(0), _sceneOpcode15Val(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
+_opcode106EndMinutes(0) {
+ _globals.push_back(new ROU16Global(1, &_time._gameMinsAdded));
+ _globals.push_back(new ROU16Global(0x64, &_gameCounterTicksUp));
+ _globals.push_back(new ROU16Global(0x62, &_lastOpcode1SceneChageNum));
+ _globals.push_back(new RWU16Global(0x61, &_sceneOp12SceneNum));
+ _globals.push_back(new RWU16Global(0x60, &_currentSelectedItem));
+ _globals.push_back(_time.getDaysGlobal(0x5F));
+ _globals.push_back(_time.getHoursGlobal(0x5E));
+ _globals.push_back(_time.getMinsGlobal(0x5D));
+ _globals.push_back(new RWU16Global(0x5C, &_gameMinsToAdd_1));
+ _globals.push_back(new RWU16Global(0x5B, &_gameMinsToAdd_2));
+ _globals.push_back(new RWU16Global(0x5A, &_gameMinsToAdd_3));
+ _globals.push_back(new RWU16Global(0x59, &_gameMinsToAdd_4));
+ _globals.push_back(new RWU16Global(0x58, &_gameMinsToAdd_5));
+ _globals.push_back(new RWU16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
+ _globals.push_back(new RWU16Global(0x56, &_gameDays2));
+ _globals.push_back(new RWU16Global(0x55, &_sceneOpcode15Flag));
+ _globals.push_back(new RWU16Global(0x54, &_sceneOpcode15Val));
+ _globals.push_back(new RWU16Global(0x20, &_sceneOpcode100Var));
+ _globals.push_back(new RWU16Global(0x21, &_arcadeModeFlag_3cdc));
+ _globals.push_back(new RWU16Global(0x22, &_opcode106EndMinutes));
+ _globals.push_back(new RWU16Global(0x23, &_table._row));
+ _globals.push_back(new RWU16Global(0x24, &_table._col));
+ _globals.push_back(new RWU16Global(0x25, &_table._divBy4));
+ _globals.push_back(new DragonDataTableGlobal(0x26, _table));
+ _globals.push_back(new DetailLevelROGlobal(0x27));
+}
+
+
+} // end namespace Dgds
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
new file mode 100644
index 00000000000..6917f749655
--- /dev/null
+++ b/engines/dgds/globals.h
@@ -0,0 +1,126 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_GLOBALS_H
+#define DGDS_GLOBALS_H
+
+#include "common/types.h"
+#include "common/array.h"
+
+#include "dgds/dgds.h"
+
+namespace Dgds {
+
+/**
+ * The original game uses a struct here with 3 entries:
+ * 1. global variable num (uint16)
+ * 2. pointer to the variable (uint16)
+ * 3. pointer - get+set function ptr **or** 1 == R/W **or** 0 == RO (32 bits)
+ * We make that a bit nicer using c++.
+ *
+ * The original also creates a lookup table to do O(1) lookups of each global,
+ * but there are only ~20 of them so we just iterate through each time.
+ */
+class Global {
+public:
+ Global(uint16 num) : _num(num) {}
+ virtual ~Global() {}
+ uint16 _num;
+ virtual uint16 get() = 0;
+ virtual uint16 set(uint16 val) = 0;
+ virtual uint16 getNum() const { return _num; }
+};
+
+
+class Globals {
+public:
+ Globals();
+ virtual ~Globals();
+
+ uint16 getGlobal(uint16 num);
+ uint16 setGlobal(uint16 num, uint16 val);
+
+protected:
+ Common::Array<Global *> _globals;
+};
+
+// TODO: Work out what this table is even for..
+class DragonDataTable {
+public:
+ DragonDataTable();
+ uint16 getValueFromTable();
+
+ uint16 _row;
+ uint16 _col;
+ uint16 _divBy4;
+ uint16 _output;
+
+private:
+ int getOffsetForVal(uint16 val);
+};
+
+class DragonGameTime {
+public:
+ DragonGameTime();
+ void addGameTime(int mins);
+
+ Global *getMinsGlobal(uint16 num);
+ Global *getHoursGlobal(uint16 num);
+ Global *getDaysGlobal(uint16 num);
+
+ uint16 _gameMinsAdded;
+
+private:
+ int _gameTimeDays;
+ int _gameTimeHours;
+ int _gameTimeMins;
+};
+
+class DragonGlobals : public Globals {
+public:
+ DragonGlobals();
+
+private:
+ uint16 _gameCounterTicksUp;
+ uint16 _gameCounterTicksDown;
+ uint16 _lastOpcode1SceneChageNum;
+ uint16 _sceneOp12SceneNum;
+ uint16 _currentSelectedItem;
+ uint16 _gameMinsToAdd_1;
+ uint16 _gameMinsToAdd_2;
+ uint16 _gameMinsToAdd_3;
+ uint16 _gameMinsToAdd_4;
+ uint16 _gameMinsToAdd_5;
+ uint16 _gameGlobal0x57;
+ uint16 _gameDays2;
+ uint16 _sceneOpcode15Flag;
+ uint16 _sceneOpcode15Val;
+ uint16 _sceneOpcode100Var;
+ uint16 _arcadeModeFlag_3cdc;
+ uint16 _opcode106EndMinutes;
+ DragonDataTable _table;
+ DragonGameTime _time;
+ // uint16 _detailSliderSetting; // kept in the engine
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_GLOBALS_H
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 51839b97076..5e5378ac48c 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -5,13 +5,14 @@ MODULE_OBJS := \
decompress.o \
dgds.o \
font.o \
+ globals.o \
image.o \
menu.o \
metaengine.o \
music.o \
parser.o \
- resource.o \
request.o \
+ resource.o \
scripts.o \
scene.o \
sound.o
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index e445b181b53..b5bb8196dc6 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -35,6 +35,7 @@
#include "dgds/request.h"
#include "dgds/scene.h"
#include "dgds/font.h"
+#include "dgds/globals.h"
namespace Dgds {
@@ -80,8 +81,9 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpNone: return "none";
case kSceneOpChangeScene: return "changeScene";
case kSceneOpNoop: return "noop";
- case kSceneOpShowDlg: return "showdlg";
- case kSceneOpEnableTrigger: return "enabletrigger";
+ case kSceneOpGlobal: return "global";
+ case kSceneOpShowDlg: return "showdlg";
+ case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpMeanwhile: return "meanwhile";
default:
return Common::String::format("sceneOp%d", (int)code);
@@ -444,6 +446,10 @@ Common::String DialogueAction::dump(const Common::String &indent) const {
return str;
}
+Common::String PerSceneGlobal::dump(const Common::String &indent) const {
+ return Common::String::format("%sPerSceneGlobal<num %d scene %d val %d>", indent.c_str(), _num, _sceneNo, _val);
+}
+
// //////////////////////////////////// //
Scene::Scene() : _magic(0) {
@@ -659,6 +665,9 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
break;
case kSceneOpNoop:
break;
+ case kSceneOpGlobal:
+ globalOps(op._args);
+ break;
case kSceneOpShowDlg:
showDialog(op._args[0]);
break;
@@ -878,6 +887,10 @@ bool SDSScene::drawActiveDialog(Graphics::Surface *dst, int mode) {
return retval;
}
+void SDSScene::globalOps(const Common::Array<uint16> &args) {
+ // The globals are held by the GDS scene
+ static_cast<DgdsEngine *>(g_engine)->getGDSScene()->globalOps(args);
+}
GDSScene::GDSScene() {
}
@@ -914,6 +927,16 @@ bool GDSScene::load(const Common::String &filename, ResourceManager *resourceMan
return result;
}
+bool GDSScene::readPerSceneGlobals(Common::SeekableReadStream *s) {
+ _perSceneGlobals.resize(s->readUint16LE());
+ for (PerSceneGlobal &dst : _perSceneGlobals) {
+ dst._num = s->readUint16LE();
+ dst._sceneNo = s->readUint16LE();
+ dst._val = s->readUint16LE();
+ }
+ return !s->err();
+}
+
bool GDSScene::parseInf(Common::SeekableReadStream *s) {
_magic = s->readUint32LE();
_version = s->readString();
@@ -928,8 +951,7 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _opList4);
if (isVersionOver(" 1.208"))
readOpList(stream, _opList5);
- Common::Array<struct SceneConditions> conditionList;
- readConditionList(stream, conditionList);
+ readPerSceneGlobals(stream);
Common::Array<struct MouseCursor> cursorList;
_iconFile = stream->readString();
readMouseHotspotList(stream, cursorList);
@@ -949,6 +971,7 @@ Common::String GDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "opList3", _opList3);
str += _dumpStructList(indent, "opList4", _opList4);
str += _dumpStructList(indent, "opList5", _opList5);
+ str += _dumpStructList(indent, "perSceneGlobals", _perSceneGlobals);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
@@ -957,6 +980,57 @@ Common::String GDSScene::dump(const Common::String &indent) const {
return str;
}
+void GDSScene::globalOps(const Common::Array<uint16> &args) {
+ for (uint i = 0; i < args.size() / 3; i++) {
+ uint16 num = args[i * 3 + 0];
+ uint16 op = args[i * 3 + 1];
+ uint16 val = args[i * 3 + 2];
+
+ // CHECK ME: The original uses a different function here, but the
+ // result appears to be the same as just calling getGlobal?
+ num = getGlobal(num);
+
+ // Op bit 3 on means use absolute val of val.
+ // Off means val is another global to lookup
+ if (op & 8)
+ op = op & 0xfff7;
+ else
+ val = getGlobal(val);
+
+ if (op == 1)
+ val = num + val;
+ else if (op == 6)
+ val = (val == 0);
+ else if (op == 5)
+ val = num - val;
+
+ setGlobal(num, val);
+ }
+}
+
+uint16 GDSScene::getGlobal(uint16 num) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ int curSceneNum = engine->getScene()->getNum();
+ for (const auto &global : _perSceneGlobals) {
+ if (global._num == num && (global._sceneNo == 0 || global._sceneNo == curSceneNum))
+ return global._val;
+ }
+ Globals *gameGlobals = engine->getGameGlobals();
+ return gameGlobals->getGlobal(num);
+}
+
+uint16 GDSScene::setGlobal(uint16 num, uint16 val) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ int curSceneNum = engine->getScene()->getNum();
+ for (auto &global : _perSceneGlobals) {
+ if (global._num == num && (global._sceneNo == 0 || global._sceneNo == curSceneNum)) {
+ global._val = val;
+ return val;
+ }
+ }
+ Globals *gameGlobals = engine->getGameGlobals();
+ return gameGlobals->setGlobal(num, val);
+}
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 4111040e42d..359c4447a8e 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -28,6 +28,10 @@
namespace Dgds {
+class ResourceManager;
+class Decompressor;
+
+
// TODO: Use Common::Rect instead.
struct Rect {
int x;
@@ -74,7 +78,7 @@ enum SceneOpCode {
kSceneOpNone = 0,
kSceneOpChangeScene = 1, // args: scene num
kSceneOpNoop = 2, // args: none. Maybe should close dialogue?
- kSceneOp3 = 3, // args: array of uints
+ kSceneOpGlobal = 3, // args: array of uints
kSceneOp4 = 4, // args: array of uint pairs [op arg, op arg], term with 0,0. a script within a script (see disasm at 1f1a:4b51)
kSceneOp5 = 5, // args: [item num, ??, ??]. give item?
kSceneOp6 = 6, // args: item num?
@@ -214,6 +218,17 @@ struct DialogueAction {
Common::String dump(const Common::String &indent) const;
};
+/* A global value that only applies on a per-SDS-scene,
+ but stays with the GDS data as it sticks around during
+ the game */
+struct PerSceneGlobal {
+ uint16 _num;
+ uint16 _sceneNo;
+ uint16 _val;
+
+ Common::String dump(const Common::String &indent) const;
+};
+
/**
* A scene is described by an SDS file, which points to the ADS script to load
@@ -249,13 +264,12 @@ protected:
virtual void enableTrigger(uint16 num) {}
virtual void showDialog(uint16 num) {}
+ virtual void globalOps(const Common::Array<uint16> &args) {}
uint32 _magic;
Common::String _version;
};
-class ResourceManager;
-class Decompressor;
class GDSScene : public Scene {
public:
@@ -265,11 +279,17 @@ public:
bool parse(Common::SeekableReadStream *s) override;
bool parseInf(Common::SeekableReadStream *s);
const Common::String &getIconFile() const { return _iconFile; }
+ bool readPerSceneGlobals(Common::SeekableReadStream *s);
+
+ uint16 getGlobal(uint num);
Common::String dump(const Common::String &indent) const;
void runStartGameOps() { runOps(_startGameOps); }
void runQuitGameOps() { runOps(_quitGameOps); }
+ void globalOps(const Common::Array<uint16> &args) override;
+ uint16 getGlobal(uint16 num);
+ uint16 setGlobal(uint16 num, uint16 val);
private:
//byte _unk[32];
@@ -280,6 +300,7 @@ private:
Common::Array<struct SceneOp> _opList3;
Common::Array<struct SceneOp> _opList4;
Common::Array<struct SceneOp> _opList5;
+ Common::Array<struct PerSceneGlobal> _perSceneGlobals;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
};
@@ -303,6 +324,8 @@ public:
bool checkDialogActive();
bool drawActiveDialog(Graphics::Surface *dst, int mode);
+ void globalOps(const Common::Array<uint16> &args) override;
+
private:
void enableTrigger(uint16 num) override;
void showDialog(uint16 num) override;
Commit: 0d3d6caa30173d216a3a8847dac8b478100953ff
https://github.com/scummvm/scummvm/commit/0d3d6caa30173d216a3a8847dac8b478100953ff
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Rename some op lists to better names, call some on scene change
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/parser.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 4c93337b845..4125acfdf64 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -148,7 +148,7 @@ void DgdsEngine::loadIcons() {
}
}
-void DgdsEngine::changeScene(int sceneNum) {
+void DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
assert(_scene && _adsInterp);
if (sceneNum == _scene->getNum()) {
@@ -160,6 +160,8 @@ void DgdsEngine::changeScene(int sceneNum) {
_scene->runLeaveSceneOps();
_scene->unload();
+ _gdsScene->runChangeSceneOps();
+
if (!_icons.empty()) {
CursorMan.popAllCursors();
CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
@@ -322,7 +324,7 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
// TODO: This will be done by the trigger once we know how to do it.
// It's trigger number 3 in scene 3.
- changeScene(55);
+ changeScene(55, false);
}
} else {
return Common::kNoError;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 71e5ba50de5..ec5c89897a6 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -112,7 +112,7 @@ public:
GDSScene *getGDSScene() { return _gdsScene; }
const FontManager *getFontMan() const { return _fontManager; }
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
- void changeScene(int sceneNum);
+ void changeScene(int sceneNum, bool runChangeOps);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 9747e67c7a0..4dd13f5851e 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -111,6 +111,7 @@ bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
break;
}
scriptData->_pages = chunk.getContent()->readUint16LE();
+ scriptData->_pageOffsets.resize(scriptData->_pages + 1);
break;
default:
warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk.getId()), chunk.getSize(), _filename.c_str());
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index b5bb8196dc6..8253a4b3204 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -661,7 +661,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
for (const SceneOp &op : ops) {
switch(op._opCode) {
case kSceneOpChangeScene:
- engine->changeScene(op._args[0]);
+ engine->changeScene(op._args[0], true);
break;
case kSceneOpNoop:
break;
@@ -675,7 +675,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
enableTrigger(op._args[0]);
break;
case kSceneOpMeanwhile:
- error("TODO: Implement meanwhile screen");
+ warning("TODO: Implement meanwhile screen");
break;
default:
warning("TODO: Implement scene op %d", op._opCode);
@@ -688,6 +688,9 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (conds.empty())
return true;
uint truecount = 0;
+
+ Globals *globals = static_cast<DgdsEngine *>(g_engine)->getGameGlobals();
+
for (const auto & c : conds) {
uint16 refval = c._val;
uint16 checkval;
@@ -698,17 +701,18 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (cflag & kSceneCond80) {
refval = 1;
// TODO: check something about current ADS script?
- checkval = 0;
+ checkval = 0; // ADS_2642_38f6(c._num);
SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
refval = 0;
} else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemField12) {
- // TODO: Get game object c._num and check value from object table
+ // TODO: Get game item c._num and check value from item attributes
checkval = 0;
} else {
- // TODO: Check something about current SDS scene??
- checkval = 0;
+ checkval = globals->getGlobal(c._num);
+ if (!(cflag & kSceneCondSceneAbsVal))
+ refval = globals->getGlobal(refval);
}
bool result = false;
@@ -771,9 +775,9 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _enterSceneOps);
readOpList(stream, _leaveSceneOps);
if (isVersionOver(" 1.206")) {
- readOpList(stream, _opList3);
+ readOpList(stream, _preTickOps);
}
- readOpList(stream, _opList4);
+ readOpList(stream, _postTickOps);
_field6_0x14 = stream->readUint16LE();
_adsFile = stream->readString();
readStruct2List(stream, _struct2List);
@@ -793,8 +797,8 @@ void SDSScene::unload() {
_num = 0;
_enterSceneOps.clear();
_leaveSceneOps.clear();
- _opList3.clear();
- _opList4.clear();
+ _preTickOps.clear();
+ _postTickOps.clear();
_field6_0x14 = 0;
_adsFile.clear();
_struct2List.clear();
@@ -809,8 +813,8 @@ Common::String SDSScene::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSDSScene<num %d %d ads %s", indent.c_str(), _num, _field6_0x14, _adsFile.c_str());
str += _dumpStructList(indent, "enterSceneOps", _enterSceneOps);
str += _dumpStructList(indent, "leaveSceneOps", _leaveSceneOps);
- str += _dumpStructList(indent, "opList3", _opList3);
- str += _dumpStructList(indent, "opList4", _opList4);
+ str += _dumpStructList(indent, "preTickOps", _preTickOps);
+ str += _dumpStructList(indent, "postTickOps", _postTickOps);
str += _dumpStructList(indent, "struct2List", _struct2List);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
@@ -947,10 +951,10 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _startGameOps);
readOpList(stream, _quitGameOps);
if (isVersionOver(" 1.206"))
- readOpList(stream, _opList3);
- readOpList(stream, _opList4);
+ readOpList(stream, _preTickOps);
+ readOpList(stream, _postTickOps);
if (isVersionOver(" 1.208"))
- readOpList(stream, _opList5);
+ readOpList(stream, _onChangeSceneOps);
readPerSceneGlobals(stream);
Common::Array<struct MouseCursor> cursorList;
_iconFile = stream->readString();
@@ -968,9 +972,9 @@ Common::String GDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "gameItems", _gameItems);
str += _dumpStructList(indent, "startGameOps", _startGameOps);
str += _dumpStructList(indent, "quitGameOps", _quitGameOps);
- str += _dumpStructList(indent, "opList3", _opList3);
- str += _dumpStructList(indent, "opList4", _opList4);
- str += _dumpStructList(indent, "opList5", _opList5);
+ str += _dumpStructList(indent, "preTickOps", _preTickOps);
+ str += _dumpStructList(indent, "postTickOps", _postTickOps);
+ str += _dumpStructList(indent, "onChangeSceneOps", _onChangeSceneOps);
str += _dumpStructList(indent, "perSceneGlobals", _perSceneGlobals);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 359c4447a8e..f2a105ac885 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -246,6 +246,8 @@ public:
uint32 getMagic() const { return _magic; }
const Common::String &getVersion() const { return _version; }
+ void runPreTickOps() { runOps(_preTickOps); }
+ void runPostTickOps() { runOps(_postTickOps); }
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
@@ -268,6 +270,9 @@ protected:
uint32 _magic;
Common::String _version;
+
+ Common::Array<struct SceneOp> _preTickOps;
+ Common::Array<struct SceneOp> _postTickOps;
};
@@ -287,6 +292,7 @@ public:
void runStartGameOps() { runOps(_startGameOps); }
void runQuitGameOps() { runOps(_quitGameOps); }
+ void runChangeSceneOps() { runOps(_onChangeSceneOps); }
void globalOps(const Common::Array<uint16> &args) override;
uint16 getGlobal(uint16 num);
uint16 setGlobal(uint16 num, uint16 val);
@@ -297,9 +303,7 @@ private:
Common::Array<struct GameItem> _gameItems;
Common::Array<struct SceneOp> _startGameOps;
Common::Array<struct SceneOp> _quitGameOps;
- Common::Array<struct SceneOp> _opList3;
- Common::Array<struct SceneOp> _opList4;
- Common::Array<struct SceneOp> _opList5;
+ Common::Array<struct SceneOp> _onChangeSceneOps;
Common::Array<struct PerSceneGlobal> _perSceneGlobals;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
@@ -333,8 +337,6 @@ private:
int _num;
Common::Array<struct SceneOp> _enterSceneOps;
Common::Array<struct SceneOp> _leaveSceneOps;
- Common::Array<struct SceneOp> _opList3;
- Common::Array<struct SceneOp> _opList4;
//uint _field5_0x12;
uint _field6_0x14;
Common::String _adsFile;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 9ab570462e9..7917b542014 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -501,7 +501,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1520: // PLAY_SCENE_ENDIF, 5 params
case 0x2000:
case 0x2010: // STOP_SCENE, 3 params
- case 0x2020: // RESET SCENE?
+ case 0x2020: // RESET SCENE, 2 params (scene, subScene)
case 0x3010: // RANDOM_START, 0 params
case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index c5c527d93fd..cbe787bfd6a 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -43,7 +43,9 @@ public:
class TTMData : public ScriptParserData {
public:
+ TTMData() : _pages(330), ScriptParserData() {}
uint16 _pages;
+ Common::Array<int> _pageOffsets;
};
struct TTMState {
Commit: 94a3aa994cfe847c3e28bab24902b6812b8c365f
https://github.com/scummvm/scummvm/commit/94a3aa994cfe847c3e28bab24902b6812b8c365f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Work out more scene opcodes
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 4125acfdf64..9a629da8d2d 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -66,7 +66,8 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
- _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr), _detailLevel(kDgdsDetailHigh) {
+ _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr), _detailLevel(kDgdsDetailHigh),
+ _showClockUser(false), _showClockScript(false) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -218,6 +219,7 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
_gameGlobals = new DragonGlobals();
+ _showClockUser = true;
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index ec5c89897a6..5e336dba0b6 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -94,6 +94,10 @@ private:
Common::Array<Common::SharedPtr<Image>> _icons;
DgdsDetailLevel _detailLevel;
+ // Clock is shown if both are true;
+ bool _showClockUser;
+ bool _showClockScript;
+
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
virtual ~DgdsEngine();
@@ -117,6 +121,7 @@ public:
Globals *getGameGlobals() { return _gameGlobals; }
DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
+ void setShowClock(bool val) { _showClockScript = val; }
private:
void loadCorners(const Common::String &filename);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8253a4b3204..316bab43e3d 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -59,7 +59,7 @@ Common::String Rect::dump(const Common::String &indent) const {
Common::String SceneConditions::dump(const Common::String &indent) const {
- return Common::String::format("%sSceneCondition<%d flg 0x%02x %d>", indent.c_str(), _num, _flags, _val);
+ return Common::String::format("%sSceneCondition<flg 0x%02x %d %d>", indent.c_str(), _flags, _num, _val);
}
@@ -82,8 +82,16 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpChangeScene: return "changeScene";
case kSceneOpNoop: return "noop";
case kSceneOpGlobal: return "global";
+ case kSceneOp4MetaScript: return "sceneOp4(metascript?)";
+ case kSceneOpSetItemAttr: return "setitemattr?";
+ case kSceneOpGiveItem: return "giveitem?";
case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
+ case kSceneOpChangeSceneToStored: return "changeSceneToStored";
+ case kSceneOpShowClock: return "sceneOpShowClock";
+ case kSceneOpHideClock: return "sceneOpHideClock";
+ case kSceneOp18Menu: return "sceneOp18(menu1?)";
+ case kSceneOp19Menu: return "sceneOp18(menu0?)";
case kSceneOpMeanwhile: return "meanwhile";
default:
return Common::String::format("sceneOp%d", (int)code);
@@ -115,9 +123,9 @@ Common::String GameItem::dump(const Common::String &indent) const {
Common::String super = SceneStruct2::dump(indent + " ");
Common::String str = Common::String::format(
- "%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d unk13 %d unk14 %d",
+ "%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d flags %d unk14 %d",
indent.c_str(), super.c_str(), indent.c_str(), field10_0x24,
- _iconNum, field12_0x28, field13_0x2a, field14_0x2c);
+ _iconNum, field12_0x28, _flags, field14_0x2c);
str += _dumpStructList(indent, "oplist5", opList5);
str += _dumpStructList(indent, "oplist6", opList6);
str += "\n";
@@ -509,7 +517,7 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
dst.field12_0x28 = s->readUint16LE();
dst.field14_0x2c = s->readUint16LE();
if (!isVersionUnder(" 1.211"))
- dst.field13_0x2a = s->readUint16LE() & 0xfffe;
+ dst._flags = s->readUint16LE() & 0xfffe;
if (!isVersionUnder(" 1.204")) {
dst.field10_0x24 = s->readUint16LE();
readOpList(s, dst.opList5);
@@ -517,7 +525,6 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
}
}
return !s->err();
-
}
@@ -674,6 +681,16 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpEnableTrigger:
enableTrigger(op._args[0]);
break;
+ case kSceneOpChangeSceneToStored: {
+ uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
+ engine->changeScene(sceneNo, true);
+ }
+ case kSceneOpShowClock:
+ engine->setShowClock(true);
+ break;
+ case kSceneOpHideClock:
+ engine->setShowClock(false);
+ break;
case kSceneOpMeanwhile:
warning("TODO: Implement meanwhile screen");
break;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index f2a105ac885..b01cd8d503d 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -79,22 +79,22 @@ enum SceneOpCode {
kSceneOpChangeScene = 1, // args: scene num
kSceneOpNoop = 2, // args: none. Maybe should close dialogue?
kSceneOpGlobal = 3, // args: array of uints
- kSceneOp4 = 4, // args: array of uint pairs [op arg, op arg], term with 0,0. a script within a script (see disasm at 1f1a:4b51)
- kSceneOp5 = 5, // args: [item num, ??, ??]. give item?
- kSceneOp6 = 6, // args: item num?
+ kSceneOp4MetaScript = 4, // args: array of uint pairs [op arg, op arg], term with 0,0. a script within a script (see disasm at 1f1a:4b51)
+ kSceneOpSetItemAttr = 5, // args: [item num, item param 0x28, item param 0x2c]. set item attrs?
+ kSceneOpGiveItem = 6, // args: item num. give item?
kSceneOp7 = 7, // args: none.
kSceneOpShowDlg = 8, // args: dialogue number. show dialogue?
kSceneOp9 = 9, // args: none.
kSceneOp10 = 10, // args: none. Looks through the struct2 list for something.
kSceneOpEnableTrigger = 11, // args: trigger num
- kSceneOp12 = 12, // args: none. Change scene to stored number (previous?)
+ kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
kSceneOp13 = 13, // args: none.
kSceneOp14 = 14, // args: none.
kSceneOp15 = 15, // args: none.
- kSceneOp16 = 16, // args: none.
- kSceneOp17 = 17, // args: none.
- kSceneOp18 = 18, // args: none.
- kSceneOp19 = 19, // args: none.
+ kSceneOpShowClock = 16, // args: none. set some clock-related globals
+ kSceneOpHideClock = 17, // args: none. set some clock-related values.
+ kSceneOp18Menu = 18, // args: none. set menu-related globals to 1
+ kSceneOp19Menu = 19, // args: none. set menu-related globals to 0
kSceneOp100 = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOp102 = 102, // args: none.
@@ -120,7 +120,7 @@ struct GameItem : public SceneStruct2 {
uint16 field10_0x24;
uint16 _iconNum;
uint16 field12_0x28;
- uint16 field13_0x2a;
+ uint16 _flags;
uint16 field14_0x2c;
Common::String dump(const Common::String &indent) const override;
Commit: c72cca34e3c3da8406e6007c580992e227c57e15
https://github.com/scummvm/scummvm/commit/c72cca34e3c3da8406e6007c580992e227c57e15
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: ADS and TTM implementation
* Rename TTM objects to match original ideas of environment and sequence
* Implement more ADS stuff in line with original - states etc
* Implement sceneop 4 which changes ADS states
Currently this breaks everything (no scenes execute) but the implementation is
far closer to the original, so it's a necessary step to get to a correct
reimplementation.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/music.cpp
engines/dgds/parser.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
engines/dgds/sound.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 9a629da8d2d..463d35bdb8c 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -334,7 +334,7 @@ Common::Error DgdsEngine::run() {
}
_scene->checkTriggers();
} else if (getGameId() == GID_BEAMISH) {
- if (_adsInterp->run())
+ if (!_adsInterp->run())
return Common::kNoError;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 5e336dba0b6..e661c1116da 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -122,6 +122,7 @@ public:
DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
void setShowClock(bool val) { _showClockScript = val; }
+ ADSInterpreter *adsInterpreter() { return _adsInterp; }
private:
void loadCorners(const Common::String &filename);
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 23a1d7e57c9..565fb0dcab4 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -171,7 +171,7 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
int Image::frameCount(const Common::String &filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
- error("Couldn't get bitmap resource %s", filename.c_str());
+ error("Couldn't get bitmap resource '%s'", filename.c_str());
int tileCount = -1;
DgdsChunkReader chunk(fileStream);
@@ -191,7 +191,7 @@ void Image::loadBitmap(const Common::String &filename, int number) {
uint16 *mtx;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
- error("Couldn't get bitmap resource %s", filename.c_str());
+ error("Couldn't get bitmap resource '%s'", filename.c_str());
_bmpData.free();
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
index 2ec0a337516..4aebe7ad550 100644
--- a/engines/dgds/music.cpp
+++ b/engines/dgds/music.cpp
@@ -48,7 +48,7 @@ public:
~MidiParser_DGDS();
void sendInitCommands();
-
+
bool loadMusic(byte *data, uint32 size);
bool validateNextRead(uint i, uint16 *_curPos);
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 4dd13f5851e..865145d36d6 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -121,6 +121,7 @@ bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
return false;
}
+
bool ADSParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
ADSData *scriptData = static_cast<ADSData *>(data);
Common::SeekableReadStream *chunkStream = chunk.getContent();
@@ -136,7 +137,7 @@ bool ADSParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
assert(idx == (i + 1));
Common::String string = chunkStream->readString();
- scriptData->names.push_back(string);
+ scriptData->_scriptNames.push_back(string);
}
} break;
case ID_SCR:
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 316bab43e3d..6b0af629c54 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -34,6 +34,7 @@
#include "dgds/resource.h"
#include "dgds/request.h"
#include "dgds/scene.h"
+#include "dgds/scripts.h"
#include "dgds/font.h"
#include "dgds/globals.h"
@@ -82,7 +83,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpChangeScene: return "changeScene";
case kSceneOpNoop: return "noop";
case kSceneOpGlobal: return "global";
- case kSceneOp4MetaScript: return "sceneOp4(metascript?)";
+ case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
case kSceneOpSetItemAttr: return "setitemattr?";
case kSceneOpGiveItem: return "giveitem?";
case kSceneOpShowDlg: return "showdlg";
@@ -663,6 +664,50 @@ void SDSScene::enableTrigger(uint16 num) {
}
+void Scene::segmentStateOps(const Common::Array<uint16> &args) {
+ ADSInterpreter *interp = static_cast<DgdsEngine *>(g_engine)->adsInterpreter();
+
+ for (uint i = 0; i < args.size(); i+= 2) {
+ uint16 subop = args[i];
+ uint16 arg = args[i + 1];
+ if (!subop && !arg)
+ return;
+ switch (subop) {
+ case 1:
+ interp->segmentOrState(arg, 3);
+ break;
+ case 2:
+ interp->segmentOrState(arg, 4);
+ break;
+ case 3:
+ interp->segmentSetState(arg, 6);
+ break;
+ case 4:
+ interp->segmentSetState(arg, 5);
+ break;
+ case 9:
+ warning("TODO: Apply segment state 3 to all loaded ADS texts");
+ interp->segmentOrState(arg, 3);
+ break;
+ case 10:
+ warning("TODO: Apply segment state 4 to all loaded ADS texts");
+ interp->segmentOrState(arg, 4);
+ break;
+ case 11:
+ warning("TODO: Apply segment state 6 to all loaded ADS texts");
+ interp->segmentSetState(arg, 6);
+ break;
+ case 12:
+ warning("TODO: Apply segment state 5 to all loaded ADS texts");
+ interp->segmentSetState(arg, 5);
+ break;
+ default:
+ error("Unknown scene op 4 sub-opcode %d", subop);
+ }
+ }
+}
+
+
void Scene::runOps(const Common::Array<SceneOp> &ops) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
@@ -675,6 +720,9 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpGlobal:
globalOps(op._args);
break;
+ case kSceneOpSegmentStateOps:
+ segmentStateOps(op._args);
+ break;
case kSceneOpShowDlg:
showDialog(op._args[0]);
break;
@@ -705,9 +753,9 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (conds.empty())
return true;
uint truecount = 0;
-
+
Globals *globals = static_cast<DgdsEngine *>(g_engine)->getGameGlobals();
-
+
for (const auto & c : conds) {
uint16 refval = c._val;
uint16 checkval;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index b01cd8d503d..e64fa5e1439 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -79,7 +79,7 @@ enum SceneOpCode {
kSceneOpChangeScene = 1, // args: scene num
kSceneOpNoop = 2, // args: none. Maybe should close dialogue?
kSceneOpGlobal = 3, // args: array of uints
- kSceneOp4MetaScript = 4, // args: array of uint pairs [op arg, op arg], term with 0,0. a script within a script (see disasm at 1f1a:4b51)
+ kSceneOpSegmentStateOps = 4, // args: array of uint pairs [op seg, op seg], term with 0,0 that modify segment states
kSceneOpSetItemAttr = 5, // args: [item num, item param 0x28, item param 0x2c]. set item attrs?
kSceneOpGiveItem = 6, // args: item num. give item?
kSceneOp7 = 7, // args: none.
@@ -175,7 +175,7 @@ public:
uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
-
+
uint _hideTime;
void draw(Graphics::Surface *dst, int mode);
@@ -267,6 +267,11 @@ protected:
virtual void enableTrigger(uint16 num) {}
virtual void showDialog(uint16 num) {}
virtual void globalOps(const Common::Array<uint16> &args) {}
+ virtual void segmentStateOps(const Common::Array<uint16> &args);
+ void segmentStateOp9(uint16 arg);
+ void segmentStateOp10(uint16 arg);
+ void segmentStateOp11(uint16 arg);
+ void segmentStateOp12(uint16 arg);
uint32 _magic;
Common::String _version;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 7917b542014..bd049210202 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -44,26 +44,22 @@ namespace Dgds {
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
-bool TTMInterpreter::load(const Common::String &filename) {
+bool TTMInterpreter::load(const Common::String &filename, TTMData &scriptData) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- bool parseResult = dgds.parse(&_scriptData, filename);
+ bool parseResult = dgds.parse(&scriptData, filename);
- _state._delay = 0;
- _state.scene = 0;
- _scriptData.scr->seek(0);
+ scriptData.scr->seek(0);
return parseResult;
}
void TTMInterpreter::unload() {
- delete _scriptData.scr;
- _scriptData.scr = nullptr;
}
-void TTMInterpreter::updateScreen() {
+void TTMInterpreter::updateScreen(struct TTMSeq &state) {
g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- if (_state._setupFinished && _vm->getScene()->checkDialogActive()) {
+ if (state._runFlag && _vm->getScene()->checkDialogActive()) {
Graphics::Surface *screen = g_system->lockScreen();
_vm->getScene()->drawActiveDialog(screen, 1);
_vm->getScene()->drawActiveDialog(screen, 4);
@@ -73,7 +69,7 @@ void TTMInterpreter::updateScreen() {
g_system->updateScreen();
}
-void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval) {
+void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
switch (op) {
@@ -88,7 +84,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
case 0x0110: // PURGE void
// .. shouldn't actually clear the bmps, what should it do?
- _state._currentBmpId = 0;
+ state._currentBmpId = 0;
break;
case 0x0ff0: {
// REFRESH: void
@@ -98,20 +94,19 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
_vm->getTopBuffer().fillRect(bmpArea, 0);
} break;
case 0x1020: // SET DELAY: i:int [0..n]
- _state._delay += ivals[0] * 10;
- _state._delayStart = g_system->getMillis();
+ state._timeNext = g_system->getMillis() + ivals[0] * 10;
break;
case 0x1030: {
// SET BMP: id:int [-1:n]
int bk = ivals[0];
if (bk != -1) {
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], bk);
+ _vm->_image->loadBitmap(env._bmpNames[state._currentBmpId], bk);
}
break;
}
case 0x1050:
// SELECT BMP: id:int [0:n]
- _state._currentBmpId = ivals[0];
+ state._currentBmpId = ivals[0];
break;
case 0x1060:
// SELECT PAL: id:int [0]
@@ -122,26 +117,24 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
debug("SCENE SETUP DONE: %u", ivals[0]);
- _state._setupFinished = true;
break;
case 0x1110: { // SET_SCENE: i:int [1..n]
// DESCRIPTION IN TTM TAGS.
debug("SET SCENE: %u", ivals[0]);
- _state.scene = ivals[0];
- _state._setupFinished = false;
+ state._currentFrame = ivals[0];
break;
}
case 0x1200: // GOTO? How different to SET SCENE??
debug("GOTO SCENE: %u", ivals[0]);
- _state.scene = ivals[0];
+ state._currentFrame = ivals[0];
break;
case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
- _state._drawColFG = static_cast<byte>(ivals[0]);
- _state._drawColBG = static_cast<byte>(ivals[1]);
+ state._drawColFG = static_cast<byte>(ivals[0]);
+ state._drawColBG = static_cast<byte>(ivals[1]);
break;
case 0x4000:
// SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
- _state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
case 0x4110:
// FADE OUT: colorno,ncolors,targetcol,speed:byte
@@ -153,7 +146,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
for (int i = 0; i < 320; i += ivals[3]) {
int fade = MIN(i / 5, 63);
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- updateScreen();
+ updateScreen(state);
g_system->delayMillis(5);
}
}
@@ -166,7 +159,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
_vm->getTopBuffer().fillRect(bmpArea, 0);
-
+
// FADE IN: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -174,7 +167,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
for (int i = 320; i > 0; i -= ivals[3]) {
int fade = MAX(0, MIN(i / 5, 63));
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- updateScreen();
+ updateScreen(state);
g_system->delayMillis(5);
}
}
@@ -189,7 +182,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
}
case 0xa000: // DRAW PIXEL x,y:int
- _vm->getTopBuffer().setPixel(ivals[0], ivals[1], _state._drawColFG);
+ _vm->getTopBuffer().setPixel(ivals[0], ivals[1], state._drawColFG);
break;
case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l]
// it works like a bitblit, but it doesn't write if there's something already at the destination?
@@ -198,19 +191,19 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
_vm->getTopBuffer().copyFrom(_vm->_resData);
break;
case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], _state._drawColFG);
+ _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], state._drawColFG);
break;
case 0xa100:
// DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- _vm->getTopBuffer().fillRect(bmpArea, _state._drawColFG);
+ _vm->getTopBuffer().fillRect(bmpArea, state._drawColFG);
break;
case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, _state._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, _state._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, _state._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, _state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, state._drawColFG);
break;
case 0xa520:
// DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
@@ -221,25 +214,25 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
// FALL THROUGH
case 0xa500:
- debug("DRAW \"%s\"", _state.bmpNames[_state._currentBmpId].c_str());
+ debug("DRAW \"%s\"", env._bmpNames[state._currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
int tileId = ivals[2];
- _state._currentBmpId = ivals[3];
+ state._currentBmpId = ivals[3];
if (tileId != -1) {
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], tileId);
+ _vm->_image->loadBitmap(env._bmpNames[state._currentBmpId], tileId);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", _state._currentBmpId, _state.bmpNames[_state._currentBmpId].c_str());
- _vm->_image->loadBitmap(_state.bmpNames[_state._currentBmpId], 0);
+ warning("trying to load bmp %d (%s) on demand", state._currentBmpId, env._bmpNames[state._currentBmpId].c_str());
+ _vm->_image->loadBitmap(env._bmpNames[state._currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], _state._drawWin, _vm->getTopBuffer());
+ _vm->_image->drawBitmap(ivals[0], ivals[1], state._drawWin, _vm->getTopBuffer());
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
break;
@@ -249,7 +242,7 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
break;
case 0xf020:
// LOAD BMP: filename:str
- _state.bmpNames[_state._currentBmpId] = sval;
+ env._bmpNames[state._currentBmpId] = sval;
break;
case 0xf050:
// LOAD PAL: filename:str
@@ -299,18 +292,17 @@ void TTMInterpreter::handleOperation(uint16 op, byte count, int16 *ivals, Common
}
}
-bool TTMInterpreter::run() {
- Common::SeekableReadStream *scr = _scriptData.scr;
+bool TTMInterpreter::run(TTMData &env, struct TTMSeq &seq) {
+ Common::SeekableReadStream *scr = env.scr;
if (!scr)
return false;
if (scr->pos() >= scr->size())
return false;
- if (_state._delayStart + _state._delay > g_system->getMillis()) {
+ if (seq._timeNext > g_system->getMillis()) {
return true;
}
- _state._delay = 0;
- _state._delayStart = 0;
+ seq._timeNext = 0;
uint16 code = scr->readUint16LE();
uint16 op = code & 0xFFF0;
@@ -345,14 +337,73 @@ bool TTMInterpreter::run() {
}
debug(" ");
- handleOperation(op, count, ivals, sval);
+ handleOperation(env, seq, op, count, ivals, sval);
- updateScreen();
+ updateScreen(seq);
return true;
}
-ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm) {
+void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &seqArray) {
+ int16 envno = env._enviro;
+ env.scr->seek(0);
+ uint16 op = 0;
+ for (uint page = 0; page < env._pages; page++) {
+ while (op != 0xff0 && !env.scr->eos()) {
+ op = env.scr->readUint16LE();
+ switch (op & 0xf) {
+ case 0:
+ break;
+ case 1:
+ if (op == 0x1111) {
+ TTMSeq newseq;
+ newseq._enviro = envno;
+ newseq._seqNum = env.scr->readUint16LE();
+ newseq._startFrame = page;
+ newseq._currentFrame = page;
+ newseq._lastFrame = -1;
+ seqArray.push_back(newseq);
+ } else {
+ env.scr->skip(2);
+ }
+ break;
+ case 0xf: {
+ byte ch[2];
+ do {
+ ch[0] = env.scr->readByte();
+ ch[1] = env.scr->readByte();
+ } while (ch[0] != 0 && ch[1] != 0);
+ break;
+ }
+ default:
+ env.scr->skip((op & 0xf) * 2);
+ break;
+ }
+ }
+ }
+ env.scr->seek(0);
+}
+
+void TTMSeq::reset() {
+ ARRAYCLEAR(_slot);
+ _currentFrame = _startFrame;
+ _gotoFrame = -1;
+ _drawColBG = 0xf;
+ _drawColFG = 0xf;
+ //_brush_num = 0;
+ _currentBmpId = 0;
+ _timeCut = 0;
+ _timeNext = 0;
+ _runCount = 0;
+ _runPlayed = 0;
+ _executed = 0;
+ _runFlag = kRunTypeStopped;
+ _scriptFlag = 0;
+ _selfLoop = 0;
+ _drawWin = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+}
+
+ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _currentTTMSeq(nullptr) {
_ttmInterpreter = new TTMInterpreter(_vm);
}
@@ -375,44 +426,85 @@ bool ADSInterpreter::load(const Common::String &filename) {
detailfile = filename;
ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- dgds.parse(&_scriptData, detailfile);
+ dgds.parse(&_adsData, detailfile);
+
+ for (const auto &file : _adsData._scriptNames) {
+ _adsData._scriptEnvs.resize(_adsData._scriptEnvs.size() + 1);
+ TTMData &data = _adsData._scriptEnvs.back();
+ data._enviro = _adsData._scriptEnvs.size();
+ _ttmInterpreter->load(file, data);
+ _ttmInterpreter->findAndAddSequences(data, _adsData._ttmSeqs);
+ }
- _state.scene = 0;
- _state.subIdx = 0;
- _state.subMax = 0;
- _scriptData.scr->seek(0);
- _scriptData.filename = filename;
+ _adsData.scr->seek(0);
+
+ uint16 opcode = 0;
+ int segcount = 0;
+ while (_adsData.scr->pos() < _adsData.scr->eos()) {
+ opcode = _adsData.scr->readUint16LE();
+ if (opcode == 0xffff) {
+ findUsedSequencesForSegment(segcount);
+ segcount++;
+ } else {
+ _adsData.scr->skip(numArgs(opcode) * 2);
+ }
+ }
+
+ _adsData._maxSegments = segcount + 1;
+
+ _adsData.filename = filename;
- _state._subsPlayed.resize(_scriptData.names.size());
- _state._subsRunning.resize(_scriptData.names.size());
return true;
}
+static const uint16 ADS_SEQ_OPCODES[] = {
+ 0x2000, 0x2005, 0x2010, 0x2015, 0x4000, 0x4010, 0x1330,
+ 0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
+};
+
+void ADSInterpreter::findUsedSequencesForSegment(int segno) {
+ _adsData._usedSeqs[segno].clear();
+ int64 startoff = _adsData.scr->pos();
+ uint16 opcode = 0;
+ while (opcode != 0xffff && _adsData.scr->pos() < _adsData.scr->size()) {
+ opcode = _adsData.scr->readUint16LE();
+ for (uint16 o : ADS_SEQ_OPCODES) {
+ if (opcode == o) {
+ TTMSeq *seq = findTTMSeq(_adsData.scr->readUint16LE(), _adsData.scr->readUint16LE());
+ _adsData._usedSeqs[segno].push_back(seq);
+ _adsData.scr->seek(-4, SEEK_CUR);
+ break;
+ }
+ }
+ _adsData.scr->skip(numArgs(opcode) * 2);
+ }
+ _adsData.scr->seek(startoff);
+}
+
+
void ADSInterpreter::unload() {
- _scriptData.names.clear();
- delete _scriptData.scr;
- _scriptData.scr = nullptr;
- _state = ADSState();
+ _adsData._scriptNames.clear();
+ _adsData._scriptEnvs.clear();
+ delete _adsData.scr;
+ _adsData.scr = nullptr;
+ _currentTTMSeq = nullptr;
+ _adsData._ttmSeqs.clear();
}
-void ADSInterpreter::playScene() {
- // This is the main scene player loop, which will run
- // after the first time the ADS script is loaded below
- // TODO/FIXME: Rewrite this
- if (_state.subMax != 0) {
- if (!_ttmInterpreter->run()) {
- _state._subsRunning[_state.subIdx - 1] = false;
- _state._subsPlayed[_state.subIdx - 1] = true;
- const uint16 id = _state.subIdx - 1;
- if (id + 1 < _scriptData.names.size()) {
- _state.subIdx++;
- _ttmInterpreter->load(_scriptData.names[_state.subIdx - 1]);
- _state._subsRunning[_state.subIdx - 1] = true;
- } else {
- _state.subMax = 0; // continue ADS script execution
- }
- }
+bool ADSInterpreter::playScene() {
+ if (!_currentTTMSeq)
+ return false;
+
+ TTMData *env = findTTMEnviro(_currentTTMSeq->_enviro);
+ if (!env)
+ error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
+
+ if (!_ttmInterpreter->run(*env, *_currentTTMSeq)) {
+ _currentTTMSeq->_runCount++;
+ // TODO: Continue or load next???
+ _currentTTMSeq = findTTMSeq(_currentTTMSeq->_enviro, _currentTTMSeq->_seqNum + 1);
}
+ return true;
}
void ADSInterpreter::skipToEndIf(Common::SeekableReadStream *scr) {
@@ -428,59 +520,124 @@ void ADSInterpreter::skipToEndIf(Common::SeekableReadStream *scr) {
}
}
+TTMData *ADSInterpreter::findTTMEnviro(int16 enviro) {
+ for (auto & env : _adsData._scriptEnvs) {
+ if (env._enviro == enviro)
+ return &env;
+ }
+ return nullptr;
+}
+
+TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seq) {
+ for (auto & ttm : _adsData._ttmSeqs) {
+ if (ttm._enviro == enviro && ttm._seqNum == seq)
+ return &ttm;
+ }
+ return nullptr;
+}
+
+
+void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
+ seg -= 1;
+ if (seg >= 0) {
+ _adsData._charWhile[seg] = 0;
+ if (_adsData._state[seg] != 8)
+ _adsData._state[seg] = (_adsData._state[seg] & 8) | val;
+ }
+}
+
+
+void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
+ seg -= 1;
+ if (seg >= 0) {
+ _adsData._charWhile[seg] = 0;
+ if (_adsData._state[seg] != 8)
+ _adsData._state[seg] = val;
+ }
+}
+
+void ADSInterpreter::findEndOrInitOp() {
+ Common::SeekableReadStream *scr = _adsData.scr;
+ while (true && scr->pos() < scr->size()) {
+ uint16 opcode = scr->readUint16LE();
+ if (opcode == 0xffff || opcode == 0x0000) {
+ scr->seek(-4, SEEK_CUR);
+ return;
+ }
+ if (opcode == 0x0005)
+ return;
+ scr->skip(numArgs(opcode) * 2);
+ }
+}
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
- uint16 subIdx, subMax;
+ uint16 enviro, seqnum;
switch (code) {
case 0x0001:
case 0x0005:
- // Seems to be "enter" or "label", does nothing. 0x0005 can be used for searching..
- break;
- case 0x2005: { // ADD SCENE TO QUEUE
- subIdx = scr->readUint16LE();
- subMax = scr->readUint16LE();
- // TODO: We only add the first scene here, ignoring the rest
- if (_state.subMax == 0) {
- _state.scene = subIdx;
- _state.subIdx = subIdx;
- _state.subMax = subMax;
- _ttmInterpreter->load(_scriptData.names[subIdx - 1]);
+ // "init". 0x0005 can be used for searching for next thing.
+ break;
+ case 0x2000: // ADD sequence and reset frame
+ case 0x2005: { // ADD sequence
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ int16 runCount = scr->readSint16LE();
+
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (!state)
+ error("ADS invalid seq requested %d %d", enviro, seqnum);
+
+ if (code == 0x2000)
+ state->_currentFrame = state->_startFrame;
+
+ _currentTTMSeq = state;
+ if (runCount == 0) {
+ state->_runFlag = kRunType1;
+ } else if (runCount < 0) {
+ // Negative run count sets the cut time
+ state->_timeCut = g_system->getMillis() + runCount;
+ // Should this be *10 like delays?
+ warning("TODO: checkhandling of negative runcount %d", runCount);
+ state->_runFlag = kRunTypeTimeLimited;
+ } else {
+ state->_runFlag = kRunTypeMulti;
+ state->_runCount++;
}
- uint16 unk1 = scr->readUint16LE();
- uint16 unk2 = scr->readUint16LE();
- debug("ADSInterpreter add scene - subIdx: %d, subMax: %d, unk1: %d, unk2: %d", subIdx, subMax, unk1, unk2);
+ state->_runPlayed++;
+ uint16 unk = scr->readUint16LE();
+ debug("ADSInterpreter add scene - enviro: %d, seqNum: %d, runCount: %d, unk: %d", enviro, seqnum, runCount, unk);
break;
}
case 0x1330: { // IF_NOT_PLAYED, 2 params
- subIdx = scr->readUint16LE();
- subMax = scr->readUint16LE();
- warning("Unimplemented ADS opcode: IF_NOT_PLAYED subIdx: %d, subMax: %d", subIdx, subMax);
- if (_state._subsPlayed[subIdx - 1])
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (state && !state->_runPlayed)
skipToEndIf(scr);
break;
}
case 0x1350: { // IF_PLAYED, 2 params
- subIdx = scr->readUint16LE();
- subMax = scr->readUint16LE();
- warning("Unimplemented ADS opcode: IF_PLAYED subIdx: %d, subMax: %d", subIdx, subMax);
- if (!_state._subsPlayed[subIdx - 1])
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (state && state->_runPlayed)
skipToEndIf(scr);
break;
}
case 0x1360: { // IF_NOT_RUNNING, 2 params
- subIdx = scr->readUint16LE();
- subMax = scr->readUint16LE();
- warning("Unimplemented ADS opcode: IF_NOT_RUNNING subIdx: %d, subMax: %d", subIdx, subMax);
- if (_state._subsRunning[subIdx - 1])
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (state && state->_runFlag == 0)
skipToEndIf(scr);
break;
}
case 0x1370: { // IF_RUNNING, 2 params
- subIdx = scr->readUint16LE();
- subMax = scr->readUint16LE();
- warning("Unimplemented ADS opcode: IF_RUNNING subIdx: %d, subMax: %d", subIdx, subMax);
- if (!_state._subsRunning[subIdx - 1])
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (state && (state->_runFlag == 1 || state->_runFlag == 2 || state->_runFlag == 3))
skipToEndIf(scr);
break;
}
@@ -491,23 +648,27 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xffff: // END
return false;
+ case 0xF010: {// FADE_OUT, 1 param
+ uint16 segment = scr->readUint16LE();
+ debug("ADS FADE OUT?? segment param %x", segment);
+
+ }
//// unknown / to-be-implemented
case 0x0190:
case 0x1070: // unknown, 2 params
+ case 0x1080: // unknown if-related, 1 param
case 0x1340:
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
- case 0x1500:
+ case 0x1500: // ? IF ?
case 0x1520: // PLAY_SCENE_ENDIF, 5 params
- case 0x2000:
case 0x2010: // STOP_SCENE, 3 params
case 0x2020: // RESET SCENE, 2 params (scene, subScene)
case 0x3010: // RANDOM_START, 0 params
case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
- case 0x4000: // unknown, 3 params
- case 0x4010:
- case 0xF010: // FADE_OUT, 0 params
+ case 0x4000: // MOVE TO FRONT?, 3 params
+ case 0x4010: // MOVE TO BACK??, 3 params
case 0xF200: // RUN_SCRIPT, 1 param
case 0xFDA8:
case 0xFE98:
@@ -522,20 +683,92 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
break;
}
}
-
+
return true;
}
bool ADSInterpreter::run() {
- if (_state.subMax > 0) {
- playScene();
- return true;
+ if (_adsData._ttmSeqs.empty())
+ return false;
+
+ for (int i = 0; i < _adsData._maxSegments; i++) {
+ int16 flag = _adsData._state[i] & 0xfff7;
+ for (auto seq : _adsData._usedSeqs[i]) {
+ if (flag == 3) {
+ seq->reset();
+ } else {
+ seq->_scriptFlag = flag;
+ }
+ }
}
- Common::SeekableReadStream *scr = _scriptData.scr;
- if (!scr)
- return false;
- if (scr->pos() >= scr->size())
+ for (int i = 0; i < _adsData._maxSegments; i++) {
+ int16 state = _adsData._state[i];
+ int32 offset = _adsData._segments[i];
+ _adsData.scr->seek(offset);
+ if (state & 8) {
+ _adsData._state[i] &= 0xfff7;
+ } else {
+ findEndOrInitOp();
+ }
+
+ if (_adsData._charWhile[i])
+ offset = _adsData._charWhile[i];
+
+ if (state == 3 || state == 4) {
+ _adsData._state[i] = 1;
+ state = 1;
+ }
+
+ if (_adsData.scr && state == 1) {
+ _adsData.scr->seek(offset);
+ runUntilScenePlayedOrEnd();
+ }
+ }
+
+ bool result = false;
+ for (auto &seq : _adsData._ttmSeqs) {
+ _currentTTMSeq = &seq;
+ seq._lastFrame = -1;
+ int sflag = seq._scriptFlag;
+ TTMRunType rflag = seq._runFlag;
+ if (sflag == 6 || (rflag != kRunType1 && rflag != kRunTypeTimeLimited && rflag != kRunTypeMulti && rflag != kRunType5)) {
+ if (sflag != 6 && sflag != 5 && rflag == kRunType4) {
+ seq._runFlag = kRunTypeStopped;
+ }
+ } else {
+ int16 curframe = seq._currentFrame;
+ TTMData *env = findTTMEnviro(seq._enviro);
+ bool scriptresult = false;
+ if (curframe < env->_pages && curframe > -1 && env->_pageOffsets[curframe] > -1) {
+ env->scr->seek(env->_pageOffsets[curframe]);
+ _currentTTMSeq = &seq;
+ scriptresult = playScene();
+ }
+
+ if (scriptresult) {
+ seq._executed = 1;
+ seq._lastFrame = seq._currentFrame;
+ result = true;
+ warning("TODO: ADSInterpreter::run Finish script result true section");
+ // TODO: set script delay here
+ // TODO: Finish lines 118 to 149 of disasm.
+ } else if (sflag != 5) {
+ seq._gotoFrame = seq._startFrame;
+ seq._runFlag = kRunType4;
+ }
+ }
+
+ if (rflag == kRunTypeTimeLimited && seq._timeCut > g_system->getMillis()) {
+ seq._runFlag = kRunTypeStopped;
+ }
+ }
+ return result;
+}
+
+bool ADSInterpreter::runUntilScenePlayedOrEnd() {
+ Common::SeekableReadStream *scr = _adsData.scr;
+ if (!scr || scr->pos() >= scr->size())
return false;
bool more = true;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index cbe787bfd6a..981075bcef9 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -44,55 +44,89 @@ public:
class TTMData : public ScriptParserData {
public:
TTMData() : _pages(330), ScriptParserData() {}
+ uint16 _enviro;
uint16 _pages;
Common::Array<int> _pageOffsets;
+ Common::String _bmpNames[16];
};
-struct TTMState {
- TTMState() : scene(0), _delay(0), _drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), _currentBmpId(0), _currentPalId(0), _drawColFG(0), _drawColBG(0), _delayStart(0), _setupFinished(false) {}
- uint16 scene;
- int _delay;
- uint32 _delayStart;
+enum TTMRunType {
+ kRunTypeStopped = 0,
+ kRunType1 = 1,
+ kRunTypeMulti = 2,
+ kRunTypeTimeLimited = 3,
+ kRunType4 = 4,
+ kRunType5 = 5,
+};
+
+
+struct TTMSeq {
+ TTMSeq() : _enviro(0), _seqNum(0), _currentFrame(0), _currentPalId(0), _startFrame(0) {
+ reset();
+ }
+
+ void reset();
+
+ int16 _enviro;
+ int16 _seqNum;
+ int16 _startFrame;
+ int16 _gotoFrame;
+ int16 _currentFrame;
+ int16 _lastFrame;
+ int16 _selfLoop;
+ int16 _executed;
+ int16 _slot[6];
+ uint32 _timeNext;
+ uint32 _timeCut;
Common::Rect _drawWin;
int _currentBmpId;
int _currentPalId;
byte _drawColFG;
byte _drawColBG;
- bool _setupFinished;
- Common::String bmpNames[16];
+ int _runPlayed;
+ int _runCount;
+ TTMRunType _runFlag;
+ int _scriptFlag;
};
class ADSData : public ScriptParserData {
public:
- ADSData() {}
- Common::Array<Common::String> names;
-};
-
-struct ADSState {
- ADSState() : scene(0), subIdx(0), subMax(0) {}
- uint16 scene;
- uint16 subIdx, subMax;
- Common::Array<bool> _subsPlayed;
- Common::Array<bool> _subsRunning;
+ ADSData() : _initFlag(0), _maxSegments(0) {
+ for (int i = 0; i < ARRAYSIZE(_state); i++) {
+ _state[i] = 8;
+ }
+ ARRAYCLEAR(_countdown);
+ ARRAYCLEAR(_segments);
+ ARRAYCLEAR(_charWhile);
+ }
+ Common::Array<Common::String> _scriptNames;
+ Common::Array<TTMData> _scriptEnvs;
+ Common::Array<TTMSeq> _ttmSeqs;
+ int _initFlag;
+ int _maxSegments;
+ // TODO: replace these with dynamic arrays - fixed arrays inherited from original.
+ int _state[80];
+ int _countdown[80];
+ // note: originals uses char * but we use offsets into script for less pointers..
+ int32 _segments[80];
+ int32 _charWhile[80];
+ Common::Array<struct TTMSeq *> _usedSeqs[80];
};
class TTMInterpreter {
public:
TTMInterpreter(DgdsEngine *vm);
- bool load(const Common::String &filename);
+ bool load(const Common::String &filename, TTMData &env);
void unload();
- bool run();
-
- uint16 getScene() const { return _state.scene; }
+ bool run(TTMData &env, struct TTMSeq &seq);
+ void findAndAddSequences(TTMData &scriptData, Common::Array<TTMSeq> &seqArray);
protected:
- void handleOperation(uint16 op, byte count, int16 *ivals, Common::String &sval);
- void updateScreen();
+ void handleOperation(TTMData &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
+ void updateScreen(struct TTMSeq &seq);
DgdsEngine *_vm;
- TTMData _scriptData;
- TTMState _state;
};
class ADSInterpreter {
@@ -104,17 +138,25 @@ public:
void unload();
bool run();
int numArgs(uint16 opcode) const;
+ void segmentOrState(int16 seg, uint16 val);
+ void segmentSetState(int16 seg, uint16 val);
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
- void playScene();
+ bool playScene();
void skipToEndIf(Common::SeekableReadStream *scr);
+ TTMSeq *findTTMSeq(int16 enviro, int16 seq);
+ TTMData *findTTMEnviro(int16 enviro);
+ bool runUntilScenePlayedOrEnd();
+ void findUsedSequencesForSegment(int segno);
+ void findEndOrInitOp();
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
- ADSData _scriptData;
- ADSState _state;
+ ADSData _adsData;
+
+ TTMSeq *_currentTTMSeq;
};
} // End of namespace Dgds
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index e8c30222cbd..057b3fea97e 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -205,7 +205,7 @@ void Sound::playMusic(const Common::String &filename) {
if (chunk.isContainer()) {
continue;
}
-
+
chunk.readContent(_decompressor);
Common::SeekableReadStream *stream = chunk.getContent();
Commit: 7bd0be7a719616e9a1a3ba6a8172e082100ed194
https://github.com/scummvm/scummvm/commit/7bd0be7a719616e9a1a3ba6a8172e082100ed194
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More work on ADS and TTM
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
engines/dgds/sound.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 463d35bdb8c..befe083f5db 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -181,7 +181,7 @@ void DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_adsInterp->load(_scene->getAdsFile());
_scene->runEnterSceneOps();
- debug("%s", _scene->dump("").c_str());
+ //debug("%s", _scene->dump("").c_str());
}
Common::Error DgdsEngine::run() {
@@ -223,7 +223,7 @@ Common::Error DgdsEngine::run() {
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
- debug("%s", _gdsScene->dump("").c_str());
+ //debug("%s", _gdsScene->dump("").c_str());
loadCorners("DCORNERS.BMP");
reqParser.parse(&invRequestData, "DINV.REQ");
@@ -264,8 +264,8 @@ Common::Error DgdsEngine::run() {
//getDebugger()->attach();
- debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
- debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
+ //debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
+ //debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
bool triggerMenu = false;
@@ -321,6 +321,7 @@ Common::Error DgdsEngine::run() {
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
+ /*
if (!creditsShown) {
creditsShown = true;
if (getGameId() == GID_DRAGON) {
@@ -330,7 +331,7 @@ Common::Error DgdsEngine::run() {
}
} else {
return Common::kNoError;
- }
+ }*/
}
_scene->checkTriggers();
} else if (getGameId() == GID_BEAMISH) {
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index bd049210202..eda8a177ee2 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -83,8 +83,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
_vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
break;
case 0x0110: // PURGE void
- // .. shouldn't actually clear the bmps, what should it do?
- state._currentBmpId = 0;
+ _vm->adsInterpreter()->setHitTTMOp0110();
break;
case 0x0ff0: {
// REFRESH: void
@@ -114,20 +113,24 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
break;
case 0x1090:
// SELECT SONG: id:int [0]
+ state._currentSongId = ivals[0];
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
debug("SCENE SETUP DONE: %u", ivals[0]);
break;
+ case 0x1100: // SET_SCENE: i:int [1..n]
case 0x1110: { // SET_SCENE: i:int [1..n]
// DESCRIPTION IN TTM TAGS.
debug("SET SCENE: %u", ivals[0]);
- state._currentFrame = ivals[0];
break;
}
case 0x1200: // GOTO? How different to SET SCENE??
debug("GOTO SCENE: %u", ivals[0]);
state._currentFrame = ivals[0];
break;
+ case 0x1300: // PLAY SFX? i:int - eg [72], found in Dragon + HoC intro
+ debug("TODO: PLAY SFX?: %u", ivals[0]);
+ break;
case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
state._drawColFG = static_cast<byte>(ivals[0]);
state._drawColBG = static_cast<byte>(ivals[1]);
@@ -264,9 +267,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
case 0x0220: // STOP CURRENT MUSIC
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1070: // SELECT FONT i:int
- case 0x1100: // ? i:int [9]
case 0x1120: // SET_BACKGROUND
- case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
case 0x1310: // STOP SFX i:int eg [107]
case 0x2010: // SET FRAME
case 0x2020: // SET TIMER
@@ -304,43 +305,45 @@ bool TTMInterpreter::run(TTMData &env, struct TTMSeq &seq) {
}
seq._timeNext = 0;
- uint16 code = scr->readUint16LE();
- uint16 op = code & 0xFFF0;
- byte count = code & 0x000F;
- int16 ivals[8];
- Common::String sval;
-
- if (count > 8 && count != 0x0f)
- error("Invalid TTM opcode %04x requires %d locals", code, count);
-
- debugN("\tOP: 0x%4.4x %2u ", op, count);
- if (count == 0x0F) {
- byte ch[2];
-
- do {
- ch[0] = scr->readByte();
- ch[1] = scr->readByte();
- if (ch[0])
- sval += ch[0];
- if (ch[1])
- sval += ch[1];
- } while (ch[0] != 0 && ch[1] != 0);
-
- debugN("\"%s\"", sval.c_str());
- } else {
- for (byte i = 0; i < count; i++) {
- ivals[i] = scr->readSint16LE();
- if (i > 0)
- debugN(", ");
- debugN("%d", ivals[i]);
+ uint16 code = 0;
+ while (code != 0xff0 && scr->pos() < scr->size()) {
+ code = scr->readUint16LE();
+ uint16 op = code & 0xFFF0;
+ byte count = code & 0x000F;
+ int16 ivals[8];
+ Common::String sval;
+
+ if (count > 8 && count != 0x0f)
+ error("Invalid TTM opcode %04x requires %d locals", code, count);
+
+ debugN("\tOP: 0x%4.4x %2u ", op, count);
+ if (count == 0x0F) {
+ byte ch[2];
+
+ do {
+ ch[0] = scr->readByte();
+ ch[1] = scr->readByte();
+ if (ch[0])
+ sval += ch[0];
+ if (ch[1])
+ sval += ch[1];
+ } while (ch[0] != 0 && ch[1] != 0);
+
+ debugN("\"%s\"", sval.c_str());
+ } else {
+ for (byte i = 0; i < count; i++) {
+ ivals[i] = scr->readSint16LE();
+ if (i > 0)
+ debugN(", ");
+ debugN("%d", ivals[i]);
+ }
}
- }
- debug(" ");
+ debug(" ");
- handleOperation(env, seq, op, count, ivals, sval);
+ handleOperation(env, seq, op, count, ivals, sval);
+ }
updateScreen(seq);
-
return true;
}
@@ -349,7 +352,7 @@ void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &se
env.scr->seek(0);
uint16 op = 0;
for (uint page = 0; page < env._pages; page++) {
- while (op != 0xff0 && !env.scr->eos()) {
+ while (op != 0xff0 && env.scr->pos() < env.scr->size()) {
op = env.scr->readUint16LE();
switch (op & 0xf) {
case 0:
@@ -396,10 +399,10 @@ void TTMSeq::reset() {
_timeNext = 0;
_runCount = 0;
_runPlayed = 0;
- _executed = 0;
+ _executed = false;
_runFlag = kRunTypeStopped;
_scriptFlag = 0;
- _selfLoop = 0;
+ _selfLoop = false;
_drawWin = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
@@ -440,20 +443,30 @@ bool ADSInterpreter::load(const Common::String &filename) {
uint16 opcode = 0;
int segcount = 0;
- while (_adsData.scr->pos() < _adsData.scr->eos()) {
+ findUsedSequencesForSegment(0);
+ _adsData._segments[0] = 0;
+ while (_adsData.scr->pos() < _adsData.scr->size()) {
opcode = _adsData.scr->readUint16LE();
if (opcode == 0xffff) {
- findUsedSequencesForSegment(segcount);
segcount++;
+ _adsData._segments[segcount] = _adsData.scr->pos();
+ findUsedSequencesForSegment(segcount);
} else {
_adsData.scr->skip(numArgs(opcode) * 2);
}
}
- _adsData._maxSegments = segcount + 1;
+ for (uint i = segcount + 1; i < ARRAYSIZE(_adsData._segments); i++)
+ _adsData._segments[i] = 0;
+ _adsData._maxSegments = segcount + 1;
_adsData.filename = filename;
+ for (uint i = 0; i < ARRAYSIZE(_adsData._state); i++)
+ _adsData._state[i] = 8;
+ for (auto &seq : _adsData._ttmSeqs)
+ seq.reset();
+
return true;
}
@@ -462,6 +475,25 @@ static const uint16 ADS_SEQ_OPCODES[] = {
0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
};
+bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
+ if (seq._timeInterval != 0) {
+ uint32 now = g_system->getMillis();
+ if (now < seq._timeNext)
+ return false;
+ seq._timeNext = now + seq._timeInterval;
+ }
+
+ seq._executed = false;
+ if (seq._gotoFrame == -1) {
+ seq._currentFrame++;
+ } else {
+ seq._currentFrame = seq._gotoFrame;
+ seq._gotoFrame = -1;
+ }
+
+ return true;
+}
+
void ADSInterpreter::findUsedSequencesForSegment(int segno) {
_adsData._usedSeqs[segno].clear();
int64 startoff = _adsData.scr->pos();
@@ -470,8 +502,14 @@ void ADSInterpreter::findUsedSequencesForSegment(int segno) {
opcode = _adsData.scr->readUint16LE();
for (uint16 o : ADS_SEQ_OPCODES) {
if (opcode == o) {
- TTMSeq *seq = findTTMSeq(_adsData.scr->readUint16LE(), _adsData.scr->readUint16LE());
- _adsData._usedSeqs[segno].push_back(seq);
+ int16 envno = _adsData.scr->readSint16LE();
+ int16 seqno = _adsData.scr->readSint16LE();
+ TTMSeq *seq = findTTMSeq(envno, seqno);
+ if (!seq)
+ warning("ADS references unknown seq %d %d", envno, seqno);
+ else
+ _adsData._usedSeqs[segno].push_back(seq);
+ // Go back as we will go forward again outside this loop.
_adsData.scr->seek(-4, SEEK_CUR);
break;
}
@@ -558,10 +596,10 @@ void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
void ADSInterpreter::findEndOrInitOp() {
Common::SeekableReadStream *scr = _adsData.scr;
- while (true && scr->pos() < scr->size()) {
+ while (scr->pos() < scr->size()) {
uint16 opcode = scr->readUint16LE();
if (opcode == 0xffff || opcode == 0x0000) {
- scr->seek(-4, SEEK_CUR);
+ scr->seek(-2, SEEK_CUR);
return;
}
if (opcode == 0x0005)
@@ -578,7 +616,50 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x0005:
// "init". 0x0005 can be used for searching for next thing.
break;
- case 0x2000: // ADD sequence and reset frame
+ case 0x1330: { // IF_NOT_PLAYED, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (state && !state->_runPlayed)
+ skipToEndIf(scr);
+ break;
+ }
+ case 0x1350: { // IF_PLAYED, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *state = findTTMSeq(enviro, seqnum);
+ if (state && state->_runPlayed)
+ skipToEndIf(scr);
+ break;
+ }
+ case 0x1360: { // IF_NOT_RUNNING, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && seq->_runFlag == kRunTypeStopped)
+ skipToEndIf(scr);
+ break;
+ }
+ case 0x1370: { // IF_RUNNING, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && (seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited))
+ skipToEndIf(scr);
+ break;
+ }
+ case 0x1500: // ? IF ?, 0 params
+ debug("Unimplemented ADS branch logic opcode 0x1500");
+ //sceneLogicOps();
+ _adsData._hitBranchOp = true;
+ return true;
+ case 0x1510: // PLAY_SCENE? 0 params
+ return false;
+ case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
+ _adsData._hitBranchOp = true;
+ return false;
+
+ case 0x2000:
case 0x2005: { // ADD sequence
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
@@ -602,48 +683,22 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
state->_runFlag = kRunTypeTimeLimited;
} else {
state->_runFlag = kRunTypeMulti;
- state->_runCount++;
+ state->_runCount = runCount - 1;
}
state->_runPlayed++;
uint16 unk = scr->readUint16LE();
debug("ADSInterpreter add scene - enviro: %d, seqNum: %d, runCount: %d, unk: %d", enviro, seqnum, runCount, unk);
break;
}
- case 0x1330: { // IF_NOT_PLAYED, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && !state->_runPlayed)
- skipToEndIf(scr);
- break;
- }
- case 0x1350: { // IF_PLAYED, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && state->_runPlayed)
- skipToEndIf(scr);
- break;
- }
- case 0x1360: { // IF_NOT_RUNNING, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && state->_runFlag == 0)
- skipToEndIf(scr);
- break;
- }
- case 0x1370: { // IF_RUNNING, 2 params
+ case 0x2020: { // RESET SEQ, 2 params (env, seq)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && (state->_runFlag == 1 || state->_runFlag == 2 || state->_runFlag == 3))
- skipToEndIf(scr);
+ uint16 unk = scr->readUint16LE();
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq)
+ seq->reset();
break;
}
- case 0x1510: // PLAY_SCENE, 0 params
- debug("ADS PLAY SCENE");
- return false;
case 0xffff: // END
return false;
@@ -651,28 +706,28 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xF010: {// FADE_OUT, 1 param
uint16 segment = scr->readUint16LE();
debug("ADS FADE OUT?? segment param %x", segment);
-
+ break;
}
+
//// unknown / to-be-implemented
- case 0x0190:
+ case 0x1010: // unknown, 2 params
+ case 0x1020: // unknown, 2 params
+ case 0x1030: // unknown, 2 params
+ case 0x1040: // unknown, 2 params
+ case 0x1050: // unknown, 2 params
+ case 0x1060: // unknown, 2 params
case 0x1070: // unknown, 2 params
case 0x1080: // unknown if-related, 1 param
case 0x1340:
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
- case 0x1500: // ? IF ?
- case 0x1520: // PLAY_SCENE_ENDIF, 5 params
case 0x2010: // STOP_SCENE, 3 params
- case 0x2020: // RESET SCENE, 2 params (scene, subScene)
case 0x3010: // RANDOM_START, 0 params
case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
case 0x4000: // MOVE TO FRONT?, 3 params
case 0x4010: // MOVE TO BACK??, 3 params
case 0xF200: // RUN_SCRIPT, 1 param
- case 0xFDA8:
- case 0xFE98:
- case 0xFF88:
case 0xFF10:
case 0xFFF0: // END_IF, 0 params
default: {
@@ -710,6 +765,7 @@ bool ADSInterpreter::run() {
_adsData._state[i] &= 0xfff7;
} else {
findEndOrInitOp();
+ offset = _adsData.scr->pos();
}
if (_adsData._charWhile[i])
@@ -722,7 +778,7 @@ bool ADSInterpreter::run() {
if (_adsData.scr && state == 1) {
_adsData.scr->seek(offset);
- runUntilScenePlayedOrEnd();
+ runUntilBrancOpOrEnd();
}
}
@@ -739,6 +795,7 @@ bool ADSInterpreter::run() {
} else {
int16 curframe = seq._currentFrame;
TTMData *env = findTTMEnviro(seq._enviro);
+ _adsData._hitTTMOp0110 = false;
bool scriptresult = false;
if (curframe < env->_pages && curframe > -1 && env->_pageOffsets[curframe] > -1) {
env->scr->seek(env->_pageOffsets[curframe]);
@@ -747,10 +804,42 @@ bool ADSInterpreter::run() {
}
if (scriptresult) {
- seq._executed = 1;
+ seq._executed = true;
seq._lastFrame = seq._currentFrame;
result = true;
- warning("TODO: ADSInterpreter::run Finish script result true section");
+ if (_adsData._scriptDelay != -1 && seq._timeInterval != _adsData._scriptDelay) {
+ uint32 now = g_system->getMillis();
+ seq._timeNext = now + _adsData._scriptDelay;
+ seq._timeInterval = _adsData._scriptDelay;
+ }
+
+ // TODO: What is global 4804?
+ if (!_adsData._hitTTMOp0110) {
+ warning("TODO: ADSInterpreter::run Finish script result true section");
+ // if (global4806 != -1) {
+ // seq._gotoFrame = global4806;
+ // if (seq._currentFrame == global4806)
+ // seq._selfLoop = 1;
+ // }
+ if (seq._runFlag != kRunType5)
+ updateSeqTimeAndFrame(seq);
+ } else {
+ seq._gotoFrame = seq._startFrame;
+ if (seq._runFlag == kRunTypeMulti && seq._runCount != 0) {
+ bool updated = updateSeqTimeAndFrame(seq);
+ if (updated) {
+ seq._runCount--;
+ }
+ } else if (seq._runFlag == kRunTypeTimeLimited && seq._timeCut != 0) {
+ updateSeqTimeAndFrame(seq);
+ } else {
+ bool updated = updateSeqTimeAndFrame(seq);
+ if (updated) {
+ seq._runFlag = kRunType4;
+ seq._timeInterval = 0;
+ }
+ }
+ }
// TODO: set script delay here
// TODO: Finish lines 118 to 149 of disasm.
} else if (sflag != 5) {
@@ -766,7 +855,7 @@ bool ADSInterpreter::run() {
return result;
}
-bool ADSInterpreter::runUntilScenePlayedOrEnd() {
+bool ADSInterpreter::runUntilBrancOpOrEnd() {
Common::SeekableReadStream *scr = _adsData.scr;
if (!scr || scr->pos() >= scr->size())
return false;
@@ -775,11 +864,17 @@ bool ADSInterpreter::runUntilScenePlayedOrEnd() {
do {
uint16 code = scr->readUint16LE();
more = handleOperation(code, scr);
- } while (more && scr->pos() < scr->size());
+ } while (!_adsData._hitBranchOp && more && scr->pos() < scr->size());
+
+ _adsData._hitBranchOp = false;
return true;
}
+void ADSInterpreter::setHitTTMOp0110() {
+ _adsData._hitTTMOp0110 = true;
+}
+
int ADSInterpreter::numArgs(uint16 opcode) const {
// TODO: This list is from DRAGON, there may be more entries in newer games.
switch (opcode) {
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 981075bcef9..d4529c88415 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -61,7 +61,7 @@ enum TTMRunType {
struct TTMSeq {
- TTMSeq() : _enviro(0), _seqNum(0), _currentFrame(0), _currentPalId(0), _startFrame(0) {
+ TTMSeq() : _enviro(0), _seqNum(0), _currentFrame(0), _currentPalId(0), _startFrame(0), _currentSongId(-1) {
reset();
}
@@ -73,25 +73,27 @@ struct TTMSeq {
int16 _gotoFrame;
int16 _currentFrame;
int16 _lastFrame;
- int16 _selfLoop;
- int16 _executed;
+ bool _selfLoop;
+ bool _executed;
int16 _slot[6];
uint32 _timeNext;
uint32 _timeCut;
Common::Rect _drawWin;
- int _currentBmpId;
- int _currentPalId;
+ int16 _currentBmpId;
+ int16 _currentSongId;
+ int16 _currentPalId;
byte _drawColFG;
byte _drawColBG;
- int _runPlayed;
- int _runCount;
+ int16 _runPlayed;
+ int16 _runCount;
+ int16 _timeInterval;
TTMRunType _runFlag;
- int _scriptFlag;
+ int16 _scriptFlag;
};
class ADSData : public ScriptParserData {
public:
- ADSData() : _initFlag(0), _maxSegments(0) {
+ ADSData() : _initFlag(0), _maxSegments(0), _scriptDelay(-1), _hitTTMOp0110(false), _hitBranchOp(false) {
for (int i = 0; i < ARRAYSIZE(_state); i++) {
_state[i] = 8;
}
@@ -111,6 +113,9 @@ public:
int32 _segments[80];
int32 _charWhile[80];
Common::Array<struct TTMSeq *> _usedSeqs[80];
+ int32 _scriptDelay;
+ bool _hitTTMOp0110;
+ bool _hitBranchOp;
};
class TTMInterpreter {
@@ -140,6 +145,8 @@ public:
int numArgs(uint16 opcode) const;
void segmentOrState(int16 seg, uint16 val);
void segmentSetState(int16 seg, uint16 val);
+
+ void setHitTTMOp0110(); // TODO: What is this global?
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
@@ -147,10 +154,10 @@ protected:
void skipToEndIf(Common::SeekableReadStream *scr);
TTMSeq *findTTMSeq(int16 enviro, int16 seq);
TTMData *findTTMEnviro(int16 enviro);
- bool runUntilScenePlayedOrEnd();
+ bool runUntilBrancOpOrEnd();
void findUsedSequencesForSegment(int segno);
void findEndOrInitOp();
-
+ bool updateSeqTimeAndFrame(TTMSeq &seq);
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 057b3fea97e..2e62b541566 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -216,10 +216,10 @@ void Sound::playMusic(const Common::String &filename) {
stream->read(_musicData, _musicSize);
} else if (chunk.isSection(ID_INF)) {
uint32 count = stream->size() / 2;
- //debug(" [%u]", count);
+ debug(" [%u]", count);
for (uint32 k = 0; k < count; k++) {
- /*uint16 idx = */stream->readUint16LE();
- //debug(" %2u: %u", k, idx);
+ uint16 idx = stream->readUint16LE();
+ debug(" %2u: %u", k, idx);
}
}
}
Commit: 1aca7ded40c890c609d2331ddbdbfb8c593144fc
https://github.com/scummvm/scummvm/commit/1aca7ded40c890c609d2331ddbdbfb8c593144fc
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More work to move ADS and TTM execution closer to original
Scenes still don't play, but the logic is getting very close to the original
now. Probably just a few small tweaks to get it going.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index befe083f5db..7408b9015d9 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -318,6 +318,7 @@ Common::Error DgdsEngine::run() {
}
if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
+ _scene->runPreTickOps();
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
@@ -333,6 +334,7 @@ Common::Error DgdsEngine::run() {
return Common::kNoError;
}*/
}
+ _scene->runPostTickOps();
_scene->checkTriggers();
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 6b0af629c54..81a10b1862a 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -732,6 +732,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpChangeSceneToStored: {
uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
engine->changeScene(sceneNo, true);
+ break;
}
case kSceneOpShowClock:
engine->setShowClock(true);
@@ -742,6 +743,12 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpMeanwhile:
warning("TODO: Implement meanwhile screen");
break;
+ case kSceneOp10:
+ warning("TODO: Implement scene op 10 (find SDS hot spot?)");
+ break;
+ case kSceneOp107:
+ warning("TODO: Implement scene op 107 (inject key code 0xfc)");
+ break;
default:
warning("TODO: Implement scene op %d", op._opCode);
break;
@@ -754,7 +761,8 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
return true;
uint truecount = 0;
- Globals *globals = static_cast<DgdsEngine *>(g_engine)->getGameGlobals();
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ Globals *globals = engine->getGameGlobals();
for (const auto & c : conds) {
uint16 refval = c._val;
@@ -765,12 +773,12 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (cflag & kSceneCond80) {
refval = 1;
- // TODO: check something about current ADS script?
- checkval = 0; // ADS_2642_38f6(c._num);
-
+ uint16 segnum = c._num - 1;
+ checkval = engine->adsInterpreter()->getStateForSceneOp(segnum);
SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
refval = 0;
+ cflag = kSceneCondEqual;
} else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemField12) {
// TODO: Get game item c._num and check value from item attributes
checkval = 0;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index eda8a177ee2..53d5f43a3fe 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -354,6 +354,9 @@ void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &se
for (uint page = 0; page < env._pages; page++) {
while (op != 0xff0 && env.scr->pos() < env.scr->size()) {
op = env.scr->readUint16LE();
+ //debug("findAndAddSequences: check ttm op %04x", op);
+ if (op == 0xaf1f || op == 0xaf2f)
+ warning("TODO: Fix findAndAddSequences for opcode %x which has variable length arg", op);
switch (op & 0xf) {
case 0:
break;
@@ -365,6 +368,7 @@ void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &se
newseq._startFrame = page;
newseq._currentFrame = page;
newseq._lastFrame = -1;
+ debug("findAndAddSequences: found env %d seq %d", newseq._enviro, newseq._seqNum);
seqArray.push_back(newseq);
} else {
env.scr->skip(2);
@@ -505,11 +509,21 @@ void ADSInterpreter::findUsedSequencesForSegment(int segno) {
int16 envno = _adsData.scr->readSint16LE();
int16 seqno = _adsData.scr->readSint16LE();
TTMSeq *seq = findTTMSeq(envno, seqno);
- if (!seq)
- warning("ADS references unknown seq %d %d", envno, seqno);
- else
- _adsData._usedSeqs[segno].push_back(seq);
- // Go back as we will go forward again outside this loop.
+ if (!seq) {
+ warning("ADS opcode %04x at offset %d references unknown seq %d %d",
+ opcode, (int)_adsData.scr->pos(), envno, seqno);
+ } else {
+ bool already_added = false;
+ for (TTMSeq *s : _adsData._usedSeqs[segno]) {
+ if (s == seq) {
+ already_added = true;
+ break;
+ }
+ }
+ if (!already_added)
+ _adsData._usedSeqs[segno].push_back(seq);
+ }
+ // Rewind as we will go forward again outside this loop.
_adsData.scr->seek(-4, SEEK_CUR);
break;
}
@@ -742,6 +756,21 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
return true;
}
+int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
+ if (segnum > _adsData._maxSegments)
+ return 0;
+ if (!(_adsData._state[segnum] & 4)) {
+ for (auto *seq : _adsData._usedSeqs[segnum]) {
+ if (!seq)
+ return 0;
+ if (seq->_runFlag != kRunTypeStopped && !seq->_selfLoop)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
bool ADSInterpreter::run() {
if (_adsData._ttmSeqs.empty())
return false;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index d4529c88415..910bbe4d687 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -147,6 +147,7 @@ public:
void segmentSetState(int16 seg, uint16 val);
void setHitTTMOp0110(); // TODO: What is this global?
+ int16 getStateForSceneOp(uint16 segnum);
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
Commit: 1c9ea680697bc88f1732f0c2ea5678530c0e029c
https://github.com/scummvm/scummvm/commit/1c9ea680697bc88f1732f0c2ea5678530c0e029c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More ADS fixes, now mostly working
ADS files now seem to basically execute correctly! Now to move on to fixing
TTMs - currently screen updates are broken.
Changed paths:
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/parser.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 565fb0dcab4..4b7408e04ea 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -47,12 +47,12 @@ GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompres
_resourceMan(resourceMan), _decompressor(decompressor) {
}
-void GamePalettes::loadPalette(Common::String filename) {
+int GamePalettes::loadPalette(Common::String filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream) {
// Happens in the Amiga version of Dragon
warning("Couldn't load palette resource %s", filename.c_str());
- return;
+ return 0;
}
_palettes.resize(_palettes.size() + 1);
@@ -75,8 +75,9 @@ void GamePalettes::loadPalette(Common::String filename) {
}
delete fileStream;
+ selectPalNum(_palettes.size() - 1);
- selectPalNum(0);
+ return _palettes.size() - 1;
}
void GamePalettes::selectPalNum(int num) {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 98383c0995b..2eb34555e50 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -46,7 +46,7 @@ public:
class GamePalettes {
public:
GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor);
- void loadPalette(Common::String filename);
+ int loadPalette(Common::String filename);
void selectPalNum(int num);
void setPalette();
void clearPalette();
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 865145d36d6..8cc54c65e9d 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -91,7 +91,7 @@ Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableRea
bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
- TTMData *scriptData = static_cast<TTMData *>(data);
+ TTMEnviro *scriptData = static_cast<TTMEnviro *>(data);
switch (chunk.getId()) {
case ID_TTI: // Ignore containers
@@ -110,8 +110,8 @@ bool TTMParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
warning("unspected PAG chunk size %d in %s", chunk.getSize(), _filename.c_str());
break;
}
- scriptData->_pages = chunk.getContent()->readUint16LE();
- scriptData->_pageOffsets.resize(scriptData->_pages + 1);
+ scriptData->_totalFrames = chunk.getContent()->readUint16LE();
+ scriptData->_frameOffsets.resize(scriptData->_totalFrames + 1, -1);
break;
default:
warning("Unexpected chunk '%s' of size %d found in file '%s'", tag2str(chunk.getId()), chunk.getSize(), _filename.c_str());
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 81a10b1862a..b1786db3a87 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -25,6 +25,7 @@
#include "common/file.h"
#include "common/rect.h"
#include "common/system.h"
+#include "graphics/cursorman.h"
#include "graphics/surface.h"
#include "graphics/primitives.h"
@@ -79,9 +80,9 @@ Common::String SceneStruct2::dump(const Common::String &indent) const {
static Common::String _sceneOpCodeName(SceneOpCode code) {
switch (code) {
- case kSceneOpNone: return "none";
- case kSceneOpChangeScene: return "changeScene";
- case kSceneOpNoop: return "noop";
+ case kSceneOpNone: return "none";
+ case kSceneOpChangeScene: return "changeScene";
+ case kSceneOpNoop: return "noop";
case kSceneOpGlobal: return "global";
case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
case kSceneOpSetItemAttr: return "setitemattr?";
@@ -91,9 +92,9 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
case kSceneOpShowClock: return "sceneOpShowClock";
case kSceneOpHideClock: return "sceneOpHideClock";
- case kSceneOp18Menu: return "sceneOp18(menu1?)";
- case kSceneOp19Menu: return "sceneOp18(menu0?)";
- case kSceneOpMeanwhile: return "meanwhile";
+ case kSceneOpShowMouse: return "sceneOpShowMouse";
+ case kSceneOpHideMouse: return "sceneOpHideMouse";
+ case kSceneOpMeanwhile: return "meanwhile";
default:
return Common::String::format("sceneOp%d", (int)code);
}
@@ -740,6 +741,12 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpHideClock:
engine->setShowClock(false);
break;
+ case kSceneOpShowMouse:
+ CursorMan.showMouse(true);
+ break;
+ case kSceneOpHideMouse:
+ CursorMan.showMouse(false);
+ break;
case kSceneOpMeanwhile:
warning("TODO: Implement meanwhile screen");
break;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index e64fa5e1439..d30f746ae1e 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -93,8 +93,8 @@ enum SceneOpCode {
kSceneOp15 = 15, // args: none.
kSceneOpShowClock = 16, // args: none. set some clock-related globals
kSceneOpHideClock = 17, // args: none. set some clock-related values.
- kSceneOp18Menu = 18, // args: none. set menu-related globals to 1
- kSceneOp19Menu = 19, // args: none. set menu-related globals to 0
+ kSceneOpShowMouse = 18, // args: none.
+ kSceneOpHideMouse = 19, // args: none.
kSceneOp100 = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOp102 = 102, // args: none.
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 53d5f43a3fe..473a50926af 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -44,7 +44,7 @@ namespace Dgds {
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
-bool TTMInterpreter::load(const Common::String &filename, TTMData &scriptData) {
+bool TTMInterpreter::load(const Common::String &filename, TTMEnviro &scriptData) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
bool parseResult = dgds.parse(&scriptData, filename);
@@ -69,7 +69,7 @@ void TTMInterpreter::updateScreen(struct TTMSeq &state) {
g_system->updateScreen();
}
-void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
+void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
switch (op) {
@@ -79,9 +79,15 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
case 0x0020: // SAVE BACKGROUND
_vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
break;
+ case 0x0070: // FREE PALETTE
+ error("TODO: Implement me: free palette (current pal)");
+ break;
case 0x0080: // DRAW BACKGROUND
_vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
break;
+ case 0x0090: // FREE FONT
+ error("TODO: Implement me: free font (current one)");
+ break;
case 0x0110: // PURGE void
_vm->adsInterpreter()->setHitTTMOp0110();
break;
@@ -99,7 +105,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
// SET BMP: id:int [-1:n]
int bk = ivals[0];
if (bk != -1) {
- _vm->_image->loadBitmap(env._bmpNames[state._currentBmpId], bk);
+ _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], bk);
}
break;
}
@@ -109,7 +115,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
break;
case 0x1060:
// SELECT PAL: id:int [0]
- _vm->getGamePals()->selectPalNum(ivals[0]);
+ _vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
break;
case 0x1090:
// SELECT SONG: id:int [0]
@@ -217,7 +223,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
// FALL THROUGH
case 0xa500:
- debug("DRAW \"%s\"", env._bmpNames[state._currentBmpId].c_str());
+ debug("DRAW \"%s\"", env._scriptShapes[state._currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
@@ -225,12 +231,12 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
int tileId = ivals[2];
state._currentBmpId = ivals[3];
if (tileId != -1) {
- _vm->_image->loadBitmap(env._bmpNames[state._currentBmpId], tileId);
+ _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], tileId);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", state._currentBmpId, env._bmpNames[state._currentBmpId].c_str());
- _vm->_image->loadBitmap(env._bmpNames[state._currentBmpId], 0);
+ warning("trying to load bmp %d (%s) on demand", state._currentBmpId, env._scriptShapes[state._currentBmpId].c_str());
+ _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
@@ -245,12 +251,19 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
break;
case 0xf020:
// LOAD BMP: filename:str
- env._bmpNames[state._currentBmpId] = sval;
+ env._scriptShapes[state._currentBmpId] = sval;
break;
- case 0xf050:
+ case 0xf040: {
+ // LOAD FONT: filename:str
+ error("TODO: Implement opcode 0xf040 load font");
+ break;
+ }
+ case 0xf050: {
// LOAD PAL: filename:str
- _vm->getGamePals()->loadPalette(sval);
+ int newPalNum = _vm->getGamePals()->loadPalette(sval);
+ env._scriptPals[state._currentPalId] = newPalNum;
break;
+ }
case 0xf060:
// LOAD SONG: filename:str
if (_vm->_platform == Common::kPlatformAmiga) {
@@ -263,7 +276,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
break;
// Unimplemented / unknown
- case 0x0070: // ? (0 args)
+ case 0x00C0: // does something with slot 5?
case 0x0220: // STOP CURRENT MUSIC
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1070: // SELECT FONT i:int
@@ -293,7 +306,7 @@ void TTMInterpreter::handleOperation(TTMData &env, struct TTMSeq &state, uint16
}
}
-bool TTMInterpreter::run(TTMData &env, struct TTMSeq &seq) {
+bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
Common::SeekableReadStream *scr = env.scr;
if (!scr)
return false;
@@ -347,13 +360,15 @@ bool TTMInterpreter::run(TTMData &env, struct TTMSeq &seq) {
return true;
}
-void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &seqArray) {
+void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &seqArray) {
int16 envno = env._enviro;
env.scr->seek(0);
uint16 op = 0;
- for (uint page = 0; page < env._pages; page++) {
+ for (uint frame = 0; frame < env._totalFrames; frame++) {
+ env._frameOffsets[frame] = env.scr->pos();
+ //debug("findAndAddSequences: frame %d at offset %d", frame, (int)env.scr->pos());
+ op = env.scr->readUint16LE();
while (op != 0xff0 && env.scr->pos() < env.scr->size()) {
- op = env.scr->readUint16LE();
//debug("findAndAddSequences: check ttm op %04x", op);
if (op == 0xaf1f || op == 0xaf2f)
warning("TODO: Fix findAndAddSequences for opcode %x which has variable length arg", op);
@@ -365,10 +380,10 @@ void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &se
TTMSeq newseq;
newseq._enviro = envno;
newseq._seqNum = env.scr->readUint16LE();
- newseq._startFrame = page;
- newseq._currentFrame = page;
+ newseq._startFrame = frame;
+ newseq._currentFrame = frame;
newseq._lastFrame = -1;
- debug("findAndAddSequences: found env %d seq %d", newseq._enviro, newseq._seqNum);
+ //debug("findAndAddSequences: found env %d seq %d at %d", newseq._enviro, newseq._seqNum, (int)env.scr->pos());
seqArray.push_back(newseq);
} else {
env.scr->skip(2);
@@ -386,6 +401,7 @@ void TTMInterpreter::findAndAddSequences(TTMData &env, Common::Array<TTMSeq> &se
env.scr->skip((op & 0xf) * 2);
break;
}
+ op = env.scr->readUint16LE();
}
}
env.scr->seek(0);
@@ -437,7 +453,7 @@ bool ADSInterpreter::load(const Common::String &filename) {
for (const auto &file : _adsData._scriptNames) {
_adsData._scriptEnvs.resize(_adsData._scriptEnvs.size() + 1);
- TTMData &data = _adsData._scriptEnvs.back();
+ TTMEnviro &data = _adsData._scriptEnvs.back();
data._enviro = _adsData._scriptEnvs.size();
_ttmInterpreter->load(file, data);
_ttmInterpreter->findAndAddSequences(data, _adsData._ttmSeqs);
@@ -547,7 +563,7 @@ bool ADSInterpreter::playScene() {
if (!_currentTTMSeq)
return false;
- TTMData *env = findTTMEnviro(_currentTTMSeq->_enviro);
+ TTMEnviro *env = findTTMEnviro(_currentTTMSeq->_enviro);
if (!env)
error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
@@ -563,16 +579,14 @@ void ADSInterpreter::skipToEndIf(Common::SeekableReadStream *scr) {
while (scr->pos() < scr->size()) {
uint16 op = scr->readUint16LE();
if (op == 0x1520)
- scr->seek(-2);
+ scr->seek(-2, SEEK_CUR);
if (op == 0 || op == 0x1520)
return;
- int nargs = numArgs(op);
- for (int i = 0; i < nargs; i++)
- scr->readUint16LE();
+ scr->skip(numArgs(op) * 2);
}
}
-TTMData *ADSInterpreter::findTTMEnviro(int16 enviro) {
+TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
for (auto & env : _adsData._scriptEnvs) {
if (env._enviro == enviro)
return &env;
@@ -610,20 +624,26 @@ void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
void ADSInterpreter::findEndOrInitOp() {
Common::SeekableReadStream *scr = _adsData.scr;
+ int32 startoff = scr->pos();
while (scr->pos() < scr->size()) {
uint16 opcode = scr->readUint16LE();
- if (opcode == 0xffff || opcode == 0x0000) {
- scr->seek(-2, SEEK_CUR);
+ // on FFFF return the original offset
+ if (opcode == 0xffff) {
+ scr->seek(startoff);
return;
}
+ // on 5 (init) return the next offset (don't rewind)
if (opcode == 0x0005)
return;
+ // everything else just go forward.
scr->skip(numArgs(opcode) * 2);
}
}
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
+
+ //debug("ADSOP: 0x%04x", code);
switch (code) {
case 0x0001:
@@ -634,7 +654,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && !state->_runPlayed)
+ if (state && state->_runPlayed)
skipToEndIf(scr);
break;
}
@@ -642,7 +662,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && state->_runPlayed)
+ if (state && !state->_runPlayed)
skipToEndIf(scr);
break;
}
@@ -708,6 +728,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
+ debug("ADSInterpreter reset scene - enviro: %d, seqNum: %d, unk: %d", enviro, seqnum, unk);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq)
seq->reset();
@@ -807,7 +828,7 @@ bool ADSInterpreter::run() {
if (_adsData.scr && state == 1) {
_adsData.scr->seek(offset);
- runUntilBrancOpOrEnd();
+ runUntilBranchOpOrEnd();
}
}
@@ -823,11 +844,11 @@ bool ADSInterpreter::run() {
}
} else {
int16 curframe = seq._currentFrame;
- TTMData *env = findTTMEnviro(seq._enviro);
+ TTMEnviro *env = findTTMEnviro(seq._enviro);
_adsData._hitTTMOp0110 = false;
bool scriptresult = false;
- if (curframe < env->_pages && curframe > -1 && env->_pageOffsets[curframe] > -1) {
- env->scr->seek(env->_pageOffsets[curframe]);
+ if (curframe < env->_totalFrames && curframe > -1 && env->_frameOffsets[curframe] > -1) {
+ env->scr->seek(env->_frameOffsets[curframe]);
_currentTTMSeq = &seq;
scriptresult = playScene();
}
@@ -884,7 +905,7 @@ bool ADSInterpreter::run() {
return result;
}
-bool ADSInterpreter::runUntilBrancOpOrEnd() {
+bool ADSInterpreter::runUntilBranchOpOrEnd() {
Common::SeekableReadStream *scr = _adsData.scr;
if (!scr || scr->pos() >= scr->size())
return false;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 910bbe4d687..d5def32f88d 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -41,13 +41,16 @@ public:
Common::HashMap<uint16, Common::String> _tags;
};
-class TTMData : public ScriptParserData {
+class TTMEnviro : public ScriptParserData {
public:
- TTMData() : _pages(330), ScriptParserData() {}
+ TTMEnviro() : _totalFrames(330), ScriptParserData() {
+ ARRAYCLEAR(_scriptPals);
+ }
uint16 _enviro;
- uint16 _pages;
- Common::Array<int> _pageOffsets;
- Common::String _bmpNames[16];
+ uint16 _totalFrames;
+ Common::Array<int> _frameOffsets;
+ Common::String _scriptShapes[6];
+ int _scriptPals[6];
};
enum TTMRunType {
@@ -102,7 +105,7 @@ public:
ARRAYCLEAR(_charWhile);
}
Common::Array<Common::String> _scriptNames;
- Common::Array<TTMData> _scriptEnvs;
+ Common::Array<TTMEnviro> _scriptEnvs;
Common::Array<TTMSeq> _ttmSeqs;
int _initFlag;
int _maxSegments;
@@ -122,13 +125,13 @@ class TTMInterpreter {
public:
TTMInterpreter(DgdsEngine *vm);
- bool load(const Common::String &filename, TTMData &env);
+ bool load(const Common::String &filename, TTMEnviro &env);
void unload();
- bool run(TTMData &env, struct TTMSeq &seq);
- void findAndAddSequences(TTMData &scriptData, Common::Array<TTMSeq> &seqArray);
+ bool run(TTMEnviro &env, struct TTMSeq &seq);
+ void findAndAddSequences(TTMEnviro &scriptData, Common::Array<TTMSeq> &seqArray);
protected:
- void handleOperation(TTMData &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
+ void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
void updateScreen(struct TTMSeq &seq);
DgdsEngine *_vm;
@@ -154,8 +157,8 @@ protected:
bool playScene();
void skipToEndIf(Common::SeekableReadStream *scr);
TTMSeq *findTTMSeq(int16 enviro, int16 seq);
- TTMData *findTTMEnviro(int16 enviro);
- bool runUntilBrancOpOrEnd();
+ TTMEnviro *findTTMEnviro(int16 enviro);
+ bool runUntilBranchOpOrEnd();
void findUsedSequencesForSegment(int segno);
void findEndOrInitOp();
bool updateSeqTimeAndFrame(TTMSeq &seq);
Commit: aadb9ecbc1b107f5add4f441626b9351e4d8e34c
https://github.com/scummvm/scummvm/commit/aadb9ecbc1b107f5add4f441626b9351e4d8e34c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix TTM initialization
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 473a50926af..a6de33448ea 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -82,7 +82,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
case 0x0070: // FREE PALETTE
error("TODO: Implement me: free palette (current pal)");
break;
- case 0x0080: // DRAW BACKGROUND
+ case 0x0080: // FREE SHAPE // DRAW BACKGROUND??
_vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
break;
case 0x0090: // FREE FONT
@@ -102,7 +102,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
state._timeNext = g_system->getMillis() + ivals[0] * 10;
break;
case 0x1030: {
- // SET BMP: id:int [-1:n]
+ // SET BRUSH: id:int [-1:n]
int bk = ivals[0];
if (bk != -1) {
_vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], bk);
@@ -115,6 +115,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
case 0x1060:
// SELECT PAL: id:int [0]
+ state._currentPalId = ivals[0];
_vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
break;
case 0x1090:
@@ -142,7 +143,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
state._drawColBG = static_cast<byte>(ivals[1]);
break;
case 0x4000:
- // SET DRAW WINDOW? x,y,w,h:int [0..320,0..200]
+ // SET CLIP WINDOW x,y,w,h:int [0..320,0..200]
state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
case 0x4110:
@@ -276,11 +277,11 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
// Unimplemented / unknown
- case 0x00C0: // does something with slot 5?
+ case 0x00C0: // FREE BACKGROUND (probably, does something with slot 5)
case 0x0220: // STOP CURRENT MUSIC
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1070: // SELECT FONT i:int
- case 0x1120: // SET_BACKGROUND
+ case 0x1120: // SET_BACKGROUND - set slot 5 (background
case 0x1310: // STOP SFX i:int eg [107]
case 0x2010: // SET FRAME
case 0x2020: // SET TIMER
@@ -319,7 +320,7 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
seq._timeNext = 0;
uint16 code = 0;
- while (code != 0xff0 && scr->pos() < scr->size()) {
+ while (code != 0x0ff0 && scr->pos() < scr->size()) {
code = scr->readUint16LE();
uint16 op = code & 0xFFF0;
byte count = code & 0x000F;
@@ -368,7 +369,7 @@ void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &
env._frameOffsets[frame] = env.scr->pos();
//debug("findAndAddSequences: frame %d at offset %d", frame, (int)env.scr->pos());
op = env.scr->readUint16LE();
- while (op != 0xff0 && env.scr->pos() < env.scr->size()) {
+ while (op != 0x0ff0 && env.scr->pos() < env.scr->size()) {
//debug("findAndAddSequences: check ttm op %04x", op);
if (op == 0xaf1f || op == 0xaf2f)
warning("TODO: Fix findAndAddSequences for opcode %x which has variable length arg", op);
@@ -465,8 +466,8 @@ bool ADSInterpreter::load(const Common::String &filename) {
int segcount = 0;
findUsedSequencesForSegment(0);
_adsData._segments[0] = 0;
+ opcode = _adsData.scr->readUint16LE();
while (_adsData.scr->pos() < _adsData.scr->size()) {
- opcode = _adsData.scr->readUint16LE();
if (opcode == 0xffff) {
segcount++;
_adsData._segments[segcount] = _adsData.scr->pos();
@@ -474,6 +475,7 @@ bool ADSInterpreter::load(const Common::String &filename) {
} else {
_adsData.scr->skip(numArgs(opcode) * 2);
}
+ opcode = _adsData.scr->readUint16LE();
}
for (uint i = segcount + 1; i < ARRAYSIZE(_adsData._segments); i++)
@@ -646,6 +648,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
//debug("ADSOP: 0x%04x", code);
switch (code) {
+ case 0x0002: // FIXME: Is this ok? seen in dragon intro.
case 0x0001:
case 0x0005:
// "init". 0x0005 can be used for searching for next thing.
@@ -899,7 +902,7 @@ bool ADSInterpreter::run() {
}
if (rflag == kRunTypeTimeLimited && seq._timeCut > g_system->getMillis()) {
- seq._runFlag = kRunTypeStopped;
+ seq._runFlag = kRunType4;
}
}
return result;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index d5def32f88d..c9855a637ec 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -43,7 +43,7 @@ public:
class TTMEnviro : public ScriptParserData {
public:
- TTMEnviro() : _totalFrames(330), ScriptParserData() {
+ TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
ARRAYCLEAR(_scriptPals);
}
uint16 _enviro;
@@ -64,7 +64,10 @@ enum TTMRunType {
struct TTMSeq {
- TTMSeq() : _enviro(0), _seqNum(0), _currentFrame(0), _currentPalId(0), _startFrame(0), _currentSongId(-1) {
+ TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _currentFrame(0),
+ _lastFrame(0), _selfLoop(false), _executed(false), _timeNext(0),
+ _timeCut(0), _currentBmpId(0), _currentSongId(-1), _currentPalId(0),
+ _timeInterval(0) {
reset();
}
Commit: 66800f48dc5ae7b4568675e22d9b7cb8a21cc970
https://github.com/scummvm/scummvm/commit/66800f48dc5ae7b4568675e22d9b7cb8a21cc970
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Properly implement some ADS if conditions
Still don't support OR and AND operations but this should be enough for the
first parts of the game.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7408b9015d9..661cb153a1b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -210,7 +210,6 @@ Common::Error DgdsEngine::run() {
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
- bool creditsShown = false;
REQFileData invRequestData;
REQFileData vcrRequestData;
RequestParser reqParser(_resource, _decompressor);
@@ -321,18 +320,6 @@ Common::Error DgdsEngine::run() {
_scene->runPreTickOps();
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
-
- /*
- if (!creditsShown) {
- creditsShown = true;
- if (getGameId() == GID_DRAGON) {
- // TODO: This will be done by the trigger once we know how to do it.
- // It's trigger number 3 in scene 3.
- changeScene(55, false);
- }
- } else {
- return Common::kNoError;
- }*/
}
_scene->runPostTickOps();
_scene->checkTriggers();
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index b1786db3a87..538f941140a 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -787,6 +787,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
refval = 0;
cflag = kSceneCondEqual;
} else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemField12) {
+ debug("TODO: Check game item attribute for scene condition");
// TODO: Get game item c._num and check value from item attributes
checkval = 0;
} else {
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index a6de33448ea..ab7554a931a 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -103,9 +103,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
case 0x1030: {
// SET BRUSH: id:int [-1:n]
- int bk = ivals[0];
- if (bk != -1) {
- _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], bk);
+ state._brushNum = ivals[0];
+ if (state._brushNum != -1) {
+ _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], state._brushNum);
}
break;
}
@@ -127,10 +127,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
case 0x1100: // SET_SCENE: i:int [1..n]
case 0x1110: { // SET_SCENE: i:int [1..n]
- // DESCRIPTION IN TTM TAGS.
+ // DESCRIPTION IN TTM TAGS. num only used for GOTO.
debug("SET SCENE: %u", ivals[0]);
break;
}
+ case 0x1120: // SET GETPUT NUM
+ state._currentGetPutId = ivals[0];
+ break;
case 0x1200: // GOTO? How different to SET SCENE??
debug("GOTO SCENE: %u", ivals[0]);
state._currentFrame = ivals[0];
@@ -191,6 +194,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
_vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
break;
}
+ case 0x4210: // SAVE IMAGE REGION (getput area)
+ warning("TODO: Implement TTM opcode 0x4210 save getput region");
+ break;
case 0xa000: // DRAW PIXEL x,y:int
_vm->getTopBuffer().setPixel(ivals[0], ivals[1], state._drawColFG);
break;
@@ -277,16 +283,14 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
// Unimplemented / unknown
- case 0x00C0: // FREE BACKGROUND (probably, does something with slot 5)
+ case 0x00C0: // FREE BACKGROUND (free getput item pointed to by _currentGetPutId)
case 0x0220: // STOP CURRENT MUSIC
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1070: // SELECT FONT i:int
- case 0x1120: // SET_BACKGROUND - set slot 5 (background
case 0x1310: // STOP SFX i:int eg [107]
case 0x2010: // SET FRAME
case 0x2020: // SET TIMER
- case 0x4210: // SAVE IMAGE REGION
- case 0xa300: // DRAW some string? x,y,w,h:int
+ case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa424: // DRAW EMPTY CIRCLE
case 0xa510: // DRAW SPRITE1
@@ -361,6 +365,10 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
return true;
}
+int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq) {
+ error("TODO: implement TTMInterpreter::findGOTOTarget");
+}
+
void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &seqArray) {
int16 envno = env._enviro;
env.scr->seek(0);
@@ -569,12 +577,7 @@ bool ADSInterpreter::playScene() {
if (!env)
error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
- if (!_ttmInterpreter->run(*env, *_currentTTMSeq)) {
- _currentTTMSeq->_runCount++;
- // TODO: Continue or load next???
- _currentTTMSeq = findTTMSeq(_currentTTMSeq->_enviro, _currentTTMSeq->_seqNum + 1);
- }
- return true;
+ return _ttmInterpreter->run(*env, *_currentTTMSeq);
}
void ADSInterpreter::skipToEndIf(Common::SeekableReadStream *scr) {
@@ -651,48 +654,81 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x0002: // FIXME: Is this ok? seen in dragon intro.
case 0x0001:
case 0x0005:
+ debug("ADS: init code 0x%04x", code);
// "init". 0x0005 can be used for searching for next thing.
break;
+ case 0x1310: { // IF runtype 5, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ debug("ADS: if runtype 5 env %d seq %d", enviro, seqnum);
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && seq->_runFlag != kRunType5)
+ skipToEndIf(scr);
+ break;
+ }
+ case 0x1320: { // IF not runtype 5, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ debug("ADS: if not runtype 5 env %d seq %d", enviro, seqnum);
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && seq->_runFlag == kRunType5)
+ skipToEndIf(scr);
+ break;
+ }
case 0x1330: { // IF_NOT_PLAYED, 2 params
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && state->_runPlayed)
+ debug("ADS: if not played env %d seq %d", enviro, seqnum);
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && seq->_runPlayed)
skipToEndIf(scr);
break;
}
- case 0x1350: { // IF_PLAYED, 2 params
+ case 0x1340: { // IF_PLAYED, 2 params
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (state && !state->_runPlayed)
+ debug("ADS: if played env %d seq %d", enviro, seqnum);
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && !seq->_runPlayed)
+ skipToEndIf(scr);
+ break;
+ }
+ case 0x1350: { // IF_FINISHED, 2 params
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ debug("ADS: if finished env %d seq %d", enviro, seqnum);
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (seq && seq->_runFlag != kRunTypeFinished)
skipToEndIf(scr);
break;
}
case 0x1360: { // IF_NOT_RUNNING, 2 params
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
+ debug("ADS: if not running env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && seq->_runFlag == kRunTypeStopped)
+ if (seq && seq->_runFlag != kRunTypeStopped)
skipToEndIf(scr);
break;
}
case 0x1370: { // IF_RUNNING, 2 params
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
+ debug("ADS: if running env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && (seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited))
+ if (seq && (seq->_runFlag != kRunType1 && seq->_runFlag != kRunTypeMulti && seq->_runFlag != kRunTypeTimeLimited))
skipToEndIf(scr);
break;
}
case 0x1500: // ? IF ?, 0 params
- debug("Unimplemented ADS branch logic opcode 0x1500");
+ debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
//sceneLogicOps();
_adsData._hitBranchOp = true;
return true;
case 0x1510: // PLAY_SCENE? 0 params
return false;
case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
+ debug("ADS: 0x%04x hit branch op", code);
_adsData._hitBranchOp = true;
return false;
@@ -701,6 +737,8 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
int16 runCount = scr->readSint16LE();
+ uint16 unk = scr->readUint16LE();
+ debug("ADS: add scene - env %d seq %d runCount %d unk %d", enviro, seqnum, runCount, unk);
TTMSeq *state = findTTMSeq(enviro, seqnum);
if (!state)
@@ -723,15 +761,13 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
state->_runCount = runCount - 1;
}
state->_runPlayed++;
- uint16 unk = scr->readUint16LE();
- debug("ADSInterpreter add scene - enviro: %d, seqNum: %d, runCount: %d, unk: %d", enviro, seqnum, runCount, unk);
break;
}
case 0x2020: { // RESET SEQ, 2 params (env, seq)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug("ADSInterpreter reset scene - enviro: %d, seqNum: %d, unk: %d", enviro, seqnum, unk);
+ debug("ADS: reset scene env %d seq %d unk %d", enviro, seqnum, unk);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq)
seq->reset();
@@ -742,8 +778,11 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
return false;
case 0xF010: {// FADE_OUT, 1 param
- uint16 segment = scr->readUint16LE();
- debug("ADS FADE OUT?? segment param %x", segment);
+ int16 segment = scr->readSint16LE();
+ segment--;
+ debug("ADS: set state 2, segment param %x", segment);
+ if (segment >= 0)
+ _adsData._state[segment] = true;
break;
}
@@ -755,8 +794,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1050: // unknown, 2 params
case 0x1060: // unknown, 2 params
case 0x1070: // unknown, 2 params
- case 0x1080: // unknown if-related, 1 param
- case 0x1340:
+ case 0x1080: // if current seq countdown, 1 param
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
case 0x2010: // STOP_SCENE, 3 params
@@ -770,7 +808,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xFFF0: // END_IF, 0 params
default: {
int nops = numArgs(code);
- warning("Unimplemented ADS opcode: 0x%04X (skip %d args)", code, nops);
+ warning("ADS: Unimplemented opcode: 0x%04X (skip %d args)", code, nops);
for (int i = 0; i < nops; i++)
scr->readUint16LE();
break;
@@ -842,7 +880,7 @@ bool ADSInterpreter::run() {
int sflag = seq._scriptFlag;
TTMRunType rflag = seq._runFlag;
if (sflag == 6 || (rflag != kRunType1 && rflag != kRunTypeTimeLimited && rflag != kRunTypeMulti && rflag != kRunType5)) {
- if (sflag != 6 && sflag != 5 && rflag == kRunType4) {
+ if (sflag != 6 && sflag != 5 && rflag == kRunTypeFinished) {
seq._runFlag = kRunTypeStopped;
}
} else {
@@ -866,14 +904,12 @@ bool ADSInterpreter::run() {
seq._timeInterval = _adsData._scriptDelay;
}
- // TODO: What is global 4804?
if (!_adsData._hitTTMOp0110) {
- warning("TODO: ADSInterpreter::run Finish script result true section");
- // if (global4806 != -1) {
- // seq._gotoFrame = global4806;
- // if (seq._currentFrame == global4806)
- // seq._selfLoop = 1;
- // }
+ if (_adsData._gotoTarget != -1) {
+ seq._gotoFrame = _adsData._gotoTarget;
+ if (seq._currentFrame == _adsData._gotoTarget)
+ seq._selfLoop = true;
+ }
if (seq._runFlag != kRunType5)
updateSeqTimeAndFrame(seq);
} else {
@@ -888,21 +924,19 @@ bool ADSInterpreter::run() {
} else {
bool updated = updateSeqTimeAndFrame(seq);
if (updated) {
- seq._runFlag = kRunType4;
+ seq._runFlag = kRunTypeFinished;
seq._timeInterval = 0;
}
}
}
- // TODO: set script delay here
- // TODO: Finish lines 118 to 149 of disasm.
} else if (sflag != 5) {
seq._gotoFrame = seq._startFrame;
- seq._runFlag = kRunType4;
+ seq._runFlag = kRunTypeFinished;
}
}
if (rflag == kRunTypeTimeLimited && seq._timeCut > g_system->getMillis()) {
- seq._runFlag = kRunType4;
+ seq._runFlag = kRunTypeFinished;
}
}
return result;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index c9855a637ec..169ea029a51 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -58,7 +58,7 @@ enum TTMRunType {
kRunType1 = 1,
kRunTypeMulti = 2,
kRunTypeTimeLimited = 3,
- kRunType4 = 4,
+ kRunTypeFinished = 4,
kRunType5 = 5,
};
@@ -66,8 +66,8 @@ enum TTMRunType {
struct TTMSeq {
TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _currentFrame(0),
_lastFrame(0), _selfLoop(false), _executed(false), _timeNext(0),
- _timeCut(0), _currentBmpId(0), _currentSongId(-1), _currentPalId(0),
- _timeInterval(0) {
+ _timeCut(0), _currentBmpId(0), _brushNum(0), _currentSongId(-1),
+ _currentPalId(0), _currentGetPutId(0), _timeInterval(0) {
reset();
}
@@ -86,8 +86,10 @@ struct TTMSeq {
uint32 _timeCut;
Common::Rect _drawWin;
int16 _currentBmpId;
+ int16 _brushNum;
int16 _currentSongId;
int16 _currentPalId;
+ int16 _currentGetPutId;
byte _drawColFG;
byte _drawColBG;
int16 _runPlayed;
@@ -99,7 +101,8 @@ struct TTMSeq {
class ADSData : public ScriptParserData {
public:
- ADSData() : _initFlag(0), _maxSegments(0), _scriptDelay(-1), _hitTTMOp0110(false), _hitBranchOp(false) {
+ ADSData() : _initFlag(0), _maxSegments(0), _scriptDelay(-1),
+ _hitTTMOp0110(false), _hitBranchOp(false), _gotoTarget(-1) {
for (int i = 0; i < ARRAYSIZE(_state); i++) {
_state[i] = 8;
}
@@ -120,6 +123,7 @@ public:
int32 _charWhile[80];
Common::Array<struct TTMSeq *> _usedSeqs[80];
int32 _scriptDelay;
+ int32 _gotoTarget;
bool _hitTTMOp0110;
bool _hitBranchOp;
};
@@ -136,6 +140,7 @@ public:
protected:
void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
void updateScreen(struct TTMSeq &seq);
+ int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq);
DgdsEngine *_vm;
};
Commit: 247b1750f7b5102871dcad776e53996d17e514d0
https://github.com/scummvm/scummvm/commit/247b1750f7b5102871dcad776e53996d17e514d0
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More ADS improvements
Changed paths:
engines/dgds/console.cpp
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index f7600a00fab..3bed389085b 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -132,9 +132,13 @@ bool Console::cmdFileDump(int argc, const char **argv) {
Common::DumpFile out;
out.open(Common::Path(dstPath + fileName));
- out.write(data, size);
- out.flush();
- out.close();
+ if (!out.isOpen()) {
+ warning("Couldn't open path %s%s", dstPath.c_str(), fileName.c_str());
+ } else {
+ out.write(data, size);
+ out.flush();
+ out.close();
+ }
delete[] data;
return true;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 538f941140a..649036bd8ff 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -780,8 +780,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (cflag & kSceneCond80) {
refval = 1;
- uint16 segnum = c._num - 1;
- checkval = engine->adsInterpreter()->getStateForSceneOp(segnum);
+ checkval = engine->adsInterpreter()->getStateForSceneOp(c._num);
SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
refval = 0;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index ab7554a931a..448ad351f2f 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -99,7 +99,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
_vm->getTopBuffer().fillRect(bmpArea, 0);
} break;
case 0x1020: // SET DELAY: i:int [0..n]
- state._timeNext = g_system->getMillis() + ivals[0] * 10;
+ _vm->adsInterpreter()->setScriptDelay(ivals[0] * 10);
break;
case 0x1030: {
// SET BRUSH: id:int [-1:n]
@@ -273,6 +273,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
}
case 0xf060:
// LOAD SONG: filename:str
+ // TODO: use state._currentSongId
if (_vm->_platform == Common::kPlatformAmiga) {
_vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
} else if (_vm->_platform == Common::kPlatformMacintosh) {
@@ -457,6 +458,8 @@ bool ADSInterpreter::load(const Common::String &filename) {
if (!_vm->getResourceManager()->hasResource(detailfile))
detailfile = filename;
+ debug("ADSInterpreter: load %s", detailfile.c_str());
+
ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
dgds.parse(&_adsData, detailfile);
@@ -528,6 +531,8 @@ void ADSInterpreter::findUsedSequencesForSegment(int segno) {
_adsData._usedSeqs[segno].clear();
int64 startoff = _adsData.scr->pos();
uint16 opcode = 0;
+ // Skip the segment number.
+ _adsData.scr->readUint16LE();
while (opcode != 0xffff && _adsData.scr->pos() < _adsData.scr->size()) {
opcode = _adsData.scr->readUint16LE();
for (uint16 o : ADS_SEQ_OPCODES) {
@@ -609,21 +614,21 @@ TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seq) {
void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
- seg -= 1;
- if (seg >= 0) {
- _adsData._charWhile[seg] = 0;
- if (_adsData._state[seg] != 8)
- _adsData._state[seg] = (_adsData._state[seg] & 8) | val;
+ int idx = getArrIndexOfSegNum(seg);
+ if (idx >= 0) {
+ _adsData._charWhile[idx] = 0;
+ if (_adsData._state[idx] != 8)
+ _adsData._state[idx] = (_adsData._state[idx] & 8) | val;
}
}
void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
- seg -= 1;
- if (seg >= 0) {
- _adsData._charWhile[seg] = 0;
- if (_adsData._state[seg] != 8)
- _adsData._state[seg] = val;
+ int idx = getArrIndexOfSegNum(seg);
+ if (idx >= 0) {
+ _adsData._charWhile[idx] = 0;
+ if (_adsData._state[idx] != 8)
+ _adsData._state[idx] = val;
}
}
@@ -651,10 +656,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
//debug("ADSOP: 0x%04x", code);
switch (code) {
- case 0x0002: // FIXME: Is this ok? seen in dragon intro.
case 0x0001:
case 0x0005:
- debug("ADS: init code 0x%04x", code);
+ //debug("ADS: init code 0x%04x", code);
// "init". 0x0005 can be used for searching for next thing.
break;
case 0x1310: { // IF runtype 5, 2 params
@@ -678,7 +682,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1330: { // IF_NOT_PLAYED, 2 params
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- debug("ADS: if not played env %d seq %d", enviro, seqnum);
+ //debug("ADS: if not played env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runPlayed)
skipToEndIf(scr);
@@ -779,10 +783,10 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xF010: {// FADE_OUT, 1 param
int16 segment = scr->readSint16LE();
- segment--;
- debug("ADS: set state 2, segment param %x", segment);
- if (segment >= 0)
- _adsData._state[segment] = true;
+ int16 idx = getArrIndexOfSegNum(segment);
+ debug("ADS: set state 2, segment param %x (idx %d)", segment, idx);
+ if (idx >= 0)
+ _adsData._state[idx] = 2;
break;
}
@@ -819,10 +823,11 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
}
int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
- if (segnum > _adsData._maxSegments)
+ int idx = getArrIndexOfSegNum(segnum);
+ if (idx < 0)
return 0;
- if (!(_adsData._state[segnum] & 4)) {
- for (auto *seq : _adsData._usedSeqs[segnum]) {
+ if (!(_adsData._state[idx] & 4)) {
+ for (auto *seq : _adsData._usedSeqs[idx]) {
if (!seq)
return 0;
if (seq->_runFlag != kRunTypeStopped && !seq->_selfLoop)
@@ -833,6 +838,22 @@ int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
}
+int ADSInterpreter::getArrIndexOfSegNum(uint16 segnum) {
+ int32 startoff = _adsData.scr->pos();
+ int result = -1;
+ for (int i = 0; i < _adsData._maxSegments; i++) {
+ _adsData.scr->seek(_adsData._segments[i]);
+ int16 seg = _adsData.scr->readSint16LE();
+ if (seg == segnum) {
+ result = i;
+ break;
+ }
+ }
+ _adsData.scr->seek(startoff);
+ return result;
+}
+
+
bool ADSInterpreter::run() {
if (_adsData._ttmSeqs.empty())
return false;
@@ -850,7 +871,7 @@ bool ADSInterpreter::run() {
for (int i = 0; i < _adsData._maxSegments; i++) {
int16 state = _adsData._state[i];
- int32 offset = _adsData._segments[i];
+ int32 offset = _adsData._segments[i] + 2;
_adsData.scr->seek(offset);
if (state & 8) {
_adsData._state[i] &= 0xfff7;
@@ -887,6 +908,7 @@ bool ADSInterpreter::run() {
int16 curframe = seq._currentFrame;
TTMEnviro *env = findTTMEnviro(seq._enviro);
_adsData._hitTTMOp0110 = false;
+ _adsData._scriptDelay = -1;
bool scriptresult = false;
if (curframe < env->_totalFrames && curframe > -1 && env->_frameOffsets[curframe] > -1) {
env->scr->seek(env->_frameOffsets[curframe]);
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 169ea029a51..5271eeb7de6 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -157,8 +157,9 @@ public:
void segmentOrState(int16 seg, uint16 val);
void segmentSetState(int16 seg, uint16 val);
- void setHitTTMOp0110(); // TODO: What is this global?
+ void setHitTTMOp0110(); // TODO: better name for this global?
int16 getStateForSceneOp(uint16 segnum);
+ void setScriptDelay(int16 delay) { _adsData._scriptDelay = delay; }
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
@@ -170,6 +171,7 @@ protected:
void findUsedSequencesForSegment(int segno);
void findEndOrInitOp();
bool updateSeqTimeAndFrame(TTMSeq &seq);
+ int getArrIndexOfSegNum(uint16 segnum);
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
Commit: bbe68b84d781077071d7d86de5a41db3890d8eca
https://github.com/scummvm/scummvm/commit/bbe68b84d781077071d7d86de5a41db3890d8eca
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix ADS and TTM interpreters even more
The first part of the intro now runs again! And now it's all running in the
way it's supposed to - script states are being controlled by scene ops as
designed, rather than just running through them in order.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 661cb153a1b..647555ccfbb 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -157,7 +157,6 @@ void DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
return;
}
- _adsInterp->unload();
_scene->runLeaveSceneOps();
_scene->unload();
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 4b7408e04ea..08a4acb6197 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -89,7 +89,7 @@ void GamePalettes::setPalette() {
if (_curPalNum >= _palettes.size())
error("request to set pal %d but only have %d pals", _curPalNum, _palettes.size());
- _curPal = _palettes[_palettes.size() - _curPalNum - 1];
+ _curPal = _palettes[_curPalNum];
g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
}
@@ -105,7 +105,7 @@ void GamePalettes::setFade(int col, int ncols, int targetcol, int fade) {
if (col + ncols > 256)
error("GamePalettes::setFade: request to fade past the end of the palette");
- Palette &pal = _palettes[_palettes.size() - _curPalNum - 1];
+ Palette &pal = _palettes[_curPalNum];
byte r2 = pal._palette[targetcol * 3 + 0];
byte g2 = pal._palette[targetcol * 3 + 1];
@@ -285,8 +285,13 @@ void Image::loadBitmap(const Common::String &filename, int number) {
nextOffset = ((nextOffset + 7) / 8) * 8;
}
} else {
- if (number)
+ if (number) {
+ if ((number + 1) * 4 > (int)chunk.getSize()) {
+ warning("Trying to load %s frame %d off the end of the list", filename.c_str(), number);
+ break;
+ }
stream->skip(4 * number);
+ }
uint32 subImgOffset = stream->readUint32LE();
if (vqtpos != -1) {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 649036bd8ff..01d3bd4381d 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -668,7 +668,7 @@ void SDSScene::enableTrigger(uint16 num) {
void Scene::segmentStateOps(const Common::Array<uint16> &args) {
ADSInterpreter *interp = static_cast<DgdsEngine *>(g_engine)->adsInterpreter();
- for (uint i = 0; i < args.size(); i+= 2) {
+ for (uint i = 0; i < args.size(); i += 2) {
uint16 subop = args[i];
uint16 arg = args[i + 1];
if (!subop && !arg)
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 448ad351f2f..7ddc6f68b28 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -566,12 +566,9 @@ void ADSInterpreter::findUsedSequencesForSegment(int segno) {
void ADSInterpreter::unload() {
- _adsData._scriptNames.clear();
- _adsData._scriptEnvs.clear();
delete _adsData.scr;
- _adsData.scr = nullptr;
+ _adsData = ADSData();
_currentTTMSeq = nullptr;
- _adsData._ttmSeqs.clear();
}
bool ADSInterpreter::playScene() {
@@ -617,8 +614,7 @@ void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
int idx = getArrIndexOfSegNum(seg);
if (idx >= 0) {
_adsData._charWhile[idx] = 0;
- if (_adsData._state[idx] != 8)
- _adsData._state[idx] = (_adsData._state[idx] & 8) | val;
+ _adsData._state[idx] = (_adsData._state[idx] & 8) | val;
}
}
@@ -871,10 +867,13 @@ bool ADSInterpreter::run() {
for (int i = 0; i < _adsData._maxSegments; i++) {
int16 state = _adsData._state[i];
- int32 offset = _adsData._segments[i] + 2;
+ int32 offset = _adsData._segments[i];
_adsData.scr->seek(offset);
+ int16 segnum = _adsData.scr->readSint16LE();
+ offset += 2;
if (state & 8) {
- _adsData._state[i] &= 0xfff7;
+ state &= 0xfff7;
+ _adsData._state[i] = state;
} else {
findEndOrInitOp();
offset = _adsData.scr->pos();
@@ -890,6 +889,7 @@ bool ADSInterpreter::run() {
if (_adsData.scr && state == 1) {
_adsData.scr->seek(offset);
+ debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData._maxSegments);
runUntilBranchOpOrEnd();
}
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 5271eeb7de6..4bf89927e4b 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -101,7 +101,7 @@ struct TTMSeq {
class ADSData : public ScriptParserData {
public:
- ADSData() : _initFlag(0), _maxSegments(0), _scriptDelay(-1),
+ ADSData() : _initFlag(false), _maxSegments(0), _scriptDelay(-1),
_hitTTMOp0110(false), _hitBranchOp(false), _gotoTarget(-1) {
for (int i = 0; i < ARRAYSIZE(_state); i++) {
_state[i] = 8;
@@ -113,7 +113,7 @@ public:
Common::Array<Common::String> _scriptNames;
Common::Array<TTMEnviro> _scriptEnvs;
Common::Array<TTMSeq> _ttmSeqs;
- int _initFlag;
+ bool _initFlag;
int _maxSegments;
// TODO: replace these with dynamic arrays - fixed arrays inherited from original.
int _state[80];
Commit: be29343c7c647aa8580c600b437d10778d183430
https://github.com/scummvm/scummvm/commit/be29343c7c647aa8580c600b437d10778d183430
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add sfx as a separate thing from music
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/music.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 647555ccfbb..9ee8d60cc3e 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -65,9 +65,9 @@ namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
- _soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _gdsScene(nullptr),
- _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr), _detailLevel(kDgdsDetailHigh),
- _showClockUser(false), _showClockScript(false) {
+ _soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
+ _gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
+ _detailLevel(kDgdsDetailHigh), _showClockUser(false), _showClockScript(false) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -103,20 +103,6 @@ DgdsEngine::~DgdsEngine() {
_bottomBuffer.free();
}
-void readStrings(Common::SeekableReadStream *stream) {
- uint16 count = stream->readUint16LE();
- debug(" %u:", count);
-
- for (uint16 k = 0; k < count; k++) {
- byte ch;
- uint16 idx = stream->readUint16LE();
-
- Common::String str;
- while ((ch = stream->readByte()))
- str += ch;
- debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
- }
-}
void DgdsEngine::loadCorners(const Common::String &filename) {
Image imgRes(_resource, _decompressor);
@@ -149,16 +135,23 @@ void DgdsEngine::loadIcons() {
}
}
-void DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
+bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
assert(_scene && _adsInterp);
if (sceneNum == _scene->getNum()) {
warning("Tried to change from scene %d to itself, doing nothing.", sceneNum);
- return;
+ return false;
+ }
+
+ const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
+ if (!_resource->hasResource(sceneFile)) {
+ warning("Tried to switch to non-existant scene %d", sceneNum);
+ return false;
}
_scene->runLeaveSceneOps();
_scene->unload();
+ _soundPlayer->unloadMusic();
_gdsScene->runChangeSceneOps();
@@ -167,10 +160,6 @@ void DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
}
- const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
- if (!_resource->hasResource(sceneFile))
- error("Tried to switch to non-existant scene %d", sceneNum);
-
_scene->load(sceneFile, _resource, _decompressor);
if (_scene->getMagic() != _gdsScene->getMagic())
@@ -181,6 +170,7 @@ void DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_scene->runEnterSceneOps();
//debug("%s", _scene->dump("").c_str());
+ return true;
}
Common::Error DgdsEngine::run() {
@@ -216,6 +206,7 @@ Common::Error DgdsEngine::run() {
_fontManager->loadFonts(getGameId(), _resource, _decompressor);
if (getGameId() == GID_DRAGON) {
+ _soundPlayer->loadSFX("SOUNDS.SNG");
_gameGlobals = new DragonGlobals();
_showClockUser = true;
_gamePals->loadPalette("DRAGON.PAL");
@@ -316,10 +307,15 @@ Common::Error DgdsEngine::run() {
}
if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
+ _gdsScene->runPreTickOps();
_scene->runPreTickOps();
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
}
+
+ // Note: Hard-coded logic for DRAGON, check others
+ //if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
+ // _gdsScene->runPostTickOps();
_scene->runPostTickOps();
_scene->checkTriggers();
} else if (getGameId() == GID_BEAMISH) {
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index e661c1116da..441b8bb9222 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -116,7 +116,7 @@ public:
GDSScene *getGDSScene() { return _gdsScene; }
const FontManager *getFontMan() const { return _fontManager; }
const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
- void changeScene(int sceneNum, bool runChangeOps);
+ bool changeScene(int sceneNum, bool runChangeOps);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 08a4acb6197..2b91d10c21d 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -548,7 +548,8 @@ bool Image::loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::Seeka
for (uint16 i = 0; i < (val + 1) / 2; i++) {
byte color = stream->readByte();
dst[y * tw + x + i * 2] = (color >> 4) + addVal;
- dst[y * tw + x + i * 2 + 1] = (color & 0xf) + addVal;
+ if (x + i * 2 + 1 < tw)
+ dst[y * tw + x + i * 2 + 1] = (color & 0xf) + addVal;
}
x += val;
break;
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
index 4aebe7ad550..cc18bf41c71 100644
--- a/engines/dgds/music.cpp
+++ b/engines/dgds/music.cpp
@@ -207,7 +207,7 @@ void MidiParser_DGDS::mixChannels() {
totalSize += _trackSz[i];
}
- byte *output = (byte*)malloc(totalSize * 2);
+ byte *output = (byte *)malloc(totalSize * 2);
_tracks[0] = output;
uint32 ticker = 0;
@@ -351,7 +351,7 @@ void DgdsMidiPlayer::play(byte *data, uint32 size) {
_parser = parser;
syncVolume();
- _isLooping = true;
+ _isLooping = false;
_isPlaying = true;
debug("Playing music track");
} else {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 01d3bd4381d..5f9e35cd35b 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -59,9 +59,37 @@ Common::String Rect::dump(const Common::String &indent) const {
return Common::String::format("%sRect<%d,%d %d,%d>", indent.c_str(), x, y, width, height);
}
+Common::String _sceneConditionStr(SceneCondition cflag) {
+ Common::String ret;
+
+ if (cflag & kSceneCondAlwaysTrue)
+ return "true";
+
+ if (cflag & kSceneCondSceneState)
+ ret += "state|";
+ if (cflag & kSceneCondNeedItemField12)
+ ret += "item12|";
+ if (cflag & kSceneCondNeedItemField14)
+ ret += "item14|";
+ if ((cflag & (kSceneCondSceneState | kSceneCondNeedItemField12 | kSceneCondNeedItemField14)) == 0)
+ ret += "global|";
+
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemField12 | kSceneCondNeedItemField14));
+ if (cflag == kSceneCondNone)
+ ret += "nocond";
+ if (cflag & kSceneCondLessThan)
+ ret += "less";
+ if (cflag & kSceneCondEqual)
+ ret += "equal";
+ if (cflag & kSceneCondNegate)
+ ret += "-not";
+
+ return ret;
+}
Common::String SceneConditions::dump(const Common::String &indent) const {
- return Common::String::format("%sSceneCondition<flg 0x%02x %d %d>", indent.c_str(), _flags, _num, _val);
+ return Common::String::format("%sSceneCondition<flg 0x%02x(%s) num %d val %d>", indent.c_str(),
+ _flags, _sceneConditionStr(_flags).c_str(), _num, _val);
}
@@ -712,9 +740,12 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
void Scene::runOps(const Common::Array<SceneOp> &ops) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
+ debug("Exec %s", op.dump("").c_str());
switch(op._opCode) {
case kSceneOpChangeScene:
- engine->changeScene(op._args[0], true);
+ if (engine->changeScene(op._args[0], true))
+ // This probably reset the list - stop now.
+ return;
break;
case kSceneOpNoop:
break;
@@ -732,7 +763,9 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
break;
case kSceneOpChangeSceneToStored: {
uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
- engine->changeScene(sceneNo, true);
+ if (engine->changeScene(sceneNo, true))
+ // This probably reset the list - stop now.
+ return;
break;
}
case kSceneOpShowClock:
@@ -771,14 +804,14 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
Globals *globals = engine->getGameGlobals();
- for (const auto & c : conds) {
+ for (const auto &c : conds) {
uint16 refval = c._val;
uint16 checkval;
SceneCondition cflag = c._flags;
if (cflag & kSceneCondAlwaysTrue)
return true;
- if (cflag & kSceneCond80) {
+ if (cflag & kSceneCondSceneState) {
refval = 1;
checkval = engine->adsInterpreter()->getStateForSceneOp(c._num);
SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
@@ -791,12 +824,12 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
checkval = 0;
} else {
checkval = globals->getGlobal(c._num);
- if (!(cflag & kSceneCondSceneAbsVal))
+ if (!(cflag & kSceneCondAbsVal))
refval = globals->getGlobal(refval);
}
bool result = false;
- cflag = static_cast<SceneCondition>(cflag & ~(kSceneCond80 | kSceneCondNeedItemField12 | kSceneCondNeedItemField14));
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemField12 | kSceneCondNeedItemField14));
if (cflag == kSceneCondNone)
cflag = static_cast<SceneCondition>(kSceneCondEqual | kSceneCondNegate);
if ((cflag & kSceneCondLessThan) && checkval < refval)
@@ -806,6 +839,8 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (cflag & kSceneCondNegate)
result = !result;
+ debug("Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
+
if (result)
truecount++;
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index d30f746ae1e..edfb9064a39 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -47,11 +47,11 @@ enum SceneCondition {
kSceneCondLessThan = 1,
kSceneCondEqual = 2,
kSceneCondNegate = 4,
- kSceneCondSceneAbsVal = 8,
+ kSceneCondAbsVal = 8,
kSceneCondAlwaysTrue = 0x10,
kSceneCondNeedItemField14 = 0x20,
kSceneCondNeedItemField12 = 0x40,
- kSceneCond80 = 0x80
+ kSceneCondSceneState = 0x80
};
struct SceneConditions {
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 7ddc6f68b28..f8972fe004f 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -138,8 +138,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
debug("GOTO SCENE: %u", ivals[0]);
state._currentFrame = ivals[0];
break;
- case 0x1300: // PLAY SFX? i:int - eg [72], found in Dragon + HoC intro
- debug("TODO: PLAY SFX?: %u", ivals[0]);
+ case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
+ _vm->_soundPlayer->playSFX(ivals[0]);
break;
case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
state._drawColFG = static_cast<byte>(ivals[0]);
@@ -273,19 +273,24 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
}
case 0xf060:
// LOAD SONG: filename:str
- // TODO: use state._currentSongId
if (_vm->_platform == Common::kPlatformAmiga) {
+ // TODO: remove hard-coded stuff..
_vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
} else if (_vm->_platform == Common::kPlatformMacintosh) {
- _vm->_soundPlayer->playMacMusic(sval.c_str());
+ _vm->_soundPlayer->loadMacMusic(sval.c_str());
+ _vm->_soundPlayer->playMusic(state._currentSongId);
} else {
- _vm->_soundPlayer->playMusic(sval.c_str());
+ _vm->_soundPlayer->loadMusic(sval.c_str());
+ _vm->_soundPlayer->playMusic(state._currentSongId);
}
break;
+ case 0x0220: // STOP CURRENT MUSIC
+ _vm->_soundPlayer->stopMusic();
+ break;
+
// Unimplemented / unknown
case 0x00C0: // FREE BACKGROUND (free getput item pointed to by _currentGetPutId)
- case 0x0220: // STOP CURRENT MUSIC
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1070: // SELECT FONT i:int
case 0x1310: // STOP SFX i:int eg [107]
@@ -375,7 +380,7 @@ void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &
env.scr->seek(0);
uint16 op = 0;
for (uint frame = 0; frame < env._totalFrames; frame++) {
- env._frameOffsets[frame] = env.scr->pos();
+ env._frameOffsets[frame] = env.scr->pos() + (op == 0x0ff0 ? 2 : 0);
//debug("findAndAddSequences: frame %d at offset %d", frame, (int)env.scr->pos());
op = env.scr->readUint16LE();
while (op != 0x0ff0 && env.scr->pos() < env.scr->size()) {
@@ -579,6 +584,7 @@ bool ADSInterpreter::playScene() {
if (!env)
error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
+ _adsData._gotoTarget = -1;
return _ttmInterpreter->run(*env, *_currentTTMSeq);
}
@@ -740,27 +746,27 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
uint16 unk = scr->readUint16LE();
debug("ADS: add scene - env %d seq %d runCount %d unk %d", enviro, seqnum, runCount, unk);
- TTMSeq *state = findTTMSeq(enviro, seqnum);
- if (!state)
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (!seq)
error("ADS invalid seq requested %d %d", enviro, seqnum);
if (code == 0x2000)
- state->_currentFrame = state->_startFrame;
+ seq->_currentFrame = seq->_startFrame;
- _currentTTMSeq = state;
+ _currentTTMSeq = seq;
if (runCount == 0) {
- state->_runFlag = kRunType1;
+ seq->_runFlag = kRunType1;
} else if (runCount < 0) {
// Negative run count sets the cut time
- state->_timeCut = g_system->getMillis() + runCount;
+ seq->_timeCut = g_system->getMillis() + runCount;
// Should this be *10 like delays?
- warning("TODO: checkhandling of negative runcount %d", runCount);
- state->_runFlag = kRunTypeTimeLimited;
+ warning("TODO: check handling of negative runcount %d", runCount);
+ seq->_runFlag = kRunTypeTimeLimited;
} else {
- state->_runFlag = kRunTypeMulti;
- state->_runCount = runCount - 1;
+ seq->_runFlag = kRunTypeMulti;
+ seq->_runCount = runCount - 1;
}
- state->_runPlayed++;
+ seq->_runPlayed++;
break;
}
case 0x2020: { // RESET SEQ, 2 params (env, seq)
@@ -768,9 +774,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
debug("ADS: reset scene env %d seq %d unk %d", enviro, seqnum, unk);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq)
- seq->reset();
+ _currentTTMSeq = findTTMSeq(enviro, seqnum);
+ if (_currentTTMSeq)
+ _currentTTMSeq->reset();
break;
}
@@ -779,11 +785,16 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xF010: {// FADE_OUT, 1 param
int16 segment = scr->readSint16LE();
- int16 idx = getArrIndexOfSegNum(segment);
- debug("ADS: set state 2, segment param %x (idx %d)", segment, idx);
+ int16 idx = _adsData._runningSegmentIdx;
+ if (segment >= 0)
+ idx = getArrIndexOfSegNum(segment);
+ debug("ADS: set state 2, segment param %d (idx %d)", segment, idx);
if (idx >= 0)
_adsData._state[idx] = 2;
- break;
+ if (idx == _adsData._runningSegmentIdx)
+ return false;
+ else
+ return true;
}
//// unknown / to-be-implemented
@@ -797,7 +808,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1080: // if current seq countdown, 1 param
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
- case 0x2010: // STOP_SCENE, 3 params
+ case 0x2010: // STOP_SCENE, 3 params (ttmenv, ttmseq, ?)
case 0x3010: // RANDOM_START, 0 params
case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
@@ -829,8 +840,9 @@ int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
if (seq->_runFlag != kRunTypeStopped && !seq->_selfLoop)
return 1;
}
+ return 0;
}
- return 0;
+ return 1;
}
@@ -869,7 +881,7 @@ bool ADSInterpreter::run() {
int16 state = _adsData._state[i];
int32 offset = _adsData._segments[i];
_adsData.scr->seek(offset);
- int16 segnum = _adsData.scr->readSint16LE();
+ /*int16 segnum =*/ _adsData.scr->readSint16LE();
offset += 2;
if (state & 8) {
state &= 0xfff7;
@@ -887,9 +899,10 @@ bool ADSInterpreter::run() {
state = 1;
}
+ _adsData._runningSegmentIdx = i;
if (_adsData.scr && state == 1) {
_adsData.scr->seek(offset);
- debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData._maxSegments);
+ //debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData._maxSegments);
runUntilBranchOpOrEnd();
}
}
@@ -910,13 +923,13 @@ bool ADSInterpreter::run() {
_adsData._hitTTMOp0110 = false;
_adsData._scriptDelay = -1;
bool scriptresult = false;
+ // Next few lines of code in a separate function in the original..
if (curframe < env->_totalFrames && curframe > -1 && env->_frameOffsets[curframe] > -1) {
env->scr->seek(env->_frameOffsets[curframe]);
- _currentTTMSeq = &seq;
scriptresult = playScene();
}
- if (scriptresult) {
+ if (scriptresult && sflag != 5) {
seq._executed = true;
seq._lastFrame = seq._currentFrame;
result = true;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 4bf89927e4b..b04181bfe68 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -102,7 +102,8 @@ struct TTMSeq {
class ADSData : public ScriptParserData {
public:
ADSData() : _initFlag(false), _maxSegments(0), _scriptDelay(-1),
- _hitTTMOp0110(false), _hitBranchOp(false), _gotoTarget(-1) {
+ _hitTTMOp0110(false), _hitBranchOp(false), _gotoTarget(-1),
+ _runningSegmentIdx(0) {
for (int i = 0; i < ARRAYSIZE(_state); i++) {
_state[i] = 8;
}
@@ -126,6 +127,7 @@ public:
int32 _gotoTarget;
bool _hitTTMOp0110;
bool _hitBranchOp;
+ int16 _runningSegmentIdx;
};
class TTMInterpreter {
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 2e62b541566..20ba3e2b7de 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -45,13 +45,12 @@ Sound::Sound(Audio::Mixer *mixer, ResourceManager *resource, Decompressor *decom
}
Sound::~Sound() {
- delete _midiPlayer;
- delete _soundData;
- delete[] _musicData;
-}
+ unloadMusic();
+
+ for (auto *data: _sfxData)
+ delete [] data;
-void Sound::loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor) {
- _musicData = decompressor->decompress(&file, file.size() - file.pos(), _musicSize);
+ delete _midiPlayer;
}
void Sound::playAmigaSfx(const Common::String &filename, byte channel, byte volume) {
@@ -133,12 +132,25 @@ bool Sound::playPCM(const byte *data, uint32 size) {
return true;
}
-extern void readStrings(Common::SeekableReadStream *stream);
+static void readStrings(Common::SeekableReadStream *stream) {
+ uint16 count = stream->readUint16LE();
+ debug(" %u:", count);
+
+ for (uint16 k = 0; k < count; k++) {
+ byte ch;
+ uint16 idx = stream->readUint16LE();
+
+ Common::String str;
+ while ((ch = stream->readByte()))
+ str += ch;
+ debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
+ }
+}
-void Sound::playMacMusic(const Common::String &filename) {
+void Sound::loadMacMusic(const Common::String &filename) {
if (filename.hasSuffixIgnoreCase(".sng")) {
Common::String macFileName = filename.substr(0, filename.find(".")) + ".sx";
- playMacMusic(macFileName);
+ loadMacMusic(macFileName);
return;
}
@@ -171,27 +183,33 @@ void Sound::playMacMusic(const Common::String &filename) {
} else if (chunk.isSection(ID_TAG) || chunk.isSection(ID_FNM)) {
readStrings(stream);
} else if (chunk.isSection(ID_DAT)) {
+ // TODO: Should we record the indexes?
/*uint16 idx = */ stream->readUint16LE();
/*uint16 type = */ stream->readUint16LE();
- _musicData = _decompressor->decompress(stream, stream->size() - stream->pos(), _musicSize);
+ uint32 sz;
+ _musicData.push_back(_decompressor->decompress(stream, stream->size() - stream->pos(), sz));
+ _musicSizes.push_back(sz);
}
}
delete musicStream;
+
+ stopMusic();
+}
- // stopMusic();
+void Sound::loadMusic(const Common::String &filename) {
+ stopMusic();
+ unloadMusic();
+ loadPCSound(filename, _musicSizes, _musicData);
+}
- // TODO: This isn't correct
- if (_musicData) {
- uint32 tracks = availableSndTracks(_musicData, _musicSize);
- if (tracks & TRACK_MT32)
- _midiPlayer->play(_musicData, _musicSize);
- else if (tracks & DIGITAL_PCM)
- playPCM(_musicData, _musicSize);
- }
+void Sound::loadSFX(const Common::String &filename) {
+ if (_sfxSizes.size())
+ error("Sound: SFX data should only be loaded once");
+ loadPCSound(filename, _sfxSizes, _sfxData);
}
-void Sound::playMusic(const Common::String &filename) {
+void Sound::loadPCSound(const Common::String &filename, Common::Array<uint32> &sizeArray, Common::Array<byte *> &dataArray) {
if (!filename.hasSuffixIgnoreCase(".sng"))
error("Unhandled music file type: %s", filename.c_str());
@@ -209,11 +227,12 @@ void Sound::playMusic(const Common::String &filename) {
chunk.readContent(_decompressor);
Common::SeekableReadStream *stream = chunk.getContent();
-
if (chunk.isSection(ID_SNG)) {
- _musicSize = stream->size();
- _musicData = new byte[_musicSize];
- stream->read(_musicData, _musicSize);
+ int32 musicSize = stream->size();
+ byte *data = new byte[musicSize];
+ stream->read(data, musicSize);
+ sizeArray.push_back(musicSize);
+ dataArray.push_back(data);
} else if (chunk.isSection(ID_INF)) {
uint32 count = stream->size() / 2;
debug(" [%u]", count);
@@ -226,15 +245,45 @@ void Sound::playMusic(const Common::String &filename) {
delete musicStream;
- // stopMusic();
+}
+
+void Sound::playSFX(uint num) {
+ playPCSound(num, _sfxSizes, _sfxData);
+}
- if (_musicData) {
- uint32 tracks = availableSndTracks(_musicData, _musicSize);
+void Sound::playMusic(uint num) {
+ playPCSound(num, _musicSizes, _musicData);
+}
+
+void Sound::playPCSound(uint num, const Common::Array<uint32> &sizeArray, const Common::Array<byte *> &dataArray) {
+ if (num < dataArray.size()) {
+ uint32 tracks = availableSndTracks(dataArray[num], sizeArray[num]);
if (tracks & TRACK_MT32)
- _midiPlayer->play(_musicData, _musicSize);
+ _midiPlayer->play(dataArray[num], sizeArray[num]);
else if (tracks & DIGITAL_PCM)
- playPCM(_musicData, _musicSize);
+ playPCM(dataArray[num], sizeArray[num]);
+ } else {
+ warning("Sound: Requested to play %d but only have %d tracks", num, dataArray.size());
}
+
+}
+
+void Sound::stopMusic() {
+ _midiPlayer->stop();
+ _mixer->stopAll();
+}
+
+void Sound::unloadMusic() {
+ stopMusic();
+ _musicSizes.clear();
+ for (auto *data: _musicData)
+ delete [] data;
+ _musicData.clear();
+
+ // Don't unload the sfx data.
+
+ delete _soundData;
+ _soundData = nullptr;
}
static inline
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index ab044e188ff..a29f46aef9e 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -45,19 +45,33 @@ public:
~Sound();
void playAmigaSfx(const Common::String &filename, byte channel, byte volume);
- void loadMusic(Common::SeekableReadStream &file, Decompressor *decompressor);
- void playMusic(const Common::String &filename);
- void playMacMusic(const Common::String &filename);
+ void loadMusic(const Common::String &filename);
+ void loadMacMusic(const Common::String &filename);
+ void loadSFX(const Common::String &filename);
+
+ void playMusic(uint num);
+ void stopMusic();
+ void unloadMusic();
+
+ void playSFX(uint num);
void stopSfx(byte channel);
bool playPCM(const byte *data, uint32 size);
private:
+ void loadPCSound(const Common::String &filename, Common::Array<uint32> &sizeArray, Common::Array<byte *> &dataArray);
+ void playPCSound(uint num, const Common::Array<uint32> &sizeArray, const Common::Array<byte *> &dataArray);
+
struct Channel _channels[2];
Common::SeekableReadStream *_soundData = nullptr;
- uint32 _musicSize = 0;
- byte *_musicData = nullptr;
+
+ Common::Array<uint32> _musicSizes;
+ Common::Array<byte *> _musicData;
+
+ Common::Array<uint32> _sfxSizes;
+ Common::Array<byte *> _sfxData;
+
Audio::Mixer *_mixer;
DgdsMidiPlayer *_midiPlayer;
ResourceManager *_resource;
Commit: f7770582fd075b4e489e360f73b12b08d75fb0f7
https://github.com/scummvm/scummvm/commit/f7770582fd075b4e489e360f73b12b08d75fb0f7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add more debugging for frame progression
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index f8972fe004f..b03f3b61e4d 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -380,7 +380,7 @@ void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &
env.scr->seek(0);
uint16 op = 0;
for (uint frame = 0; frame < env._totalFrames; frame++) {
- env._frameOffsets[frame] = env.scr->pos() + (op == 0x0ff0 ? 2 : 0);
+ env._frameOffsets[frame] = env.scr->pos();
//debug("findAndAddSequences: frame %d at offset %d", frame, (int)env.scr->pos());
op = env.scr->readUint16LE();
while (op != 0x0ff0 && env.scr->pos() < env.scr->size()) {
@@ -524,9 +524,11 @@ bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
seq._executed = false;
if (seq._gotoFrame == -1) {
seq._currentFrame++;
+ debug("env %d seq %d advance to frame %d", seq._enviro, seq._seqNum, seq._currentFrame);
} else {
seq._currentFrame = seq._gotoFrame;
seq._gotoFrame = -1;
+ debug("env %d seq %d goto to frame %d", seq._enviro, seq._seqNum, seq._currentFrame);
}
return true;
@@ -915,7 +917,7 @@ bool ADSInterpreter::run() {
TTMRunType rflag = seq._runFlag;
if (sflag == 6 || (rflag != kRunType1 && rflag != kRunTypeTimeLimited && rflag != kRunTypeMulti && rflag != kRunType5)) {
if (sflag != 6 && sflag != 5 && rflag == kRunTypeFinished) {
- seq._runFlag = kRunTypeStopped;
+ seq._runFlag = kRunTypeStopped;
}
} else {
int16 curframe = seq._currentFrame;
Commit: 65fc35e32b017313b9bc38f9df50a532dec52113
https://github.com/scummvm/scummvm/commit/65fc35e32b017313b9bc38f9df50a532dec52113
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Better struct names
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 5f9e35cd35b..7dbfc9b11c6 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -93,13 +93,13 @@ Common::String SceneConditions::dump(const Common::String &indent) const {
}
-Common::String SceneStruct2::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sSceneStruct2<%s %d %d",
+Common::String HotArea::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sHotArea<%s %d %d",
indent.c_str(), rect.dump("").c_str(), field1_0x8, field2_0xa);
- str += _dumpStructList(indent, "struct1list", struct1List);
- str += _dumpStructList(indent, "oplist1", opList1);
- str += _dumpStructList(indent, "oplist2", opList2);
- str += _dumpStructList(indent, "oplist3", opList3);
+ str += _dumpStructList(indent, "enableConditions", enableConditions);
+ str += _dumpStructList(indent, "opList1", opList1);
+ str += _dumpStructList(indent, "opList2", opList2);
+ str += _dumpStructList(indent, "onClickOps", onClickOps);
str += "\n";
str += indent + ">";
return str;
@@ -150,7 +150,7 @@ Common::String SceneOp::dump(const Common::String &indent) const {
}
Common::String GameItem::dump(const Common::String &indent) const {
- Common::String super = SceneStruct2::dump(indent + " ");
+ Common::String super = HotArea::dump(indent + " ");
Common::String str = Common::String::format(
"%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d flags %d unk14 %d",
@@ -513,25 +513,25 @@ bool Scene::readConditionList(Common::SeekableReadStream *s, Common::Array<Scene
}
-bool Scene::readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const {
+bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
dst.rect.x = s->readUint16LE();
dst.rect.y = s->readUint16LE();
dst.rect.width = s->readUint16LE();
dst.rect.height = s->readUint16LE();
dst.field1_0x8 = s->readUint16LE();
dst.field2_0xa = s->readUint16LE();
- readConditionList(s, dst.struct1List);
+ readConditionList(s, dst.enableConditions);
readOpList(s, dst.opList1);
readOpList(s, dst.opList2);
- readOpList(s, dst.opList3);
+ readOpList(s, dst.onClickOps);
return !s->err();
}
-bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const {
+bool Scene::readHotAreaList(Common::SeekableReadStream *s, Common::Array<HotArea> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct2 &dst : list) {
- readStruct2(s, dst);
+ for (HotArea &dst : list) {
+ readHotArea(s, dst);
}
return !s->err();
}
@@ -540,7 +540,7 @@ bool Scene::readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneSt
bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const {
list.resize(s->readUint16LE());
for (GameItem &dst : list) {
- readStruct2(s, dst);
+ readHotArea(s, dst);
}
for (GameItem &dst : list) {
dst._iconNum = s->readUint16LE();
@@ -787,7 +787,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
warning("TODO: Implement scene op 10 (find SDS hot spot?)");
break;
case kSceneOp107:
- warning("TODO: Implement scene op 107 (inject key code 0xfc)");
+ warning("TODO: Implement scene op 107 (inject key code 0xfc, open menu to play intro or not)");
break;
default:
warning("TODO: Implement scene op %d", op._opCode);
@@ -895,7 +895,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _postTickOps);
_field6_0x14 = stream->readUint16LE();
_adsFile = stream->readString();
- readStruct2List(stream, _struct2List);
+ readHotAreaList(stream, _struct2List);
readStruct4List(stream, _struct4List1);
if (isVersionOver(" 1.205")) {
readStruct4List(stream, _struct4List2);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index edfb9064a39..2a69641ea3f 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -62,14 +62,14 @@ struct SceneConditions {
Common::String dump(const Common::String &indent) const;
};
-struct SceneStruct2 {
+struct HotArea {
struct Rect rect;
uint16 field1_0x8;
uint16 field2_0xa;
- Common::Array<struct SceneConditions> struct1List;
+ Common::Array<struct SceneConditions> enableConditions;
Common::Array<struct SceneOp> opList1;
Common::Array<struct SceneOp> opList2;
- Common::Array<struct SceneOp> opList3;
+ Common::Array<struct SceneOp> onClickOps;
virtual Common::String dump(const Common::String &indent) const;
};
@@ -114,7 +114,7 @@ struct SceneOp {
Common::String dump(const Common::String &indent) const;
};
-struct GameItem : public SceneStruct2 {
+struct GameItem : public HotArea {
Common::Array<struct SceneOp> opList5;
Common::Array<struct SceneOp> opList6;
uint16 field10_0x24;
@@ -251,8 +251,8 @@ public:
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
- bool readStruct2(Common::SeekableReadStream *s, SceneStruct2 &dst) const;
- bool readStruct2List(Common::SeekableReadStream *s, Common::Array<SceneStruct2> &list) const;
+ bool readHotArea(Common::SeekableReadStream *s, HotArea &dst) const;
+ bool readHotAreaList(Common::SeekableReadStream *s, Common::Array<HotArea> &list) const;
bool readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
@@ -346,7 +346,7 @@ private:
uint _field6_0x14;
Common::String _adsFile;
//uint _field8_0x23;
- Common::Array<struct SceneStruct2> _struct2List;
+ Common::Array<struct HotArea> _struct2List;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
//uint _field12_0x2b;
Commit: f273055d2b9022f2cc8b7dc1fa306d1922cf0757
https://github.com/scummvm/scummvm/commit/f273055d2b9022f2cc8b7dc1fa306d1922cf0757
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Slight script execution improvements
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index b03f3b61e4d..3e868f0c225 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -69,6 +69,72 @@ void TTMInterpreter::updateScreen(struct TTMSeq &state) {
g_system->updateScreen();
}
+static const char *ttmOpName(uint16 op) {
+ switch (op) {
+ case 0x0000: return "FINISH";
+ case 0x0020: return "SAVE(free?) BACKGROUND";
+ case 0x0070: return "FREE PALETTE";
+ case 0x0080: return "FREE SHAPE / DRAW BACKGROUND??";
+ case 0x0090: return "FREE FONT";
+ case 0x00B0: return "NULLOP";
+ case 0x0110: return "PURGE";
+ case 0x0ff0: return "FINISH FRAME / DRAW";
+ case 0x1020: return "SET DELAY";
+ case 0x1030: return "SET BRUSH";
+ case 0x1050: return "SELECT BMP";
+ case 0x1060: return "SELECT PAL";
+ case 0x1090: return "SELECT SONG";
+ case 0x10a0: return "SET SCENE";
+ case 0x1100: // fall through
+ case 0x1110: return "SET SCENE";
+ case 0x1120: return "SET GETPUT NUM";
+ case 0x1200: return "GOTO";
+ case 0x1300: return "PLAY SFX";
+ case 0x2000: return "SET DRAW COLORS";
+ case 0x4000: return "SET CLIP WINDOW";
+ case 0x4110: return "FADE OUT";
+ case 0x4120: return "FADE IN";
+ case 0x4200: return "STORE AREA";
+ case 0x4210: return "SAVE GETPUT REGION";
+ case 0xa000: return "DRAW PIXEL";
+ case 0xa050: return "SAVE REGION";
+ case 0xa0a0: return "DRAW LINE";
+ case 0xa100: return "DRAW FILLED RECT";
+ case 0xa110: return "DRAW EMPTY RECT";
+ case 0xa520: return "DRAW SPRITE FLIP";
+ case 0xa530: return "DRAW BMP4";
+ case 0xa500: return "DRAW BMP";
+ case 0xf010: return "LOAD SCR";
+ case 0xf020: return "LOAD BMP";
+ case 0xf040: return "LOAD FONT";
+ case 0xf050: return "LOAD PAL";
+ case 0xf060: return "LOAD SONG";
+ case 0x0220: return "STOP CURRENT MUSIC";
+
+ case 0x00C0: return "FREE BACKGROUND";
+ case 0x0230: return "reset current music?";
+ case 0x1070: return "SELECT FONT";
+ case 0x1310: return "STOP SFX";
+ case 0x2010: return "SET FRAME";
+ case 0x2020: return "SET TIMER";
+ case 0xa300: return "DRAW some string";
+ case 0xa400: return "DRAW FILLED CIRCLE";
+ case 0xa424: return "DRAW EMPTY CIRCLE";
+ case 0xa510: return "DRAW SPRITE1";
+ case 0xa600: return "CLEAR SCREEN";
+ case 0xb000: return "? (0 args)";
+ case 0xb010: return "? (3 args: 30, 2, 19)";
+ case 0xb600: return "DRAW SCREEN";
+ case 0xc020: return "LOAD_SAMPLE";
+ case 0xc030: return "SELECT_SAMPLE";
+ case 0xc040: return "DESELECT_SAMPLE";
+ case 0xc050: return "PLAY_SAMPLE";
+ case 0xc060: return "STOP_SAMPLE";
+
+ default: return "UNKNOWN!!";
+ }
+}
+
void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -76,7 +142,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
case 0x0000:
// FINISH: void
break;
- case 0x0020: // SAVE BACKGROUND
+ case 0x0020: // SAVE (free?) BACKGROUND
_vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
break;
case 0x0070: // FREE PALETTE
@@ -88,6 +154,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
case 0x0090: // FREE FONT
error("TODO: Implement me: free font (current one)");
break;
+ case 0x00B0:
+ // Does nothing?
+ break;
case 0x0110: // PURGE void
_vm->adsInterpreter()->setHitTTMOp0110();
break;
@@ -99,7 +168,10 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
_vm->getTopBuffer().fillRect(bmpArea, 0);
} break;
case 0x1020: // SET DELAY: i:int [0..n]
- _vm->adsInterpreter()->setScriptDelay(ivals[0] * 10);
+ // Delay of 240 should be 2 seconds, so this is in quarter-frames.
+ // TODO: Probably should do this accounting (as well as timeCut and dialogs)
+ // in game frames, not millis.
+ _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * 8.33));
break;
case 0x1030: {
// SET BRUSH: id:int [-1:n]
@@ -156,6 +228,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
} else {
// The original tight-loops here with 640 steps and i/10 as the fade level..
// bring that down a bit to use less cpu.
+ // Speed 4 should complete fade in 2 seconds (eg, Dynamix logo fade)
for (int i = 0; i < 320; i += ivals[3]) {
int fade = MIN(i / 5, 63);
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
@@ -324,11 +397,14 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
if (scr->pos() >= scr->size())
return false;
- if (seq._timeNext > g_system->getMillis()) {
- return true;
- }
- seq._timeNext = 0;
+ // TODO: This seems to not be how it works in the original?
+ //if (seq._timeNext > g_system->getMillis()) {
+ // return true;
+ //}
+ //seq._timeNext = 0;
+ debug("TTM: Run env %d seq %d frame %d (scr offset %d)", seq._enviro, seq._seqNum,
+ seq._currentFrame, (int)scr->pos());
uint16 code = 0;
while (code != 0x0ff0 && scr->pos() < scr->size()) {
code = scr->readUint16LE();
@@ -362,7 +438,7 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
debugN("%d", ivals[i]);
}
}
- debug(" ");
+ debug(" (%s)", ttmOpName(op));
handleOperation(env, seq, op, count, ivals, sval);
}
@@ -423,14 +499,17 @@ void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &
}
void TTMSeq::reset() {
- ARRAYCLEAR(_slot);
+ _currentFontId = 0;
+ _currentPalId = 0;
+ _currentPalId = 0;
+ _currentBmpId = 0;
+ _currentGetPutId = 0;
_currentFrame = _startFrame;
_gotoFrame = -1;
_drawColBG = 0xf;
_drawColFG = 0xf;
- //_brush_num = 0;
- _currentBmpId = 0;
- _timeCut = 0;
+ _brushNum = 0;
+ _timeInterval = 0;
_timeNext = 0;
_runCount = 0;
_runPlayed = 0;
@@ -516,19 +595,24 @@ static const uint16 ADS_SEQ_OPCODES[] = {
bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
if (seq._timeInterval != 0) {
uint32 now = g_system->getMillis();
- if (now < seq._timeNext)
+ if (now < seq._timeNext) {
+ debug("env %d seq %d not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
+ seq._seqNum, seq._currentFrame, now, seq._timeNext, seq._timeInterval);
return false;
+ }
seq._timeNext = now + seq._timeInterval;
}
seq._executed = false;
if (seq._gotoFrame == -1) {
+ debug("env %d seq %d advance to frame %d->%d (start %d last %d)", seq._enviro,
+ seq._seqNum, seq._currentFrame, seq._currentFrame + 1, seq._startFrame, seq._lastFrame);
seq._currentFrame++;
- debug("env %d seq %d advance to frame %d", seq._enviro, seq._seqNum, seq._currentFrame);
} else {
+ debug("env %d seq %d goto to frame %d->%d (start %d last %d)", seq._enviro,
+ seq._seqNum, seq._currentFrame, seq._gotoFrame, seq._startFrame, seq._lastFrame);
seq._currentFrame = seq._gotoFrame;
seq._gotoFrame = -1;
- debug("env %d seq %d goto to frame %d", seq._enviro, seq._seqNum, seq._currentFrame);
}
return true;
@@ -656,7 +740,7 @@ void ADSInterpreter::findEndOrInitOp() {
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
-
+
//debug("ADSOP: 0x%04x", code);
switch (code) {
@@ -884,7 +968,6 @@ bool ADSInterpreter::run() {
int32 offset = _adsData._segments[i];
_adsData.scr->seek(offset);
/*int16 segnum =*/ _adsData.scr->readSint16LE();
- offset += 2;
if (state & 8) {
state &= 0xfff7;
_adsData._state[i] = state;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index b04181bfe68..4f8699a0281 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -64,10 +64,8 @@ enum TTMRunType {
struct TTMSeq {
- TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _currentFrame(0),
- _lastFrame(0), _selfLoop(false), _executed(false), _timeNext(0),
- _timeCut(0), _currentBmpId(0), _brushNum(0), _currentSongId(-1),
- _currentPalId(0), _currentGetPutId(0), _timeInterval(0) {
+ TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _lastFrame(0), _timeCut(0) {
+ // Other members are initialized in the reset function.
reset();
}
@@ -81,15 +79,16 @@ struct TTMSeq {
int16 _lastFrame;
bool _selfLoop;
bool _executed;
- int16 _slot[6];
uint32 _timeNext;
uint32 _timeCut;
Common::Rect _drawWin;
- int16 _currentBmpId;
+ // these are just called "slot"s in the original
+ int16 _currentFontId; // aka slot 0
+ int16 _currentPalId; // aka slot 1
+ int16 _currentSongId; // aka slot 3
+ int16 _currentBmpId; // aka slot 4
+ int16 _currentGetPutId; // aka slot 5
int16 _brushNum;
- int16 _currentSongId;
- int16 _currentPalId;
- int16 _currentGetPutId;
byte _drawColFG;
byte _drawColBG;
int16 _runPlayed;
Commit: 24b306ac9a3ee3cdad1f191662613b15763b45eb
https://github.com/scummvm/scummvm/commit/24b306ac9a3ee3cdad1f191662613b15763b45eb
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix one-shot ttm opcodes
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 7dbfc9b11c6..e22d9e7a380 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -895,7 +895,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
readOpList(stream, _postTickOps);
_field6_0x14 = stream->readUint16LE();
_adsFile = stream->readString();
- readHotAreaList(stream, _struct2List);
+ readHotAreaList(stream, _hotAreaList);
readStruct4List(stream, _struct4List1);
if (isVersionOver(" 1.205")) {
readStruct4List(stream, _struct4List2);
@@ -916,7 +916,7 @@ void SDSScene::unload() {
_postTickOps.clear();
_field6_0x14 = 0;
_adsFile.clear();
- _struct2List.clear();
+ _hotAreaList.clear();
_struct4List1.clear();
_struct4List2.clear();
_dialogs.clear();
@@ -930,7 +930,7 @@ Common::String SDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "leaveSceneOps", _leaveSceneOps);
str += _dumpStructList(indent, "preTickOps", _preTickOps);
str += _dumpStructList(indent, "postTickOps", _postTickOps);
- str += _dumpStructList(indent, "struct2List", _struct2List);
+ str += _dumpStructList(indent, "hotAreaList", _hotAreaList);
str += _dumpStructList(indent, "struct4List1", _struct4List1);
str += _dumpStructList(indent, "struct4List2", _struct4List2);
str += _dumpStructList(indent, "dialogues", _dialogs);
@@ -972,7 +972,7 @@ void SDSScene::showDialog(uint16 num) {
}
bool SDSScene::checkDialogActive() {
- uint32 timeNow = g_system->getMillis();
+ uint32 timeNow = g_engine->getTotalPlayTime();
bool retval = false;
for (auto &dialog : _dialogs) {
if (dialog.hasFlag(kDlgFlagVisible)) {
@@ -997,7 +997,7 @@ bool SDSScene::drawActiveDialog(Graphics::Surface *dst, int mode) {
if (dialog.hasFlag(kDlgFlagVisible)) {
if (dialog._hideTime == 0 && dialog._time > 0) {
// TOOD: This should be (9 - text-speed-slider-setting)
- dialog._hideTime = g_system->getMillis() + dialog._time * 9;
+ dialog._hideTime = g_engine->getTotalPlayTime() + dialog._time * 9;
}
dialog.draw(dst, mode);
retval = true;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 2a69641ea3f..39d210d3f61 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -64,7 +64,7 @@ struct SceneConditions {
struct HotArea {
struct Rect rect;
- uint16 field1_0x8;
+ uint16 field1_0x8; //
uint16 field2_0xa;
Common::Array<struct SceneConditions> enableConditions;
Common::Array<struct SceneOp> opList1;
@@ -346,7 +346,7 @@ private:
uint _field6_0x14;
Common::String _adsFile;
//uint _field8_0x23;
- Common::Array<struct HotArea> _struct2List;
+ Common::Array<struct HotArea> _hotAreaList;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
//uint _field12_0x2b;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 3e868f0c225..6160e232a8b 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -135,7 +135,7 @@ static const char *ttmOpName(uint16 op) {
}
}
-void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
+void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
switch (op) {
@@ -143,15 +143,21 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
// FINISH: void
break;
case 0x0020: // SAVE (free?) BACKGROUND
+ if (seq._executed) // this is a one-shot op
+ break;
_vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
break;
case 0x0070: // FREE PALETTE
+ if (seq._executed) // this is a one-shot op
+ break;
error("TODO: Implement me: free palette (current pal)");
break;
case 0x0080: // FREE SHAPE // DRAW BACKGROUND??
_vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
break;
case 0x0090: // FREE FONT
+ if (seq._executed) // this is a one-shot op
+ break;
error("TODO: Implement me: free font (current one)");
break;
case 0x00B0:
@@ -175,24 +181,24 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
case 0x1030: {
// SET BRUSH: id:int [-1:n]
- state._brushNum = ivals[0];
- if (state._brushNum != -1) {
- _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], state._brushNum);
+ seq._brushNum = ivals[0];
+ if (seq._brushNum != -1) {
+ _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
}
break;
}
case 0x1050:
// SELECT BMP: id:int [0:n]
- state._currentBmpId = ivals[0];
+ seq._currentBmpId = ivals[0];
break;
case 0x1060:
// SELECT PAL: id:int [0]
- state._currentPalId = ivals[0];
+ seq._currentPalId = ivals[0];
_vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
break;
case 0x1090:
// SELECT SONG: id:int [0]
- state._currentSongId = ivals[0];
+ seq._currentSongId = ivals[0];
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
debug("SCENE SETUP DONE: %u", ivals[0]);
@@ -204,24 +210,26 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
break;
}
case 0x1120: // SET GETPUT NUM
- state._currentGetPutId = ivals[0];
+ seq._currentGetPutId = ivals[0];
break;
case 0x1200: // GOTO? How different to SET SCENE??
debug("GOTO SCENE: %u", ivals[0]);
- state._currentFrame = ivals[0];
+ seq._currentFrame = ivals[0];
break;
case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
_vm->_soundPlayer->playSFX(ivals[0]);
break;
case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
- state._drawColFG = static_cast<byte>(ivals[0]);
- state._drawColBG = static_cast<byte>(ivals[1]);
+ seq._drawColFG = static_cast<byte>(ivals[0]);
+ seq._drawColBG = static_cast<byte>(ivals[1]);
break;
case 0x4000:
// SET CLIP WINDOW x,y,w,h:int [0..320,0..200]
- state._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
case 0x4110:
+ if (seq._executed) // this is a one-shot op.
+ break;
// FADE OUT: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->clearPalette();
@@ -232,13 +240,15 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
for (int i = 0; i < 320; i += ivals[3]) {
int fade = MIN(i / 5, 63);
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- updateScreen(state);
+ updateScreen(seq);
g_system->delayMillis(5);
}
}
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x4120: {
+ if (seq._executed) // this is a one-shot op.
+ break;
// blt first?
_vm->_resData.blitFrom(_vm->getBottomBuffer());
Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
@@ -253,13 +263,15 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
for (int i = 320; i > 0; i -= ivals[3]) {
int fade = MAX(0, MIN(i / 5, 63));
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- updateScreen(state);
+ updateScreen(seq);
g_system->delayMillis(5);
}
}
break;
}
case 0x4200: {
+ if (seq._executed) // this is a one-shot op
+ break;
// STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
_vm->_resData.blitFrom(_vm->getBottomBuffer());
@@ -271,7 +283,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
warning("TODO: Implement TTM opcode 0x4210 save getput region");
break;
case 0xa000: // DRAW PIXEL x,y:int
- _vm->getTopBuffer().setPixel(ivals[0], ivals[1], state._drawColFG);
+ _vm->getTopBuffer().setPixel(ivals[0], ivals[1], seq._drawColFG);
break;
case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l]
// it works like a bitblit, but it doesn't write if there's something already at the destination?
@@ -280,19 +292,19 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
_vm->getTopBuffer().copyFrom(_vm->_resData);
break;
case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], state._drawColFG);
+ _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
break;
case 0xa100:
// DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- _vm->getTopBuffer().fillRect(bmpArea, state._drawColFG);
+ _vm->getTopBuffer().fillRect(bmpArea, seq._drawColFG);
break;
case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, state._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, state._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, state._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, state._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, seq._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, seq._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, seq._drawColFG);
+ _vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, seq._drawColFG);
break;
case 0xa520:
// DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
@@ -303,62 +315,74 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &state, uint1
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
// FALL THROUGH
case 0xa500:
- debug("DRAW \"%s\"", env._scriptShapes[state._currentBmpId].c_str());
+ debug("DRAW \"%s\"", env._scriptShapes[seq._currentBmpId].c_str());
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
if (count == 4) {
int tileId = ivals[2];
- state._currentBmpId = ivals[3];
+ seq._currentBmpId = ivals[3];
if (tileId != -1) {
- _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], tileId);
+ _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], tileId);
}
} else if (!_vm->_image->isLoaded()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", state._currentBmpId, env._scriptShapes[state._currentBmpId].c_str());
- _vm->_image->loadBitmap(env._scriptShapes[state._currentBmpId], 0);
+ warning("trying to load bmp %d (%s) on demand", seq._currentBmpId, env._scriptShapes[seq._currentBmpId].c_str());
+ _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], 0);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], state._drawWin, _vm->getTopBuffer());
+ _vm->_image->drawBitmap(ivals[0], ivals[1], seq._drawWin, _vm->getTopBuffer());
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
break;
case 0xf010:
+ if (seq._executed) // this is a one-shot op
+ break;
// LOAD SCR: filename:str
_vm->_image->drawScreen(sval, _vm->getBottomBuffer());
break;
case 0xf020:
+ if (seq._executed) // this is a one-shot op
+ break;
// LOAD BMP: filename:str
- env._scriptShapes[state._currentBmpId] = sval;
+ env._scriptShapes[seq._currentBmpId] = sval;
break;
case 0xf040: {
+ if (seq._executed) // this is a one-shot op
+ break;
// LOAD FONT: filename:str
error("TODO: Implement opcode 0xf040 load font");
break;
}
case 0xf050: {
+ if (seq._executed) // this is a one-shot op
+ break;
// LOAD PAL: filename:str
int newPalNum = _vm->getGamePals()->loadPalette(sval);
- env._scriptPals[state._currentPalId] = newPalNum;
+ env._scriptPals[seq._currentPalId] = newPalNum;
break;
}
case 0xf060:
+ if (seq._executed) // this is a one-shot op
+ break;
// LOAD SONG: filename:str
if (_vm->_platform == Common::kPlatformAmiga) {
// TODO: remove hard-coded stuff..
_vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
} else if (_vm->_platform == Common::kPlatformMacintosh) {
_vm->_soundPlayer->loadMacMusic(sval.c_str());
- _vm->_soundPlayer->playMusic(state._currentSongId);
+ _vm->_soundPlayer->playMusic(seq._currentSongId);
} else {
_vm->_soundPlayer->loadMusic(sval.c_str());
- _vm->_soundPlayer->playMusic(state._currentSongId);
+ _vm->_soundPlayer->playMusic(seq._currentSongId);
}
break;
case 0x0220: // STOP CURRENT MUSIC
+ if (seq._executed) // this is a one-shot op
+ break;
_vm->_soundPlayer->stopMusic();
break;
@@ -398,7 +422,7 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
return false;
// TODO: This seems to not be how it works in the original?
- //if (seq._timeNext > g_system->getMillis()) {
+ //if (seq._timeNext > g_engine->getTotalPlayTime()) {
// return true;
//}
//seq._timeNext = 0;
@@ -594,7 +618,7 @@ static const uint16 ADS_SEQ_OPCODES[] = {
bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
if (seq._timeInterval != 0) {
- uint32 now = g_system->getMillis();
+ uint32 now = g_engine->getTotalPlayTime();
if (now < seq._timeNext) {
debug("env %d seq %d not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
seq._seqNum, seq._currentFrame, now, seq._timeNext, seq._timeInterval);
@@ -844,7 +868,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seq->_runFlag = kRunType1;
} else if (runCount < 0) {
// Negative run count sets the cut time
- seq->_timeCut = g_system->getMillis() + runCount;
+ seq->_timeCut = g_engine->getTotalPlayTime() + runCount;
// Should this be *10 like delays?
warning("TODO: check handling of negative runcount %d", runCount);
seq->_runFlag = kRunTypeTimeLimited;
@@ -1019,7 +1043,7 @@ bool ADSInterpreter::run() {
seq._lastFrame = seq._currentFrame;
result = true;
if (_adsData._scriptDelay != -1 && seq._timeInterval != _adsData._scriptDelay) {
- uint32 now = g_system->getMillis();
+ uint32 now = g_engine->getTotalPlayTime();
seq._timeNext = now + _adsData._scriptDelay;
seq._timeInterval = _adsData._scriptDelay;
}
@@ -1055,7 +1079,7 @@ bool ADSInterpreter::run() {
}
}
- if (rflag == kRunTypeTimeLimited && seq._timeCut > g_system->getMillis()) {
+ if (rflag == kRunTypeTimeLimited && seq._timeCut > g_engine->getTotalPlayTime()) {
seq._runFlag = kRunTypeFinished;
}
}
Commit: a3c54589858e5260ec15e06d87ddecdec1d0f8c7
https://github.com/scummvm/scummvm/commit/a3c54589858e5260ec15e06d87ddecdec1d0f8c7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More ADS execution improvements
Changed paths:
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 6160e232a8b..b422283c358 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -765,7 +765,7 @@ void ADSInterpreter::findEndOrInitOp() {
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
- //debug("ADSOP: 0x%04x", code);
+ debug(" ADSOP: 0x%04x", code);
switch (code) {
case 0x0001:
@@ -794,7 +794,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1330: { // IF_NOT_PLAYED, 2 params
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- //debug("ADS: if not played env %d seq %d", enviro, seqnum);
+ debug("ADS: if not played env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runPlayed)
skipToEndIf(scr);
@@ -842,7 +842,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
_adsData._hitBranchOp = true;
return true;
case 0x1510: // PLAY_SCENE? 0 params
- return false;
+ debug("ADS: 0x%04x hit branch op true", code);
+ _adsData._hitBranchOp = true;
+ return true;
case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
debug("ADS: 0x%04x hit branch op", code);
_adsData._hitBranchOp = true;
@@ -879,6 +881,16 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seq->_runPlayed++;
break;
}
+ case 0x2010: { // STOP_SCENE, 3 params (ttmenv, ttmseq, ?)
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ debug("ADS: stop seq env %d seq %d unk %d", enviro, seqnum, unk);
+ _currentTTMSeq = findTTMSeq(enviro, seqnum);
+ if (_currentTTMSeq)
+ _currentTTMSeq->_runFlag = kRunTypeStopped;
+ break;
+ }
case 0x2020: { // RESET SEQ, 2 params (env, seq)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
@@ -918,7 +930,6 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1080: // if current seq countdown, 1 param
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
- case 0x2010: // STOP_SCENE, 3 params (ttmenv, ttmseq, ?)
case 0x3010: // RANDOM_START, 0 params
case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
@@ -991,6 +1002,7 @@ bool ADSInterpreter::run() {
int16 state = _adsData._state[i];
int32 offset = _adsData._segments[i];
_adsData.scr->seek(offset);
+ offset += 2;
/*int16 segnum =*/ _adsData.scr->readSint16LE();
if (state & 8) {
state &= 0xfff7;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 4f8699a0281..fea9f903605 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -73,16 +73,16 @@ struct TTMSeq {
int16 _enviro;
int16 _seqNum;
- int16 _startFrame;
- int16 _gotoFrame;
- int16 _currentFrame;
- int16 _lastFrame;
- bool _selfLoop;
- bool _executed;
- uint32 _timeNext;
- uint32 _timeCut;
+ int16 _startFrame; // first frame in this sequence
+ int16 _gotoFrame; // frame to GOTO (or -1 if not currently set)
+ int16 _currentFrame; // currently executing frame
+ int16 _lastFrame; // previous frame processed (-1 if none)
+ bool _selfLoop; // does the script frame loop back on itself
+ bool _executed; // has the current frame already been run
+ uint32 _timeNext; // time the next frame should be run
+ uint32 _timeCut; // time to finish execution
Common::Rect _drawWin;
- // these are just called "slot"s in the original
+ // these current ids are called "slot"s in the original
int16 _currentFontId; // aka slot 0
int16 _currentPalId; // aka slot 1
int16 _currentSongId; // aka slot 3
@@ -91,9 +91,9 @@ struct TTMSeq {
int16 _brushNum;
byte _drawColFG;
byte _drawColBG;
- int16 _runPlayed;
- int16 _runCount;
- int16 _timeInterval;
+ int16 _runPlayed; // number of times the sequence has been started from ADS
+ int16 _runCount; // number of times to play the sequence before stopping
+ int16 _timeInterval; // interval between frames
TTMRunType _runFlag;
int16 _scriptFlag;
};
@@ -118,7 +118,7 @@ public:
// TODO: replace these with dynamic arrays - fixed arrays inherited from original.
int _state[80];
int _countdown[80];
- // note: originals uses char * but we use offsets into script for less pointers..
+ // note: originals uses char * but we use offsets into script for less pointers. -1 is nullptr
int32 _segments[80];
int32 _charWhile[80];
Common::Array<struct TTMSeq *> _usedSeqs[80];
Commit: ea049fe010b139636322ec1813a55d038aa4ccaf
https://github.com/scummvm/scummvm/commit/ea049fe010b139636322ec1813a55d038aa4ccaf
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix ADS branch handling to match original
Now the Dragon intro gets up to the actual intro sequence, then locks up
because we don't yet handle dialog events correctly.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 9ee8d60cc3e..355739b3f46 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -169,7 +169,7 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_adsInterp->load(_scene->getAdsFile());
_scene->runEnterSceneOps();
- //debug("%s", _scene->dump("").c_str());
+ debug("%s", _scene->dump("").c_str());
return true;
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index e22d9e7a380..8c97ca50926 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -978,6 +978,10 @@ bool SDSScene::checkDialogActive() {
if (dialog.hasFlag(kDlgFlagVisible)) {
if (dialog._hideTime > 0 && dialog._hideTime < timeNow) {
dialog.clearFlag(kDlgFlagVisible);
+ for (auto &action : dialog._subStrings) {
+ if (action.strStart == action.strEnd)
+ runOps(action.sceneOpList);
+ }
dialog._hideTime = 0;
if (dialog._nextDialogNum) {
showDialog(dialog._nextDialogNum);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index b422283c358..0289c9f36bb 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -698,15 +698,38 @@ bool ADSInterpreter::playScene() {
return _ttmInterpreter->run(*env, *_currentTTMSeq);
}
-void ADSInterpreter::skipToEndIf(Common::SeekableReadStream *scr) {
+bool ADSInterpreter::skipSceneLogicBranch() {
+ Common::SeekableReadStream *scr = _adsData.scr;
+ bool result = true;
while (scr->pos() < scr->size()) {
uint16 op = scr->readUint16LE();
- if (op == 0x1520)
+ if (op == 0x1510 || op == 0x1500) {
scr->seek(-2, SEEK_CUR);
- if (op == 0 || op == 0x1520)
- return;
- scr->skip(numArgs(op) * 2);
+ return true;
+ } else if (op == 0 || op == 0xffff) {
+ return false;
+ } else if ((op & 0xff0f) == 0x1300) {
+ // a 0x13x0 logic op
+ error("TODO: Implement nested ADS condition handling");
+ } else {
+ scr->skip(numArgs(op) * 2);
+ }
}
+ return result && scr->pos() < scr->size();
+}
+
+bool ADSInterpreter::skipToEndIf() {
+ Common::SeekableReadStream *scr = _adsData.scr;
+ bool result = skipSceneLogicBranch();
+ if (result) {
+ uint16 op = scr->readUint16LE();
+ if (op == 0x1500) {
+ result = runUntilBranchOpOrEnd();
+ }
+ // don't rewind - the calls to this should always return ptr+2
+ //scr->seek(-2, SEEK_CUR);
+ }
+ return result;
}
TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
@@ -779,8 +802,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if runtype 5 env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runFlag != kRunType5)
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1320: { // IF not runtype 5, 2 params
enviro = scr->readUint16LE();
@@ -788,8 +812,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if not runtype 5 env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runFlag == kRunType5)
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1330: { // IF_NOT_PLAYED, 2 params
enviro = scr->readUint16LE();
@@ -797,8 +822,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if not played env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runPlayed)
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1340: { // IF_PLAYED, 2 params
enviro = scr->readUint16LE();
@@ -806,8 +832,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if played env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && !seq->_runPlayed)
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1350: { // IF_FINISHED, 2 params
enviro = scr->readUint16LE();
@@ -815,8 +842,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if finished env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runFlag != kRunTypeFinished)
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1360: { // IF_NOT_RUNNING, 2 params
enviro = scr->readUint16LE();
@@ -824,8 +852,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if not running env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && seq->_runFlag != kRunTypeStopped)
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1370: { // IF_RUNNING, 2 params
enviro = scr->readUint16LE();
@@ -833,8 +862,9 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug("ADS: if running env %d seq %d", enviro, seqnum);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (seq && (seq->_runFlag != kRunType1 && seq->_runFlag != kRunTypeMulti && seq->_runFlag != kRunTypeTimeLimited))
- skipToEndIf(scr);
- break;
+ return skipToEndIf();
+ else
+ return runUntilBranchOpOrEnd();
}
case 0x1500: // ? IF ?, 0 params
debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
@@ -1106,12 +1136,15 @@ bool ADSInterpreter::runUntilBranchOpOrEnd() {
bool more = true;
do {
uint16 code = scr->readUint16LE();
+ if (code == 0xffff)
+ return false;
more = handleOperation(code, scr);
+ // FIXME: Breaking on hitBranchOp here doesn't work - probably need to fix the IF handling properly.
} while (!_adsData._hitBranchOp && more && scr->pos() < scr->size());
_adsData._hitBranchOp = false;
- return true;
+ return more;
}
void ADSInterpreter::setHitTTMOp0110() {
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index fea9f903605..43bd9030b56 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -165,7 +165,8 @@ public:
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
bool playScene();
- void skipToEndIf(Common::SeekableReadStream *scr);
+ bool skipToEndIf();
+ bool skipSceneLogicBranch();
TTMSeq *findTTMSeq(int16 enviro, int16 seq);
TTMEnviro *findTTMEnviro(int16 enviro);
bool runUntilBranchOpOrEnd();
Commit: c29b9d826045210ae1146f8eddf9372e54da2ea7
https://github.com/scummvm/scummvm/commit/c29b9d826045210ae1146f8eddf9372e54da2ea7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Improve comments and debug
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8c97ca50926..0879d9a54e3 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -156,8 +156,8 @@ Common::String GameItem::dump(const Common::String &indent) const {
"%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d flags %d unk14 %d",
indent.c_str(), super.c_str(), indent.c_str(), field10_0x24,
_iconNum, field12_0x28, _flags, field14_0x2c);
- str += _dumpStructList(indent, "oplist5", opList5);
- str += _dumpStructList(indent, "oplist6", opList6);
+ str += _dumpStructList(indent, "opList5", opList5);
+ str += _dumpStructList(indent, "opList6", opList6);
str += "\n";
str += indent + ">";
return str;
@@ -172,7 +172,7 @@ Common::String MouseCursor::dump(const Common::String &indent) const {
Common::String SceneStruct4::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSceneStruct4<%d %d", indent.c_str(), val1, val2);
- str += _dumpStructList(indent, "oplist", opList);
+ str += _dumpStructList(indent, "opList", opList);
str += "\n";
str += indent + ">";
return str;
@@ -181,7 +181,7 @@ Common::String SceneStruct4::dump(const Common::String &indent) const {
Common::String SceneTrigger::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sSceneTrigger<num %d %s", indent.c_str(), _num, _enabled ? "enabled" : "disabled");
- str += _dumpStructList(indent, "struct1list", conditionList);
+ str += _dumpStructList(indent, "conditionList", conditionList);
str += _dumpStructList(indent, "opList", sceneOpList);
str += "\n";
str += indent + ">";
@@ -475,7 +475,7 @@ Common::String Dialogue::dump(const Common::String &indent) const {
Common::String DialogueAction::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
- str += _dumpStructList(indent, "oplist", sceneOpList);
+ str += _dumpStructList(indent, "opList", sceneOpList);
if (!sceneOpList.empty()) {
str += "\n";
str += indent;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 39d210d3f61..4eee4b2c4d5 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -212,7 +212,7 @@ struct DialogueAction {
uint16 strStart; /// The start of the clickable text for this action
uint16 strEnd; /// End of clickable text for this action
byte unk[8]; /* Not initialized in loader */
- Common::Array<struct SceneOp> sceneOpList;
+ Common::Array<struct SceneOp> sceneOpList; /// ops to run when this is selected
uint val; /* First entry initialized to 1 in loader */
Common::String dump(const Common::String &indent) const;
Commit: f7b92ccafeb561c3cdf25571562bc38284871b15
https://github.com/scummvm/scummvm/commit/f7b92ccafeb561c3cdf25571562bc38284871b15
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Improve dialogues - better names, more code
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 355739b3f46..72c216f8439 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -67,7 +67,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
- _detailLevel(kDgdsDetailHigh), _showClockUser(false), _showClockScript(false) {
+ _detailLevel(kDgdsDetailHigh), _showClockUser(false), _showClockScript(false),
+ _textSpeed(1) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -231,7 +232,9 @@ Common::Error DgdsEngine::run() {
reqParser.parse(&vcrRequestData, "HVCR.REQ");
//_scene->load("S101.SDS", _resource, _decompressor);
- _adsInterp->load("TITLE.ADS");
+ //_adsInterp->load("TITLE.ADS");
+ _gdsScene->runStartGameOps();
+
loadCorners("HCORNERS.BMP");
} else if (getGameId() == GID_BEAMISH) {
_gameGlobals = new Globals();
@@ -318,6 +321,7 @@ Common::Error DgdsEngine::run() {
// _gdsScene->runPostTickOps();
_scene->runPostTickOps();
_scene->checkTriggers();
+ _scene->checkDialogActive();
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
return Common::kNoError;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 441b8bb9222..3efb6aa4830 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -92,7 +92,10 @@ private:
FontManager *_fontManager;
Common::Array<Common::SharedPtr<Image>> _corners;
Common::Array<Common::SharedPtr<Image>> _icons;
+
+ // Settings which we should integrate with ScummVM settings UI
DgdsDetailLevel _detailLevel;
+ int _textSpeed;
// Clock is shown if both are true;
bool _showClockUser;
@@ -121,6 +124,7 @@ public:
Globals *getGameGlobals() { return _gameGlobals; }
DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
+ int getTextSpeed() const { return _textSpeed; }
void setShowClock(bool val) { _showClockScript = val; }
ADSInterpreter *adsInterpreter() { return _adsInterp; }
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 0879d9a54e3..adc90b0479f 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -123,6 +123,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpShowMouse: return "sceneOpShowMouse";
case kSceneOpHideMouse: return "sceneOpHideMouse";
case kSceneOpMeanwhile: return "meanwhile";
+ case kSceneOpOpenPlaySkipIntroMenu: return "openPlaySkipIntroMovie";
default:
return Common::String::format("sceneOp%d", (int)code);
}
@@ -467,7 +468,7 @@ Common::String Dialogue::dump(const Common::String &indent) const {
"%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d",
indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize,
_flags, _frameType, _time, _nextDialogNum, _field15_0x22, _field18_0x28);
- str += _dumpStructList(indent, "subStrings", _subStrings);
+ str += _dumpStructList(indent, "actions", _action);
str += "\n";
str += indent + " str='" + _str + "'>";
return str;
@@ -640,9 +641,9 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
} else {
dst._str.clear();
}
- readDialogSubstringList(s, dst._subStrings);
+ readDialogActionList(s, dst._action);
- if (isVersionUnder(" 1.209") && !dst._subStrings.empty()) {
+ if (isVersionUnder(" 1.209") && !dst._action.empty()) {
if (dst._fontColor == 0)
dst._field8_0x10 = 4;
else if (dst._fontColor == 0xff)
@@ -669,7 +670,7 @@ bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTr
}
-bool Scene::readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const {
+bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const {
list.resize(s->readUint16LE());
if (!list.empty())
@@ -786,7 +787,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOp10:
warning("TODO: Implement scene op 10 (find SDS hot spot?)");
break;
- case kSceneOp107:
+ case kSceneOpOpenPlaySkipIntroMenu:
warning("TODO: Implement scene op 107 (inject key code 0xfc, open menu to play intro or not)");
break;
default:
@@ -965,8 +966,18 @@ void SDSScene::checkTriggers() {
void SDSScene::showDialog(uint16 num) {
for (auto &dialog : _dialogs) {
if (dialog._num == num) {
+ dialog.clearFlag(kDlgFlagHi2);
+ dialog.clearFlag(kDlgFlagHi8);
+ dialog.clearFlag(kDlgFlagHi10);
+ dialog.clearFlag(kDlgFlagHi20);
+ dialog.clearFlag(kDlgFlagHi40);
+ dialog.addFlag(kDlgFlagHi20);
dialog.addFlag(kDlgFlagVisible);
+ dialog.addFlag(kDlgFlagHi100);
// hide time gets set the first time it's drawn.
+ if (dialog.hasFlag(kDlgFlagLo8)) {
+ // do something with some global dlg flags here.
+ }
}
}
}
@@ -974,22 +985,29 @@ void SDSScene::showDialog(uint16 num) {
bool SDSScene::checkDialogActive() {
uint32 timeNow = g_engine->getTotalPlayTime();
bool retval = false;
- for (auto &dialog : _dialogs) {
- if (dialog.hasFlag(kDlgFlagVisible)) {
- if (dialog._hideTime > 0 && dialog._hideTime < timeNow) {
- dialog.clearFlag(kDlgFlagVisible);
- for (auto &action : dialog._subStrings) {
- if (action.strStart == action.strEnd)
- runOps(action.sceneOpList);
- }
- dialog._hideTime = 0;
- if (dialog._nextDialogNum) {
- showDialog(dialog._nextDialogNum);
- retval = true;
- }
- } else {
+ for (auto &dlg : _dialogs) {
+ if (!dlg.hasFlag(kDlgFlagVisible))
+ continue;
+
+ if (dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40)) {
+ // TODO
+ }
+
+ if (dlg._hideTime > 0 && dlg._hideTime < timeNow) {
+ dlg.clearFlag(kDlgFlagVisible);
+ for (auto &action : dlg._action) {
+ if (action.strStart == action.strEnd)
+ runOps(action.sceneOpList);
+ }
+ dlg._hideTime = 0;
+ dlg.addFlag(kDlgFlagHiFinished);
+ if (dlg._nextDialogNum) {
+ showDialog(dlg._nextDialogNum);
+
retval = true;
}
+ } else {
+ retval = true;
}
}
return retval;
@@ -997,11 +1015,12 @@ bool SDSScene::checkDialogActive() {
bool SDSScene::drawActiveDialog(Graphics::Surface *dst, int mode) {
bool retval = false;
+ const DgdsEngine *engine = static_cast<const DgdsEngine *>(g_engine);
for (auto &dialog : _dialogs) {
if (dialog.hasFlag(kDlgFlagVisible)) {
if (dialog._hideTime == 0 && dialog._time > 0) {
- // TOOD: This should be (9 - text-speed-slider-setting)
- dialog._hideTime = g_engine->getTotalPlayTime() + dialog._time * 9;
+ dialog._hideTime = g_engine->getTotalPlayTime() +
+ dialog._time * (9 - engine->getTextSpeed());
}
dialog.draw(dst, mode);
retval = true;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 4eee4b2c4d5..2569f30f094 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -95,6 +95,8 @@ enum SceneOpCode {
kSceneOpHideClock = 17, // args: none. set some clock-related values.
kSceneOpShowMouse = 18, // args: none.
kSceneOpHideMouse = 19, // args: none.
+
+ // From here on might be game-specific?
kSceneOp100 = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOp102 = 102, // args: none.
@@ -102,7 +104,7 @@ enum SceneOpCode {
kSceneOp104 = 104, // args: none.
kSceneOp105 = 105, // args: none. Draw some number at 141, 56
kSceneOp106 = 106, // args: none. Draw some number at 42, 250
- kSceneOp107 = 107, // args: none.
+ kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. Show the "Play Introduction" / "Skip Introduction" menu. Dragon only??
kSceneOp108 = 108, // args: none.
};
@@ -144,10 +146,21 @@ struct SceneStruct4 {
};
enum DialogueFlags {
- kDlgFlagNone = 0,
- kDlgFlagFlatBg = 1,
- kDlgFlagLeftJust = 2,
- kDlgFlagVisible = 0x8000,
+ kDlgFlagNone = 0,
+ kDlgFlagFlatBg = 1,
+ kDlgFlagLeftJust = 2,
+ kDlgFlagLo4 = 4,
+ kDlgFlagLo8 = 8,
+ kDlgFlagLo80 = 0x80,
+ kDlgFlagHiFinished = 0x10000,
+ kDlgFlagHi2 = 0x20000,
+ kDlgFlagHi4 = 0x40000,
+ kDlgFlagHi8 = 0x80000,
+ kDlgFlagHi10 = 0x100000,
+ kDlgFlagHi20 = 0x200000,
+ kDlgFlagHi40 = 0x400000,
+ kDlgFlagVisible = 0x800000,
+ kDlgFlagHi100 = 0x1000000,
};
enum DialogueFrameType {
@@ -171,7 +184,7 @@ public:
DialogueFrameType _frameType;
uint16 _time;
uint16 _nextDialogNum;
- Common::Array<struct DialogueAction> _subStrings;
+ Common::Array<struct DialogueAction> _action;
uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
@@ -259,7 +272,7 @@ protected:
bool readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const;
bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const;
bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
- bool readDialogSubstringList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
+ bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
void runOps(const Common::Array<SceneOp> &ops);
bool checkConditions(const Common::Array<struct SceneConditions> &cond);
Commit: f9179c2bbcefb17df82aef04d73e951340101fd9
https://github.com/scummvm/scummvm/commit/f9179c2bbcefb17df82aef04d73e951340101fd9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Rename dialog class for shorter name
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index adc90b0479f..5ce66fbc44d 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -190,13 +190,13 @@ Common::String SceneTrigger::dump(const Common::String &indent) const {
}
-Dialogue::Dialogue() : _num(0), _bgColor(0), _fontColor(0), _field7_0xe(0), _field8_0x10(0),
+Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _field7_0xe(0), _field8_0x10(0),
_fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
_field15_0x22(0), _field18_0x28(0), _hideTime(0)
{}
-void Dialogue::draw(Graphics::Surface *dst, int stage) {
+void Dialog::draw(Graphics::Surface *dst, int stage) {
switch (_frameType) {
case kDlgFramePlain: return drawType1(dst, stage);
case kDlgFrameBorder: return drawType2(dst, stage);
@@ -215,7 +215,7 @@ static void _drawPixel(int x, int y, int color, void *data) {
// box with simple frame
-void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
+void Dialog::drawType1(Graphics::Surface *dst, int stage) {
//if (!_field15_0x22)
// return;
int x = _rect.x;
@@ -237,7 +237,7 @@ void Dialogue::drawType1(Graphics::Surface *dst, int stage) {
}
// box with fancy frame and optional title (everything before ":")
-void Dialogue::drawType2(Graphics::Surface *dst, int stage) {
+void Dialog::drawType2(Graphics::Surface *dst, int stage) {
Common::String title;
Common::String txt;
uint32 colonpos = _str.find(':');
@@ -283,7 +283,7 @@ static void _filledCircle(int x, int y, int xr, int yr, Graphics::Surface *dst,
// Comic tought box made up of circles with 2 circles going up to it.
// Draw circles with 5/4 more pixels in x because the pixels are not square.
-void Dialogue::drawType3(Graphics::Surface *dst, int stage) {
+void Dialog::drawType3(Graphics::Surface *dst, int stage) {
if (stage == 1) {
uint16 xradius = 9999;
uint16 yradius = 40;
@@ -370,7 +370,7 @@ void Dialogue::drawType3(Graphics::Surface *dst, int stage) {
}
// ellipse
-void Dialogue::drawType4(Graphics::Surface *dst, int stage) {
+void Dialog::drawType4(Graphics::Surface *dst, int stage) {
int x = _rect.x;
int y = _rect.y;
int w = _rect.width;
@@ -404,15 +404,15 @@ void Dialogue::drawType4(Graphics::Surface *dst, int stage) {
}
}
-void Dialogue::drawStage2(Graphics::Surface *dst) {
+void Dialog::drawStage2(Graphics::Surface *dst) {
// TODO: various text wrapping and alignment calculations happen here.
}
-void Dialogue::drawStage3(Graphics::Surface *dst) {
+void Dialog::drawStage3(Graphics::Surface *dst) {
// TODO: various text wrapping and alignment calculations happen here.
}
-void Dialogue::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
+void Dialog::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const FontManager *fontman = engine->getFontMan();
FontManager::FontType fontType = FontManager::kGameDlgFont;
@@ -451,19 +451,19 @@ void Dialogue::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::
}
-void Dialogue::addFlag(DialogueFlags flg) {
- _flags = static_cast<DialogueFlags>(_flags | flg);
+void Dialog::addFlag(DialogFlags flg) {
+ _flags = static_cast<DialogFlags>(_flags | flg);
}
-void Dialogue::clearFlag(DialogueFlags flg) {
- _flags = static_cast<DialogueFlags>(_flags & ~flg);
+void Dialog::clearFlag(DialogFlags flg) {
+ _flags = static_cast<DialogFlags>(_flags & ~flg);
}
-bool Dialogue::hasFlag(DialogueFlags flg) const {
+bool Dialog::hasFlag(DialogFlags flg) const {
return _flags & flg;
}
-Common::String Dialogue::dump(const Common::String &indent) const {
+Common::String Dialog::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
"%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d",
indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize,
@@ -474,7 +474,7 @@ Common::String Dialogue::dump(const Common::String &indent) const {
return str;
}
-Common::String DialogueAction::dump(const Common::String &indent) const {
+Common::String DialogAction::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
str += _dumpStructList(indent, "opList", sceneOpList);
if (!sceneOpList.empty()) {
@@ -601,11 +601,11 @@ bool Scene::readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &li
}
-bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const {
+bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list) const {
// Some data on this format here https://www.oldgamesitalia.net/forum/index.php?showtopic=24055&st=25&p=359214&#entry359214
list.resize(s->readUint16LE());
- for (Dialogue &dst : list) {
+ for (Dialog &dst : list) {
dst._num = s->readUint16LE();
dst._rect.x = s->readUint16LE();
dst._rect.y = s->readUint16LE();
@@ -622,14 +622,14 @@ bool Scene::readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialog
}
dst._fontSize = s->readUint16LE(); // 01 = 8x8, 02 = 6x6, 03 = 4x5
if (isVersionUnder(" 1.210")) {
- dst._flags = static_cast<DialogueFlags>(s->readUint16LE());
+ dst._flags = static_cast<DialogFlags>(s->readUint16LE());
} else {
// Game reads a 32 bit int but then truncates anyway..
// probably never used the full thing.
- dst._flags = static_cast<DialogueFlags>(s->readUint32LE() & 0xffff);
+ dst._flags = static_cast<DialogFlags>(s->readUint32LE() & 0xffff);
}
- dst._frameType = static_cast<DialogueFrameType>(s->readUint16LE());
+ dst._frameType = static_cast<DialogFrameType>(s->readUint16LE());
dst._time = s->readUint16LE();
if (isVersionOver(" 1.207")) {
dst._nextDialogNum = s->readUint16LE();
@@ -670,13 +670,13 @@ bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTr
}
-bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const {
+bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const {
list.resize(s->readUint16LE());
if (!list.empty())
list[0].val = 1;
- for (DialogueAction &dst : list) {
+ for (DialogAction &dst : list) {
dst.strStart = s->readUint16LE();
dst.strEnd = s->readUint16LE();
readOpList(s, dst.sceneOpList);
@@ -901,7 +901,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
if (isVersionOver(" 1.205")) {
readStruct4List(stream, _struct4List2);
}
- readDialogueList(stream, _dialogs);
+ readDialogList(stream, _dialogs);
if (isVersionOver(" 1.203")) {
readTriggerList(stream, _triggers);
}
@@ -973,7 +973,7 @@ void SDSScene::showDialog(uint16 num) {
dialog.clearFlag(kDlgFlagHi40);
dialog.addFlag(kDlgFlagHi20);
dialog.addFlag(kDlgFlagVisible);
- dialog.addFlag(kDlgFlagHi100);
+ dialog.addFlag(kDlgFlagOpening);
// hide time gets set the first time it's drawn.
if (dialog.hasFlag(kDlgFlagLo8)) {
// do something with some global dlg flags here.
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 2569f30f094..8f73dc04a67 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -145,7 +145,7 @@ struct SceneStruct4 {
Common::String dump(const Common::String &indent) const;
};
-enum DialogueFlags {
+enum DialogFlags {
kDlgFlagNone = 0,
kDlgFlagFlatBg = 1,
kDlgFlagLeftJust = 2,
@@ -160,19 +160,19 @@ enum DialogueFlags {
kDlgFlagHi20 = 0x200000,
kDlgFlagHi40 = 0x400000,
kDlgFlagVisible = 0x800000,
- kDlgFlagHi100 = 0x1000000,
+ kDlgFlagOpening = 0x1000000,
};
-enum DialogueFrameType {
+enum DialogFrameType {
kDlgFramePlain = 1,
kDlgFrameBorder = 2,
kDlgFrameThought = 3,
kDlgFrameRounded = 4
};
-class Dialogue {
+class Dialog {
public:
- Dialogue();
+ Dialog();
uint16 _num;
Rect _rect;
uint16 _bgColor;
@@ -180,11 +180,11 @@ public:
uint16 _field7_0xe;
uint16 _field8_0x10;
uint16 _fontSize;
- DialogueFlags _flags;
- DialogueFrameType _frameType;
+ DialogFlags _flags;
+ DialogFrameType _frameType;
uint16 _time;
uint16 _nextDialogNum;
- Common::Array<struct DialogueAction> _action;
+ Common::Array<struct DialogAction> _action;
uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
@@ -192,9 +192,9 @@ public:
uint _hideTime;
void draw(Graphics::Surface *dst, int mode);
- void addFlag(DialogueFlags flg);
- void clearFlag(DialogueFlags flg);
- bool hasFlag(DialogueFlags flg) const;
+ void addFlag(DialogFlags flg);
+ void clearFlag(DialogFlags flg);
+ bool hasFlag(DialogFlags flg) const;
Common::String dump(const Common::String &indent) const;
@@ -220,7 +220,7 @@ struct SceneTrigger {
Common::String dump(const Common::String &indent) const;
};
-struct DialogueAction {
+struct DialogAction {
// The game initializes str offsets to pointers, but let's be a bit nicer.
uint16 strStart; /// The start of the clickable text for this action
uint16 strEnd; /// End of clickable text for this action
@@ -245,7 +245,7 @@ struct PerSceneGlobal {
/**
* A scene is described by an SDS file, which points to the ADS script to load
- * and holds the dialogue info.
+ * and holds the dialog info.
*/
class Scene {
public:
@@ -270,9 +270,9 @@ protected:
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
bool readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const;
- bool readDialogueList(Common::SeekableReadStream *s, Common::Array<Dialogue> &list) const;
+ bool readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list) const;
bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
- bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogueAction> &list) const;
+ bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const;
void runOps(const Common::Array<SceneOp> &ops);
bool checkConditions(const Common::Array<struct SceneConditions> &cond);
@@ -363,7 +363,7 @@ private:
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
//uint _field12_0x2b;
- Common::Array<class Dialogue> _dialogs;
+ Common::Array<class Dialog> _dialogs;
Common::Array<struct SceneTrigger> _triggers;
//uint _field15_0x33;
};
Commit: 470e01f0ca82f9f6f2f8792b47e4b605dec50249
https://github.com/scummvm/scummvm/commit/470e01f0ca82f9f6f2f8792b47e4b605dec50249
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Mostly implement original dialog behavior
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 72c216f8439..bf6ee8064ff 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -68,7 +68,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _showClockUser(false), _showClockScript(false),
- _textSpeed(1) {
+ _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false), _random("dgds") {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -171,6 +171,10 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_scene->runEnterSceneOps();
debug("%s", _scene->dump("").c_str());
+
+ _justChangedScene1 = true;
+ _justChangedScene2 = true;
+
return true;
}
@@ -221,6 +225,9 @@ Common::Error DgdsEngine::run() {
_gdsScene->runStartGameOps();
+ // To skip credits for testing
+ changeScene(55, true);
+
} else if (getGameId() == GID_CHINA) {
_gameGlobals = new Globals();
_gamePals->loadPalette("HOC.PAL");
@@ -281,6 +288,8 @@ Common::Error DgdsEngine::run() {
}
} else if (ev.type == Common::EVENT_LBUTTONUP) {
mouseEvent = true;
+ } else if (ev.type == Common::EVENT_MOUSEMOVE) {
+ _lastMouse = ev.mouse;
}
}
@@ -312,24 +321,33 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
_gdsScene->runPreTickOps();
_scene->runPreTickOps();
+
+ _scene->drawActiveDialogBgs(_resData.surfacePtr());
+
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
}
-
+
// Note: Hard-coded logic for DRAGON, check others
//if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
// _gdsScene->runPostTickOps();
+
_scene->runPostTickOps();
_scene->checkTriggers();
_scene->checkDialogActive();
+
+ _scene->drawAndUpdateDialogs(_resData.surfacePtr());
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
return Common::kNoError;
}
+ g_system->copyRectToScreen(_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g_system->updateScreen();
g_system->delayMillis(10);
+ _justChangedScene1 = false;
+ _justChangedScene2 = false;
}
return Common::kNoError;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 3efb6aa4830..96823da8b0e 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -26,6 +26,7 @@
#include "common/error.h"
#include "common/events.h"
#include "common/platform.h"
+#include "common/random.h"
#include "graphics/surface.h"
#include "graphics/managed_surface.h"
@@ -101,6 +102,12 @@ private:
bool _showClockUser;
bool _showClockScript;
+ bool _justChangedScene1;
+ bool _justChangedScene2;
+
+ Common::RandomSource _random;
+ Common::Point _lastMouse; // originals start mouse at 0,0.
+
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
virtual ~DgdsEngine();
@@ -127,6 +134,10 @@ public:
int getTextSpeed() const { return _textSpeed; }
void setShowClock(bool val) { _showClockScript = val; }
ADSInterpreter *adsInterpreter() { return _adsInterp; }
+ bool justChangedScene1() const { return _justChangedScene1; }
+ bool justChangedScene2() const { return _justChangedScene2; }
+ Common::RandomSource &getRandom() { return _random; }
+ Common::Point getLastMouse() const { return _lastMouse; }
private:
void loadCorners(const Common::String &filename);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 5ce66fbc44d..6b485d69cc1 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -190,13 +190,21 @@ Common::String SceneTrigger::dump(const Common::String &indent) const {
}
+int Dialog::_lastSelectedDialogItemNum = 0;
+Dialog *Dialog::_lastDialogSelectionChangedFor = nullptr;
+
+
Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _field7_0xe(0), _field8_0x10(0),
_fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
- _field15_0x22(0), _field18_0x28(0), _hideTime(0)
+ _field18_0x28(0)
{}
-void Dialog::draw(Graphics::Surface *dst, int stage) {
+void Dialog::draw(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state) {
+ _state.reset(new DialogState());
+ }
+
switch (_frameType) {
case kDlgFramePlain: return drawType1(dst, stage);
case kDlgFrameBorder: return drawType2(dst, stage);
@@ -214,30 +222,44 @@ static void _drawPixel(int x, int y, int color, void *data) {
}
+const Font *Dialog::getDlgTextFont() const {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+ FontManager::FontType fontType = FontManager::kGameDlgFont;
+ if (_fontSize == 1)
+ fontType = FontManager::k8x8Font;
+ else if (_fontSize == 3)
+ fontType = FontManager::k4x5Font;
+ return fontman->getFont(fontType);
+}
+
// box with simple frame
-void Dialog::drawType1(Graphics::Surface *dst, int stage) {
- //if (!_field15_0x22)
- // return;
+void Dialog::drawType1(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
int x = _rect.x;
int y = _rect.y;
int w = _rect.width;
int h = _rect.height;
- if (stage == 1) {
+ if (stage == kDlgDrawStageBackground) {
dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
- } else if (stage == 2) {
- drawStage2(dst);
- } else if (stage == 3) {
- drawStage3(dst);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
} else {
_textDrawRect = Common::Rect(x + 3, y + 3, x + w - 3, y + h - 3);
- drawStage4(dst, _bgColor, _str);
+ drawForeground(dst, _bgColor, _str);
}
}
// box with fancy frame and optional title (everything before ":")
-void Dialog::drawType2(Graphics::Surface *dst, int stage) {
+void Dialog::drawType2(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+
Common::String title;
Common::String txt;
uint32 colonpos = _str.find(':');
@@ -248,7 +270,7 @@ void Dialog::drawType2(Graphics::Surface *dst, int stage) {
txt = _str;
}
- if (stage == 1) {
+ if (stage == kDlgDrawStageBackground) {
_textDrawRect = Common::Rect (_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
@@ -258,7 +280,7 @@ void Dialog::drawType2(Graphics::Surface *dst, int stage) {
_textDrawRect.top += 10;
RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
}
- if (_flags & kDlgFlagFlatBg)
+ if (hasFlag(kDlgFlagFlatBg))
dst->fillRect(_textDrawRect, 0);
else
RequestData::fillBackground(dst, _textDrawRect.left, _textDrawRect.top, _textDrawRect.width(), _textDrawRect.height(), 6);
@@ -267,12 +289,12 @@ void Dialog::drawType2(Graphics::Surface *dst, int stage) {
_textDrawRect.left += 8;
_textDrawRect.right -= 8;
- } else if (stage == 2) {
- drawStage2(dst);
- } else if (stage == 3) {
- drawStage3(dst);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
} else {
- drawStage4(dst, _fontColor, txt);
+ drawForeground(dst, _fontColor, txt);
}
}
@@ -283,8 +305,11 @@ static void _filledCircle(int x, int y, int xr, int yr, Graphics::Surface *dst,
// Comic tought box made up of circles with 2 circles going up to it.
// Draw circles with 5/4 more pixels in x because the pixels are not square.
-void Dialog::drawType3(Graphics::Surface *dst, int stage) {
- if (stage == 1) {
+void Dialog::drawType3(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+
+ if (stage == kDlgDrawStageBackground) {
uint16 xradius = 9999;
uint16 yradius = 40;
const int16 usabley = _rect.height - 31;
@@ -315,7 +340,7 @@ void Dialog::drawType3(Graphics::Surface *dst, int stage) {
byte fgcol = 0;
byte bgcol = 15;
- if (_flags & kDlgFlagFlatBg) {
+ if (hasFlag(kDlgFlagFlatBg)) {
bgcol = _bgColor;
fgcol = _fontColor;
}
@@ -360,17 +385,20 @@ void Dialog::drawType3(Graphics::Surface *dst, int stage) {
int16 textRectX = x - xradius / 2;
int16 textRectY = y - yradius / 2;
_textDrawRect = Common::Rect(textRectX, textRectY, textRectX + circlesAcross * xradius , textRectY + circlesDown * yradius);
- } else if (stage == 2) {
- drawStage2(dst);
- } else if (stage == 3) {
- drawStage3(dst);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
} else {
- drawStage4(dst, _fontColor, _str);
+ drawForeground(dst, _fontColor, _str);
}
}
// ellipse
-void Dialog::drawType4(Graphics::Surface *dst, int stage) {
+void Dialog::drawType4(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+
int x = _rect.x;
int y = _rect.y;
int w = _rect.width;
@@ -379,7 +407,7 @@ void Dialog::drawType4(Graphics::Surface *dst, int stage) {
int midy = (h - 1) / 2;
byte fillcolor;
byte fillbgcolor;
- if (!(_flags & 1)) {
+ if (!hasFlag(kDlgFlagFlatBg)) {
fillcolor = 0;
fillbgcolor = 15;
} else {
@@ -387,52 +415,144 @@ void Dialog::drawType4(Graphics::Surface *dst, int stage) {
fillbgcolor = _bgColor;
}
- if (stage == 1) {
+ if (stage == kDlgDrawStageBackground) {
//int radius = (midy * 5) / 4;
// This is not exactly the same as the original - might need some work to get pixel-perfect
Common::Rect drawRect(x, y, x + w, y + h);
Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, _drawPixel, dst);
Graphics::drawRoundRect(drawRect, midy, fillcolor, false, _drawPixel, dst);
- } else if (stage == 2) {
- drawStage2(dst);
- } else if (stage == 2) {
- drawStage2(dst);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
} else {
_textDrawRect = Common::Rect(x + midy, y + 1, x + w - midy, y + h - 1);
- drawStage4(dst, fillcolor, _str);
+ drawForeground(dst, fillcolor, _str);
}
}
-void Dialog::drawStage2(Graphics::Surface *dst) {
- // TODO: various text wrapping and alignment calculations happen here.
-}
+void Dialog::drawFindSelectionXY() {
+ if (!_state)
+ return;
+
+ const Font *font = getDlgTextFont();
+
+ // Find the appropriate _lastMouseX/lastMouseY value given the last _strMouseLoc.
+
+ int x = _state->_loc.x;
+ _state->_lastMouseX = x;
+ int y = _state->_loc.y + 1;
+ _state->_lastMouseY = y;
+ _state->_charWidth = font->getMaxCharWidth();
+ _state->_charHeight = font->getFontHeight();
+ if (_state->_strMouseLoc) {
+ Common::Array<Common::String> lines;
+ int maxWidth = font->wordWrapText(_str, _state->_loc.width, lines);
+
+ if (hasFlag(kDlgFlagLeftJust)) {
+ x = x + (_state->_loc.width - maxWidth - 1) / 2;
+ _state->_lastMouseX = x;
+ y = y + (_state->_loc.height - (lines.size() * _state->_charHeight) - 1) / 2;
+ _state->_lastMouseY = y;
+ }
+
+ if (_state->_strMouseLoc >= (int)_str.size())
+ _state->_strMouseLoc = _str.size() - 1;
+
+ // Find the location of the mouse loc in the wrapped string.
+ int totalchars = 0;
+ for (uint lineno = 0; lineno < lines.size(); lineno++) {
+ // +1 char for the space or CR that caused the wrap.
+ int nexttotalchars = totalchars + lines[lineno].size() + 1;
+ if (nexttotalchars > _state->_strMouseLoc)
+ break;
+ totalchars = nexttotalchars;
+ y += _state->_charHeight;
+ }
+
+ // now get width of the remaining string to the mouse str offset
+ x += font->getStringWidth(_str.substr(totalchars, _state->_strMouseLoc - totalchars));
+
+ // TODO: does this make sense?
+ if (_state->_loc.x + _state->_loc.width < (x + font->getCharWidth(_state->_strMouseLoc))) {
+ if (_str[_state->_strMouseLoc] < '!') {
+ _state->_charHeight = 0;
+ _state->_charWidth = 0;
+ _state->_lastMouseY = 0;
+ _state->_lastMouseX = 0;
+ return;
+ }
+ x = _state->_loc.x;
+ y += _state->_charHeight;
+ }
-void Dialog::drawStage3(Graphics::Surface *dst) {
- // TODO: various text wrapping and alignment calculations happen here.
+ _state->_lastMouseX = x;
+ _state->_lastMouseY = y;
+ _state->_charWidth = font->getCharWidth(_state->_strMouseLoc);
+ }
}
-void Dialog::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
- FontManager::FontType fontType = FontManager::kGameDlgFont;
- if (_fontSize == 1)
- fontType = FontManager::k8x8Font;
- else if (_fontSize == 3)
- fontType = FontManager::k4x5Font;
- const Font *font = fontman->getFont(fontType);
+void Dialog::drawFindSelectionTxtOffset() {
+ if (!_state)
+ return;
+
+ // Find the appropriate _strMouseLoc value given the last x/y position.
+
+ const Font *font = getDlgTextFont();
+ int lastMouseX = _state->_lastMouseX;
+ int lastMouseY = _state->_lastMouseY;
+ int lineHeight = font->getFontHeight();
+ int dlgx = _state->_loc.x;
+ int dlgy = _state->_loc.y;
+
+ Common::Array<Common::String> lines;
+ int maxWidth = font->wordWrapText(_str, dlgy, lines);
+
+ if (hasFlag(kDlgFlagLeftJust)) {
+ dlgx += (_state->_loc.width - maxWidth - 1) / 2;
+ dlgy += (_state->_loc.height - (lines.size() * lineHeight) - 1) / 2;
+ }
+ uint lineno;
+ uint totalchars = 0;
+ for (lineno = 0; lineno < lines.size() && dlgy + lineHeight < lastMouseY; lineno++) {
+ totalchars += lines[lineno].size() + 1;
+ dlgy = dlgy + lineHeight;
+ }
+
+ int startx = dlgx;
+ while (lineno < lines.size()) {
+ const Common::String &line = lines[lineno];
+ for (uint charno = 0; charno < line.size(); charno++) {
+ int charwidth = font->getCharWidth(line[charno]);
+ if (lastMouseX <= dlgx + charwidth) {
+ _state->_strMouseLoc = totalchars + charno;
+ return;
+ }
+ dlgx += charwidth;
+ }
+ dlgx = startx;
+ totalchars += line.size() + 1;
+ }
+
+ _state->_strMouseLoc = _str.size();
+ return;
+}
+
+void Dialog::drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
// TODO: some more text calcuations happen here.
// This is where we actually draw the text.
- // For now do the simplest wrapping.
+ // For now do the simplest wrapping, no highlighting.
Common::StringArray lines;
+ const Font *font = getDlgTextFont();
const int h = font->getFontHeight();
font->wordWrapText(txt, _textDrawRect.width(), lines);
int ystart = _textDrawRect.top + (_textDrawRect.height() - lines.size() * h) / 2;
int x = _textDrawRect.left;
- if (_flags & kDlgFlagLeftJust) {
+ if (hasFlag(kDlgFlagLeftJust)) {
// each line left-aligned, but overall block is still centered
int maxlen = -1;
for (const auto &line : lines)
@@ -448,10 +568,12 @@ void Dialog::drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::St
font->drawString(dst, lines[i], x, ystart + i * h, _textDrawRect.width(), fontcol, Graphics::kTextAlignCenter);
}
-
+ if (_state->_selectedAction) {
+ warning("TODO: Draw highlight on selected action.");
+ }
}
-void Dialog::addFlag(DialogFlags flg) {
+void Dialog::setFlag(DialogFlags flg) {
_flags = static_cast<DialogFlags>(_flags | flg);
}
@@ -459,21 +581,99 @@ void Dialog::clearFlag(DialogFlags flg) {
_flags = static_cast<DialogFlags>(_flags & ~flg);
}
+void Dialog::flipFlag(DialogFlags flg) {
+ _flags = static_cast<DialogFlags>(_flags ^ flg);
+}
+
bool Dialog::hasFlag(DialogFlags flg) const {
return _flags & flg;
}
+void Dialog::updateSelectedAction(int delta) {
+ if (!_lastDialogSelectionChangedFor)
+ _lastDialogSelectionChangedFor = this;
+ else
+ _lastSelectedDialogItemNum = 0;
+
+ if (!_state)
+ return;
+
+ if (_state->_selectedAction) {
+ for (uint i = 0; i < _action.size(); i++) {
+ if (_state->_selectedAction == &_action[i]) {
+ _lastSelectedDialogItemNum = i;
+ break;
+ }
+ }
+ }
+ _lastSelectedDialogItemNum += delta;
+ if (!_action.empty()) {
+ while (_lastSelectedDialogItemNum < 0)
+ _lastSelectedDialogItemNum += _action.size();
+ _lastSelectedDialogItemNum = _lastSelectedDialogItemNum % _action.size();
+ }
+ _lastDialogSelectionChangedFor = this;
+
+ int mouseX = _state->_loc.x + _state->_loc.width;
+ int mouseY = _state->_loc.y + _state->_loc.height - 2;
+ if (_action.size() > 1) {
+ _state->_strMouseLoc = _action[_lastSelectedDialogItemNum].strStart;
+ draw(nullptr, kDlgDrawFindSelectionPointXY);
+ // Move the mouse over the selected item
+ mouseY = _state->_lastMouseY + _state->_charHeight / 2;
+ }
+
+ if (_action.size() > 1 || !delta) {
+ g_system->warpMouse(mouseX, mouseY);
+ }
+}
+
+struct DialogAction *Dialog::pickAction(bool isClosing) {
+ struct DialogAction *retval = nullptr;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (/* some game flags?? && */isClosing) {
+ return &_action[engine->getRandom().getRandomNumber(_action.size() - 1)];
+ }
+ assert(_state);
+ const Common::Point lastMouse = engine->getLastMouse();
+ if (_state->_loc.x <= lastMouse.x &&
+ _state->_loc.x + _state->_loc.width <= lastMouse.x &&
+ _state->_loc.y <= lastMouse.y &&
+ _state->_loc.y + _state->_loc.height <= lastMouse.y) {
+ _state->_lastMouseX = lastMouse.x;
+ _state->_lastMouseY = lastMouse.y;
+ draw(nullptr, kDlgDrawFindSelectionTxtOffset);
+
+ char underMouse = _str[_state->_strMouseLoc];
+ for (auto &action : _action) {
+ if ((action.strStart <= _state->_strMouseLoc && _state->_strMouseLoc <= action.strEnd) ||
+ (_state->_strMouseLoc == action.strEnd + 1 && underMouse == '\r' && _str[action.strEnd] != '\r')) {
+ return &action;
+ }
+ }
+ }
+ return retval;
+}
+
+
Common::String Dialog::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
- "%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk15 %d unk18 %d",
+ "%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize,
- _flags, _frameType, _time, _nextDialogNum, _field15_0x22, _field18_0x28);
+ _flags, _frameType, _time, _nextDialogNum, _field18_0x28);
+ str += indent + "state=" + (_state ? _state->dump("") : "null");
+ str += "\n";
str += _dumpStructList(indent, "actions", _action);
str += "\n";
str += indent + " str='" + _str + "'>";
return str;
}
+Common::String DialogState::dump(const Common::String &indent) const {
+ return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>", indent.c_str(), _hideTime, _loc.dump("").c_str(),
+ _lastMouseX, _lastMouseY, _charWidth, _charHeight, _strMouseLoc, _selectedAction);
+}
+
Common::String DialogAction::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
str += _dumpStructList(indent, "opList", sceneOpList);
@@ -625,7 +825,8 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
dst._flags = static_cast<DialogFlags>(s->readUint16LE());
} else {
// Game reads a 32 bit int but then truncates anyway..
- // probably never used the full thing.
+ // probably never used the full thing in SDS files
+ // as most higher bits are render state.
dst._flags = static_cast<DialogFlags>(s->readUint32LE() & 0xffff);
}
@@ -738,7 +939,7 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
}
-void Scene::runOps(const Common::Array<SceneOp> &ops) {
+bool Scene::runOps(const Common::Array<SceneOp> &ops) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
debug("Exec %s", op.dump("").c_str());
@@ -746,7 +947,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpChangeScene:
if (engine->changeScene(op._args[0], true))
// This probably reset the list - stop now.
- return;
+ return false;
break;
case kSceneOpNoop:
break;
@@ -766,7 +967,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
if (engine->changeScene(sceneNo, true))
// This probably reset the list - stop now.
- return;
+ return false;
break;
}
case kSceneOpShowClock:
@@ -795,6 +996,7 @@ void Scene::runOps(const Common::Array<SceneOp> &ops) {
break;
}
}
+ return true;
}
bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds) {
@@ -971,9 +1173,9 @@ void SDSScene::showDialog(uint16 num) {
dialog.clearFlag(kDlgFlagHi10);
dialog.clearFlag(kDlgFlagHi20);
dialog.clearFlag(kDlgFlagHi40);
- dialog.addFlag(kDlgFlagHi20);
- dialog.addFlag(kDlgFlagVisible);
- dialog.addFlag(kDlgFlagOpening);
+ dialog.setFlag(kDlgFlagHi20);
+ dialog.setFlag(kDlgFlagVisible);
+ dialog.setFlag(kDlgFlagOpening);
// hide time gets set the first time it's drawn.
if (dialog.hasFlag(kDlgFlagLo8)) {
// do something with some global dlg flags here.
@@ -985,45 +1187,129 @@ void SDSScene::showDialog(uint16 num) {
bool SDSScene::checkDialogActive() {
uint32 timeNow = g_engine->getTotalPlayTime();
bool retval = false;
+
+ bool someFlag = false; // ((g_gameStateFlag_41f6 | UINT_39e5_41f8) & 6) != 0); ??
+
for (auto &dlg : _dialogs) {
if (!dlg.hasFlag(kDlgFlagVisible))
continue;
- if (dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40)) {
- // TODO
+ if (!dlg._state)
+ dlg._state.reset(new DialogState());
+
+ bool finished = false;
+ if (dlg._state->_hideTime && dlg._state->_hideTime < timeNow) {
+ finished = someFlag;
}
- if (dlg._hideTime > 0 && dlg._hideTime < timeNow) {
- dlg.clearFlag(kDlgFlagVisible);
- for (auto &action : dlg._action) {
- if (action.strStart == action.strEnd)
- runOps(action.sceneOpList);
+ bool no_options = false;
+ if ((dlg._state->_hideTime == 0) && dlg._action.size() < 2)
+ no_options = true;
+
+ if ((!finished && !no_options) || (dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40))) {
+ if (!finished && dlg._action.size() > 1 && !dlg.hasFlag(kDlgFlagHiFinished)) {
+ struct DialogAction *action = dlg.pickAction(false);
+ if (dlg._state->_selectedAction != action) {
+ dlg._state->_selectedAction = action;
+ dlg.clearFlag(kDlgFlagHi10);
+ dlg.setFlag(kDlgFlagHi8);
+ }
+ }
+ } else {
+ // this dialog is finished - call the ops and maybe show the next one
+ struct DialogAction *action = dlg.pickAction(true);
+ if (action || dlg._action.empty()) {
+ dlg.setFlag(kDlgFlagHiFinished);
+ if (action) {
+ if (!runOps(action->sceneOpList))
+ return true;
+ }
}
- dlg._hideTime = 0;
- dlg.addFlag(kDlgFlagHiFinished);
if (dlg._nextDialogNum) {
+ dlg.setFlag(kDlgFlagHiFinished);
showDialog(dlg._nextDialogNum);
+ }
+ }
+ }
+ return retval;
+}
- retval = true;
+bool SDSScene::drawActiveDialogBgs(Graphics::Surface *dst) {
+ bool retval = false;
+ const DgdsEngine *engine = static_cast<const DgdsEngine *>(g_engine);
+ for (auto &dlg : _dialogs) {
+ if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagOpening)) {
+ assert(dlg._state);
+ if (dlg._state->_hideTime == 0 && dlg._time > 0) {
+ dlg._state->_hideTime = g_engine->getTotalPlayTime() +
+ dlg._time * (9 - engine->getTextSpeed());
}
- } else {
+ dlg.draw(dst, kDlgDrawStageBackground);
+ dlg.clearFlag(kDlgFlagHi20);
+ dlg.setFlag(kDlgFlagHi40);
retval = true;
}
}
return retval;
}
-bool SDSScene::drawActiveDialog(Graphics::Surface *dst, int mode) {
+bool SDSScene::drawAndUpdateDialogs(Graphics::Surface *dst) {
bool retval = false;
const DgdsEngine *engine = static_cast<const DgdsEngine *>(g_engine);
- for (auto &dialog : _dialogs) {
- if (dialog.hasFlag(kDlgFlagVisible)) {
- if (dialog._hideTime == 0 && dialog._time > 0) {
- dialog._hideTime = g_engine->getTotalPlayTime() +
- dialog._time * (9 - engine->getTextSpeed());
+ for (auto &dlg : _dialogs) {
+ if (dlg.hasFlag(kDlgFlagLo80) && !dlg.hasFlag(kDlgFlagLo4) &&
+ !dlg.hasFlag(kDlgFlagHi20) && !dlg.hasFlag(kDlgFlagHi40)) {
+ // TODO: do something with "transfer"s?
+ dlg.setFlag(kDlgFlagHi4);
+ }
+ if (!dlg.hasFlag(kDlgFlagVisible) || (!dlg.hasFlag(kDlgFlagLo4) && !dlg.hasFlag(kDlgFlagOpening))) {
+ if (dlg.hasFlag(kDlgFlagHi8) || dlg.hasFlag(kDlgFlagHi10)) {
+ dlg.draw(dst, kDlgDrawStageForeground);
+ if (!dlg.hasFlag(kDlgFlagHi8)) {
+ dlg.clearFlag(kDlgFlagHi10);
+ } else {
+ dlg.flipFlag(kDlgFlagHi8);
+ dlg.flipFlag(kDlgFlagHi10);
+ }
}
- dialog.draw(dst, mode);
+ } else if (!dlg.hasFlag(kDlgFlagOpening)) {
+ dlg.draw(dst, kDlgDrawStageBackground);
+ if (dlg.hasFlag(kDlgFlagHi20)) {
+ // Reset the dialog time and selected action
+ int delay = -1;
+ if (dlg._time)
+ delay = dlg._time;
+
+ int time = delay * (9 - engine->getTextSpeed());
+ assert(dlg._state);
+
+ dlg._state->_hideTime = g_engine->getTotalPlayTime() + time;
+ dlg._state->_selectedAction = nullptr;
+ dlg.updateSelectedAction(0);
+ if (dlg._action.size() > 1 && !dlg._state->_selectedAction) {
+ dlg._state->_selectedAction = dlg.pickAction(false);
+ if (dlg._state->_selectedAction)
+ dlg.draw(dst, kDlgDrawStageForeground);
+ }
+ }
+
+ if (!dlg.hasFlag(kDlgFlagHi20)) {
+ dlg.clearFlag(kDlgFlagHi40);
+ } else {
+ dlg.flipFlag(kDlgFlagHi20);
+ dlg.flipFlag(kDlgFlagHi40);
+ }
+ dlg.clearFlag(kDlgFlagHi4);
retval = true;
+ } else if (!engine->justChangedScene1()) {
+ dlg.clearFlag(kDlgFlagOpening);
+ }
+
+ if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagLo4) &&
+ !dlg.hasFlag(kDlgFlagHi20) && !dlg.hasFlag(kDlgFlagHi40)) {
+ // TODO: do something with "transfer"s?
+ warning("SDSScene::drawActiveDrawAndUpdateDialogs: Do something with transfers?");
+ dlg.setFlag(kDlgFlagHi4);
}
}
return retval;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 8f73dc04a67..4f279fade68 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -30,10 +30,12 @@ namespace Dgds {
class ResourceManager;
class Decompressor;
-
+class Font;
// TODO: Use Common::Rect instead.
-struct Rect {
+class Rect {
+public:
+ Rect(): x(0), y(0), width(0), height(0) {}
int x;
int y;
int width;
@@ -170,6 +172,29 @@ enum DialogFrameType {
kDlgFrameRounded = 4
};
+enum DialogDrawStage {
+ kDlgDrawStageForeground = 0,
+ kDlgDrawStageBackground = 1,
+ kDlgDrawFindSelectionPointXY = 2,
+ kDlgDrawFindSelectionTxtOffset = 3,
+};
+
+class DialogState {
+public:
+ DialogState() : _hideTime(0), _lastMouseX(0), _lastMouseY(0), _charWidth(0),
+ _charHeight(0), _strMouseLoc(0), _selectedAction(nullptr) {}
+ uint _hideTime;
+ struct Rect _loc;
+ int _lastMouseX;
+ int _lastMouseY;
+ uint16 _charWidth;
+ uint16 _charHeight;
+ int _strMouseLoc;
+ struct DialogAction *_selectedAction;
+
+ Common::String dump(const Common::String &indent) const;
+};
+
class Dialog {
public:
Dialog();
@@ -185,30 +210,36 @@ public:
uint16 _time;
uint16 _nextDialogNum;
Common::Array<struct DialogAction> _action;
- uint16 _field15_0x22;
Common::String _str;
uint16 _field18_0x28;
- uint _hideTime;
+ Common::SharedPtr<struct DialogState> _state;
- void draw(Graphics::Surface *dst, int mode);
- void addFlag(DialogFlags flg);
+ void draw(Graphics::Surface *dst, DialogDrawStage stage);
+ void setFlag(DialogFlags flg);
void clearFlag(DialogFlags flg);
+ void flipFlag(DialogFlags flg);
bool hasFlag(DialogFlags flg) const;
-
+ void updateSelectedAction(int delta);
+ struct DialogAction *pickAction(bool isClosing);
Common::String dump(const Common::String &indent) const;
private:
Common::Rect _textDrawRect; // Calculated while drawing the background.
- void drawType1(Graphics::Surface *dst, int mode);
- void drawType2(Graphics::Surface *dst, int mode);
- void drawType3(Graphics::Surface *dst, int mode);
- void drawType4(Graphics::Surface *dst, int mode);
+ void drawType1(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType2(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType3(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType4(Graphics::Surface *dst, DialogDrawStage stage);
+
+ void drawFindSelectionXY();
+ void drawFindSelectionTxtOffset();
+ void drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt);
+
+ const Font *getDlgTextFont() const;
- void drawStage2(Graphics::Surface *dst);
- void drawStage3(Graphics::Surface *dst);
- void drawStage4(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt);
+ static int _lastSelectedDialogItemNum;
+ static Dialog *_lastDialogSelectionChangedFor;
};
struct SceneTrigger {
@@ -274,7 +305,7 @@ protected:
bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const;
- void runOps(const Common::Array<SceneOp> &ops);
+ bool runOps(const Common::Array<SceneOp> &ops);
bool checkConditions(const Common::Array<struct SceneConditions> &cond);
virtual void enableTrigger(uint16 num) {}
@@ -344,7 +375,8 @@ public:
Common::String dump(const Common::String &indent) const;
bool checkDialogActive();
- bool drawActiveDialog(Graphics::Surface *dst, int mode);
+ bool drawActiveDialogBgs(Graphics::Surface *dst);
+ bool drawAndUpdateDialogs(Graphics::Surface *dst);
void globalOps(const Common::Array<uint16> &args) override;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 0289c9f36bb..73d763f2a31 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -56,19 +56,6 @@ bool TTMInterpreter::load(const Common::String &filename, TTMEnviro &scriptData)
void TTMInterpreter::unload() {
}
-void TTMInterpreter::updateScreen(struct TTMSeq &state) {
- g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-
- if (state._runFlag && _vm->getScene()->checkDialogActive()) {
- Graphics::Surface *screen = g_system->lockScreen();
- _vm->getScene()->drawActiveDialog(screen, 1);
- _vm->getScene()->drawActiveDialog(screen, 4);
- g_system->unlockScreen();
- }
-
- g_system->updateScreen();
-}
-
static const char *ttmOpName(uint16 op) {
switch (op) {
case 0x0000: return "FINISH";
@@ -201,6 +188,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
seq._currentSongId = ivals[0];
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
+ // In the original this sets a global that seems to be never used?
debug("SCENE SETUP DONE: %u", ivals[0]);
break;
case 0x1100: // SET_SCENE: i:int [1..n]
@@ -214,7 +202,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
case 0x1200: // GOTO? How different to SET SCENE??
debug("GOTO SCENE: %u", ivals[0]);
- seq._currentFrame = ivals[0];
+ _vm->adsInterpreter()->setGotoTarget(ivals[0]);
break;
case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
_vm->_soundPlayer->playSFX(ivals[0]);
@@ -237,10 +225,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// The original tight-loops here with 640 steps and i/10 as the fade level..
// bring that down a bit to use less cpu.
// Speed 4 should complete fade in 2 seconds (eg, Dynamix logo fade)
+
+ // TODO: this is a pretty bad way to do it - maybe should pump messages at least.
for (int i = 0; i < 320; i += ivals[3]) {
int fade = MIN(i / 5, 63);
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- updateScreen(seq);
+ g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ g_system->updateScreen();
g_system->delayMillis(5);
}
}
@@ -255,7 +246,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
_vm->getTopBuffer().fillRect(bmpArea, 0);
-
// FADE IN: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -263,7 +253,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
for (int i = 320; i > 0; i -= ivals[3]) {
int fade = MAX(0, MIN(i / 5, 63));
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- updateScreen(seq);
+ g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ g_system->updateScreen();
g_system->delayMillis(5);
}
}
@@ -467,7 +458,6 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
handleOperation(env, seq, op, count, ivals, sval);
}
- updateScreen(seq);
return true;
}
@@ -1151,6 +1141,10 @@ void ADSInterpreter::setHitTTMOp0110() {
_adsData._hitTTMOp0110 = true;
}
+void ADSInterpreter::setGotoTarget(int32 target) {
+ _adsData._gotoTarget = target;
+}
+
int ADSInterpreter::numArgs(uint16 opcode) const {
// TODO: This list is from DRAGON, there may be more entries in newer games.
switch (opcode) {
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 43bd9030b56..b2cc3d6f289 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -140,7 +140,6 @@ public:
protected:
void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
- void updateScreen(struct TTMSeq &seq);
int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq);
DgdsEngine *_vm;
@@ -157,8 +156,9 @@ public:
int numArgs(uint16 opcode) const;
void segmentOrState(int16 seg, uint16 val);
void segmentSetState(int16 seg, uint16 val);
-
+
void setHitTTMOp0110(); // TODO: better name for this global?
+ void setGotoTarget(int32 target);
int16 getStateForSceneOp(uint16 segnum);
void setScriptDelay(int16 delay) { _adsData._scriptDelay = delay; }
Commit: 4db0782221d60d3d10d4a455132b115ffa7c9b2d
https://github.com/scummvm/scummvm/commit/4db0782221d60d3d10d4a455132b115ffa7c9b2d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More small improvements to dialogs
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 6b485d69cc1..13c1bb750bf 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -94,8 +94,8 @@ Common::String SceneConditions::dump(const Common::String &indent) const {
Common::String HotArea::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sHotArea<%s %d %d",
- indent.c_str(), rect.dump("").c_str(), field1_0x8, field2_0xa);
+ Common::String str = Common::String::format("%sHotArea<%s num %d cursor %d",
+ indent.c_str(), rect.dump("").c_str(), _num, _cursorNum);
str += _dumpStructList(indent, "enableConditions", enableConditions);
str += _dumpStructList(indent, "opList1", opList1);
str += _dumpStructList(indent, "opList2", opList2);
@@ -118,6 +118,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
+ case kSceneOpRestartGame: return "restartGame";
case kSceneOpShowClock: return "sceneOpShowClock";
case kSceneOpHideClock: return "sceneOpHideClock";
case kSceneOpShowMouse: return "sceneOpShowMouse";
@@ -157,8 +158,8 @@ Common::String GameItem::dump(const Common::String &indent) const {
"%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d flags %d unk14 %d",
indent.c_str(), super.c_str(), indent.c_str(), field10_0x24,
_iconNum, field12_0x28, _flags, field14_0x2c);
+ str += _dumpStructList(indent, "opList4", opList4);
str += _dumpStructList(indent, "opList5", opList5);
- str += _dumpStructList(indent, "opList6", opList6);
str += "\n";
str += indent + ">";
return str;
@@ -194,7 +195,7 @@ int Dialog::_lastSelectedDialogItemNum = 0;
Dialog *Dialog::_lastDialogSelectionChangedFor = nullptr;
-Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _field7_0xe(0), _field8_0x10(0),
+Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _selectionBgCol(0), _selectonFontCol(0),
_fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
_field18_0x28(0)
{}
@@ -658,8 +659,8 @@ struct DialogAction *Dialog::pickAction(bool isClosing) {
Common::String Dialog::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
- "%sDialogue<num %d %s bgcol %d fcol %d unk7 %d unk8 %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
- indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _field7_0xe, _field8_0x10, _fontSize,
+ "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
+ indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _selectionBgCol, _selectonFontCol, _fontSize,
_flags, _frameType, _time, _nextDialogNum, _field18_0x28);
str += indent + "state=" + (_state ? _state->dump("") : "null");
str += "\n";
@@ -670,8 +671,9 @@ Common::String Dialog::dump(const Common::String &indent) const {
}
Common::String DialogState::dump(const Common::String &indent) const {
- return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>", indent.c_str(), _hideTime, _loc.dump("").c_str(),
- _lastMouseX, _lastMouseY, _charWidth, _charHeight, _strMouseLoc, _selectedAction);
+ return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>",
+ indent.c_str(), _hideTime, _loc.dump("").c_str(), _lastMouseX, _lastMouseY, _charWidth,
+ _charHeight, _strMouseLoc, _selectedAction);
}
Common::String DialogAction::dump(const Common::String &indent) const {
@@ -719,8 +721,8 @@ bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
dst.rect.y = s->readUint16LE();
dst.rect.width = s->readUint16LE();
dst.rect.height = s->readUint16LE();
- dst.field1_0x8 = s->readUint16LE();
- dst.field2_0xa = s->readUint16LE();
+ dst._num = s->readUint16LE();
+ dst._cursorNum = s->readUint16LE();
readConditionList(s, dst.enableConditions);
readOpList(s, dst.opList1);
readOpList(s, dst.opList2);
@@ -751,8 +753,8 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
dst._flags = s->readUint16LE() & 0xfffe;
if (!isVersionUnder(" 1.204")) {
dst.field10_0x24 = s->readUint16LE();
+ readOpList(s, dst.opList4);
readOpList(s, dst.opList5);
- readOpList(s, dst.opList6);
}
}
return !s->err();
@@ -814,11 +816,11 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
dst._bgColor = s->readUint16LE();
dst._fontColor = s->readUint16LE(); // 0 = black, 0xf = white
if (isVersionUnder(" 1.209")) {
- dst._field7_0xe = dst._bgColor;
- dst._field8_0x10 = dst._fontColor;
+ dst._selectionBgCol = dst._bgColor;
+ dst._selectonFontCol = dst._fontColor;
} else {
- dst._field7_0xe = s->readUint16LE();
- dst._field8_0x10 = s->readUint16LE();
+ dst._selectionBgCol = s->readUint16LE();
+ dst._selectonFontCol = s->readUint16LE();
}
dst._fontSize = s->readUint16LE(); // 01 = 8x8, 02 = 6x6, 03 = 4x5
if (isVersionUnder(" 1.210")) {
@@ -846,7 +848,7 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
if (isVersionUnder(" 1.209") && !dst._action.empty()) {
if (dst._fontColor == 0)
- dst._field8_0x10 = 4;
+ dst._selectonFontCol = 4;
else if (dst._fontColor == 0xff)
dst._fontColor = 7;
else
@@ -970,6 +972,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
return false;
break;
}
+ case kSceneOpRestartGame:
+ error("TODO: Implement restart game scene op");
+ break;
case kSceneOpShowClock:
engine->setShowClock(true);
break;
@@ -1155,13 +1160,12 @@ void SDSScene::checkTriggers() {
if (!checkConditions(trigger.conditionList))
continue;
+ trigger._enabled = false;
runOps(trigger.sceneOpList);
// If the scene changed, the list is no longer valid. Abort!
if (_num != startSceneNum)
return;
-
- trigger._enabled = false;
}
}
@@ -1262,7 +1266,7 @@ bool SDSScene::drawAndUpdateDialogs(Graphics::Surface *dst) {
// TODO: do something with "transfer"s?
dlg.setFlag(kDlgFlagHi4);
}
- if (!dlg.hasFlag(kDlgFlagVisible) || (!dlg.hasFlag(kDlgFlagLo4) && !dlg.hasFlag(kDlgFlagOpening))) {
+ if (!dlg.hasFlag(kDlgFlagVisible) || (!dlg.hasFlag(kDlgFlagLo4) && !dlg.hasFlag(kDlgFlagHi4) && !dlg.hasFlag(kDlgFlagHi20) && !dlg.hasFlag(kDlgFlagHi40))) {
if (dlg.hasFlag(kDlgFlagHi8) || dlg.hasFlag(kDlgFlagHi10)) {
dlg.draw(dst, kDlgDrawStageForeground);
if (!dlg.hasFlag(kDlgFlagHi8)) {
@@ -1308,7 +1312,7 @@ bool SDSScene::drawAndUpdateDialogs(Graphics::Surface *dst) {
if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagLo4) &&
!dlg.hasFlag(kDlgFlagHi20) && !dlg.hasFlag(kDlgFlagHi40)) {
// TODO: do something with "transfer"s?
- warning("SDSScene::drawActiveDrawAndUpdateDialogs: Do something with transfers?");
+ // warning("SDSScene::drawActiveDrawAndUpdateDialogs: Do something with transfers?");
dlg.setFlag(kDlgFlagHi4);
}
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 4f279fade68..0eb8a3c3b37 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -66,8 +66,8 @@ struct SceneConditions {
struct HotArea {
struct Rect rect;
- uint16 field1_0x8; //
- uint16 field2_0xa;
+ uint16 _num; //
+ uint16 _cursorNum;
Common::Array<struct SceneConditions> enableConditions;
Common::Array<struct SceneOp> opList1;
Common::Array<struct SceneOp> opList2;
@@ -87,11 +87,11 @@ enum SceneOpCode {
kSceneOp7 = 7, // args: none.
kSceneOpShowDlg = 8, // args: dialogue number. show dialogue?
kSceneOp9 = 9, // args: none.
- kSceneOp10 = 10, // args: none. Looks through the struct2 list for something.
+ kSceneOp10 = 10, // args: none. Clean up the hot area list?
kSceneOpEnableTrigger = 11, // args: trigger num
kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
kSceneOp13 = 13, // args: none.
- kSceneOp14 = 14, // args: none.
+ kSceneOpRestartGame = 14, // args: none.
kSceneOp15 = 15, // args: none.
kSceneOpShowClock = 16, // args: none. set some clock-related globals
kSceneOpHideClock = 17, // args: none. set some clock-related values.
@@ -119,8 +119,8 @@ struct SceneOp {
};
struct GameItem : public HotArea {
+ Common::Array<struct SceneOp> opList4;
Common::Array<struct SceneOp> opList5;
- Common::Array<struct SceneOp> opList6;
uint16 field10_0x24;
uint16 _iconNum;
uint16 field12_0x28;
@@ -202,8 +202,8 @@ public:
Rect _rect;
uint16 _bgColor;
uint16 _fontColor;
- uint16 _field7_0xe;
- uint16 _field8_0x10;
+ uint16 _selectionBgCol;
+ uint16 _selectonFontCol;
uint16 _fontSize;
DialogFlags _flags;
DialogFrameType _frameType;
Commit: 6051f5f36520a03fce203765506cbbcea1af63cd
https://github.com/scummvm/scummvm/commit/6051f5f36520a03fce203765506cbbcea1af63cd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Split dialog functions into their own file
Changed paths:
A engines/dgds/dgds_rect.cpp
A engines/dgds/dgds_rect.h
A engines/dgds/dialog.cpp
A engines/dgds/dialog.h
engines/dgds/module.mk
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds_rect.cpp b/engines/dgds/dgds_rect.cpp
new file mode 100644
index 00000000000..49d63bceb27
--- /dev/null
+++ b/engines/dgds/dgds_rect.cpp
@@ -0,0 +1,30 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dgds/dgds_rect.h"
+
+namespace Dgds {
+
+Common::String DgdsRect::dump(const Common::String &indent) const {
+ return Common::String::format("%sRect<%d,%d %d,%d>", indent.c_str(), x, y, width, height);
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/dgds_rect.h b/engines/dgds/dgds_rect.h
new file mode 100644
index 00000000000..6d04b0a4900
--- /dev/null
+++ b/engines/dgds/dgds_rect.h
@@ -0,0 +1,42 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_DGDS_RECT_H
+#define DGDS_DGDS_RECT_H
+
+#include "common/str.h"
+
+namespace Dgds {
+
+class DgdsRect {
+public:
+ DgdsRect(): x(0), y(0), width(0), height(0) {}
+ int x;
+ int y;
+ int width;
+ int height;
+
+ Common::String dump(const Common::String &indent) const;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_DGDS_RECT_H
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
new file mode 100644
index 00000000000..284ad8fd8bb
--- /dev/null
+++ b/engines/dgds/dialog.cpp
@@ -0,0 +1,550 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dgds/dialog.h"
+
+#include "common/debug.h"
+#include "common/endian.h"
+#include "common/rect.h"
+#include "common/system.h"
+
+#include "graphics/surface.h"
+#include "graphics/primitives.h"
+
+#include "dgds/dgds.h"
+#include "dgds/includes.h"
+#include "dgds/request.h"
+#include "dgds/scripts.h"
+#include "dgds/font.h"
+
+namespace Dgds {
+
+// TODO: This is repeated here and in scene.cpp
+template<class S> static Common::String _dumpStructList(const Common::String &indent, const Common::String &name, const Common::Array<S> &list) {
+ if (list.empty())
+ return "";
+
+ const Common::String nextind = indent + " ";
+ Common::String str = Common::String::format("\n%s%s=", Common::String(indent + " ").c_str(), name.c_str());
+ for (const auto &s : list) {
+ str += "\n";
+ str += s.dump(nextind);
+ }
+ return str;
+}
+
+
+int Dialog::_lastSelectedDialogItemNum = 0;
+Dialog *Dialog::_lastDialogSelectionChangedFor = nullptr;
+
+
+Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _selectionBgCol(0), _selectonFontCol(0),
+ _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
+ _field18_0x28(0)
+{}
+
+
+void Dialog::draw(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ _state.reset(new DialogState());
+
+ switch (_frameType) {
+ case kDlgFramePlain: return drawType1(dst, stage);
+ case kDlgFrameBorder: return drawType2(dst, stage);
+ case kDlgFrameThought: return drawType3(dst, stage);
+ case kDlgFrameRounded: return drawType4(dst, stage);
+ default: error("unexpected frame type %d for dialog %d", _frameType, _num);
+ }
+}
+
+static void _drawPixel(int x, int y, int color, void *data) {
+ Graphics::Surface *surface = (Graphics::Surface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
+ *((byte *)surface->getBasePtr(x, y)) = (byte)color;
+}
+
+
+const Font *Dialog::getDlgTextFont() const {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+ FontManager::FontType fontType = FontManager::kGameDlgFont;
+ if (_fontSize == 1)
+ fontType = FontManager::k8x8Font;
+ else if (_fontSize == 3)
+ fontType = FontManager::k4x5Font;
+ return fontman->getFont(fontType);
+}
+
+// box with simple frame
+void Dialog::drawType1(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+ int x = _rect.x;
+ int y = _rect.y;
+ int w = _rect.width;
+ int h = _rect.height;
+
+ if (stage == kDlgDrawStageBackground) {
+ dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
+ dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
+ } else {
+ _textDrawRect = Common::Rect(x + 3, y + 3, x + w - 3, y + h - 3);
+ drawForeground(dst, _bgColor, _str);
+ }
+}
+
+// box with fancy frame and optional title (everything before ":")
+void Dialog::drawType2(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+
+ Common::String title;
+ Common::String txt;
+ uint32 colonpos = _str.find(':');
+ if (colonpos != Common::String::npos) {
+ title = _str.substr(0, colonpos);
+ txt = _str.substr(colonpos + 1);
+ } else {
+ txt = _str;
+ }
+
+ if (stage == kDlgDrawStageBackground) {
+ _textDrawRect = Common::Rect (_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
+ Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
+ RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
+ RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
+ if (!title.empty()) {
+ // TODO: Maybe should measure the font?
+ _textDrawRect.top += 10;
+ RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
+ }
+ if (hasFlag(kDlgFlagFlatBg))
+ dst->fillRect(_textDrawRect, 0);
+ else
+ RequestData::fillBackground(dst, _textDrawRect.left, _textDrawRect.top, _textDrawRect.width(), _textDrawRect.height(), 6);
+
+ RequestData::drawCorners(dst, 19, _textDrawRect.left - 2, _textDrawRect.top - 2, _textDrawRect.width() + 4, _textDrawRect.height() + 4);
+
+ _textDrawRect.left += 8;
+ _textDrawRect.right -= 8;
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
+ } else {
+ drawForeground(dst, _fontColor, txt);
+ }
+}
+
+static void _filledCircle(int x, int y, int xr, int yr, Graphics::Surface *dst, byte fgcol, byte bgcol) {
+ Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, bgcol, true, _drawPixel, dst);
+ Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, _drawPixel, dst);
+}
+
+// Comic tought box made up of circles with 2 circles going up to it.
+// Draw circles with 5/4 more pixels in x because the pixels are not square.
+void Dialog::drawType3(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+
+ if (stage == kDlgDrawStageBackground) {
+ uint16 xradius = 9999;
+ uint16 yradius = 40;
+ const int16 usabley = _rect.height - 31;
+ const int16 usablex = _rect.width - 30;
+ for (uint16 testyradius = 40; testyradius != 0; testyradius--) {
+ int16 testxradius = (testyradius * 5) / 4;
+ if ((usablex / testxradius > 2) && (usabley / testyradius > 2)) {
+ testxradius = usablex % testxradius + usabley % testyradius;
+ if (testxradius < xradius) {
+ yradius = testyradius;
+ xradius = testxradius;
+ }
+ }
+ if (testyradius < 20 && xradius != 9999)
+ break;
+ }
+
+ xradius = (yradius * 5) / 4;
+ const int16 circlesAcross = usablex / xradius - 1;
+ const int16 circlesDown = usabley / yradius - 1;
+
+ uint16 x = _rect.x + xradius;
+ uint16 y = _rect.y + yradius;
+
+ bool isbig = _rect.x + _rect.width / 2 > 160;
+ if (isbig)
+ x = x + 30;
+
+ byte fgcol = 0;
+ byte bgcol = 15;
+ if (hasFlag(kDlgFlagFlatBg)) {
+ bgcol = _bgColor;
+ fgcol = _fontColor;
+ }
+
+ for (int i = 1; i < circlesDown; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ y += yradius;
+ }
+ for (int i = 1; i < circlesAcross; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ x += xradius;
+ }
+ for (int i = 1; i < circlesDown; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ y -= yradius;
+ }
+ for (int i = 1; i < circlesAcross; i++) {
+ _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+ x -= xradius;
+ }
+
+ uint16 smallCircleX;
+ if (isbig) {
+ _filledCircle((x - xradius) - 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
+ smallCircleX = (x - xradius) - 20;
+ } else {
+ _filledCircle(x + circlesAcross * xradius + 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
+ smallCircleX = x + circlesAcross * xradius + 20;
+ }
+
+ _filledCircle(smallCircleX, y + circlesDown * yradius + 25, 5, 4, dst, fgcol, bgcol);
+
+ int16 yoff = (yradius * 27) / 32;
+ dst->fillRect(Common::Rect(x, y - yoff,
+ x + (circlesAcross - 1) * xradius + 1,
+ y + (circlesDown - 1) * yradius + yoff + 1), bgcol);
+ int16 xoff = (xradius * 27) / 32;
+ dst->fillRect(Common::Rect(x - xoff, y,
+ x + (circlesAcross - 1) * xradius + xoff + 1,
+ y + (circlesDown - 1) * yradius + 1), bgcol);
+
+ int16 textRectX = x - xradius / 2;
+ int16 textRectY = y - yradius / 2;
+ _textDrawRect = Common::Rect(textRectX, textRectY, textRectX + circlesAcross * xradius , textRectY + circlesDown * yradius);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
+ } else {
+ drawForeground(dst, _fontColor, _str);
+ }
+}
+
+// ellipse
+void Dialog::drawType4(Graphics::Surface *dst, DialogDrawStage stage) {
+ if (!_state)
+ return;
+
+ int x = _rect.x;
+ int y = _rect.y;
+ int w = _rect.width;
+ int h = _rect.height;
+
+ int midy = (h - 1) / 2;
+ byte fillcolor;
+ byte fillbgcolor;
+ if (!hasFlag(kDlgFlagFlatBg)) {
+ fillcolor = 0;
+ fillbgcolor = 15;
+ } else {
+ fillcolor = _fontColor;
+ fillbgcolor = _bgColor;
+ }
+
+ if (stage == kDlgDrawStageBackground) {
+ //int radius = (midy * 5) / 4;
+
+ // This is not exactly the same as the original - might need some work to get pixel-perfect
+ Common::Rect drawRect(x, y, x + w, y + h);
+ Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, _drawPixel, dst);
+ Graphics::drawRoundRect(drawRect, midy, fillcolor, false, _drawPixel, dst);
+ } else if (stage == kDlgDrawFindSelectionPointXY) {
+ drawFindSelectionXY();
+ } else if (stage == kDlgDrawFindSelectionTxtOffset) {
+ drawFindSelectionTxtOffset();
+ } else {
+ _textDrawRect = Common::Rect(x + midy, y + 1, x + w - midy, y + h - 1);
+ drawForeground(dst, fillcolor, _str);
+ }
+}
+
+void Dialog::drawFindSelectionXY() {
+ if (!_state)
+ return;
+
+ const Font *font = getDlgTextFont();
+
+ // Find the appropriate _lastMouseX/lastMouseY value given the last _strMouseLoc.
+
+ int x = _state->_loc.x;
+ _state->_lastMouseX = x;
+ int y = _state->_loc.y + 1;
+ _state->_lastMouseY = y;
+ _state->_charWidth = font->getMaxCharWidth();
+ _state->_charHeight = font->getFontHeight();
+ if (_state->_strMouseLoc) {
+ Common::Array<Common::String> lines;
+ int maxWidth = font->wordWrapText(_str, _state->_loc.width, lines);
+
+ if (hasFlag(kDlgFlagLeftJust)) {
+ x = x + (_state->_loc.width - maxWidth - 1) / 2;
+ _state->_lastMouseX = x;
+ y = y + (_state->_loc.height - (lines.size() * _state->_charHeight) - 1) / 2;
+ _state->_lastMouseY = y;
+ }
+
+ if (_state->_strMouseLoc >= (int)_str.size())
+ _state->_strMouseLoc = _str.size() - 1;
+
+ // Find the location of the mouse loc in the wrapped string.
+ int totalchars = 0;
+ for (uint lineno = 0; lineno < lines.size(); lineno++) {
+ // +1 char for the space or CR that caused the wrap.
+ int nexttotalchars = totalchars + lines[lineno].size() + 1;
+ if (nexttotalchars > _state->_strMouseLoc)
+ break;
+ totalchars = nexttotalchars;
+ y += _state->_charHeight;
+ }
+
+ // now get width of the remaining string to the mouse str offset
+ x += font->getStringWidth(_str.substr(totalchars, _state->_strMouseLoc - totalchars));
+
+ // TODO: does this make sense?
+ if (_state->_loc.x + _state->_loc.width < (x + font->getCharWidth(_state->_strMouseLoc))) {
+ if (_str[_state->_strMouseLoc] < '!') {
+ _state->_charHeight = 0;
+ _state->_charWidth = 0;
+ _state->_lastMouseY = 0;
+ _state->_lastMouseX = 0;
+ return;
+ }
+ x = _state->_loc.x;
+ y += _state->_charHeight;
+ }
+
+ _state->_lastMouseX = x;
+ _state->_lastMouseY = y;
+ _state->_charWidth = font->getCharWidth(_state->_strMouseLoc);
+ }
+}
+
+void Dialog::drawFindSelectionTxtOffset() {
+ if (!_state)
+ return;
+
+ // Find the appropriate _strMouseLoc value given the last x/y position.
+
+ const Font *font = getDlgTextFont();
+ int lastMouseX = _state->_lastMouseX;
+ int lastMouseY = _state->_lastMouseY;
+ int lineHeight = font->getFontHeight();
+ int dlgx = _state->_loc.x;
+ int dlgy = _state->_loc.y;
+
+ Common::Array<Common::String> lines;
+ int maxWidth = font->wordWrapText(_str, dlgy, lines);
+
+ if (hasFlag(kDlgFlagLeftJust)) {
+ dlgx += (_state->_loc.width - maxWidth - 1) / 2;
+ dlgy += (_state->_loc.height - (lines.size() * lineHeight) - 1) / 2;
+ }
+
+ uint lineno;
+ uint totalchars = 0;
+ for (lineno = 0; lineno < lines.size() && dlgy + lineHeight < lastMouseY; lineno++) {
+ totalchars += lines[lineno].size() + 1;
+ dlgy = dlgy + lineHeight;
+ }
+
+ int startx = dlgx;
+ while (lineno < lines.size()) {
+ const Common::String &line = lines[lineno];
+ for (uint charno = 0; charno < line.size(); charno++) {
+ int charwidth = font->getCharWidth(line[charno]);
+ if (lastMouseX <= dlgx + charwidth) {
+ _state->_strMouseLoc = totalchars + charno;
+ return;
+ }
+ dlgx += charwidth;
+ }
+ dlgx = startx;
+ totalchars += line.size() + 1;
+ }
+
+ _state->_strMouseLoc = _str.size();
+ return;
+}
+
+void Dialog::drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
+ // TODO: some more text calcuations happen here.
+ // This is where we actually draw the text.
+ // For now do the simplest wrapping, no highlighting.
+ Common::StringArray lines;
+ const Font *font = getDlgTextFont();
+ const int h = font->getFontHeight();
+ font->wordWrapText(txt, _textDrawRect.width(), lines);
+
+ int ystart = _textDrawRect.top + (_textDrawRect.height() - lines.size() * h) / 2;
+
+ int x = _textDrawRect.left;
+ if (hasFlag(kDlgFlagLeftJust)) {
+ // each line left-aligned, but overall block is still centered
+ int maxlen = -1;
+ for (const auto &line : lines)
+ maxlen = MAX(maxlen, font->getStringWidth(line));
+
+ x += (_textDrawRect.width() - maxlen) / 2;
+
+ for (uint i = 0; i < lines.size(); i++)
+ font->drawString(dst, lines[i], x, ystart + i * h, maxlen, fontcol, Graphics::kTextAlignLeft);
+ } else {
+ // center each line
+ for (uint i = 0; i < lines.size(); i++)
+ font->drawString(dst, lines[i], x, ystart + i * h, _textDrawRect.width(), fontcol, Graphics::kTextAlignCenter);
+ }
+
+ if (_state->_selectedAction) {
+ warning("TODO: Draw highlight on selected action.");
+ }
+}
+
+void Dialog::setFlag(DialogFlags flg) {
+ _flags = static_cast<DialogFlags>(_flags | flg);
+}
+
+void Dialog::clearFlag(DialogFlags flg) {
+ _flags = static_cast<DialogFlags>(_flags & ~flg);
+}
+
+void Dialog::flipFlag(DialogFlags flg) {
+ _flags = static_cast<DialogFlags>(_flags ^ flg);
+}
+
+bool Dialog::hasFlag(DialogFlags flg) const {
+ return _flags & flg;
+}
+
+void Dialog::updateSelectedAction(int delta) {
+ if (!_lastDialogSelectionChangedFor)
+ _lastDialogSelectionChangedFor = this;
+ else
+ _lastSelectedDialogItemNum = 0;
+
+ if (!_state)
+ return;
+
+ if (_state->_selectedAction) {
+ for (uint i = 0; i < _action.size(); i++) {
+ if (_state->_selectedAction == &_action[i]) {
+ _lastSelectedDialogItemNum = i;
+ break;
+ }
+ }
+ }
+ _lastSelectedDialogItemNum += delta;
+ if (!_action.empty()) {
+ while (_lastSelectedDialogItemNum < 0)
+ _lastSelectedDialogItemNum += _action.size();
+ _lastSelectedDialogItemNum = _lastSelectedDialogItemNum % _action.size();
+ }
+ _lastDialogSelectionChangedFor = this;
+
+ int mouseX = _state->_loc.x + _state->_loc.width;
+ int mouseY = _state->_loc.y + _state->_loc.height - 2;
+ if (_action.size() > 1) {
+ _state->_strMouseLoc = _action[_lastSelectedDialogItemNum].strStart;
+ draw(nullptr, kDlgDrawFindSelectionPointXY);
+ // Move the mouse over the selected item
+ mouseY = _state->_lastMouseY + _state->_charHeight / 2;
+ }
+
+ if (_action.size() > 1 || !delta) {
+ g_system->warpMouse(mouseX, mouseY);
+ }
+}
+
+struct DialogAction *Dialog::pickAction(bool isClosing) {
+ struct DialogAction *retval = nullptr;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (/* some game flags?? && */isClosing) {
+ return &_action[engine->getRandom().getRandomNumber(_action.size() - 1)];
+ }
+ assert(_state);
+ const Common::Point lastMouse = engine->getLastMouse();
+ if (_state->_loc.x <= lastMouse.x &&
+ _state->_loc.x + _state->_loc.width <= lastMouse.x &&
+ _state->_loc.y <= lastMouse.y &&
+ _state->_loc.y + _state->_loc.height <= lastMouse.y) {
+ _state->_lastMouseX = lastMouse.x;
+ _state->_lastMouseY = lastMouse.y;
+ draw(nullptr, kDlgDrawFindSelectionTxtOffset);
+
+ char underMouse = _str[_state->_strMouseLoc];
+ for (auto &action : _action) {
+ if ((action.strStart <= _state->_strMouseLoc && _state->_strMouseLoc <= action.strEnd) ||
+ (_state->_strMouseLoc == action.strEnd + 1 && underMouse == '\r' && _str[action.strEnd] != '\r')) {
+ return &action;
+ }
+ }
+ }
+ return retval;
+}
+
+
+Common::String Dialog::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format(
+ "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
+ indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _selectionBgCol, _selectonFontCol, _fontSize,
+ _flags, _frameType, _time, _nextDialogNum, _field18_0x28);
+ str += indent + "state=" + (_state ? _state->dump("") : "null");
+ str += "\n";
+ str += _dumpStructList(indent, "actions", _action);
+ str += "\n";
+ str += indent + " str='" + _str + "'>";
+ return str;
+}
+
+Common::String DialogState::dump(const Common::String &indent) const {
+ return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>",
+ indent.c_str(), _hideTime, _loc.dump("").c_str(), _lastMouseX, _lastMouseY, _charWidth,
+ _charHeight, _strMouseLoc, _selectedAction);
+}
+
+Common::String DialogAction::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
+ str += _dumpStructList(indent, "opList", sceneOpList);
+ if (!sceneOpList.empty()) {
+ str += "\n";
+ str += indent;
+ }
+ str += ">";
+ return str;
+}
+
+} // End of namespace Dgds
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
new file mode 100644
index 00000000000..2e304379b80
--- /dev/null
+++ b/engines/dgds/dialog.h
@@ -0,0 +1,149 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_DIALOG_H
+#define DGDS_DIALOG_H
+
+#include "common/stream.h"
+#include "common/array.h"
+#include "common/rect.h"
+
+#include "dgds/dgds_rect.h"
+
+namespace Graphics {
+class Surface;
+}
+
+namespace Dgds {
+
+class Font;
+
+enum DialogFlags {
+ kDlgFlagNone = 0,
+ kDlgFlagFlatBg = 1,
+ kDlgFlagLeftJust = 2,
+ kDlgFlagLo4 = 4,
+ kDlgFlagLo8 = 8,
+ kDlgFlagLo80 = 0x80,
+ kDlgFlagHiFinished = 0x10000,
+ kDlgFlagHi2 = 0x20000,
+ kDlgFlagHi4 = 0x40000,
+ kDlgFlagHi8 = 0x80000,
+ kDlgFlagHi10 = 0x100000,
+ kDlgFlagHi20 = 0x200000,
+ kDlgFlagHi40 = 0x400000,
+ kDlgFlagVisible = 0x800000,
+ kDlgFlagOpening = 0x1000000,
+};
+
+enum DialogFrameType {
+ kDlgFramePlain = 1,
+ kDlgFrameBorder = 2,
+ kDlgFrameThought = 3,
+ kDlgFrameRounded = 4
+};
+
+enum DialogDrawStage {
+ kDlgDrawStageForeground = 0,
+ kDlgDrawStageBackground = 1,
+ kDlgDrawFindSelectionPointXY = 2,
+ kDlgDrawFindSelectionTxtOffset = 3,
+};
+
+struct DialogAction {
+ // The game initializes str offsets to pointers, but let's be a bit nicer.
+ uint16 strStart; /// The start of the clickable text for this action
+ uint16 strEnd; /// End of clickable text for this action
+ byte unk[8]; /* Not initialized in loader */
+ Common::Array<struct SceneOp> sceneOpList; /// ops to run when this is selected
+ uint val; /* First entry initialized to 1 in loader */
+
+ Common::String dump(const Common::String &indent) const;
+};
+
+class DialogState {
+public:
+ DialogState() : _hideTime(0), _lastMouseX(0), _lastMouseY(0), _charWidth(0),
+ _charHeight(0), _strMouseLoc(0), _selectedAction(nullptr) {}
+ uint _hideTime;
+ DgdsRect _loc;
+ int _lastMouseX;
+ int _lastMouseY;
+ uint16 _charWidth;
+ uint16 _charHeight;
+ int _strMouseLoc;
+ struct DialogAction *_selectedAction;
+
+ Common::String dump(const Common::String &indent) const;
+};
+
+class Dialog {
+public:
+ Dialog();
+ uint16 _num;
+ DgdsRect _rect;
+ uint16 _bgColor;
+ uint16 _fontColor;
+ uint16 _selectionBgCol;
+ uint16 _selectonFontCol;
+ uint16 _fontSize;
+ DialogFlags _flags;
+ DialogFrameType _frameType;
+ uint16 _time;
+ uint16 _nextDialogNum;
+ Common::Array<struct DialogAction> _action;
+ Common::String _str;
+ uint16 _field18_0x28;
+
+ Common::SharedPtr<struct DialogState> _state;
+
+ void draw(Graphics::Surface *dst, DialogDrawStage stage);
+ void setFlag(DialogFlags flg);
+ void clearFlag(DialogFlags flg);
+ void flipFlag(DialogFlags flg);
+ bool hasFlag(DialogFlags flg) const;
+ void updateSelectedAction(int delta);
+ struct DialogAction *pickAction(bool isClosing);
+ Common::String dump(const Common::String &indent) const;
+
+private:
+ Common::Rect _textDrawRect; // Calculated while drawing the background.
+
+ void drawType1(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType2(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType3(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType4(Graphics::Surface *dst, DialogDrawStage stage);
+
+ void drawFindSelectionXY();
+ void drawFindSelectionTxtOffset();
+ void drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt);
+
+ const Font *getDlgTextFont() const;
+
+ static int _lastSelectedDialogItemNum;
+ static Dialog *_lastDialogSelectionChangedFor;
+};
+
+
+
+} // end namespace Dgds
+
+#endif // DGDS_DIALOG_H
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 5e5378ac48c..ce46714ed6f 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -4,6 +4,8 @@ MODULE_OBJS := \
console.o \
decompress.o \
dgds.o \
+ dgds_rect.o \
+ dialog.o \
font.o \
globals.o \
image.o \
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 13c1bb750bf..f02d4ee223e 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -55,10 +55,6 @@ template<class S> Common::String _dumpStructList(const Common::String &indent, c
}
-Common::String Rect::dump(const Common::String &indent) const {
- return Common::String::format("%sRect<%d,%d %d,%d>", indent.c_str(), x, y, width, height);
-}
-
Common::String _sceneConditionStr(SceneCondition cflag) {
Common::String ret;
@@ -191,502 +187,6 @@ Common::String SceneTrigger::dump(const Common::String &indent) const {
}
-int Dialog::_lastSelectedDialogItemNum = 0;
-Dialog *Dialog::_lastDialogSelectionChangedFor = nullptr;
-
-
-Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _selectionBgCol(0), _selectonFontCol(0),
- _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
- _field18_0x28(0)
-{}
-
-
-void Dialog::draw(Graphics::Surface *dst, DialogDrawStage stage) {
- if (!_state) {
- _state.reset(new DialogState());
- }
-
- switch (_frameType) {
- case kDlgFramePlain: return drawType1(dst, stage);
- case kDlgFrameBorder: return drawType2(dst, stage);
- case kDlgFrameThought: return drawType3(dst, stage);
- case kDlgFrameRounded: return drawType4(dst, stage);
- default: error("unexpected frame type %d for dialog %d", _frameType, _num);
- }
-}
-
-static void _drawPixel(int x, int y, int color, void *data) {
- Graphics::Surface *surface = (Graphics::Surface *)data;
-
- if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
- *((byte *)surface->getBasePtr(x, y)) = (byte)color;
-}
-
-
-const Font *Dialog::getDlgTextFont() const {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
- FontManager::FontType fontType = FontManager::kGameDlgFont;
- if (_fontSize == 1)
- fontType = FontManager::k8x8Font;
- else if (_fontSize == 3)
- fontType = FontManager::k4x5Font;
- return fontman->getFont(fontType);
-}
-
-// box with simple frame
-void Dialog::drawType1(Graphics::Surface *dst, DialogDrawStage stage) {
- if (!_state)
- return;
- int x = _rect.x;
- int y = _rect.y;
- int w = _rect.width;
- int h = _rect.height;
-
- if (stage == kDlgDrawStageBackground) {
- dst->fillRect(Common::Rect(x, y, x + w, y + h), _bgColor);
- dst->fillRect(Common::Rect(x + 1, y + 1, x + w - 1, y + h - 1), _fontColor);
- } else if (stage == kDlgDrawFindSelectionPointXY) {
- drawFindSelectionXY();
- } else if (stage == kDlgDrawFindSelectionTxtOffset) {
- drawFindSelectionTxtOffset();
- } else {
- _textDrawRect = Common::Rect(x + 3, y + 3, x + w - 3, y + h - 3);
- drawForeground(dst, _bgColor, _str);
- }
-}
-
-// box with fancy frame and optional title (everything before ":")
-void Dialog::drawType2(Graphics::Surface *dst, DialogDrawStage stage) {
- if (!_state)
- return;
-
- Common::String title;
- Common::String txt;
- uint32 colonpos = _str.find(':');
- if (colonpos != Common::String::npos) {
- title = _str.substr(0, colonpos);
- txt = _str.substr(colonpos + 1);
- } else {
- txt = _str;
- }
-
- if (stage == kDlgDrawStageBackground) {
- _textDrawRect = Common::Rect (_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
- Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
- RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
- RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
- if (!title.empty()) {
- // TODO: Maybe should measure the font?
- _textDrawRect.top += 10;
- RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
- }
- if (hasFlag(kDlgFlagFlatBg))
- dst->fillRect(_textDrawRect, 0);
- else
- RequestData::fillBackground(dst, _textDrawRect.left, _textDrawRect.top, _textDrawRect.width(), _textDrawRect.height(), 6);
-
- RequestData::drawCorners(dst, 19, _textDrawRect.left - 2, _textDrawRect.top - 2, _textDrawRect.width() + 4, _textDrawRect.height() + 4);
-
- _textDrawRect.left += 8;
- _textDrawRect.right -= 8;
- } else if (stage == kDlgDrawFindSelectionPointXY) {
- drawFindSelectionXY();
- } else if (stage == kDlgDrawFindSelectionTxtOffset) {
- drawFindSelectionTxtOffset();
- } else {
- drawForeground(dst, _fontColor, txt);
- }
-}
-
-static void _filledCircle(int x, int y, int xr, int yr, Graphics::Surface *dst, byte fgcol, byte bgcol) {
- Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, bgcol, true, _drawPixel, dst);
- Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, _drawPixel, dst);
-}
-
-// Comic tought box made up of circles with 2 circles going up to it.
-// Draw circles with 5/4 more pixels in x because the pixels are not square.
-void Dialog::drawType3(Graphics::Surface *dst, DialogDrawStage stage) {
- if (!_state)
- return;
-
- if (stage == kDlgDrawStageBackground) {
- uint16 xradius = 9999;
- uint16 yradius = 40;
- const int16 usabley = _rect.height - 31;
- const int16 usablex = _rect.width - 30;
- for (uint16 testyradius = 40; testyradius != 0; testyradius--) {
- int16 testxradius = (testyradius * 5) / 4;
- if ((usablex / testxradius > 2) && (usabley / testyradius > 2)) {
- testxradius = usablex % testxradius + usabley % testyradius;
- if (testxradius < xradius) {
- yradius = testyradius;
- xradius = testxradius;
- }
- }
- if (testyradius < 20 && xradius != 9999)
- break;
- }
-
- xradius = (yradius * 5) / 4;
- const int16 circlesAcross = usablex / xradius - 1;
- const int16 circlesDown = usabley / yradius - 1;
-
- uint16 x = _rect.x + xradius;
- uint16 y = _rect.y + yradius;
-
- bool isbig = _rect.x + _rect.width / 2 > 160;
- if (isbig)
- x = x + 30;
-
- byte fgcol = 0;
- byte bgcol = 15;
- if (hasFlag(kDlgFlagFlatBg)) {
- bgcol = _bgColor;
- fgcol = _fontColor;
- }
-
- for (int i = 1; i < circlesDown; i++) {
- _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
- y += yradius;
- }
- for (int i = 1; i < circlesAcross; i++) {
- _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
- x += xradius;
- }
- for (int i = 1; i < circlesDown; i++) {
- _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
- y -= yradius;
- }
- for (int i = 1; i < circlesAcross; i++) {
- _filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
- x -= xradius;
- }
-
- uint16 smallCircleX;
- if (isbig) {
- _filledCircle((x - xradius) - 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
- smallCircleX = (x - xradius) - 20;
- } else {
- _filledCircle(x + circlesAcross * xradius + 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
- smallCircleX = x + circlesAcross * xradius + 20;
- }
-
- _filledCircle(smallCircleX, y + circlesDown * yradius + 25, 5, 4, dst, fgcol, bgcol);
-
- int16 yoff = (yradius * 27) / 32;
- dst->fillRect(Common::Rect(x, y - yoff,
- x + (circlesAcross - 1) * xradius + 1,
- y + (circlesDown - 1) * yradius + yoff + 1), bgcol);
- int16 xoff = (xradius * 27) / 32;
- dst->fillRect(Common::Rect(x - xoff, y,
- x + (circlesAcross - 1) * xradius + xoff + 1,
- y + (circlesDown - 1) * yradius + 1), bgcol);
-
- int16 textRectX = x - xradius / 2;
- int16 textRectY = y - yradius / 2;
- _textDrawRect = Common::Rect(textRectX, textRectY, textRectX + circlesAcross * xradius , textRectY + circlesDown * yradius);
- } else if (stage == kDlgDrawFindSelectionPointXY) {
- drawFindSelectionXY();
- } else if (stage == kDlgDrawFindSelectionTxtOffset) {
- drawFindSelectionTxtOffset();
- } else {
- drawForeground(dst, _fontColor, _str);
- }
-}
-
-// ellipse
-void Dialog::drawType4(Graphics::Surface *dst, DialogDrawStage stage) {
- if (!_state)
- return;
-
- int x = _rect.x;
- int y = _rect.y;
- int w = _rect.width;
- int h = _rect.height;
-
- int midy = (h - 1) / 2;
- byte fillcolor;
- byte fillbgcolor;
- if (!hasFlag(kDlgFlagFlatBg)) {
- fillcolor = 0;
- fillbgcolor = 15;
- } else {
- fillcolor = _fontColor;
- fillbgcolor = _bgColor;
- }
-
- if (stage == kDlgDrawStageBackground) {
- //int radius = (midy * 5) / 4;
-
- // This is not exactly the same as the original - might need some work to get pixel-perfect
- Common::Rect drawRect(x, y, x + w, y + h);
- Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, _drawPixel, dst);
- Graphics::drawRoundRect(drawRect, midy, fillcolor, false, _drawPixel, dst);
- } else if (stage == kDlgDrawFindSelectionPointXY) {
- drawFindSelectionXY();
- } else if (stage == kDlgDrawFindSelectionTxtOffset) {
- drawFindSelectionTxtOffset();
- } else {
- _textDrawRect = Common::Rect(x + midy, y + 1, x + w - midy, y + h - 1);
- drawForeground(dst, fillcolor, _str);
- }
-}
-
-void Dialog::drawFindSelectionXY() {
- if (!_state)
- return;
-
- const Font *font = getDlgTextFont();
-
- // Find the appropriate _lastMouseX/lastMouseY value given the last _strMouseLoc.
-
- int x = _state->_loc.x;
- _state->_lastMouseX = x;
- int y = _state->_loc.y + 1;
- _state->_lastMouseY = y;
- _state->_charWidth = font->getMaxCharWidth();
- _state->_charHeight = font->getFontHeight();
- if (_state->_strMouseLoc) {
- Common::Array<Common::String> lines;
- int maxWidth = font->wordWrapText(_str, _state->_loc.width, lines);
-
- if (hasFlag(kDlgFlagLeftJust)) {
- x = x + (_state->_loc.width - maxWidth - 1) / 2;
- _state->_lastMouseX = x;
- y = y + (_state->_loc.height - (lines.size() * _state->_charHeight) - 1) / 2;
- _state->_lastMouseY = y;
- }
-
- if (_state->_strMouseLoc >= (int)_str.size())
- _state->_strMouseLoc = _str.size() - 1;
-
- // Find the location of the mouse loc in the wrapped string.
- int totalchars = 0;
- for (uint lineno = 0; lineno < lines.size(); lineno++) {
- // +1 char for the space or CR that caused the wrap.
- int nexttotalchars = totalchars + lines[lineno].size() + 1;
- if (nexttotalchars > _state->_strMouseLoc)
- break;
- totalchars = nexttotalchars;
- y += _state->_charHeight;
- }
-
- // now get width of the remaining string to the mouse str offset
- x += font->getStringWidth(_str.substr(totalchars, _state->_strMouseLoc - totalchars));
-
- // TODO: does this make sense?
- if (_state->_loc.x + _state->_loc.width < (x + font->getCharWidth(_state->_strMouseLoc))) {
- if (_str[_state->_strMouseLoc] < '!') {
- _state->_charHeight = 0;
- _state->_charWidth = 0;
- _state->_lastMouseY = 0;
- _state->_lastMouseX = 0;
- return;
- }
- x = _state->_loc.x;
- y += _state->_charHeight;
- }
-
- _state->_lastMouseX = x;
- _state->_lastMouseY = y;
- _state->_charWidth = font->getCharWidth(_state->_strMouseLoc);
- }
-}
-
-void Dialog::drawFindSelectionTxtOffset() {
- if (!_state)
- return;
-
- // Find the appropriate _strMouseLoc value given the last x/y position.
-
- const Font *font = getDlgTextFont();
- int lastMouseX = _state->_lastMouseX;
- int lastMouseY = _state->_lastMouseY;
- int lineHeight = font->getFontHeight();
- int dlgx = _state->_loc.x;
- int dlgy = _state->_loc.y;
-
- Common::Array<Common::String> lines;
- int maxWidth = font->wordWrapText(_str, dlgy, lines);
-
- if (hasFlag(kDlgFlagLeftJust)) {
- dlgx += (_state->_loc.width - maxWidth - 1) / 2;
- dlgy += (_state->_loc.height - (lines.size() * lineHeight) - 1) / 2;
- }
-
- uint lineno;
- uint totalchars = 0;
- for (lineno = 0; lineno < lines.size() && dlgy + lineHeight < lastMouseY; lineno++) {
- totalchars += lines[lineno].size() + 1;
- dlgy = dlgy + lineHeight;
- }
-
- int startx = dlgx;
- while (lineno < lines.size()) {
- const Common::String &line = lines[lineno];
- for (uint charno = 0; charno < line.size(); charno++) {
- int charwidth = font->getCharWidth(line[charno]);
- if (lastMouseX <= dlgx + charwidth) {
- _state->_strMouseLoc = totalchars + charno;
- return;
- }
- dlgx += charwidth;
- }
- dlgx = startx;
- totalchars += line.size() + 1;
- }
-
- _state->_strMouseLoc = _str.size();
- return;
-}
-
-void Dialog::drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
- // TODO: some more text calcuations happen here.
- // This is where we actually draw the text.
- // For now do the simplest wrapping, no highlighting.
- Common::StringArray lines;
- const Font *font = getDlgTextFont();
- const int h = font->getFontHeight();
- font->wordWrapText(txt, _textDrawRect.width(), lines);
-
- int ystart = _textDrawRect.top + (_textDrawRect.height() - lines.size() * h) / 2;
-
- int x = _textDrawRect.left;
- if (hasFlag(kDlgFlagLeftJust)) {
- // each line left-aligned, but overall block is still centered
- int maxlen = -1;
- for (const auto &line : lines)
- maxlen = MAX(maxlen, font->getStringWidth(line));
-
- x += (_textDrawRect.width() - maxlen) / 2;
-
- for (uint i = 0; i < lines.size(); i++)
- font->drawString(dst, lines[i], x, ystart + i * h, maxlen, fontcol, Graphics::kTextAlignLeft);
- } else {
- // center each line
- for (uint i = 0; i < lines.size(); i++)
- font->drawString(dst, lines[i], x, ystart + i * h, _textDrawRect.width(), fontcol, Graphics::kTextAlignCenter);
- }
-
- if (_state->_selectedAction) {
- warning("TODO: Draw highlight on selected action.");
- }
-}
-
-void Dialog::setFlag(DialogFlags flg) {
- _flags = static_cast<DialogFlags>(_flags | flg);
-}
-
-void Dialog::clearFlag(DialogFlags flg) {
- _flags = static_cast<DialogFlags>(_flags & ~flg);
-}
-
-void Dialog::flipFlag(DialogFlags flg) {
- _flags = static_cast<DialogFlags>(_flags ^ flg);
-}
-
-bool Dialog::hasFlag(DialogFlags flg) const {
- return _flags & flg;
-}
-
-void Dialog::updateSelectedAction(int delta) {
- if (!_lastDialogSelectionChangedFor)
- _lastDialogSelectionChangedFor = this;
- else
- _lastSelectedDialogItemNum = 0;
-
- if (!_state)
- return;
-
- if (_state->_selectedAction) {
- for (uint i = 0; i < _action.size(); i++) {
- if (_state->_selectedAction == &_action[i]) {
- _lastSelectedDialogItemNum = i;
- break;
- }
- }
- }
- _lastSelectedDialogItemNum += delta;
- if (!_action.empty()) {
- while (_lastSelectedDialogItemNum < 0)
- _lastSelectedDialogItemNum += _action.size();
- _lastSelectedDialogItemNum = _lastSelectedDialogItemNum % _action.size();
- }
- _lastDialogSelectionChangedFor = this;
-
- int mouseX = _state->_loc.x + _state->_loc.width;
- int mouseY = _state->_loc.y + _state->_loc.height - 2;
- if (_action.size() > 1) {
- _state->_strMouseLoc = _action[_lastSelectedDialogItemNum].strStart;
- draw(nullptr, kDlgDrawFindSelectionPointXY);
- // Move the mouse over the selected item
- mouseY = _state->_lastMouseY + _state->_charHeight / 2;
- }
-
- if (_action.size() > 1 || !delta) {
- g_system->warpMouse(mouseX, mouseY);
- }
-}
-
-struct DialogAction *Dialog::pickAction(bool isClosing) {
- struct DialogAction *retval = nullptr;
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- if (/* some game flags?? && */isClosing) {
- return &_action[engine->getRandom().getRandomNumber(_action.size() - 1)];
- }
- assert(_state);
- const Common::Point lastMouse = engine->getLastMouse();
- if (_state->_loc.x <= lastMouse.x &&
- _state->_loc.x + _state->_loc.width <= lastMouse.x &&
- _state->_loc.y <= lastMouse.y &&
- _state->_loc.y + _state->_loc.height <= lastMouse.y) {
- _state->_lastMouseX = lastMouse.x;
- _state->_lastMouseY = lastMouse.y;
- draw(nullptr, kDlgDrawFindSelectionTxtOffset);
-
- char underMouse = _str[_state->_strMouseLoc];
- for (auto &action : _action) {
- if ((action.strStart <= _state->_strMouseLoc && _state->_strMouseLoc <= action.strEnd) ||
- (_state->_strMouseLoc == action.strEnd + 1 && underMouse == '\r' && _str[action.strEnd] != '\r')) {
- return &action;
- }
- }
- }
- return retval;
-}
-
-
-Common::String Dialog::dump(const Common::String &indent) const {
- Common::String str = Common::String::format(
- "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
- indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _selectionBgCol, _selectonFontCol, _fontSize,
- _flags, _frameType, _time, _nextDialogNum, _field18_0x28);
- str += indent + "state=" + (_state ? _state->dump("") : "null");
- str += "\n";
- str += _dumpStructList(indent, "actions", _action);
- str += "\n";
- str += indent + " str='" + _str + "'>";
- return str;
-}
-
-Common::String DialogState::dump(const Common::String &indent) const {
- return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>",
- indent.c_str(), _hideTime, _loc.dump("").c_str(), _lastMouseX, _lastMouseY, _charWidth,
- _charHeight, _strMouseLoc, _selectedAction);
-}
-
-Common::String DialogAction::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
- str += _dumpStructList(indent, "opList", sceneOpList);
- if (!sceneOpList.empty()) {
- str += "\n";
- str += indent;
- }
- str += ">";
- return str;
-}
-
Common::String PerSceneGlobal::dump(const Common::String &indent) const {
return Common::String::format("%sPerSceneGlobal<num %d scene %d val %d>", indent.c_str(), _num, _sceneNo, _val);
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 0eb8a3c3b37..56369770b9d 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -26,24 +26,15 @@
#include "common/stream.h"
#include "common/array.h"
+#include "dgds/dialog.h"
+#include "dgds/dgds_rect.h"
+
namespace Dgds {
class ResourceManager;
class Decompressor;
class Font;
-// TODO: Use Common::Rect instead.
-class Rect {
-public:
- Rect(): x(0), y(0), width(0), height(0) {}
- int x;
- int y;
- int width;
- int height;
-
- Common::String dump(const Common::String &indent) const;
-};
-
enum SceneCondition {
kSceneCondNone = 0,
kSceneCondLessThan = 1,
@@ -65,7 +56,7 @@ struct SceneConditions {
};
struct HotArea {
- struct Rect rect;
+ DgdsRect rect;
uint16 _num; //
uint16 _cursorNum;
Common::Array<struct SceneConditions> enableConditions;
@@ -147,101 +138,6 @@ struct SceneStruct4 {
Common::String dump(const Common::String &indent) const;
};
-enum DialogFlags {
- kDlgFlagNone = 0,
- kDlgFlagFlatBg = 1,
- kDlgFlagLeftJust = 2,
- kDlgFlagLo4 = 4,
- kDlgFlagLo8 = 8,
- kDlgFlagLo80 = 0x80,
- kDlgFlagHiFinished = 0x10000,
- kDlgFlagHi2 = 0x20000,
- kDlgFlagHi4 = 0x40000,
- kDlgFlagHi8 = 0x80000,
- kDlgFlagHi10 = 0x100000,
- kDlgFlagHi20 = 0x200000,
- kDlgFlagHi40 = 0x400000,
- kDlgFlagVisible = 0x800000,
- kDlgFlagOpening = 0x1000000,
-};
-
-enum DialogFrameType {
- kDlgFramePlain = 1,
- kDlgFrameBorder = 2,
- kDlgFrameThought = 3,
- kDlgFrameRounded = 4
-};
-
-enum DialogDrawStage {
- kDlgDrawStageForeground = 0,
- kDlgDrawStageBackground = 1,
- kDlgDrawFindSelectionPointXY = 2,
- kDlgDrawFindSelectionTxtOffset = 3,
-};
-
-class DialogState {
-public:
- DialogState() : _hideTime(0), _lastMouseX(0), _lastMouseY(0), _charWidth(0),
- _charHeight(0), _strMouseLoc(0), _selectedAction(nullptr) {}
- uint _hideTime;
- struct Rect _loc;
- int _lastMouseX;
- int _lastMouseY;
- uint16 _charWidth;
- uint16 _charHeight;
- int _strMouseLoc;
- struct DialogAction *_selectedAction;
-
- Common::String dump(const Common::String &indent) const;
-};
-
-class Dialog {
-public:
- Dialog();
- uint16 _num;
- Rect _rect;
- uint16 _bgColor;
- uint16 _fontColor;
- uint16 _selectionBgCol;
- uint16 _selectonFontCol;
- uint16 _fontSize;
- DialogFlags _flags;
- DialogFrameType _frameType;
- uint16 _time;
- uint16 _nextDialogNum;
- Common::Array<struct DialogAction> _action;
- Common::String _str;
- uint16 _field18_0x28;
-
- Common::SharedPtr<struct DialogState> _state;
-
- void draw(Graphics::Surface *dst, DialogDrawStage stage);
- void setFlag(DialogFlags flg);
- void clearFlag(DialogFlags flg);
- void flipFlag(DialogFlags flg);
- bool hasFlag(DialogFlags flg) const;
- void updateSelectedAction(int delta);
- struct DialogAction *pickAction(bool isClosing);
- Common::String dump(const Common::String &indent) const;
-
-private:
- Common::Rect _textDrawRect; // Calculated while drawing the background.
-
- void drawType1(Graphics::Surface *dst, DialogDrawStage stage);
- void drawType2(Graphics::Surface *dst, DialogDrawStage stage);
- void drawType3(Graphics::Surface *dst, DialogDrawStage stage);
- void drawType4(Graphics::Surface *dst, DialogDrawStage stage);
-
- void drawFindSelectionXY();
- void drawFindSelectionTxtOffset();
- void drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt);
-
- const Font *getDlgTextFont() const;
-
- static int _lastSelectedDialogItemNum;
- static Dialog *_lastDialogSelectionChangedFor;
-};
-
struct SceneTrigger {
uint16 _num;
bool _enabled;
@@ -251,17 +147,6 @@ struct SceneTrigger {
Common::String dump(const Common::String &indent) const;
};
-struct DialogAction {
- // The game initializes str offsets to pointers, but let's be a bit nicer.
- uint16 strStart; /// The start of the clickable text for this action
- uint16 strEnd; /// End of clickable text for this action
- byte unk[8]; /* Not initialized in loader */
- Common::Array<struct SceneOp> sceneOpList; /// ops to run when this is selected
- uint val; /* First entry initialized to 1 in loader */
-
- Common::String dump(const Common::String &indent) const;
-};
-
/* A global value that only applies on a per-SDS-scene,
but stays with the GDS data as it sticks around during
the game */
Commit: af5fbb6f320f8e27e3c8cfec3261dc6985d150fb
https://github.com/scummvm/scummvm/commit/af5fbb6f320f8e27e3c8cfec3261dc6985d150fb
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More work on dialogs and scenes
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index bf6ee8064ff..fad0f63d811 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -156,10 +156,7 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_gdsScene->runChangeSceneOps();
- if (!_icons.empty()) {
- CursorMan.popAllCursors();
- CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
- }
+ setMouseCursor(0);
_scene->load(sceneFile, _resource, _decompressor);
@@ -178,6 +175,16 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
return true;
}
+void DgdsEngine::setMouseCursor(uint num) {
+ if (num >= _icons.size())
+ return;
+
+ // TODO: Get mouse cursors from _gdsScene for hotspot info??
+ CursorMan.popAllCursors();
+ CursorMan.pushCursor(_icons[num]->getSurface(), 0, 0, 0, 0);
+ CursorMan.showMouse(true);
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -226,7 +233,7 @@ Common::Error DgdsEngine::run() {
_gdsScene->runStartGameOps();
// To skip credits for testing
- changeScene(55, true);
+ changeScene(7, true);
} else if (getGameId() == GID_CHINA) {
_gameGlobals = new Globals();
@@ -258,17 +265,17 @@ Common::Error DgdsEngine::run() {
}
loadIcons();
- if (!_icons.empty())
- CursorMan.pushCursor(_icons[0]->getSurface(), 0, 0, 0, 0);
+ setMouseCursor(0);
//getDebugger()->attach();
- //debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
+ debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
//debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
bool triggerMenu = false;
- bool mouseEvent = false;
+ bool mouseClicked = false;
+ bool mouseMoved = false;
while (!shouldQuit()) {
while (eventMan->pollEvent(ev)) {
@@ -287,7 +294,8 @@ Common::Error DgdsEngine::run() {
break;
}
} else if (ev.type == Common::EVENT_LBUTTONUP) {
- mouseEvent = true;
+ mouseClicked = true;
+ _lastMouse = ev.mouse;
} else if (ev.type == Common::EVENT_MOUSEMOVE) {
_lastMouse = ev.mouse;
}
@@ -307,12 +315,11 @@ Common::Error DgdsEngine::run() {
triggerMenu = false;
}
- if (mouseEvent) {
- _menu->handleMenu(vcrRequestData, ev.mouse);
- mouseEvent = false;
- }
-
if (_menu->menuShown()) {
+ if (mouseClicked) {
+ _menu->handleMenu(vcrRequestData, _lastMouse);
+ mouseClicked = false;
+ }
g_system->updateScreen();
g_system->delayMillis(10);
continue;
@@ -328,6 +335,14 @@ Common::Error DgdsEngine::run() {
moveToNext = false;
}
+ if (mouseMoved) {
+ _scene->mouseMoved(_lastMouse);
+ mouseMoved = false;
+ } else if (mouseClicked) {
+ _scene->mouseClicked(_lastMouse);
+ mouseClicked = false;
+ }
+
// Note: Hard-coded logic for DRAGON, check others
//if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
// _gdsScene->runPostTickOps();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 96823da8b0e..e9f6c56178f 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -129,6 +129,7 @@ public:
bool changeScene(int sceneNum, bool runChangeOps);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
+ void setMouseCursor(uint num);
DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
int getTextSpeed() const { return _textSpeed; }
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 284ad8fd8bb..165960042d6 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -450,6 +450,16 @@ bool Dialog::hasFlag(DialogFlags flg) const {
return _flags & flg;
}
+void Dialog::clear() {
+ clearFlag(kDlgFlagHiFinished);
+ clearFlag(kDlgFlagRedrawSelectedActionChanged);
+ clearFlag(kDlgFlagHi10);
+ clearFlag(kDlgFlagHi20);
+ clearFlag(kDlgFlagHi40);
+ clearFlag(kDlgFlagVisible);
+ _state.reset();
+}
+
void Dialog::updateSelectedAction(int delta) {
if (!_lastDialogSelectionChangedFor)
_lastDialogSelectionChangedFor = this;
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 2e304379b80..5dcdeeaa42d 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -46,7 +46,7 @@ enum DialogFlags {
kDlgFlagHiFinished = 0x10000,
kDlgFlagHi2 = 0x20000,
kDlgFlagHi4 = 0x40000,
- kDlgFlagHi8 = 0x80000,
+ kDlgFlagRedrawSelectedActionChanged = 0x80000,
kDlgFlagHi10 = 0x100000,
kDlgFlagHi20 = 0x200000,
kDlgFlagHi40 = 0x400000,
@@ -123,6 +123,7 @@ public:
void updateSelectedAction(int delta);
struct DialogAction *pickAction(bool isClosing);
Common::String dump(const Common::String &indent) const;
+ void clear();
private:
Common::Rect _textDrawRect; // Calculated while drawing the background.
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index f02d4ee223e..1bdefe2195c 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -444,7 +444,7 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
bool Scene::runOps(const Common::Array<SceneOp> &ops) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
- debug("Exec %s", op.dump("").c_str());
+ //debug("Exec %s", op.dump("").c_str());
switch(op._opCode) {
case kSceneOpChangeScene:
if (engine->changeScene(op._args[0], true))
@@ -556,6 +556,9 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
}
+bool SDSScene::_dlgWithFlagLo8IsClosing = false;;
+DialogFlags SDSScene::_sceneDialogFlags = kDlgFlagNone;
+
SDSScene::SDSScene() : _num(-1) {
}
@@ -629,6 +632,7 @@ void SDSScene::unload() {
_struct4List2.clear();
_dialogs.clear();
_triggers.clear();
+ _sceneDialogFlags = kDlgFlagNone;
}
@@ -672,17 +676,20 @@ void SDSScene::checkTriggers() {
void SDSScene::showDialog(uint16 num) {
for (auto &dialog : _dialogs) {
if (dialog._num == num) {
- dialog.clearFlag(kDlgFlagHi2);
- dialog.clearFlag(kDlgFlagHi8);
+ dialog.clearFlag(kDlgFlagHiFinished);
+ dialog.clearFlag(kDlgFlagRedrawSelectedActionChanged);
dialog.clearFlag(kDlgFlagHi10);
- dialog.clearFlag(kDlgFlagHi20);
+ //dialog.clearFlag(kDlgFlagHi20);
dialog.clearFlag(kDlgFlagHi40);
dialog.setFlag(kDlgFlagHi20);
dialog.setFlag(kDlgFlagVisible);
dialog.setFlag(kDlgFlagOpening);
// hide time gets set the first time it's drawn.
- if (dialog.hasFlag(kDlgFlagLo8)) {
- // do something with some global dlg flags here.
+ if (_dlgWithFlagLo8IsClosing && dialog.hasFlag(kDlgFlagLo8)) {
+ _sceneDialogFlags = static_cast<DialogFlags>(_sceneDialogFlags | kDlgFlagLo8 | kDlgFlagVisible);
+ }
+ if (_dlgWithFlagLo8IsClosing) {
+ // TODO: call some function (FUN_1f1a_4205) here.
}
}
}
@@ -692,7 +699,9 @@ bool SDSScene::checkDialogActive() {
uint32 timeNow = g_engine->getTotalPlayTime();
bool retval = false;
- bool someFlag = false; // ((g_gameStateFlag_41f6 | UINT_39e5_41f8) & 6) != 0); ??
+ _sceneDialogFlags = kDlgFlagNone;
+
+ bool someFlag = true; // ((g_gameStateFlag_41f6 | UINT_39e5_41f8) & 6) != 0); ??
for (auto &dlg : _dialogs) {
if (!dlg.hasFlag(kDlgFlagVisible))
@@ -710,23 +719,26 @@ bool SDSScene::checkDialogActive() {
if ((dlg._state->_hideTime == 0) && dlg._action.size() < 2)
no_options = true;
- if ((!finished && !no_options) || (dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40))) {
+ if ((!finished && !no_options) || dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40)) {
if (!finished && dlg._action.size() > 1 && !dlg.hasFlag(kDlgFlagHiFinished)) {
struct DialogAction *action = dlg.pickAction(false);
if (dlg._state->_selectedAction != action) {
dlg._state->_selectedAction = action;
dlg.clearFlag(kDlgFlagHi10);
- dlg.setFlag(kDlgFlagHi8);
+ dlg.setFlag(kDlgFlagRedrawSelectedActionChanged);
}
}
} else {
// this dialog is finished - call the ops and maybe show the next one
+ _dlgWithFlagLo8IsClosing = dlg.hasFlag(kDlgFlagLo8);
struct DialogAction *action = dlg.pickAction(true);
if (action || dlg._action.empty()) {
dlg.setFlag(kDlgFlagHiFinished);
if (action) {
- if (!runOps(action->sceneOpList))
+ if (!runOps(action->sceneOpList)) {
+ _dlgWithFlagLo8IsClosing = false;
return true;
+ }
}
}
if (dlg._nextDialogNum) {
@@ -734,45 +746,58 @@ bool SDSScene::checkDialogActive() {
showDialog(dlg._nextDialogNum);
}
}
+ if (dlg.hasFlag(kDlgFlagVisible)) {
+ _sceneDialogFlags = static_cast<DialogFlags>(_sceneDialogFlags | kDlgFlagVisible);
+ }
}
return retval;
}
-bool SDSScene::drawActiveDialogBgs(Graphics::Surface *dst) {
- bool retval = false;
- const DgdsEngine *engine = static_cast<const DgdsEngine *>(g_engine);
+void SDSScene::drawActiveDialogBgs(Graphics::Surface *dst) {
for (auto &dlg : _dialogs) {
if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagOpening)) {
assert(dlg._state);
- if (dlg._state->_hideTime == 0 && dlg._time > 0) {
- dlg._state->_hideTime = g_engine->getTotalPlayTime() +
- dlg._time * (9 - engine->getTextSpeed());
- }
dlg.draw(dst, kDlgDrawStageBackground);
dlg.clearFlag(kDlgFlagHi20);
dlg.setFlag(kDlgFlagHi40);
- retval = true;
}
}
- return retval;
+}
+
+bool SDSScene::checkForClearedDialogs() {
+ bool result = false;
+ bool have8 = false;
+ for (auto &dlg : _dialogs) {
+ if (!dlg.hasFlag(kDlgFlagHiFinished) && dlg.hasFlag(kDlgFlagLo8)) {
+ have8 = true;
+ } else {
+ dlg.clear();
+ result = true;
+ }
+ }
+
+ if (!have8) {
+ _sceneDialogFlags = static_cast<DialogFlags>(_sceneDialogFlags & ~kDlgFlagLo8);
+ }
+ return result;
}
bool SDSScene::drawAndUpdateDialogs(Graphics::Surface *dst) {
bool retval = false;
const DgdsEngine *engine = static_cast<const DgdsEngine *>(g_engine);
for (auto &dlg : _dialogs) {
- if (dlg.hasFlag(kDlgFlagLo80) && !dlg.hasFlag(kDlgFlagLo4) &&
+ if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagLo4) &&
!dlg.hasFlag(kDlgFlagHi20) && !dlg.hasFlag(kDlgFlagHi40)) {
// TODO: do something with "transfer"s?
dlg.setFlag(kDlgFlagHi4);
}
if (!dlg.hasFlag(kDlgFlagVisible) || (!dlg.hasFlag(kDlgFlagLo4) && !dlg.hasFlag(kDlgFlagHi4) && !dlg.hasFlag(kDlgFlagHi20) && !dlg.hasFlag(kDlgFlagHi40))) {
- if (dlg.hasFlag(kDlgFlagHi8) || dlg.hasFlag(kDlgFlagHi10)) {
+ if (dlg.hasFlag(kDlgFlagRedrawSelectedActionChanged) || dlg.hasFlag(kDlgFlagHi10)) {
dlg.draw(dst, kDlgDrawStageForeground);
- if (!dlg.hasFlag(kDlgFlagHi8)) {
+ if (!dlg.hasFlag(kDlgFlagRedrawSelectedActionChanged)) {
dlg.clearFlag(kDlgFlagHi10);
} else {
- dlg.flipFlag(kDlgFlagHi8);
+ dlg.flipFlag(kDlgFlagRedrawSelectedActionChanged);
dlg.flipFlag(kDlgFlagHi10);
}
}
@@ -815,6 +840,9 @@ bool SDSScene::drawAndUpdateDialogs(Graphics::Surface *dst) {
// warning("SDSScene::drawActiveDrawAndUpdateDialogs: Do something with transfers?");
dlg.setFlag(kDlgFlagHi4);
}
+ if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagOpening)) {
+ _sceneDialogFlags = static_cast<DialogFlags>(_sceneDialogFlags | kDlgFlagLo8 | kDlgFlagVisible);
+ }
}
return retval;
}
@@ -824,6 +852,32 @@ void SDSScene::globalOps(const Common::Array<uint16> &args) {
static_cast<DgdsEngine *>(g_engine)->getGDSScene()->globalOps(args);
}
+void SDSScene::mouseMoved(const Common::Point &pt) {
+ HotArea *area = findAreaUnderMouse(pt);
+ if (!area)
+ return;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->setMouseCursor(area->_cursorNum);
+}
+
+void SDSScene::mouseClicked(const Common::Point &pt) {
+ HotArea *area = findAreaUnderMouse(pt);
+ if (!area)
+ return;
+ runOps(area->onClickOps);
+}
+
+HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
+ for (auto &area : _hotAreaList) {
+ if (checkConditions(area.enableConditions) &&
+ area.rect.x < pt.x && (area.rect.x + area.rect.height) > pt.x
+ && area.rect.y < pt.y && (area.rect.y + area.rect.height) > pt.y) {
+ return &area;
+ }
+ }
+ return nullptr;
+}
+
GDSScene::GDSScene() {
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 56369770b9d..53796c932b2 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -124,6 +124,7 @@ struct GameItem : public HotArea {
struct MouseCursor {
uint16 _hotX;
uint16 _hotY;
+ uint16 _iconNum;
// pointer to cursor image
//Common::SharedPtr<Image> _img;
@@ -178,6 +179,9 @@ public:
void runPreTickOps() { runOps(_preTickOps); }
void runPostTickOps() { runOps(_postTickOps); }
+ void mouseMoved(const Common::Point pt);
+ void mouseClicked(const Common::Point pt);
+
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
bool readHotArea(Common::SeekableReadStream *s, HotArea &dst) const;
@@ -260,12 +264,17 @@ public:
Common::String dump(const Common::String &indent) const;
bool checkDialogActive();
- bool drawActiveDialogBgs(Graphics::Surface *dst);
+ void drawActiveDialogBgs(Graphics::Surface *dst);
bool drawAndUpdateDialogs(Graphics::Surface *dst);
+ bool checkForClearedDialogs();
void globalOps(const Common::Array<uint16> &args) override;
+ void mouseMoved(const Common::Point &pt);
+ void mouseClicked(const Common::Point &pt);
+
private:
+ HotArea *findAreaUnderMouse(const Common::Point &pt);
void enableTrigger(uint16 num) override;
void showDialog(uint16 num) override;
@@ -283,6 +292,9 @@ private:
Common::Array<class Dialog> _dialogs;
Common::Array<struct SceneTrigger> _triggers;
//uint _field15_0x33;
+
+ static bool _dlgWithFlagLo8IsClosing;
+ static DialogFlags _sceneDialogFlags;
};
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 73d763f2a31..8fb050c2b25 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -344,7 +344,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op
break;
// LOAD FONT: filename:str
- error("TODO: Implement opcode 0xf040 load font");
+ //const FontManager *mgr = _vm->getFontMan();
+ warning("TODO: Implement opcode 0xf040 load font %s", sval.c_str());
break;
}
case 0xf050: {
@@ -700,7 +701,8 @@ bool ADSInterpreter::skipSceneLogicBranch() {
return false;
} else if ((op & 0xff0f) == 0x1300) {
// a 0x13x0 logic op
- error("TODO: Implement nested ADS condition handling");
+ scr->seek(-2, SEEK_CUR);
+ result = handleOperation(op, scr);
} else {
scr->skip(numArgs(op) * 2);
}
Commit: 302331f071380e43edbdad2fdf78297ad5fbfdaa
https://github.com/scummvm/scummvm/commit/302331f071380e43edbdad2fdf78297ad5fbfdaa
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement some more ADS and TTM opcodes
Changed paths:
engines/dgds/image.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 2b91d10c21d..e044e24bb70 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -133,6 +133,12 @@ Image::~Image() {
void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
const char *dot;
DGDS_EX ex;
+
+ if (filename.empty()) {
+ warning("Image::drawScreen Tried to draw empty image");
+ return;
+ }
+
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("Couldn't get image resource %s", filename.c_str());
@@ -172,7 +178,7 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
int Image::frameCount(const Common::String &filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
- error("Couldn't get bitmap resource '%s'", filename.c_str());
+ error("frameCount: Couldn't get bitmap resource '%s'", filename.c_str());
int tileCount = -1;
DgdsChunkReader chunk(fileStream);
@@ -192,7 +198,7 @@ void Image::loadBitmap(const Common::String &filename, int number) {
uint16 *mtx;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
- error("Couldn't get bitmap resource '%s'", filename.c_str());
+ error("loadBitmap: Couldn't get bitmap resource '%s'", filename.c_str());
_bmpData.free();
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 8fb050c2b25..fbed8bcf579 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -23,6 +23,7 @@
#include "common/debug.h"
#include "common/rect.h"
#include "common/textconsole.h"
+#include "common/random.h"
#include "common/str.h"
#include "common/stream.h"
#include "common/system.h"
@@ -170,7 +171,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// SET BRUSH: id:int [-1:n]
seq._brushNum = ivals[0];
if (seq._brushNum != -1) {
- _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
+ // TODO: This is probably not the right place to load this
+ if (!env._scriptShapes[seq._currentBmpId].empty())
+ _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
}
break;
}
@@ -207,10 +210,21 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
_vm->_soundPlayer->playSFX(ivals[0]);
break;
+ case 0x1310: // STOP SFX i:int eg [107]
+ warning("TODO: Implement TTM 0x1310 stop SFX %d", ivals[0]);
+ // Implement this:
+ //_vm->_soundPlayer->stopSfxById(ivals[0])
+ break;
case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
seq._drawColFG = static_cast<byte>(ivals[0]);
seq._drawColBG = static_cast<byte>(ivals[1]);
break;
+ case 0x2020: { // SET RANDOM SLEEP: min,max: int (eg, 60,300)
+ uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
+ // TODO: do same time fix as for 0x1020
+ _vm->adsInterpreter()->setScriptDelay((int)(sleep * 8.33));
+ break;
+ }
case 0x4000:
// SET CLIP WINDOW x,y,w,h:int [0..320,0..200]
seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
@@ -270,9 +284,18 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
break;
}
- case 0x4210: // SAVE IMAGE REGION (getput area)
- warning("TODO: Implement TTM opcode 0x4210 save getput region");
+ case 0x4210: { // SAVE IMAGE REGION (getput area)
+ if (seq._currentGetPutId >= (int)env._getPutAreas.size()) {
+ env._getPutAreas.resize(seq._currentGetPutId + 1);
+ env._getPutSurfaces.resize(seq._currentGetPutId + 1);
+ }
+ Common::Rect rect = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ env._getPutAreas[seq._currentGetPutId] = rect;
+ Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_resData.format);
+ surf->blitFrom(_vm->_resData, rect, Common::Rect(0, 0, rect.width(), rect.height()));
+ env._getPutSurfaces[seq._currentGetPutId].reset(surf);
break;
+ }
case 0xa000: // DRAW PIXEL x,y:int
_vm->getTopBuffer().setPixel(ivals[0], ivals[1], seq._drawColFG);
break;
@@ -328,6 +351,17 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
else
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
break;
+ case 0xa600: { // DRAW GETPUT
+ int16 i = ivals[0];
+ if (i >= (int16)env._getPutAreas.size() || !env._getPutSurfaces[i]) {
+ warning("Trying to put getput region %d we never got", i);
+ break;
+ }
+ const Common::Rect &r = env._getPutAreas[i];
+ _vm->getTopBuffer().copyRectToSurface(*(env._getPutSurfaces[i]->surfacePtr()),
+ r.left, r.top, Common::Rect(0, 0, r.width(), r.height()));
+ break;
+ }
case 0xf010:
if (seq._executed) // this is a one-shot op
break;
@@ -382,14 +416,11 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x00C0: // FREE BACKGROUND (free getput item pointed to by _currentGetPutId)
case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
case 0x1070: // SELECT FONT i:int
- case 0x1310: // STOP SFX i:int eg [107]
case 0x2010: // SET FRAME
- case 0x2020: // SET TIMER
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa424: // DRAW EMPTY CIRCLE
case 0xa510: // DRAW SPRITE1
- case 0xa600: // CLEAR SCREEN
// From here on are not implemented in DRAGON
case 0xb000: // ? (0 args) - found in HoC intro
case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
@@ -401,7 +432,10 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xc060: // STOP_SAMPLE
default:
- warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
+ if (count < 15)
+ warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
+ else
+ warning("Unimplemented TTM opcode: 0x%04X (sval: %s)", op, sval.c_str());
break;
}
}
@@ -777,6 +811,62 @@ void ADSInterpreter::findEndOrInitOp() {
}
}
+uint ADSInterpreter::randomOpGetVal(uint16 code, Common::SeekableReadStream *scr) {
+ int skip;
+ if (code == 0x2000 || code == 0x2005)
+ skip = 6;
+ else if (code == 0x3020)
+ skip = 0;
+ else
+ skip = 4;
+
+ scr->skip(skip);
+ uint16 result = scr->readUint16LE();
+ scr->seek(-skip, SEEK_CUR);
+ return result;
+}
+
+void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr) {
+ uint16 max = 0;
+ int64 startpos = scr->pos();
+ // Collect the random proportions
+ code = scr->readUint16LE();
+ while (code != 0 && code != 0x30ff && scr->pos() < scr->size()) {
+ uint16 val = randomOpGetVal(code, scr);
+ max += val;
+ scr->skip(numArgs(code) * 2);
+ if (scr->pos() >= scr->size())
+ break;
+ code = scr->readUint16LE();
+ }
+ if (!max)
+ return;
+
+ int64 endpos = scr->pos();
+
+ int16 randval = _vm->getRandom().getRandomNumber(max - 1);
+ scr->seek(startpos, SEEK_SET);
+
+ // Now find the random bit to jump to
+ code = scr->readUint16LE();
+ do {
+ uint16 val = randomOpGetVal(code, scr);
+ randval -= val;
+ if (randval < 1) {
+ scr->seek(-2, SEEK_CUR);
+ break;
+ }
+ scr->skip(numArgs(code));
+ if (scr->pos() >= scr->size())
+ break;
+ code = scr->readUint16LE();
+ } while (code != 0 && scr->pos() < scr->size());
+ if (code)
+ handleOperation(code, scr);
+
+ scr->seek(endpos, SEEK_SET);
+}
+
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
@@ -924,8 +1014,53 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
break;
}
- case 0xffff: // END
- return false;
+ case 0x4000: { // MOVE SEQ TO FRONT
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ // This is O(N) but the N is small and it's not called often.
+ TTMSeq seq;
+ bool success = false;
+ for (uint i = 0; i < _adsData._ttmSeqs.size(); i++) {
+ if (_adsData._ttmSeqs[i]._enviro == enviro && _adsData._ttmSeqs[i]._seqNum == seqnum) {
+ seq = _adsData._ttmSeqs[i];
+ _adsData._ttmSeqs.remove_at(i);
+ success = true;
+ break;
+ }
+ }
+
+ if (success)
+ _adsData._ttmSeqs.insert_at(0, seq);
+ else
+ warning("ADS: 0x4000 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
+
+ break;
+ }
+
+ case 0x4010: { // MOVE SEQ TO BACK
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ // This is O(N) but the N is small and it's not called often.
+ TTMSeq seq;
+ bool success = false;
+ for (uint i = 0; i < _adsData._ttmSeqs.size(); i++) {
+ if (_adsData._ttmSeqs[i]._enviro == enviro && _adsData._ttmSeqs[i]._seqNum == seqnum) {
+ seq = _adsData._ttmSeqs[i];
+ _adsData._ttmSeqs.remove_at(i);
+ success = true;
+ break;
+ }
+ }
+
+ if (success)
+ _adsData._ttmSeqs.push_back(seq);
+ else
+ warning("ADS: 0x4010 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
+
+ break;
+ }
case 0xF010: {// FADE_OUT, 1 param
int16 segment = scr->readSint16LE();
@@ -941,6 +1076,16 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
return true;
}
+ case 0xffff: // END
+ return false;
+
+ case 0x3010: // RANDOM_START, 0 params
+ case 0x3020: // RANDOM_??, 1 param
+ case 0x30FF: // RANDOM_END, 0 params
+ handleRandomOp(code, scr);
+ break;
+
+
//// unknown / to-be-implemented
case 0x1010: // unknown, 2 params
case 0x1020: // unknown, 2 params
@@ -952,11 +1097,6 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1080: // if current seq countdown, 1 param
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
- case 0x3010: // RANDOM_START, 0 params
- case 0x3020: // RANDOM_??, 1 param
- case 0x30FF: // RANDOM_END, 0 params
- case 0x4000: // MOVE TO FRONT?, 3 params
- case 0x4010: // MOVE TO BACK??, 3 params
case 0xF200: // RUN_SCRIPT, 1 param
case 0xFF10:
case 0xFFF0: // END_IF, 0 params
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index b2cc3d6f289..62f20722beb 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -50,6 +50,8 @@ public:
uint16 _totalFrames;
Common::Array<int> _frameOffsets;
Common::String _scriptShapes[6];
+ Common::Array<Common::Rect> _getPutAreas;
+ Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _getPutSurfaces;
int _scriptPals[6];
};
@@ -63,6 +65,7 @@ enum TTMRunType {
};
+// Note: this object needs to be safely copy-able - ADS opcodes 0x4000 and 0x4010 require it.
struct TTMSeq {
TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _lastFrame(0), _timeCut(0) {
// Other members are initialized in the reset function.
@@ -164,6 +167,8 @@ public:
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
+ void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
+ uint randomOpGetVal(uint16 code, Common::SeekableReadStream *scr);
bool playScene();
bool skipToEndIf();
bool skipSceneLogicBranch();
Commit: 734c67ee8cfa96572bb8b6ed5064049dcbcff0df
https://github.com/scummvm/scummvm/commit/734c67ee8cfa96572bb8b6ed5064049dcbcff0df
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix build on some platforms
Changed paths:
engines/dgds/dialog.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 5dcdeeaa42d..7f515bf23fd 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -29,7 +29,7 @@
#include "dgds/dgds_rect.h"
namespace Graphics {
-class Surface;
+struct Surface;
}
namespace Dgds {
@@ -113,7 +113,7 @@ public:
Common::String _str;
uint16 _field18_0x28;
- Common::SharedPtr<struct DialogState> _state;
+ Common::SharedPtr<DialogState> _state;
void draw(Graphics::Surface *dst, DialogDrawStage stage);
void setFlag(DialogFlags flg);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index fbed8bcf579..436ba0adf4a 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -1017,7 +1017,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x4000: { // MOVE SEQ TO FRONT
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- uint16 unk = scr->readUint16LE();
+ /*uint16 unk = */scr->readUint16LE();
// This is O(N) but the N is small and it's not called often.
TTMSeq seq;
bool success = false;
@@ -1041,7 +1041,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x4010: { // MOVE SEQ TO BACK
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
- uint16 unk = scr->readUint16LE();
+ /*uint16 unk = */scr->readUint16LE();
// This is O(N) but the N is small and it's not called often.
TTMSeq seq;
bool success = false;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 62f20722beb..85101283886 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -24,6 +24,8 @@
#define DGDS_SCRIPTS_H
#include "common/rect.h"
+#include "graphics/managed_surface.h"
+
#include "dgds/parser.h"
#include "dgds/scene.h"
Commit: f0a45e2bd25a17cdaa7847d61ca10fd697ec0626
https://github.com/scummvm/scummvm/commit/f0a45e2bd25a17cdaa7847d61ca10fd697ec0626
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement even more TT3 and ADS opcodes
Changed paths:
engines/dgds/dgds_rect.h
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds_rect.h b/engines/dgds/dgds_rect.h
index 6d04b0a4900..6ad53b0f6bd 100644
--- a/engines/dgds/dgds_rect.h
+++ b/engines/dgds/dgds_rect.h
@@ -23,17 +23,23 @@
#define DGDS_DGDS_RECT_H
#include "common/str.h"
+#include "common/rect.h"
namespace Dgds {
+// TODO: This should be replaced by Common::Rect, but during dev it's easier
+// to have one that exactly matches semantics of the origingal game's struct.
class DgdsRect {
public:
DgdsRect(): x(0), y(0), width(0), height(0) {}
+ DgdsRect(int x_, int y_, int width_, int height_): x(x_), y(y_), width(width_), height(height_) {}
int x;
int y;
int width;
int height;
+ Common::Rect toCommonRect() const { return Common::Rect(x, y, x + width, y + height); }
+
Common::String dump(const Common::String &indent) const;
};
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 165960042d6..5213039d1dd 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -111,7 +111,7 @@ void Dialog::drawType1(Graphics::Surface *dst, DialogDrawStage stage) {
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
drawFindSelectionTxtOffset();
} else {
- _textDrawRect = Common::Rect(x + 3, y + 3, x + w - 3, y + h - 3);
+ _state->_loc = DgdsRect(x + 3, y + 3, w - 3, h - 3);
drawForeground(dst, _bgColor, _str);
}
}
@@ -132,24 +132,28 @@ void Dialog::drawType2(Graphics::Surface *dst, DialogDrawStage stage) {
}
if (stage == kDlgDrawStageBackground) {
- _textDrawRect = Common::Rect (_rect.x + 6, _rect.y + 6, _rect.x + _rect.width - 6, _rect.y + _rect.height - 6);
+ _state->_loc = DgdsRect(_rect.x + 6, _rect.y + 6, _rect.width - 6, _rect.height - 6);
Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
if (!title.empty()) {
// TODO: Maybe should measure the font?
- _textDrawRect.top += 10;
+ _state->_loc.y += 10;
RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
}
- if (hasFlag(kDlgFlagFlatBg))
- dst->fillRect(_textDrawRect, 0);
- else
- RequestData::fillBackground(dst, _textDrawRect.left, _textDrawRect.top, _textDrawRect.width(), _textDrawRect.height(), 6);
- RequestData::drawCorners(dst, 19, _textDrawRect.left - 2, _textDrawRect.top - 2, _textDrawRect.width() + 4, _textDrawRect.height() + 4);
+ if (hasFlag(kDlgFlagFlatBg)) {
+ Common::Rect fr = _state->_loc.toCommonRect();
+ dst->fillRect(fr, 0);
+ } else {
+ RequestData::fillBackground(dst, _state->_loc.x, _state->_loc.y, _state->_loc.width, _state->_loc.height, 6);
+ }
+
+ RequestData::drawCorners(dst, 19, _state->_loc.x - 2, _state->_loc.y - 2,
+ _state->_loc.width + 4, _state->_loc.height + 4);
- _textDrawRect.left += 8;
- _textDrawRect.right -= 8;
+ _state->_loc.x += 8;
+ _state->_loc.y -= 8;
} else if (stage == kDlgDrawFindSelectionPointXY) {
drawFindSelectionXY();
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
@@ -245,7 +249,8 @@ void Dialog::drawType3(Graphics::Surface *dst, DialogDrawStage stage) {
int16 textRectX = x - xradius / 2;
int16 textRectY = y - yradius / 2;
- _textDrawRect = Common::Rect(textRectX, textRectY, textRectX + circlesAcross * xradius , textRectY + circlesDown * yradius);
+ assert(_state);
+ _state->_loc = DgdsRect(textRectX, textRectY, circlesAcross * xradius , circlesDown * yradius);
} else if (stage == kDlgDrawFindSelectionPointXY) {
drawFindSelectionXY();
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
@@ -288,7 +293,8 @@ void Dialog::drawType4(Graphics::Surface *dst, DialogDrawStage stage) {
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
drawFindSelectionTxtOffset();
} else {
- _textDrawRect = Common::Rect(x + midy, y + 1, x + w - midy, y + h - 1);
+ assert(_state);
+ _state->_loc = DgdsRect(x + midy, y + 1, w - midy, h - 1);
drawForeground(dst, fillcolor, _str);
}
}
@@ -395,6 +401,7 @@ void Dialog::drawFindSelectionTxtOffset() {
}
dlgx = startx;
totalchars += line.size() + 1;
+ lineno++;
}
_state->_strMouseLoc = _str.size();
@@ -405,28 +412,30 @@ void Dialog::drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common
// TODO: some more text calcuations happen here.
// This is where we actually draw the text.
// For now do the simplest wrapping, no highlighting.
+ assert(_state);
+
Common::StringArray lines;
const Font *font = getDlgTextFont();
const int h = font->getFontHeight();
- font->wordWrapText(txt, _textDrawRect.width(), lines);
+ font->wordWrapText(txt, _state->_loc.width, lines);
- int ystart = _textDrawRect.top + (_textDrawRect.height() - lines.size() * h) / 2;
+ int ystart = _state->_loc.y + (_state->_loc.height - lines.size() * h) / 2;
- int x = _textDrawRect.left;
+ int x = _state->_loc.x;
if (hasFlag(kDlgFlagLeftJust)) {
// each line left-aligned, but overall block is still centered
int maxlen = -1;
for (const auto &line : lines)
maxlen = MAX(maxlen, font->getStringWidth(line));
- x += (_textDrawRect.width() - maxlen) / 2;
+ x += (_state->_loc.width - maxlen) / 2;
for (uint i = 0; i < lines.size(); i++)
font->drawString(dst, lines[i], x, ystart + i * h, maxlen, fontcol, Graphics::kTextAlignLeft);
} else {
// center each line
for (uint i = 0; i < lines.size(); i++)
- font->drawString(dst, lines[i], x, ystart + i * h, _textDrawRect.width(), fontcol, Graphics::kTextAlignCenter);
+ font->drawString(dst, lines[i], x, ystart + i * h, _state->_loc.width, fontcol, Graphics::kTextAlignCenter);
}
if (_state->_selectedAction) {
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 7f515bf23fd..82b208f47a7 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -126,8 +126,6 @@ public:
void clear();
private:
- Common::Rect _textDrawRect; // Calculated while drawing the background.
-
void drawType1(Graphics::Surface *dst, DialogDrawStage stage);
void drawType2(Graphics::Surface *dst, DialogDrawStage stage);
void drawType3(Graphics::Surface *dst, DialogDrawStage stage);
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index e044e24bb70..ef07f86e18b 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -193,15 +193,14 @@ int Image::frameCount(const Common::String &filename) {
}
void Image::loadBitmap(const Common::String &filename, int number) {
- const char *dot;
DGDS_EX ex;
- uint16 *mtx;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("loadBitmap: Couldn't get bitmap resource '%s'", filename.c_str());
_bmpData.free();
+ const char *dot;
if ((dot = strrchr(filename.c_str(), '.'))) {
ex = MKTAG24(dot[1], dot[2], dot[3]);
} else {
@@ -216,8 +215,8 @@ void Image::loadBitmap(const Common::String &filename, int number) {
int64 vqtpos = -1;
int64 scnpos = -1;
- uint16 tileWidths[128];
- uint16 tileHeights[128];
+ Common::Array<Common::Point> tileSizes;
+ Common::Array<uint16> mtxVals;
int32 tileOffset = 0;
DgdsChunkReader chunk(fileStream);
@@ -226,20 +225,21 @@ void Image::loadBitmap(const Common::String &filename, int number) {
Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_INF)) {
uint16 tileCount = stream->readUint16LE();
- if (tileCount > ARRAYSIZE(tileWidths))
+ if (tileCount > 256)
error("Image::loadBitmap: Unexpectedly large number of tiles in image (%d)", tileCount);
- if (tileCount < number) {
+ if (tileCount <= number) {
warning("Request for frame %d from %s that only has %d frames", number, filename.c_str(), tileCount);
return;
}
+ tileSizes.resize(tileCount);
for (uint16 k = 0; k < tileCount; k++) {
- tileWidths[k] = stream->readUint16LE();
+ tileSizes[k].x = stream->readUint16LE();
}
for (uint16 k = 0; k < tileCount; k++) {
- tileHeights[k] = stream->readUint16LE();
+ tileSizes[k].y = stream->readUint16LE();
if (k < number)
- tileOffset += tileWidths[k] * tileHeights[k];
+ tileOffset += tileSizes[k].x * tileSizes[k].y;
}
} else if (chunk.isSection(ID_MTX)) {
// Scroll offset
@@ -247,20 +247,19 @@ void Image::loadBitmap(const Common::String &filename, int number) {
mw = stream->readUint16LE();
mh = stream->readUint16LE();
uint32 mcount = uint32(mw) * mh;
- debug(" %ux%u: %u bytes", mw, mh, mcount * 2);
+ mtxVals.resize(mcount);
+ debug(" %ux%u: mtx vals", mw, mh);
- mtx = new uint16[mcount];
for (uint32 k = 0; k < mcount; k++) {
uint16 tile;
tile = stream->readUint16LE();
- mtx[k] = tile;
+ mtxVals[k] = tile;
}
- // TODO: Use these
- delete mtx;
+ // TODO: Use mtxVals
} else if (chunk.isSection(ID_BIN)) {
- loadBitmap4(_bmpData, tileWidths[number], tileHeights[number], tileOffset, stream, false);
+ loadBitmap4(_bmpData, tileSizes[number].x, tileSizes[number].y, tileOffset, stream, false);
} else if (chunk.isSection(ID_VGA)) {
- loadBitmap4(_bmpData, tileWidths[number], tileHeights[number], tileOffset, stream, true);
+ loadBitmap4(_bmpData, tileSizes[number].x, tileSizes[number].y, tileOffset, stream, true);
} else if (chunk.isSection(ID_VQT)) {
// Postpone parsing this until we have the offsets, which come after.
vqtpos = fileStream->pos();
@@ -272,7 +271,7 @@ void Image::loadBitmap(const Common::String &filename, int number) {
error("Expect VQT or SCN chunk before OFF chunk in BMP resource %s", filename.c_str());
// 2 possibilities: A set of offsets (find the one which we need and use it)
- // or a single value of 0xffff. If it's only one tile the offset is always
+ // or a single value of 0xffff. If it's only one tile, the offset is always
// zero anyway. For subsequent images, round up to the next byte to start
// reading.
if (chunk.getSize() == 2) {
@@ -287,7 +286,7 @@ void Image::loadBitmap(const Common::String &filename, int number) {
for (int i = 0; i < number + 1; i++) {
fileStream->seek(vqtpos);
_bmpData.free();
- nextOffset = loadVQT(_bmpData, tileWidths[i], tileHeights[i], nextOffset, fileStream);
+ nextOffset = loadVQT(_bmpData, tileSizes[i].x, tileSizes[i].y, nextOffset, fileStream);
nextOffset = ((nextOffset + 7) / 8) * 8;
}
} else {
@@ -302,10 +301,10 @@ void Image::loadBitmap(const Common::String &filename, int number) {
uint32 subImgOffset = stream->readUint32LE();
if (vqtpos != -1) {
fileStream->seek(vqtpos + subImgOffset);
- loadVQT(_bmpData, tileWidths[number], tileHeights[number], 0, fileStream);
+ loadVQT(_bmpData, tileSizes[number].x, tileSizes[number].y, 0, fileStream);
} else {
fileStream->seek(scnpos + subImgOffset);
- loadSCN(_bmpData, tileWidths[number], tileHeights[number], fileStream);
+ loadSCN(_bmpData, tileSizes[number].x, tileSizes[number].y, fileStream);
}
}
// NOTE: This was proably the last chunk, but we don't check - should have
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 2eb34555e50..5899bb5c4b8 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -79,6 +79,8 @@ public:
int16 width() const;
int16 height() const;
+ void unload() { _bmpData.free(); }
+
const Graphics::Surface &getSurface() { return _bmpData; }
private:
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 436ba0adf4a..0296feecc72 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -89,9 +89,10 @@ static const char *ttmOpName(uint16 op) {
case 0xa0a0: return "DRAW LINE";
case 0xa100: return "DRAW FILLED RECT";
case 0xa110: return "DRAW EMPTY RECT";
+ case 0xa500: return "DRAW BMP";
case 0xa520: return "DRAW SPRITE FLIP";
case 0xa530: return "DRAW BMP4";
- case 0xa500: return "DRAW BMP";
+ case 0xa600: return "DRAW GETPUT";
case 0xf010: return "LOAD SCR";
case 0xf020: return "LOAD BMP";
case 0xf040: return "LOAD FONT";
@@ -107,9 +108,8 @@ static const char *ttmOpName(uint16 op) {
case 0x2020: return "SET TIMER";
case 0xa300: return "DRAW some string";
case 0xa400: return "DRAW FILLED CIRCLE";
- case 0xa424: return "DRAW EMPTY CIRCLE";
+ case 0xa420: return "DRAW EMPTY CIRCLE";
case 0xa510: return "DRAW SPRITE1";
- case 0xa600: return "CLEAR SCREEN";
case 0xb000: return "? (0 args)";
case 0xb010: return "? (3 args: 30, 2, 19)";
case 0xb600: return "DRAW SCREEN";
@@ -127,8 +127,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
switch (op) {
- case 0x0000:
- // FINISH: void
+ case 0x0000: // FINISH: void
break;
case 0x0020: // SAVE (free?) BACKGROUND
if (seq._executed) // this is a one-shot op
@@ -154,8 +153,12 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0110: // PURGE void
_vm->adsInterpreter()->setHitTTMOp0110();
break;
- case 0x0ff0: {
- // REFRESH: void
+ case 0x0220: // STOP CURRENT MUSIC
+ if (seq._executed) // this is a one-shot op
+ break;
+ _vm->_soundPlayer->stopMusic();
+ break;
+ case 0x0ff0: { // REFRESH: void
_vm->_resData.blitFrom(_vm->getBottomBuffer());
Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
@@ -167,27 +170,26 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// in game frames, not millis.
_vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * 8.33));
break;
- case 0x1030: {
- // SET BRUSH: id:int [-1:n]
+ case 0x1030: { // SET BRUSH: id:int [-1:n]
seq._brushNum = ivals[0];
- if (seq._brushNum != -1) {
- // TODO: This is probably not the right place to load this
- if (!env._scriptShapes[seq._currentBmpId].empty())
- _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
- }
+ _vm->_image->unload();
+ //if (seq._brushNum != -1) {
+ // TODO: This is probably not the best place to load this - it would be far more
+ // efficient to load all frames and pick during the draw.
+ //if (!env._scriptShapes[seq._currentBmpId].empty())
+ // _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
+ //}
break;
}
- case 0x1050:
- // SELECT BMP: id:int [0:n]
+ case 0x1050: // SELECT BMP: id:int [0:n]
seq._currentBmpId = ivals[0];
+ _vm->_image->unload();
break;
- case 0x1060:
- // SELECT PAL: id:int [0]
+ case 0x1060: // SELECT PAL: id:int [0]
seq._currentPalId = ivals[0];
_vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
break;
- case 0x1090:
- // SELECT SONG: id:int [0]
+ case 0x1090: // SELECT SONG: id:int [0]
seq._currentSongId = ivals[0];
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
@@ -220,19 +222,19 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
seq._drawColBG = static_cast<byte>(ivals[1]);
break;
case 0x2020: { // SET RANDOM SLEEP: min,max: int (eg, 60,300)
+ if (seq._executed) // this is a one-shot op.
+ break;
uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
// TODO: do same time fix as for 0x1020
_vm->adsInterpreter()->setScriptDelay((int)(sleep * 8.33));
break;
}
- case 0x4000:
- // SET CLIP WINDOW x,y,w,h:int [0..320,0..200]
+ case 0x4000: // SET CLIP WINDOW x,y,w,h:int [0..320,0..200]
seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
- case 0x4110:
+ case 0x4110: // FADE OUT: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
break;
- // FADE OUT: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->clearPalette();
} else {
@@ -251,7 +253,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
_vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
- case 0x4120: {
+ case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
break;
// blt first?
@@ -260,7 +262,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
_vm->getTopBuffer().fillRect(bmpArea, 0);
- // FADE IN: colorno,ncolors,targetcol,speed:byte
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
} else {
@@ -274,10 +275,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
break;
}
- case 0x4200: {
+ case 0x4200: { // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
if (seq._executed) // this is a one-shot op
break;
- // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
_vm->_resData.blitFrom(_vm->getBottomBuffer());
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
@@ -285,14 +285,17 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
}
case 0x4210: { // SAVE IMAGE REGION (getput area)
+ if (seq._executed) // this is a one-shot op.
+ break;
if (seq._currentGetPutId >= (int)env._getPutAreas.size()) {
env._getPutAreas.resize(seq._currentGetPutId + 1);
env._getPutSurfaces.resize(seq._currentGetPutId + 1);
}
Common::Rect rect = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
env._getPutAreas[seq._currentGetPutId] = rect;
- Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_resData.format);
- surf->blitFrom(_vm->_resData, rect, Common::Rect(0, 0, rect.width(), rect.height()));
+ // TODO: Check which buffer this should get things from
+ Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getTopBuffer().format);
+ surf->blitFrom(_vm->getTopBuffer(), rect, Common::Rect(0, 0, rect.width(), rect.height()));
env._getPutSurfaces[seq._currentGetPutId].reset(surf);
break;
}
@@ -308,8 +311,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
_vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
break;
- case 0xa100:
- // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
+ case 0xa100: // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
_vm->getTopBuffer().fillRect(bmpArea, seq._drawColFG);
break;
@@ -339,10 +341,12 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (tileId != -1) {
_vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], tileId);
}
- } else if (!_vm->_image->isLoaded()) {
+ } else if (!_vm->_image->isLoaded() && !env._scriptShapes[seq._currentBmpId].empty()) {
// load on demand?
- warning("trying to load bmp %d (%s) on demand", seq._currentBmpId, env._scriptShapes[seq._currentBmpId].c_str());
- _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], 0);
+ //warning("trying to draw bmp %d (%s) that was "
+ // " never loaded - do it on demand",
+ // seq._currentBmpId, env._scriptShapes[seq._currentBmpId].c_str());
+ _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
@@ -352,6 +356,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
warning("request to draw null img at %d %d", ivals[0], ivals[1]);
break;
case 0xa600: { // DRAW GETPUT
+ if (seq._executed) // this is a one-shot op.
+ break;
int16 i = ivals[0];
if (i >= (int16)env._getPutAreas.size() || !env._getPutSurfaces[i]) {
warning("Trying to put getput region %d we never got", i);
@@ -362,38 +368,34 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
r.left, r.top, Common::Rect(0, 0, r.width(), r.height()));
break;
}
- case 0xf010:
+ case 0xf010: // LOAD SCR: filename:str
if (seq._executed) // this is a one-shot op
break;
- // LOAD SCR: filename:str
_vm->_image->drawScreen(sval, _vm->getBottomBuffer());
break;
- case 0xf020:
+ case 0xf020: // LOAD BMP: filename:str
if (seq._executed) // this is a one-shot op
break;
- // LOAD BMP: filename:str
env._scriptShapes[seq._currentBmpId] = sval;
+ _vm->_image->unload();
break;
- case 0xf040: {
+ case 0xf040: { // LOAD FONT: filename:str
if (seq._executed) // this is a one-shot op
break;
- // LOAD FONT: filename:str
//const FontManager *mgr = _vm->getFontMan();
warning("TODO: Implement opcode 0xf040 load font %s", sval.c_str());
break;
}
- case 0xf050: {
+ case 0xf050: { // LOAD PAL: filename:str
if (seq._executed) // this is a one-shot op
break;
- // LOAD PAL: filename:str
int newPalNum = _vm->getGamePals()->loadPalette(sval);
env._scriptPals[seq._currentPalId] = newPalNum;
break;
}
- case 0xf060:
+ case 0xf060: // LOAD SONG: filename:str
if (seq._executed) // this is a one-shot op
break;
- // LOAD SONG: filename:str
if (_vm->_platform == Common::kPlatformAmiga) {
// TODO: remove hard-coded stuff..
_vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
@@ -406,17 +408,15 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
break;
- case 0x0220: // STOP CURRENT MUSIC
- if (seq._executed) // this is a one-shot op
- break;
- _vm->_soundPlayer->stopMusic();
- break;
// Unimplemented / unknown
case 0x00C0: // FREE BACKGROUND (free getput item pointed to by _currentGetPutId)
- case 0x0230: // reset current music? (0 args) - found in HoC intro. Sets params about current music
+ case 0x0230: // (one-shot) reset current music? (0 args) - found in HoC intro. Sets params about current music.
+ case 0x0400: // (one-shot) set palette??
+ case 0x1040: // Sets some global? i:int
case 0x1070: // SELECT FONT i:int
- case 0x2010: // SET FRAME
+ case 0x10B0: // null op?
+ case 0x2010: // SET FRAME?? x,y
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa424: // DRAW EMPTY CIRCLE
@@ -447,12 +447,6 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
if (scr->pos() >= scr->size())
return false;
- // TODO: This seems to not be how it works in the original?
- //if (seq._timeNext > g_engine->getTotalPlayTime()) {
- // return true;
- //}
- //seq._timeNext = 0;
-
debug("TTM: Run env %d seq %d frame %d (scr offset %d)", seq._enviro, seq._seqNum,
seq._currentFrame, (int)scr->pos());
uint16 code = 0;
@@ -811,28 +805,25 @@ void ADSInterpreter::findEndOrInitOp() {
}
}
-uint ADSInterpreter::randomOpGetVal(uint16 code, Common::SeekableReadStream *scr) {
- int skip;
- if (code == 0x2000 || code == 0x2005)
- skip = 6;
- else if (code == 0x3020)
- skip = 0;
- else
- skip = 4;
-
- scr->skip(skip);
- uint16 result = scr->readUint16LE();
- scr->seek(-skip, SEEK_CUR);
+int16 ADSInterpreter::randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr) {
+ int argsize = numArgs(code) * 2;
+ if (argsize == 0)
+ error("Unexpected 0-arg ADS opcode 0x%04x inside random block", code);
+ if (argsize > 2)
+ scr->seek(argsize - 2, SEEK_CUR);
+ int16 result = scr->readSint16LE();
+ scr->seek(-argsize, SEEK_CUR);
return result;
}
void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr) {
- uint16 max = 0;
+ int16 max = 0;
int64 startpos = scr->pos();
// Collect the random proportions
code = scr->readUint16LE();
while (code != 0 && code != 0x30ff && scr->pos() < scr->size()) {
- uint16 val = randomOpGetVal(code, scr);
+ int16 val = randomOpGetProportion(code, scr);
+ // leaves pointer at beginning of next op
max += val;
scr->skip(numArgs(code) * 2);
if (scr->pos() >= scr->size())
@@ -850,13 +841,13 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
// Now find the random bit to jump to
code = scr->readUint16LE();
do {
- uint16 val = randomOpGetVal(code, scr);
+ int16 val = randomOpGetProportion(code, scr);
randval -= val;
if (randval < 1) {
- scr->seek(-2, SEEK_CUR);
+ // This is the opcode we want to execute
break;
}
- scr->skip(numArgs(code));
+ scr->skip(numArgs(code) * 2);
if (scr->pos() >= scr->size())
break;
code = scr->readUint16LE();
@@ -1079,13 +1070,15 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xffff: // END
return false;
+ case 0x3020: // RANDOM_NOOP, 1 param (proportion)
+ scr->readUint16LE();
+ return true;
+
case 0x3010: // RANDOM_START, 0 params
- case 0x3020: // RANDOM_??, 1 param
case 0x30FF: // RANDOM_END, 0 params
handleRandomOp(code, scr);
break;
-
//// unknown / to-be-implemented
case 0x1010: // unknown, 2 params
case 0x1020: // unknown, 2 params
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 85101283886..a0b33094a84 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -170,7 +170,7 @@ public:
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
- uint randomOpGetVal(uint16 code, Common::SeekableReadStream *scr);
+ int16 randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr);
bool playScene();
bool skipToEndIf();
bool skipSceneLogicBranch();
Commit: 0381ea72dd8e410a4b5095d3d37bc6a0b8fc0e21
https://github.com/scummvm/scummvm/commit/0381ea72dd8e410a4b5095d3d37bc6a0b8fc0e21
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement ADS logic OR and AND opcodes
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 1bdefe2195c..fdb741255cf 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -870,7 +870,7 @@ void SDSScene::mouseClicked(const Common::Point &pt) {
HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
for (auto &area : _hotAreaList) {
if (checkConditions(area.enableConditions) &&
- area.rect.x < pt.x && (area.rect.x + area.rect.height) > pt.x
+ area.rect.x < pt.x && (area.rect.x + area.rect.width) > pt.x
&& area.rect.y < pt.y && (area.rect.y + area.rect.height) > pt.y) {
return &area;
}
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 0296feecc72..966ff267e22 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -768,7 +768,6 @@ TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seq) {
return nullptr;
}
-
void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
int idx = getArrIndexOfSegNum(seg);
if (idx >= 0) {
@@ -805,6 +804,69 @@ void ADSInterpreter::findEndOrInitOp() {
}
}
+bool ADSInterpreter::logicOpResult(uint16 code, const TTMSeq *seq) {
+ switch (code) {
+ case 0x1310: // IF runtype 5, 2 params
+ debug("ADS: if runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
+ return seq->_runFlag == kRunType5;
+ case 0x1320: // IF not runtype 5, 2 params
+ debug("ADS: if not runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
+ return seq->_runFlag != kRunType5;
+ case 0x1330: // IF_NOT_PLAYED, 2 params
+ debug("ADS: if not played env %d seq %d", seq->_enviro, seq->_seqNum);
+ return !seq->_runPlayed;
+ case 0x1340: // IF_PLAYED, 2 params
+ debug("ADS: if played env %d seq %d", seq->_enviro, seq->_seqNum);
+ return seq->_runPlayed;
+ case 0x1350: // IF_FINISHED, 2 params
+ debug("ADS: if finished env %d seq %d", seq->_enviro, seq->_seqNum);
+ return seq->_runFlag == kRunTypeFinished;
+ case 0x1360: // IF_NOT_RUNNING, 2 params
+ debug("ADS: if not running env %d seq %d", seq->_enviro, seq->_seqNum);
+ return seq->_runFlag == kRunTypeStopped;
+ case 0x1370: // IF_RUNNING, 2 params
+ debug("ADS: if running env %d seq %d", seq->_enviro, seq->_seqNum);
+ return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
+ default:
+ error("Not an ADS logic op: %04x, how did we get here?", code);
+ }
+}
+
+bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr) {
+ bool testval = true;
+ uint16 andor = 0x1420; // start with "true" AND..
+ while (scr->pos() < scr->size()) {
+ uint16 enviro = scr->readUint16LE();
+ uint16 seqnum = scr->readUint16LE();
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ if (!seq) {
+ warning("ADS if op referenced non-existant env %d seq %d", enviro, seqnum);
+ return false;
+ }
+
+ if (andor == 0x1420) // AND
+ testval &= logicOpResult(code, seq);
+ else // OR
+ testval |= logicOpResult(code, seq);
+
+ code = scr->readUint16LE();
+
+ if (code == 0x1420 || code == 0x1430) {
+ andor = code;
+ code = scr->readUint16LE();
+ // The next op should be another logic op
+ } else {
+ // No AND or OR, next op is just what to do.
+ scr->seek(-2, SEEK_CUR);
+ if (testval)
+ return runUntilBranchOpOrEnd();
+ else
+ return skipToEndIf();
+ }
+ }
+ error("didn't return from ADS logic test");
+}
+
int16 ADSInterpreter::randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr) {
int argsize = numArgs(code) * 2;
if (argsize == 0)
@@ -869,76 +931,14 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
//debug("ADS: init code 0x%04x", code);
// "init". 0x0005 can be used for searching for next thing.
break;
- case 0x1310: { // IF runtype 5, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if runtype 5 env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && seq->_runFlag != kRunType5)
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
- case 0x1320: { // IF not runtype 5, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if not runtype 5 env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && seq->_runFlag == kRunType5)
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
- case 0x1330: { // IF_NOT_PLAYED, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if not played env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && seq->_runPlayed)
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
- case 0x1340: { // IF_PLAYED, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if played env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && !seq->_runPlayed)
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
- case 0x1350: { // IF_FINISHED, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if finished env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && seq->_runFlag != kRunTypeFinished)
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
- case 0x1360: { // IF_NOT_RUNNING, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if not running env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && seq->_runFlag != kRunTypeStopped)
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
- case 0x1370: { // IF_RUNNING, 2 params
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug("ADS: if running env %d seq %d", enviro, seqnum);
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (seq && (seq->_runFlag != kRunType1 && seq->_runFlag != kRunTypeMulti && seq->_runFlag != kRunTypeTimeLimited))
- return skipToEndIf();
- else
- return runUntilBranchOpOrEnd();
- }
+ case 0x1310: // IF runtype 5, 2 params
+ case 0x1320: // IF not runtype 5, 2 params
+ case 0x1330: // IF_NOT_PLAYED, 2 params
+ case 0x1340: // IF_PLAYED, 2 params
+ case 0x1350: // IF_FINISHED, 2 params
+ case 0x1360: // IF_NOT_RUNNING, 2 params
+ case 0x1370: // IF_RUNNING, 2 params
+ return handleLogicOp(code, scr);
case 0x1500: // ? IF ?, 0 params
debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
//sceneLogicOps();
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index a0b33094a84..2f5cd6be104 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -170,6 +170,8 @@ public:
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
+ bool handleLogicOp(uint16 code, Common::SeekableReadStream *scr);
+ bool logicOpResult(uint16 code, const TTMSeq *seq);
int16 randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr);
bool playScene();
bool skipToEndIf();
Commit: 7164439ff205d6eb1770ae682ad75cf000df10f7
https://github.com/scummvm/scummvm/commit/7164439ff205d6eb1770ae682ad75cf000df10f7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Make globals signed ints
Changed paths:
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index dbe64b94b65..2a9b0123065 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -27,8 +27,8 @@ namespace Dgds {
template<typename T> class ReadOnlyGlobal : public Global {
public:
ReadOnlyGlobal(uint16 num, const T *val) : Global(num), _val(val) {}
- uint16 get() override { return *_val; }
- uint16 set(uint16 val) override { return *_val; }
+ int16 get() override { return *_val; }
+ int16 set(int16 val) override { return *_val; }
private:
const T *_val;
};
@@ -36,14 +36,14 @@ private:
template<typename T> class ReadWriteGlobal : public Global {
public:
ReadWriteGlobal(uint16 num, T *val) : Global(num), _val(val) {}
- uint16 get() override { return *_val; }
- uint16 set(uint16 val) override { *_val = val; return *_val; }
+ int16 get() override { return *_val; }
+ int16 set(int16 val) override { *_val = val; return *_val; }
private:
T *_val;
};
-typedef ReadOnlyGlobal<uint16> ROU16Global;
-typedef ReadWriteGlobal<uint16> RWU16Global;
+typedef ReadOnlyGlobal<int16> ROI16Global;
+typedef ReadWriteGlobal<int16> RWI16Global;
////////////////////////////////
@@ -56,7 +56,7 @@ Globals::~Globals() {
}
}
-uint16 Globals::getGlobal(uint16 num) {
+int16 Globals::getGlobal(uint16 num) {
for (auto &global : _globals) {
if (global->_num == num) {
return global->get();
@@ -65,7 +65,7 @@ uint16 Globals::getGlobal(uint16 num) {
return 0;
}
-uint16 Globals::setGlobal(uint16 num, uint16 val) {
+int16 Globals::setGlobal(uint16 num, int16 val) {
for (auto &global : _globals) {
if (global->_num == num) {
return global->set(val);
@@ -79,8 +79,8 @@ uint16 Globals::setGlobal(uint16 num, uint16 val) {
class DetailLevelROGlobal : public Global {
public:
DetailLevelROGlobal(uint16 num) : Global(num) {}
- uint16 get() override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
- uint16 set(uint16 val) override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
+ int16 get() override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
+ int16 set(int16 val) override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
};
////////////////////////////////
@@ -122,8 +122,8 @@ uint16 DragonDataTable::getValueFromTable() {
class DragonDataTableGlobal : public Global {
public:
DragonDataTableGlobal(uint16 num, DragonDataTable &table) : Global(num), _table(table) {}
- uint16 get() override { return _table.getValueFromTable(); }
- uint16 set(uint16 val) override { return _table.getValueFromTable(); }
+ int16 get() override { return _table.getValueFromTable(); }
+ int16 set(int16 val) override { return _table.getValueFromTable(); }
private:
DragonDataTable &_table;
};
@@ -133,7 +133,7 @@ private:
class DragonTimeGlobal : public ReadWriteGlobal<int> {
public:
DragonTimeGlobal(uint16 num, int *val, DragonGameTime &time) : ReadWriteGlobal<int>(num, val), _time(time) {}
- uint16 set(uint16 val) override {
+ int16 set(int16 val) override {
if (val != ReadWriteGlobal::get()) {
ReadWriteGlobal::set(val);
_time.addGameTime(0);
@@ -187,29 +187,29 @@ _sceneOp12SceneNum(0), _currentSelectedItem(0), _gameMinsToAdd_1(0), _gameMinsTo
_gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0), _gameDays2(0),
_sceneOpcode15Flag(0), _sceneOpcode15Val(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
- _globals.push_back(new ROU16Global(1, &_time._gameMinsAdded));
- _globals.push_back(new ROU16Global(0x64, &_gameCounterTicksUp));
- _globals.push_back(new ROU16Global(0x62, &_lastOpcode1SceneChageNum));
- _globals.push_back(new RWU16Global(0x61, &_sceneOp12SceneNum));
- _globals.push_back(new RWU16Global(0x60, &_currentSelectedItem));
+ _globals.push_back(new ROI16Global(1, &_time._gameMinsAdded));
+ _globals.push_back(new ROI16Global(0x64, &_gameCounterTicksUp));
+ _globals.push_back(new ROI16Global(0x62, &_lastOpcode1SceneChageNum));
+ _globals.push_back(new RWI16Global(0x61, &_sceneOp12SceneNum));
+ _globals.push_back(new RWI16Global(0x60, &_currentSelectedItem));
_globals.push_back(_time.getDaysGlobal(0x5F));
_globals.push_back(_time.getHoursGlobal(0x5E));
_globals.push_back(_time.getMinsGlobal(0x5D));
- _globals.push_back(new RWU16Global(0x5C, &_gameMinsToAdd_1));
- _globals.push_back(new RWU16Global(0x5B, &_gameMinsToAdd_2));
- _globals.push_back(new RWU16Global(0x5A, &_gameMinsToAdd_3));
- _globals.push_back(new RWU16Global(0x59, &_gameMinsToAdd_4));
- _globals.push_back(new RWU16Global(0x58, &_gameMinsToAdd_5));
- _globals.push_back(new RWU16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
- _globals.push_back(new RWU16Global(0x56, &_gameDays2));
- _globals.push_back(new RWU16Global(0x55, &_sceneOpcode15Flag));
- _globals.push_back(new RWU16Global(0x54, &_sceneOpcode15Val));
- _globals.push_back(new RWU16Global(0x20, &_sceneOpcode100Var));
- _globals.push_back(new RWU16Global(0x21, &_arcadeModeFlag_3cdc));
- _globals.push_back(new RWU16Global(0x22, &_opcode106EndMinutes));
- _globals.push_back(new RWU16Global(0x23, &_table._row));
- _globals.push_back(new RWU16Global(0x24, &_table._col));
- _globals.push_back(new RWU16Global(0x25, &_table._divBy4));
+ _globals.push_back(new RWI16Global(0x5C, &_gameMinsToAdd_1));
+ _globals.push_back(new RWI16Global(0x5B, &_gameMinsToAdd_2));
+ _globals.push_back(new RWI16Global(0x5A, &_gameMinsToAdd_3));
+ _globals.push_back(new RWI16Global(0x59, &_gameMinsToAdd_4));
+ _globals.push_back(new RWI16Global(0x58, &_gameMinsToAdd_5));
+ _globals.push_back(new RWI16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
+ _globals.push_back(new RWI16Global(0x56, &_gameDays2));
+ _globals.push_back(new RWI16Global(0x55, &_sceneOpcode15Flag));
+ _globals.push_back(new RWI16Global(0x54, &_sceneOpcode15Val));
+ _globals.push_back(new RWI16Global(0x20, &_sceneOpcode100Var));
+ _globals.push_back(new RWI16Global(0x21, &_arcadeModeFlag_3cdc));
+ _globals.push_back(new RWI16Global(0x22, &_opcode106EndMinutes));
+ _globals.push_back(new RWI16Global(0x23, &_table._row));
+ _globals.push_back(new RWI16Global(0x24, &_table._col));
+ _globals.push_back(new RWI16Global(0x25, &_table._divBy4));
_globals.push_back(new DragonDataTableGlobal(0x26, _table));
_globals.push_back(new DetailLevelROGlobal(0x27));
}
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 6917f749655..04fcc38672d 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -44,8 +44,8 @@ public:
Global(uint16 num) : _num(num) {}
virtual ~Global() {}
uint16 _num;
- virtual uint16 get() = 0;
- virtual uint16 set(uint16 val) = 0;
+ virtual int16 get() = 0;
+ virtual int16 set(int16 val) = 0;
virtual uint16 getNum() const { return _num; }
};
@@ -55,8 +55,8 @@ public:
Globals();
virtual ~Globals();
- uint16 getGlobal(uint16 num);
- uint16 setGlobal(uint16 num, uint16 val);
+ int16 getGlobal(uint16 num);
+ int16 setGlobal(uint16 num, int16 val);
protected:
Common::Array<Global *> _globals;
@@ -68,10 +68,10 @@ public:
DragonDataTable();
uint16 getValueFromTable();
- uint16 _row;
- uint16 _col;
- uint16 _divBy4;
- uint16 _output;
+ int16 _row;
+ int16 _col;
+ int16 _divBy4;
+ int16 _output;
private:
int getOffsetForVal(uint16 val);
@@ -86,7 +86,7 @@ public:
Global *getHoursGlobal(uint16 num);
Global *getDaysGlobal(uint16 num);
- uint16 _gameMinsAdded;
+ int16 _gameMinsAdded;
private:
int _gameTimeDays;
@@ -99,23 +99,23 @@ public:
DragonGlobals();
private:
- uint16 _gameCounterTicksUp;
- uint16 _gameCounterTicksDown;
- uint16 _lastOpcode1SceneChageNum;
- uint16 _sceneOp12SceneNum;
- uint16 _currentSelectedItem;
- uint16 _gameMinsToAdd_1;
- uint16 _gameMinsToAdd_2;
- uint16 _gameMinsToAdd_3;
- uint16 _gameMinsToAdd_4;
- uint16 _gameMinsToAdd_5;
- uint16 _gameGlobal0x57;
- uint16 _gameDays2;
- uint16 _sceneOpcode15Flag;
- uint16 _sceneOpcode15Val;
- uint16 _sceneOpcode100Var;
- uint16 _arcadeModeFlag_3cdc;
- uint16 _opcode106EndMinutes;
+ int16 _gameCounterTicksUp;
+ int16 _gameCounterTicksDown;
+ int16 _lastOpcode1SceneChageNum;
+ int16 _sceneOp12SceneNum;
+ int16 _currentSelectedItem;
+ int16 _gameMinsToAdd_1;
+ int16 _gameMinsToAdd_2;
+ int16 _gameMinsToAdd_3;
+ int16 _gameMinsToAdd_4;
+ int16 _gameMinsToAdd_5;
+ int16 _gameGlobal0x57;
+ int16 _gameDays2;
+ int16 _sceneOpcode15Flag;
+ int16 _sceneOpcode15Val;
+ int16 _sceneOpcode100Var;
+ int16 _arcadeModeFlag_3cdc;
+ int16 _opcode106EndMinutes;
DragonDataTable _table;
DragonGameTime _time;
// uint16 _detailSliderSetting; // kept in the engine
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index fdb741255cf..60c5668d5aa 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -918,7 +918,7 @@ bool GDSScene::readPerSceneGlobals(Common::SeekableReadStream *s) {
for (PerSceneGlobal &dst : _perSceneGlobals) {
dst._num = s->readUint16LE();
dst._sceneNo = s->readUint16LE();
- dst._val = s->readUint16LE();
+ dst._val = s->readSint16LE();
}
return !s->err();
}
@@ -994,7 +994,7 @@ void GDSScene::globalOps(const Common::Array<uint16> &args) {
}
}
-uint16 GDSScene::getGlobal(uint16 num) {
+int16 GDSScene::getGlobal(uint16 num) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int curSceneNum = engine->getScene()->getNum();
for (const auto &global : _perSceneGlobals) {
@@ -1005,7 +1005,7 @@ uint16 GDSScene::getGlobal(uint16 num) {
return gameGlobals->getGlobal(num);
}
-uint16 GDSScene::setGlobal(uint16 num, uint16 val) {
+int16 GDSScene::setGlobal(uint16 num, int16 val) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int curSceneNum = engine->getScene()->getNum();
for (auto &global : _perSceneGlobals) {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 53796c932b2..a1041cad6e9 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -154,7 +154,7 @@ struct SceneTrigger {
struct PerSceneGlobal {
uint16 _num;
uint16 _sceneNo;
- uint16 _val;
+ int16 _val;
Common::String dump(const Common::String &indent) const;
};
@@ -232,8 +232,8 @@ public:
void runQuitGameOps() { runOps(_quitGameOps); }
void runChangeSceneOps() { runOps(_onChangeSceneOps); }
void globalOps(const Common::Array<uint16> &args) override;
- uint16 getGlobal(uint16 num);
- uint16 setGlobal(uint16 num, uint16 val);
+ int16 getGlobal(uint16 num);
+ int16 setGlobal(uint16 num, int16 val);
private:
//byte _unk[32];
Commit: 24ff433799a9c797c67e71e6fa516732d5f62fa1
https://github.com/scummvm/scummvm/commit/24ff433799a9c797c67e71e6fa516732d5f62fa1
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Small tweaks to drawing ops
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dialog.cpp
engines/dgds/image.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index fad0f63d811..c6da474e2bd 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -151,6 +151,10 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
}
_scene->runLeaveSceneOps();
+
+ // store the last scene num
+ _gameGlobals->setGlobal(0x61, _scene->getNum());
+
_scene->unload();
_soundPlayer->unloadMusic();
@@ -224,7 +228,7 @@ Common::Error DgdsEngine::run() {
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
- //debug("%s", _gdsScene->dump("").c_str());
+ debug("%s", _gdsScene->dump("").c_str());
loadCorners("DCORNERS.BMP");
reqParser.parse(&invRequestData, "DINV.REQ");
@@ -297,6 +301,7 @@ Common::Error DgdsEngine::run() {
mouseClicked = true;
_lastMouse = ev.mouse;
} else if (ev.type == Common::EVENT_MOUSEMOVE) {
+ mouseMoved = true;
_lastMouse = ev.mouse;
}
}
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 5213039d1dd..d60163f1c20 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -524,7 +524,12 @@ struct DialogAction *Dialog::pickAction(bool isClosing) {
_state->_lastMouseY = lastMouse.y;
draw(nullptr, kDlgDrawFindSelectionTxtOffset);
- char underMouse = _str[_state->_strMouseLoc];
+ char underMouse;
+ if (_state->_strMouseLoc >= 0 && _state->_strMouseLoc < (int)_str.size())
+ underMouse = _str[_state->_strMouseLoc];
+ else
+ underMouse = '\0';
+
for (auto &action : _action) {
if ((action.strStart <= _state->_strMouseLoc && _state->_strMouseLoc <= action.strEnd) ||
(_state->_strMouseLoc == action.strEnd + 1 && underMouse == '\r' && _str[action.strEnd] != '\r')) {
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index ef07f86e18b..55048ecfbc4 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -327,7 +327,7 @@ void Image::drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surf
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- byte *src = (byte *)_bmpData.getPixels() + croppedBy.y * _bmpData.pitch + croppedBy.x;
+ const byte *src = (const byte *)_bmpData.getPixels() + croppedBy.y * _bmpData.pitch + croppedBy.x;
byte *ptr = (byte *)surface.getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 966ff267e22..82ca9114ba9 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -187,32 +187,38 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
case 0x1060: // SELECT PAL: id:int [0]
seq._currentPalId = ivals[0];
+ if (seq._executed) // this is a mostly on-shot op.
+ break;
_vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
break;
+ case 0x1070: // SELECT FONT i:int
+ seq._currentFontId = ivals[0];
+ warning("TODO: Implement TTM 0x1070 select font %d", ivals[0]);
+ break;
case 0x1090: // SELECT SONG: id:int [0]
seq._currentSongId = ivals[0];
break;
case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
// In the original this sets a global that seems to be never used?
- debug("SCENE SETUP DONE: %u", ivals[0]);
break;
- case 0x1100: // SET_SCENE: i:int [1..n]
- case 0x1110: { // SET_SCENE: i:int [1..n]
- // DESCRIPTION IN TTM TAGS. num only used for GOTO.
- debug("SET SCENE: %u", ivals[0]);
+ case 0x1100: // SET_SCENE: i:int [1..n]
+ case 0x1110: // SET_SCENE: i:int [1..n]
+ // DESCRIPTION IN TTM TAGS. num only used as GOTO target.
break;
- }
case 0x1120: // SET GETPUT NUM
seq._currentGetPutId = ivals[0];
break;
- case 0x1200: // GOTO? How different to SET SCENE??
- debug("GOTO SCENE: %u", ivals[0]);
+ case 0x1200: // GOTO
_vm->adsInterpreter()->setGotoTarget(ivals[0]);
break;
case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
+ if (seq._executed) // this is a one-shot op.
+ break;
_vm->_soundPlayer->playSFX(ivals[0]);
break;
case 0x1310: // STOP SFX i:int eg [107]
+ if (seq._executed) // this is a one-shot op.
+ break;
warning("TODO: Implement TTM 0x1310 stop SFX %d", ivals[0]);
// Implement this:
//_vm->_soundPlayer->stopSfxById(ivals[0])
@@ -229,7 +235,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->adsInterpreter()->setScriptDelay((int)(sleep * 8.33));
break;
}
- case 0x4000: // SET CLIP WINDOW x,y,w,h:int [0..320,0..200]
+ case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
+ // NOTE: params are x2/y2, NOT w/h
seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
case 0x4110: // FADE OUT: colorno,ncolors,targetcol,speed:byte
@@ -278,13 +285,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x4200: { // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
if (seq._executed) // this is a one-shot op
break;
- const Common::Rect destRect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ const Common::Rect destRect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
_vm->_resData.blitFrom(_vm->getBottomBuffer());
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
_vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
break;
}
- case 0x4210: { // SAVE IMAGE REGION (getput area)
+ case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
if (seq._executed) // this is a one-shot op.
break;
if (seq._currentGetPutId >= (int)env._getPutAreas.size()) {
@@ -302,7 +309,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa000: // DRAW PIXEL x,y:int
_vm->getTopBuffer().setPixel(ivals[0], ivals[1], seq._drawColFG);
break;
- case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l]
+ case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l] (not in DRAGON)
// it works like a bitblit, but it doesn't write if there's something already at the destination?
_vm->_resData.blitFrom(_vm->getBottomBuffer());
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
@@ -312,16 +319,19 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
break;
case 0xa100: // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
- bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ bmpArea = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
_vm->getTopBuffer().fillRect(bmpArea, seq._drawColFG);
break;
case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
- bmpArea = Common::Rect(ivals[0], ivals[1], ivals[0] + ivals[2], ivals[1] + ivals[3]);
+ bmpArea = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
_vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, seq._drawColFG);
_vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, seq._drawColFG);
_vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, seq._drawColFG);
_vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, seq._drawColFG);
break;
+ case 0xa510:
+ // DRAW SPRITE x,y:int .. how different from 0xa500??
+ // FALL THROUGH
case 0xa520:
// DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
// FALL THROUGH
@@ -331,7 +341,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
// FALL THROUGH
case 0xa500:
- debug("DRAW \"%s\"", env._scriptShapes[seq._currentBmpId].c_str());
+ debug("DRAW \"%s\" 0x%04x", env._scriptShapes[seq._currentBmpId].c_str(), op);
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
@@ -410,17 +420,17 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// Unimplemented / unknown
- case 0x00C0: // FREE BACKGROUND (free getput item pointed to by _currentGetPutId)
+ case 0x0010: // (one-shot) ??
+ case 0x00C0: // (one-shot) FREE GETPUT (free getput item pointed to by _currentGetPutId)
case 0x0230: // (one-shot) reset current music? (0 args) - found in HoC intro. Sets params about current music.
case 0x0400: // (one-shot) set palette??
case 0x1040: // Sets some global? i:int
- case 0x1070: // SELECT FONT i:int
case 0x10B0: // null op?
case 0x2010: // SET FRAME?? x,y
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa424: // DRAW EMPTY CIRCLE
- case 0xa510: // DRAW SPRITE1
+
// From here on are not implemented in DRAGON
case 0xb000: // ? (0 args) - found in HoC intro
case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
Commit: dc4b2bce3fca3a95827b5d7f66b717032b886fd8
https://github.com/scummvm/scummvm/commit/dc4b2bce3fca3a95827b5d7f66b717032b886fd8
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Load all frames of an image at once
This allows us to be more accurate to the original and more efficient.
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 3bed389085b..0935652c30e 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -169,9 +169,9 @@ bool Console::cmdImageDump(int argc, const char **argv) {
GamePalettes pal(_vm->getResourceManager(), _vm->getDecompressor());
pal.loadPalette("DYNAMIX.PAL");
pal.setPalette();
- img.loadBitmap(fname, frameno);
- int width = img.width();
- int height = img.height();
+ img.loadBitmap(fname);
+ int width = img.width(frameno);
+ int height = img.height(frameno);
if (!width || !height) {
debugPrintf("Image %s:%d not valid\n", fname, frameno);
return true;
@@ -194,7 +194,7 @@ bool Console::cmdImageDump(int argc, const char **argv) {
byte palbuf[768];
g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
- ::Image::writePNG(outf, img.getSurface(), palbuf);
+ ::Image::writePNG(outf, *(img.getSurface(frameno)->surfacePtr()), palbuf);
outf.close();
debugPrintf("wrote %dx%d png to %s\n", width, height, outfname.c_str());
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index c6da474e2bd..57ff4a1db3b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -64,7 +64,7 @@
namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
- : Engine(syst), _image(nullptr), _fontManager(nullptr), _console(nullptr),
+ : Engine(syst), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _showClockUser(false), _showClockScript(false),
@@ -89,7 +89,6 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
DgdsEngine::~DgdsEngine() {
DebugMan.removeAllDebugChannels();
- delete _image;
delete _gamePals;
delete _decompressor;
delete _resource;
@@ -99,6 +98,9 @@ DgdsEngine::~DgdsEngine() {
delete _fontManager;
delete _menu;
+ _icons.reset();
+ _corners.reset();
+
_resData.free();
_topBuffer.free();
_bottomBuffer.free();
@@ -106,16 +108,8 @@ DgdsEngine::~DgdsEngine() {
void DgdsEngine::loadCorners(const Common::String &filename) {
- Image imgRes(_resource, _decompressor);
- int numImgs = imgRes.frameCount(filename);
- if (numImgs <= 0)
- error("Corner file %s didn't have any frames?", filename.c_str());
- _corners.resize(numImgs);
- for (int i = 0; i < numImgs; i++) {
- Image *img = new Image(_resource, _decompressor);
- img->loadBitmap(filename, i);
- _corners[i].reset(img);
- }
+ _corners.reset(new Image(_resource, _decompressor));
+ _corners->loadBitmap(filename);
}
void DgdsEngine::loadIcons() {
@@ -124,16 +118,8 @@ void DgdsEngine::loadIcons() {
if (iconFileName.empty())
return;
- Image imgRes(_resource, _decompressor);
- int numImgs = imgRes.frameCount(iconFileName);
- if (numImgs <= 0)
- error("Icon file %s didn't have any frames?", iconFileName.c_str());
- _icons.resize(numImgs);
- for (int i = 0; i < numImgs; i++) {
- Image *img = new Image(_resource, _decompressor);
- img->loadBitmap(iconFileName, i);
- _icons[i].reset(img);
- }
+ _icons.reset(new Image(_resource, _decompressor));
+ _icons->loadBitmap(iconFileName);
}
bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
@@ -180,12 +166,12 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
}
void DgdsEngine::setMouseCursor(uint num) {
- if (num >= _icons.size())
+ if (!_icons || (int)num >= _icons->loadedFrameCount())
return;
// TODO: Get mouse cursors from _gdsScene for hotspot info??
CursorMan.popAllCursors();
- CursorMan.pushCursor(_icons[num]->getSurface(), 0, 0, 0, 0);
+ CursorMan.pushCursor(*(_icons->getSurface(num)->surfacePtr()), 0, 0, 0, 0);
CursorMan.showMouse(true);
}
@@ -195,7 +181,6 @@ Common::Error DgdsEngine::run() {
_console = new Console(this);
_resource = new ResourceManager();
_decompressor = new Decompressor();
- _image = new Image(_resource, _decompressor);
_gamePals = new GamePalettes(_resource, _decompressor);
_soundPlayer = new Sound(_mixer, _resource, _decompressor);
_scene = new SDSScene();
@@ -278,7 +263,8 @@ Common::Error DgdsEngine::run() {
bool moveToNext = false;
bool triggerMenu = false;
- bool mouseClicked = false;
+ bool mouseLClicked = false;
+ bool mouseRClicked = false;
bool mouseMoved = false;
while (!shouldQuit()) {
@@ -298,7 +284,10 @@ Common::Error DgdsEngine::run() {
break;
}
} else if (ev.type == Common::EVENT_LBUTTONUP) {
- mouseClicked = true;
+ mouseLClicked = true;
+ _lastMouse = ev.mouse;
+ } else if (ev.type == Common::EVENT_RBUTTONUP) {
+ mouseRClicked = true;
_lastMouse = ev.mouse;
} else if (ev.type == Common::EVENT_MOUSEMOVE) {
mouseMoved = true;
@@ -321,9 +310,9 @@ Common::Error DgdsEngine::run() {
}
if (_menu->menuShown()) {
- if (mouseClicked) {
+ if (mouseLClicked) {
_menu->handleMenu(vcrRequestData, _lastMouse);
- mouseClicked = false;
+ mouseLClicked = false;
}
g_system->updateScreen();
g_system->delayMillis(10);
@@ -334,7 +323,7 @@ Common::Error DgdsEngine::run() {
_gdsScene->runPreTickOps();
_scene->runPreTickOps();
- _scene->drawActiveDialogBgs(_resData.surfacePtr());
+ _scene->drawActiveDialogBgs(&_resData);
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
@@ -343,9 +332,12 @@ Common::Error DgdsEngine::run() {
if (mouseMoved) {
_scene->mouseMoved(_lastMouse);
mouseMoved = false;
- } else if (mouseClicked) {
- _scene->mouseClicked(_lastMouse);
- mouseClicked = false;
+ } else if (mouseLClicked) {
+ _scene->mouseLClicked(_lastMouse);
+ mouseLClicked = false;
+ } else if (mouseRClicked) {
+ _scene->mouseRClicked(_lastMouse);
+ mouseRClicked = false;
}
// Note: Hard-coded logic for DRAGON, check others
@@ -356,7 +348,7 @@ Common::Error DgdsEngine::run() {
_scene->checkTriggers();
_scene->checkDialogActive();
- _scene->drawAndUpdateDialogs(_resData.surfacePtr());
+ _scene->drawAndUpdateDialogs(&_resData);
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
return Common::kNoError;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index e9f6c56178f..8157dac2634 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -70,7 +70,6 @@ class DgdsEngine : public Engine {
public:
Common::Platform _platform;
Sound *_soundPlayer;
- Image *_image;
Graphics::ManagedSurface _resData;
private:
@@ -80,8 +79,8 @@ private:
Decompressor *_decompressor;
DgdsGameId _gameId;
- Graphics::Surface _bottomBuffer;
- Graphics::Surface _topBuffer;
+ Graphics::ManagedSurface _bottomBuffer;
+ Graphics::ManagedSurface _topBuffer;
SDSScene *_scene;
GDSScene *_gdsScene;
Menu *_menu;
@@ -91,8 +90,8 @@ private:
Globals *_gameGlobals;
FontManager *_fontManager;
- Common::Array<Common::SharedPtr<Image>> _corners;
- Common::Array<Common::SharedPtr<Image>> _icons;
+ Common::SharedPtr<Image> _corners;
+ Common::SharedPtr<Image> _icons;
// Settings which we should integrate with ScummVM settings UI
DgdsDetailLevel _detailLevel;
@@ -116,8 +115,8 @@ public:
DgdsGameId getGameId() { return _gameId; }
- Graphics::Surface &getTopBuffer() { return _topBuffer; }
- Graphics::Surface &getBottomBuffer() { return _bottomBuffer; }
+ Graphics::ManagedSurface &getTopBuffer() { return _topBuffer; }
+ Graphics::ManagedSurface &getBottomBuffer() { return _bottomBuffer; }
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
@@ -125,7 +124,7 @@ public:
SDSScene *getScene() { return _scene; }
GDSScene *getGDSScene() { return _gdsScene; }
const FontManager *getFontMan() const { return _fontManager; }
- const Common::Array<Common::SharedPtr<Image>> &getUICorners() { return _corners; }
+ const Common::SharedPtr<Image> &getUICorners() { return _corners; }
bool changeScene(int sceneNum, bool runChangeOps);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index d60163f1c20..958d7a7607a 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -62,7 +62,7 @@ Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _selectionBgCol(0), _sel
{}
-void Dialog::draw(Graphics::Surface *dst, DialogDrawStage stage) {
+void Dialog::draw(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
_state.reset(new DialogState());
@@ -76,7 +76,7 @@ void Dialog::draw(Graphics::Surface *dst, DialogDrawStage stage) {
}
static void _drawPixel(int x, int y, int color, void *data) {
- Graphics::Surface *surface = (Graphics::Surface *)data;
+ Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
*((byte *)surface->getBasePtr(x, y)) = (byte)color;
@@ -95,7 +95,7 @@ const Font *Dialog::getDlgTextFont() const {
}
// box with simple frame
-void Dialog::drawType1(Graphics::Surface *dst, DialogDrawStage stage) {
+void Dialog::drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
return;
int x = _rect.x;
@@ -117,7 +117,7 @@ void Dialog::drawType1(Graphics::Surface *dst, DialogDrawStage stage) {
}
// box with fancy frame and optional title (everything before ":")
-void Dialog::drawType2(Graphics::Surface *dst, DialogDrawStage stage) {
+void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
return;
@@ -163,14 +163,14 @@ void Dialog::drawType2(Graphics::Surface *dst, DialogDrawStage stage) {
}
}
-static void _filledCircle(int x, int y, int xr, int yr, Graphics::Surface *dst, byte fgcol, byte bgcol) {
+static void _filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol, byte bgcol) {
Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, bgcol, true, _drawPixel, dst);
Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, _drawPixel, dst);
}
// Comic tought box made up of circles with 2 circles going up to it.
// Draw circles with 5/4 more pixels in x because the pixels are not square.
-void Dialog::drawType3(Graphics::Surface *dst, DialogDrawStage stage) {
+void Dialog::drawType3(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
return;
@@ -261,7 +261,7 @@ void Dialog::drawType3(Graphics::Surface *dst, DialogDrawStage stage) {
}
// ellipse
-void Dialog::drawType4(Graphics::Surface *dst, DialogDrawStage stage) {
+void Dialog::drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
return;
@@ -408,7 +408,7 @@ void Dialog::drawFindSelectionTxtOffset() {
return;
}
-void Dialog::drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt) {
+void Dialog::drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const Common::String &txt) {
// TODO: some more text calcuations happen here.
// This is where we actually draw the text.
// For now do the simplest wrapping, no highlighting.
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 82b208f47a7..9c0311ece11 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -29,7 +29,7 @@
#include "dgds/dgds_rect.h"
namespace Graphics {
-struct Surface;
+class ManagedSurface;
}
namespace Dgds {
@@ -115,7 +115,7 @@ public:
Common::SharedPtr<DialogState> _state;
- void draw(Graphics::Surface *dst, DialogDrawStage stage);
+ void draw(Graphics::ManagedSurface *dst, DialogDrawStage stage);
void setFlag(DialogFlags flg);
void clearFlag(DialogFlags flg);
void flipFlag(DialogFlags flg);
@@ -126,14 +126,14 @@ public:
void clear();
private:
- void drawType1(Graphics::Surface *dst, DialogDrawStage stage);
- void drawType2(Graphics::Surface *dst, DialogDrawStage stage);
- void drawType3(Graphics::Surface *dst, DialogDrawStage stage);
- void drawType4(Graphics::Surface *dst, DialogDrawStage stage);
+ void drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage);
+ void drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage);
+ void drawType3(Graphics::ManagedSurface *dst, DialogDrawStage stage);
+ void drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage);
void drawFindSelectionXY();
void drawFindSelectionTxtOffset();
- void drawForeground(Graphics::Surface *dst, uint16 fontcol, const Common::String &txt);
+ void drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const Common::String &txt);
const Font *getDlgTextFont() const;
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 55048ecfbc4..5ab53fe81cf 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -127,10 +127,9 @@ Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resour
}
Image::~Image() {
- _bmpData.free();
}
-void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
+void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface &surface) {
const char *dot;
DGDS_EX ex;
@@ -139,6 +138,9 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
return;
}
+ // surface should be allocated already.
+ assert(!surface.empty());
+
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("Couldn't get image resource %s", filename.c_str());
@@ -162,13 +164,13 @@ void Image::drawScreen(Common::String filename, Graphics::Surface &surface) {
chunk.readContent(_decompressor);
Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_BIN)) {
- loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, false);
+ loadBitmap4(&surface, 0, stream, false);
} else if (chunk.isSection(ID_VGA)) {
- loadBitmap4(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream, true);
+ loadBitmap4(&surface, 0, stream, true);
} else if (chunk.isSection(ID_MA8)) {
- loadBitmap8(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream);
+ loadBitmap8(&surface, 0, stream);
} else if (chunk.isSection(ID_VQT)) {
- loadVQT(surface, SCREEN_WIDTH, SCREEN_HEIGHT, 0, stream);
+ loadVQT(&surface, 0, stream);
}
}
@@ -192,13 +194,13 @@ int Image::frameCount(const Common::String &filename) {
return tileCount;
}
-void Image::loadBitmap(const Common::String &filename, int number) {
+void Image::loadBitmap(const Common::String &filename) {
DGDS_EX ex;
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream)
error("loadBitmap: Couldn't get bitmap resource '%s'", filename.c_str());
- _bmpData.free();
+ _frames.clear();
const char *dot;
if ((dot = strrchr(filename.c_str(), '.'))) {
@@ -215,34 +217,31 @@ void Image::loadBitmap(const Common::String &filename, int number) {
int64 vqtpos = -1;
int64 scnpos = -1;
- Common::Array<Common::Point> tileSizes;
- Common::Array<uint16> mtxVals;
- int32 tileOffset = 0;
DgdsChunkReader chunk(fileStream);
while (chunk.readNextHeader(ex, filename)) {
chunk.readContent(_decompressor);
Common::SeekableReadStream *stream = chunk.getContent();
if (chunk.isSection(ID_INF)) {
+ Common::Array<Common::Point> tileSizes;
uint16 tileCount = stream->readUint16LE();
if (tileCount > 256)
error("Image::loadBitmap: Unexpectedly large number of tiles in image (%d)", tileCount);
- if (tileCount <= number) {
- warning("Request for frame %d from %s that only has %d frames", number, filename.c_str(), tileCount);
- return;
- }
+ _frames.resize(tileCount);
tileSizes.resize(tileCount);
for (uint16 k = 0; k < tileCount; k++) {
tileSizes[k].x = stream->readUint16LE();
}
-
for (uint16 k = 0; k < tileCount; k++) {
tileSizes[k].y = stream->readUint16LE();
- if (k < number)
- tileOffset += tileSizes[k].x * tileSizes[k].y;
+ }
+
+ for (uint16 k = 0; k < tileCount; k++) {
+ _frames[k].reset(new Graphics::ManagedSurface(tileSizes[k].x, tileSizes[k].y, Graphics::PixelFormat::createFormatCLUT8()));
}
} else if (chunk.isSection(ID_MTX)) {
// Scroll offset
+ Common::Array<uint16> mtxVals;
uint16 mw, mh;
mw = stream->readUint16LE();
mh = stream->readUint16LE();
@@ -255,11 +254,19 @@ void Image::loadBitmap(const Common::String &filename, int number) {
tile = stream->readUint16LE();
mtxVals[k] = tile;
}
- // TODO: Use mtxVals
+ // TODO: Use mtxVals ?
} else if (chunk.isSection(ID_BIN)) {
- loadBitmap4(_bmpData, tileSizes[number].x, tileSizes[number].y, tileOffset, stream, false);
+ for (auto & frame : _frames) {
+ int32 tileOffset = 0;
+ loadBitmap4(frame.get(), tileOffset, stream, false);
+ tileOffset += frame->w * frame->h;
+ }
} else if (chunk.isSection(ID_VGA)) {
- loadBitmap4(_bmpData, tileSizes[number].x, tileSizes[number].y, tileOffset, stream, true);
+ for (auto & frame : _frames) {
+ int32 tileOffset = 0;
+ loadBitmap4(frame.get(), tileOffset, stream, true);
+ tileOffset += frame->w * frame->h;
+ }
} else if (chunk.isSection(ID_VQT)) {
// Postpone parsing this until we have the offsets, which come after.
vqtpos = fileStream->pos();
@@ -276,35 +283,30 @@ void Image::loadBitmap(const Common::String &filename, int number) {
// reading.
if (chunk.getSize() == 2) {
assert(scnpos == -1); // don't support this mode for SCN?
- if (number != 0) {
+ if (_frames.size() > 1) {
uint16 val = stream->readUint16LE();
if (val != 0xffff)
warning("Expected 0xffff in 2-byte offset list, got %04x", val);
}
uint32 nextOffset = 0;
- for (int i = 0; i < number + 1; i++) {
+ for (auto & frame : _frames) {
fileStream->seek(vqtpos);
- _bmpData.free();
- nextOffset = loadVQT(_bmpData, tileSizes[i].x, tileSizes[i].y, nextOffset, fileStream);
+ nextOffset = loadVQT(frame.get(), nextOffset, fileStream);
nextOffset = ((nextOffset + 7) / 8) * 8;
}
} else {
- if (number) {
- if ((number + 1) * 4 > (int)chunk.getSize()) {
- warning("Trying to load %s frame %d off the end of the list", filename.c_str(), number);
- break;
+ for (auto & frame : _frames) {
+ uint32 subImgOffset = stream->readUint32LE();
+ uint64 nextOffsetPos = stream->pos();
+ if (vqtpos != -1) {
+ fileStream->seek(vqtpos + subImgOffset);
+ loadVQT(frame.get(), 0, fileStream);
+ } else {
+ fileStream->seek(scnpos + subImgOffset);
+ loadSCN(frame.get(), fileStream);
}
- stream->skip(4 * number);
- }
-
- uint32 subImgOffset = stream->readUint32LE();
- if (vqtpos != -1) {
- fileStream->seek(vqtpos + subImgOffset);
- loadVQT(_bmpData, tileSizes[number].x, tileSizes[number].y, 0, fileStream);
- } else {
- fileStream->seek(scnpos + subImgOffset);
- loadSCN(_bmpData, tileSizes[number].x, tileSizes[number].y, fileStream);
+ stream->seek(nextOffsetPos);
}
}
// NOTE: This was proably the last chunk, but we don't check - should have
@@ -317,8 +319,9 @@ void Image::loadBitmap(const Common::String &filename, int number) {
delete fileStream;
}
-void Image::drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surface &surface) {
- const Common::Rect destRect(x, y, x + _bmpData.w, y + _bmpData.h);
+void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &surface, bool flip) {
+ Common::SharedPtr<Graphics::ManagedSurface> frame = _frames[frameno];
+ const Common::Rect destRect(x, y, x + frame->w, y + frame->h);
Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
clippedDestRect.clip(destRect);
clippedDestRect.clip(drawWin);
@@ -327,35 +330,42 @@ void Image::drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surf
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- const byte *src = (const byte *)_bmpData.getPixels() + croppedBy.y * _bmpData.pitch + croppedBy.x;
+ const byte *src = (const byte *)frame->getPixels() + croppedBy.y * frame->pitch + croppedBy.x;
byte *ptr = (byte *)surface.getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
- for (int j = 0; j < columns; ++j) {
- if (src[j])
- ptr[j] = src[j];
+ if (flip) {
+ for (int j = 0; j < columns; ++j) {
+ if (src[columns - j - 1])
+ ptr[j] = src[columns - j - 1];
+ }
+ } else {
+ for (int j = 0; j < columns; ++j) {
+ if (src[j])
+ ptr[j] = src[j];
+ }
}
ptr += surface.pitch;
- src += _bmpData.pitch;
+ src += frame->pitch;
}
}
-void Image::loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte) {
- uint16 outPitch = tw;
- if (surf.h == 0)
- surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
- byte *data = (byte *)surf.getPixels();
+void Image::loadBitmap4(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream, bool highByte) {
+ uint32 tw = surf->w;
+ uint32 th = surf->h;
+ assert(th != 0);
+ byte *data = (byte *)surf->getPixels();
byte buf;
stream->skip(toffset >> 1);
if (highByte) {
- for (int i = 0; i < tw * th; i += 2) {
+ for (uint i = 0; i < tw * th; i += 2) {
buf = stream->readByte();
data[i + 0] |= buf & 0xF0;
data[i + 1] |= (buf & 0x0F) << 4;
}
} else {
- for (int i = 0; i < tw * th; i += 2) {
+ for (uint i = 0; i < tw * th; i += 2) {
buf = stream->readByte();
data[i + 0] |= (buf & 0xF0) >> 4;
data[i + 1] |= buf & 0x0F;
@@ -363,13 +373,14 @@ void Image::loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 to
}
}
-void Image::loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream) {
- uint16 outPitch = tw;
- surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
- byte *data = (byte *)surf.getPixels();
+void Image::loadBitmap8(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream) {
+ uint32 tw = surf->w;
+ uint32 th = surf->h;
+ assert(th != 0);
+ byte *data = (byte *)surf->getPixels();
stream->skip(toffset);
- stream->read(data, uint32(outPitch) * th);
+ stream->read(data, (uint32)tw * th);
}
struct VQTDecodeState {
@@ -485,13 +496,14 @@ static void _doVqtDecode(struct VQTDecodeState *state, uint16 x, uint16 y, uint1
}
-uint32 Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream) {
+uint32 Image::loadVQT(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream) {
+ uint32 tw = surf->w;
+ uint32 th = surf->h;
+ assert(th != 0);
if (th > 200)
error("Max VQT height supported is 200px");
- uint16 outPitch = tw;
- surf.create(outPitch, th, Graphics::PixelFormat::createFormatCLUT8());
VQTDecodeState state;
- state.dstPtr = (byte *)surf.getPixels();
+ state.dstPtr = (byte *)surf->getPixels();
state.offset = toffset;
// FIXME: This sometimes reads more than it needs to..
uint64 nbytes = stream->size() - stream->pos();
@@ -511,12 +523,14 @@ uint32 Image::loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toff
// SCN file parsing - eg, "WILLCRED.BMP" from Willy Beamish
// Ref: https://moddingwiki.shikadi.net/wiki/The_Incredible_Machine_Image_Format
//
-bool Image::loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::SeekableReadStream *stream) {
- surf.create(tw, th, Graphics::PixelFormat::createFormatCLUT8());
- byte *dst = (byte *)surf.getPixels();
+bool Image::loadSCN(Graphics::ManagedSurface *surf, Common::SeekableReadStream *stream) {
+ uint32 tw = surf->w;
+ uint32 th = surf->h;
+ assert(th != 0);
+ byte *dst = (byte *)surf->getPixels();
- int32 y = 0;
- int32 x = 0;
+ uint32 y = 0;
+ uint32 x = 0;
const byte addVal = stream->readByte();
@@ -567,14 +581,23 @@ bool Image::loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::Seeka
return !stream->err();
}
-int16 Image::width() const {
- return _bmpData.w;
+int16 Image::width(uint frameno) const {
+ if (frameno >= _frames.size())
+ error("Invalid frameno %d", frameno);
+ return _frames[frameno]->w;
}
-int16 Image::height() const {
- return _bmpData.h;
+int16 Image::height(uint frameno) const {
+ if (frameno >= _frames.size())
+ error("Invalid frameno %d", frameno);
+ return _frames[frameno]->h;
}
+Common::SharedPtr<Graphics::ManagedSurface> Image::getSurface(uint frameno) {
+ if (frameno >= _frames.size())
+ error("Invalid frameno %d", frameno);
+ return _frames[frameno];
+}
// grayscale palette.
/*
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 5899bb5c4b8..aad018b7864 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -23,12 +23,15 @@
#ifndef DGDS_IMAGE_H
#define DGDS_IMAGE_H
+#include <common/ptr.h>
+
namespace Common {
class SeekableReadStream;
}
namespace Graphics {
struct Surface;
+class ManagedSurface;
}
namespace Dgds {
@@ -70,26 +73,28 @@ public:
Image(ResourceManager *resourceMan, Decompressor *decompressor);
virtual ~Image();
- void drawScreen(Common::String filename, Graphics::Surface &surface);
- void loadBitmap(const Common::String &filename, int number);
+ void drawScreen(const Common::String &filename, Graphics::ManagedSurface &dst);
+
+ void loadBitmap(const Common::String &filename);
int frameCount(const Common::String &filename);
- void drawBitmap(int x, int y, const Common::Rect &drawWin, Graphics::Surface &surface);
+ void drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &dst, bool flip = false);
+
+ Common::SharedPtr<Graphics::ManagedSurface> getSurface(uint frameno);
- bool isLoaded() const { return _bmpData.getPixels() != nullptr; }
- int16 width() const;
- int16 height() const;
+ const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &getFrames() { return _frames; }
- void unload() { _bmpData.free(); }
+ int16 width(uint frameno) const;
+ int16 height(uint frameno) const;
- const Graphics::Surface &getSurface() { return _bmpData; }
+ int loadedFrameCount() const { return _frames.size(); }
private:
- void loadBitmap4(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
- void loadBitmap8(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
- uint32 loadVQT(Graphics::Surface &surf, uint16 tw, uint16 th, uint32 toffset, Common::SeekableReadStream *stream);
- bool loadSCN(Graphics::Surface &surf, uint16 tw, uint16 th, Common::SeekableReadStream *stream);
+ void loadBitmap4(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
+ void loadBitmap8(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream);
+ uint32 loadVQT(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream);
+ bool loadSCN(Graphics::ManagedSurface *surf, Common::SeekableReadStream *stream);
- Graphics::Surface _bmpData;
+ Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _frames;
ResourceManager *_resourceMan;
Decompressor *_decompressor;
};
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 9d62ae091df..91626dfbd5b 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -137,7 +137,8 @@ void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
Graphics::Surface *dst = g_system->lockScreen();
- vcrRequestData._requests[_curMenu].draw(dst);
+ Graphics::ManagedSurface managed(dst, DisposeAfterUse::NO);
+ vcrRequestData._requests[_curMenu].draw(&managed);
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 1a951877ea3..986a6b26949 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -485,7 +485,7 @@ Common::String RequestData::dump() const {
return ret;
}
-void RequestData::draw(Graphics::Surface *dst) const {
+void RequestData::draw(Graphics::ManagedSurface *dst) const {
int slidery = 0;
for (const auto &gadget : _gadgets) {
const SliderGadget *slider = dynamic_cast<const SliderGadget *>(gadget.get());
@@ -511,43 +511,41 @@ const Font *RequestData::getMenuFont() {
}
/*static*/
-const Image *RequestData::getCorner(int cornerNum) {
+const Image *RequestData::getCorners() {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- return engine->getUICorners()[cornerNum].get();
+ return engine->getUICorners().get();
}
/*static*/
-void RequestData::drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height) {
+void RequestData::drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Common::Array<Common::SharedPtr<Image>> &allCorners = engine->getUICorners();
+ const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
+ assert(uiCorners->loadedFrameCount() > startNum + 7);
+ const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &cframes = uiCorners->getFrames();
+ const Common::SharedPtr<Graphics::ManagedSurface> *corners = cframes.data() + startNum;
- assert(allCorners.size() > startNum + 7);
+ for (int xoff = x + corners[0]->w; xoff < (x + width) - corners[2]->w; xoff += corners[1]->w)
+ dst->blitFrom(*corners[1], Common::Point(xoff, y));
- const Common::SharedPtr<Image> *corners = allCorners.data() + startNum;
- const Common::Rect screenRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ for (int xoff = x + corners[6]->w; xoff < (x + width) - corners[7]->w; xoff += corners[6]->w)
+ dst->blitFrom(*corners[6], Common::Point(xoff, (y + height) - corners[6]->h));
- for (int xoff = x + corners[0]->width(); xoff < (x + width) - corners[2]->width(); xoff += corners[1]->width())
- corners[1]->drawBitmap(xoff, y, screenRect, *dst);
-
- for (int xoff = x + corners[6]->width(); xoff < (x + width) - corners[7]->width(); xoff += corners[6]->width())
- corners[6]->drawBitmap(xoff, (y + height) - corners[6]->height(), screenRect, *dst);
-
- for (int yoff = y + corners[0]->height(); yoff < (y + height) - corners[5]->height(); yoff += corners[3]->height()) {
- corners[3]->drawBitmap(x, yoff, screenRect, *dst);
+ for (int yoff = y + corners[0]->h; yoff < (y + height) - corners[5]->h; yoff += corners[3]->h) {
+ dst->blitFrom(*corners[3], Common::Point(x, yoff));
}
- for (int yoff = y + corners[2]->height(); yoff < (y + height) - corners[7]->height(); yoff += corners[4]->height()) {
- corners[4]->drawBitmap((x + width) - corners[4]->width(), yoff, screenRect, *dst);
+ for (int yoff = y + corners[2]->h; yoff < (y + height) - corners[7]->h; yoff += corners[4]->h) {
+ dst->blitFrom(*corners[4], Common::Point((x + width) - corners[4]->w, yoff));
}
- corners[0]->drawBitmap(x, y, screenRect, *dst);
- corners[2]->drawBitmap((x + width) - corners[2]->width(), y, screenRect, *dst);
- corners[5]->drawBitmap(x, (y + height) - corners[5]->height(), screenRect, *dst);
- corners[7]->drawBitmap((x + width) - corners[7]->width(), (y + height) - corners[7]->height(), screenRect, *dst);
+ dst->blitFrom(*corners[0], Common::Point(x, y));
+ dst->blitFrom(*corners[2], Common::Point((x + width) - corners[2]->w, y));
+ dst->blitFrom(*corners[5], Common::Point(x, (y + height) - corners[5]->h));
+ dst->blitFrom(*corners[7], Common::Point((x + width) - corners[7]->w, (y + height) - corners[7]->h));
}
/*static*/
-void RequestData::drawHeader(Graphics::Surface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header) {
+void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header) {
if (!header.empty()) {
const Font *font = getMenuFont();
int hwidth = font->getStringWidth(header);
@@ -565,7 +563,7 @@ void RequestData::drawHeader(Graphics::Surface *dst, int16 x, int16 y, int16 wid
}
}
-void RequestData::drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sliderHeight, const Common::String &header) const {
+void RequestData::drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, int16 sliderHeight, const Common::String &header) const {
uint16 sliderBgHeight = sliderHeight + 18;
fillBackground(dst, _x, _y, _width, sliderBgHeight, 0);
fillBackground(dst, _x + 8, _y + sliderBgHeight, _width - 16, _height - sliderBgHeight, 8 - sliderBgHeight);
@@ -573,46 +571,47 @@ void RequestData::drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sli
fillBackground(dst, _x + 17, _y + 8 + sliderHeight + 2, _width - 34, _height - sliderBgHeight, 32 - sliderBgHeight);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Common::Array<Common::SharedPtr<Image>> &corners = engine->getUICorners();
- const Common::Rect screenRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
+ assert(uiCorners->loadedFrameCount() >= 11);
+ const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &corners = uiCorners->getFrames();
- for (int xoff = _x + corners[0]->width(); xoff < (_x + _width) - corners[3]->width(); xoff += corners[2]->width()) {
- corners[2]->drawBitmap(xoff, _y, screenRect, *dst);
+ for (int xoff = _x + corners[0]->w; xoff < (_x + _width) - corners[3]->w; xoff += corners[2]->w) {
+ dst->blitFrom(*corners[2], Common::Point(xoff, _y));
}
- for (int xoff = _x + 8 + corners[6]->width(); xoff < (_x + 8 + _width - 16) - corners[8]->width(); xoff += corners[7]->width()) {
- corners[7]->drawBitmap(xoff, (_y + _height) - corners[7]->height(), screenRect, *dst);
+ for (int xoff = _x + 8 + corners[6]->w; xoff < (_x + 8 + _width - 16) - corners[8]->w; xoff += corners[7]->w) {
+ dst->blitFrom(*corners[7], Common::Point(xoff, (_y + _height) - corners[7]->h));
}
- for (int yoff = _y + corners[3]->height(); yoff < (_y + sliderBgHeight) - corners[10]->height(); yoff += corners[5]->height()) {
- corners[5]->drawBitmap((_x + _width) - corners[5]->width(), yoff, screenRect, *dst);
+ for (int yoff = _y + corners[3]->h; yoff < (_y + sliderBgHeight) - corners[10]->h; yoff += corners[5]->h) {
+ dst->blitFrom(*corners[5], Common::Point((_x + _width) - corners[5]->w, yoff));
}
- for (int yoff = _y + corners[1]->height(); yoff < (_y + sliderBgHeight) - corners[9]->height(); yoff += corners[4]->height()) {
- corners[4]->drawBitmap(_x, yoff, screenRect, *dst);
+ for (int yoff = _y + corners[1]->h; yoff < (_y + sliderBgHeight) - corners[9]->h; yoff += corners[4]->h) {
+ dst->blitFrom(*corners[4], Common::Point(_x, yoff));
}
- for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[6]->height(); yoff += corners[4]->height()) {
- corners[4]->drawBitmap(_x + 8, yoff, screenRect, *dst);
+ for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[6]->h; yoff += corners[4]->h) {
+ dst->blitFrom(*corners[4], Common::Point(_x + 8, yoff));
}
- for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[8]->height(); yoff += corners[5]->height()) {
- corners[5]->drawBitmap((_x + 8 + _width - 16) - corners[5]->width(), yoff, screenRect, *dst);
+ for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[8]->h; yoff += corners[5]->h) {
+ dst->blitFrom(*corners[5], Common::Point((_x + 8 + _width - 16) - corners[5]->w, yoff));
}
- corners[1]->drawBitmap(_x, _y, screenRect, *dst);
- corners[3]->drawBitmap((_x + _width) - corners[3]->width(), _y, screenRect, *dst);
- corners[6]->drawBitmap(_x + 8, (_y + _height) - corners[6]->height(), screenRect, *dst);
- corners[8]->drawBitmap((_x + _width - 8) - corners[8]->width(), (_y + _height) - corners[8]->height(), screenRect, *dst);
- corners[9]->drawBitmap(_x, (_y + sliderBgHeight) - corners[9]->height(), screenRect, *dst);
- corners[10]->drawBitmap((_x + _width) - corners[10]->width(), (_y + sliderBgHeight) - corners[10]->height(), screenRect, *dst);
+ dst->blitFrom(*corners[1], Common::Point(_x, _y));
+ dst->blitFrom(*corners[3], Common::Point((_x + _width) - corners[3]->w, _y));
+ dst->blitFrom(*corners[6], Common::Point(_x + 8, (_y + _height) - corners[6]->h));
+ dst->blitFrom(*corners[8], Common::Point((_x + _width - 8) - corners[8]->w, (_y + _height) - corners[8]->h));
+ dst->blitFrom(*corners[9], Common::Point(_x, (_y + sliderBgHeight) - corners[9]->h));
+ dst->blitFrom(*corners[10], Common::Point((_x + _width) - corners[10]->w, (_y + sliderBgHeight) - corners[10]->h));
drawHeader(dst, _x, _y, _width, 9, header);
}
-void RequestData::drawBackgroundNoSliders(Graphics::Surface *dst, const Common::String &header) const {
+void RequestData::drawBackgroundNoSliders(Graphics::ManagedSurface *dst, const Common::String &header) const {
fillBackground(dst, _x, _y, _width, _height, 0);
drawCorners(dst, 11, _x, _y, _width, _height);
drawHeader(dst, _x, _y, _width, 4, header);
}
/*static*/
-void RequestData::fillBackground(Graphics::Surface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset) {
+void RequestData::fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset) {
bool detailHigh = true;
if (detailHigh) {
Graphics::Surface area = dst->getSubArea(Common::Rect(x, y, x + width, y + height));
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 0881a0c3aea..9db81033333 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -148,19 +148,19 @@ public:
Common::Array<Common::SharedPtr<Gadget>> _gadgets;
Common::String dump() const;
- void draw(Graphics::Surface *dst) const;
+ void draw(Graphics::ManagedSurface *dst) const;
static const Font *getMenuFont();
- static const Image *getCorner(int cornerNum);
+ const Image *getCorners();
- static void fillBackground(Graphics::Surface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
- static void drawCorners(Graphics::Surface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
- static void drawHeader(Graphics::Surface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header);
+ static void fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
+ static void drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
+ static void drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header);
private:
- void drawBackgroundNoSliders(Graphics::Surface *dst, const Common::String &header) const;
- void drawBackgroundWithSliderArea(Graphics::Surface *dst, int16 sliderHeight, const Common::String &header) const;
+ void drawBackgroundNoSliders(Graphics::ManagedSurface *dst, const Common::String &header) const;
+ void drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, int16 sliderHeight, const Common::String &header) const;
};
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 60c5668d5aa..22e346cf9b9 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -93,9 +93,9 @@ Common::String HotArea::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sHotArea<%s num %d cursor %d",
indent.c_str(), rect.dump("").c_str(), _num, _cursorNum);
str += _dumpStructList(indent, "enableConditions", enableConditions);
- str += _dumpStructList(indent, "opList1", opList1);
+ str += _dumpStructList(indent, "onRClickOps", onRClickOps);
str += _dumpStructList(indent, "opList2", opList2);
- str += _dumpStructList(indent, "onClickOps", onClickOps);
+ str += _dumpStructList(indent, "onLClickOps", onLClickOps);
str += "\n";
str += indent + ">";
return str;
@@ -224,9 +224,9 @@ bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
dst._num = s->readUint16LE();
dst._cursorNum = s->readUint16LE();
readConditionList(s, dst.enableConditions);
- readOpList(s, dst.opList1);
+ readOpList(s, dst.onRClickOps);
readOpList(s, dst.opList2);
- readOpList(s, dst.onClickOps);
+ readOpList(s, dst.onLClickOps);
return !s->err();
}
@@ -753,7 +753,7 @@ bool SDSScene::checkDialogActive() {
return retval;
}
-void SDSScene::drawActiveDialogBgs(Graphics::Surface *dst) {
+void SDSScene::drawActiveDialogBgs(Graphics::ManagedSurface *dst) {
for (auto &dlg : _dialogs) {
if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagOpening)) {
assert(dlg._state);
@@ -782,7 +782,7 @@ bool SDSScene::checkForClearedDialogs() {
return result;
}
-bool SDSScene::drawAndUpdateDialogs(Graphics::Surface *dst) {
+bool SDSScene::drawAndUpdateDialogs(Graphics::ManagedSurface *dst) {
bool retval = false;
const DgdsEngine *engine = static_cast<const DgdsEngine *>(g_engine);
for (auto &dlg : _dialogs) {
@@ -853,18 +853,23 @@ void SDSScene::globalOps(const Common::Array<uint16> &args) {
}
void SDSScene::mouseMoved(const Common::Point &pt) {
+ HotArea *area = findAreaUnderMouse(pt);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->setMouseCursor(area ? area->_cursorNum : 0);
+}
+
+void SDSScene::mouseLClicked(const Common::Point &pt) {
HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- engine->setMouseCursor(area->_cursorNum);
+ runOps(area->onLClickOps);
}
-void SDSScene::mouseClicked(const Common::Point &pt) {
+void SDSScene::mouseRClicked(const Common::Point &pt) {
HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
- runOps(area->onClickOps);
+ runOps(area->onRClickOps);
}
HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index a1041cad6e9..0ce7866e5b9 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -60,9 +60,9 @@ struct HotArea {
uint16 _num; //
uint16 _cursorNum;
Common::Array<struct SceneConditions> enableConditions;
- Common::Array<struct SceneOp> opList1;
+ Common::Array<struct SceneOp> onRClickOps;
Common::Array<struct SceneOp> opList2;
- Common::Array<struct SceneOp> onClickOps;
+ Common::Array<struct SceneOp> onLClickOps;
virtual Common::String dump(const Common::String &indent) const;
};
@@ -264,14 +264,15 @@ public:
Common::String dump(const Common::String &indent) const;
bool checkDialogActive();
- void drawActiveDialogBgs(Graphics::Surface *dst);
- bool drawAndUpdateDialogs(Graphics::Surface *dst);
+ void drawActiveDialogBgs(Graphics::ManagedSurface *dst);
+ bool drawAndUpdateDialogs(Graphics::ManagedSurface *dst);
bool checkForClearedDialogs();
void globalOps(const Common::Array<uint16> &args) override;
void mouseMoved(const Common::Point &pt);
- void mouseClicked(const Common::Point &pt);
+ void mouseLClicked(const Common::Point &pt);
+ void mouseRClicked(const Common::Point &pt);
private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 82ca9114ba9..fa26651968a 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -71,6 +71,7 @@ static const char *ttmOpName(uint16 op) {
case 0x1030: return "SET BRUSH";
case 0x1050: return "SELECT BMP";
case 0x1060: return "SELECT PAL";
+ case 0x1070: return "SELECT FONT";
case 0x1090: return "SELECT SONG";
case 0x10a0: return "SET SCENE";
case 0x1100: // fall through
@@ -79,6 +80,8 @@ static const char *ttmOpName(uint16 op) {
case 0x1200: return "GOTO";
case 0x1300: return "PLAY SFX";
case 0x2000: return "SET DRAW COLORS";
+ case 0x2010: return "SET FRAME";
+ case 0x2020: return "SET RANDOM DELAY";
case 0x4000: return "SET CLIP WINDOW";
case 0x4110: return "FADE OUT";
case 0x4120: return "FADE IN";
@@ -102,10 +105,7 @@ static const char *ttmOpName(uint16 op) {
case 0x00C0: return "FREE BACKGROUND";
case 0x0230: return "reset current music?";
- case 0x1070: return "SELECT FONT";
case 0x1310: return "STOP SFX";
- case 0x2010: return "SET FRAME";
- case 0x2020: return "SET TIMER";
case 0xa300: return "DRAW some string";
case 0xa400: return "DRAW FILLED CIRCLE";
case 0xa420: return "DRAW EMPTY CIRCLE";
@@ -172,7 +172,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
case 0x1030: { // SET BRUSH: id:int [-1:n]
seq._brushNum = ivals[0];
- _vm->_image->unload();
//if (seq._brushNum != -1) {
// TODO: This is probably not the best place to load this - it would be far more
// efficient to load all frames and pick during the draw.
@@ -183,7 +182,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
case 0x1050: // SELECT BMP: id:int [0:n]
seq._currentBmpId = ivals[0];
- _vm->_image->unload();
break;
case 0x1060: // SELECT PAL: id:int [0]
seq._currentPalId = ivals[0];
@@ -340,31 +338,26 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
// FALL THROUGH
- case 0xa500:
- debug("DRAW \"%s\" 0x%04x", env._scriptShapes[seq._currentBmpId].c_str(), op);
-
+ case 0xa500: {
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// This is kind of file system intensive, will likely have to change to store all the BMPs.
+ int frameno;
if (count == 4) {
- int tileId = ivals[2];
+ frameno = ivals[2];
+ // TODO: Check if the bmp id is changed here in CHINA or if a temp val is used.
seq._currentBmpId = ivals[3];
- if (tileId != -1) {
- _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], tileId);
- }
- } else if (!_vm->_image->isLoaded() && !env._scriptShapes[seq._currentBmpId].empty()) {
- // load on demand?
- //warning("trying to draw bmp %d (%s) that was "
- // " never loaded - do it on demand",
- // seq._currentBmpId, env._scriptShapes[seq._currentBmpId].c_str());
- _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
+ } else {
+ frameno = seq._brushNum;
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
- if (_vm->_image->isLoaded())
- _vm->_image->drawBitmap(ivals[0], ivals[1], seq._drawWin, _vm->getTopBuffer());
+ Common::SharedPtr<Image> img = env._scriptShapes[seq._currentBmpId];
+ if (img)
+ img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->getTopBuffer(), op == 0xa520);
else
- warning("request to draw null img at %d %d", ivals[0], ivals[1]);
+ warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
break;
+ }
case 0xa600: { // DRAW GETPUT
if (seq._executed) // this is a one-shot op.
break;
@@ -378,16 +371,19 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
r.left, r.top, Common::Rect(0, 0, r.width(), r.height()));
break;
}
- case 0xf010: // LOAD SCR: filename:str
+ case 0xf010: { // LOAD SCR: filename:str
if (seq._executed) // this is a one-shot op
break;
- _vm->_image->drawScreen(sval, _vm->getBottomBuffer());
+ Image *tmp = new Image(_vm->getResourceManager(), _vm->getDecompressor());
+ tmp->drawScreen(sval, _vm->getBottomBuffer());
+ delete tmp;
break;
+ }
case 0xf020: // LOAD BMP: filename:str
if (seq._executed) // this is a one-shot op
break;
- env._scriptShapes[seq._currentBmpId] = sval;
- _vm->_image->unload();
+ env._scriptShapes[seq._currentBmpId].reset(new Image(_vm->getResourceManager(), _vm->getDecompressor()));
+ env._scriptShapes[seq._currentBmpId]->loadBitmap(sval);
break;
case 0xf040: { // LOAD FONT: filename:str
if (seq._executed) // this is a one-shot op
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 2f5cd6be104..9ee3cb69a26 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -33,7 +33,7 @@ namespace Dgds {
class DgdsEngine;
class DgdsChunkReader;
-
+class Image;
class ScriptParserData : public ParserData {
public:
@@ -51,7 +51,7 @@ public:
uint16 _enviro;
uint16 _totalFrames;
Common::Array<int> _frameOffsets;
- Common::String _scriptShapes[6];
+ Common::SharedPtr<Image> _scriptShapes[6];
Common::Array<Common::Rect> _getPutAreas;
Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _getPutSurfaces;
int _scriptPals[6];
Commit: 617c3644691db8e4e85749ca68b63f46cd0fd998
https://github.com/scummvm/scummvm/commit/617c3644691db8e4e85749ca68b63f46cd0fd998
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix more scene op running
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 57ff4a1db3b..2c88f70cde3 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -222,7 +222,7 @@ Common::Error DgdsEngine::run() {
_gdsScene->runStartGameOps();
// To skip credits for testing
- changeScene(7, true);
+ changeScene(6, true);
} else if (getGameId() == GID_CHINA) {
_gameGlobals = new Globals();
@@ -258,7 +258,7 @@ Common::Error DgdsEngine::run() {
//getDebugger()->attach();
- debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
+ //debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
//debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 22e346cf9b9..cd1a6af8d30 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -444,6 +444,8 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
bool Scene::runOps(const Common::Array<SceneOp> &ops) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
+ if (!checkConditions(op._conditionList))
+ continue;
//debug("Exec %s", op.dump("").c_str());
switch(op._opCode) {
case kSceneOpChangeScene:
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index fa26651968a..9a87216f66c 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -623,7 +623,7 @@ bool ADSInterpreter::load(const Common::String &filename) {
}
for (uint i = segcount + 1; i < ARRAYSIZE(_adsData._segments); i++)
- _adsData._segments[i] = 0;
+ _adsData._segments[i] = -1;
_adsData._maxSegments = segcount + 1;
_adsData.filename = filename;
@@ -1000,6 +1000,16 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
_currentTTMSeq->_runFlag = kRunTypeStopped;
break;
}
+ case 0x2015: { // SET RUNFLAG 5, 3 params (ttmenv, ttmseq, ?)
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ debug("ADS: set runflag5 env %d seq %d unk %d", enviro, seqnum, unk);
+ _currentTTMSeq = findTTMSeq(enviro, seqnum);
+ if (_currentTTMSeq)
+ _currentTTMSeq->_runFlag = kRunType5;
+ break;
+ }
case 0x2020: { // RESET SEQ, 2 params (env, seq)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
@@ -1011,6 +1021,15 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
break;
}
+ case 0x3020: // RANDOM_NOOP, 1 param (proportion)
+ scr->readUint16LE();
+ return true;
+
+ case 0x3010: // RANDOM_START, 0 params
+ case 0x30FF: // RANDOM_END, 0 params
+ handleRandomOp(code, scr);
+ break;
+
case 0x4000: { // MOVE SEQ TO FRONT
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
@@ -1059,6 +1078,11 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
break;
}
+ case 0xF000:
+ if (_adsData._runningSegmentIdx != -1)
+ _adsData._state[_adsData._runningSegmentIdx] = 2;
+ return false;
+
case 0xF010: {// FADE_OUT, 1 param
int16 segment = scr->readSint16LE();
int16 idx = _adsData._runningSegmentIdx;
@@ -1076,15 +1100,6 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0xffff: // END
return false;
- case 0x3020: // RANDOM_NOOP, 1 param (proportion)
- scr->readUint16LE();
- return true;
-
- case 0x3010: // RANDOM_START, 0 params
- case 0x30FF: // RANDOM_END, 0 params
- handleRandomOp(code, scr);
- break;
-
//// unknown / to-be-implemented
case 0x1010: // unknown, 2 params
case 0x1020: // unknown, 2 params
@@ -1097,6 +1112,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
case 0xF200: // RUN_SCRIPT, 1 param
+ case 0xF210: // RUN_SCRIPT, 1 param
case 0xFF10:
case 0xFFF0: // END_IF, 0 params
default: {
@@ -1163,6 +1179,7 @@ bool ADSInterpreter::run() {
int16 state = _adsData._state[i];
int32 offset = _adsData._segments[i];
_adsData.scr->seek(offset);
+ // skip over the segment num
offset += 2;
/*int16 segnum =*/ _adsData.scr->readSint16LE();
if (state & 8) {
@@ -1270,7 +1287,6 @@ bool ADSInterpreter::runUntilBranchOpOrEnd() {
if (code == 0xffff)
return false;
more = handleOperation(code, scr);
- // FIXME: Breaking on hitBranchOp here doesn't work - probably need to fix the IF handling properly.
} while (!_adsData._hitBranchOp && more && scr->pos() < scr->size());
_adsData._hitBranchOp = false;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 9ee3cb69a26..0214b066435 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -108,11 +108,13 @@ public:
ADSData() : _initFlag(false), _maxSegments(0), _scriptDelay(-1),
_hitTTMOp0110(false), _hitBranchOp(false), _gotoTarget(-1),
_runningSegmentIdx(0) {
- for (int i = 0; i < ARRAYSIZE(_state); i++) {
+ for (int i = 0; i < ARRAYSIZE(_state); i++)
_state[i] = 8;
- }
+
+ for (int i = 0; i < ARRAYSIZE(_segments); i++)
+ _segments[i] = -1;
+
ARRAYCLEAR(_countdown);
- ARRAYCLEAR(_segments);
ARRAYCLEAR(_charWhile);
}
Common::Array<Common::String> _scriptNames;
Commit: 0be203599ef37f6744235ea831ad74c09e67fd2a
https://github.com/scummvm/scummvm/commit/0be203599ef37f6744235ea831ad74c09e67fd2a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Small fixes to dialog rendering. Still broken.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dialog.cpp
engines/dgds/request.cpp
engines/dgds/scene.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 2c88f70cde3..32356cac36a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -320,6 +320,8 @@ Common::Error DgdsEngine::run() {
}
if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
+ _scene->checkForClearedDialogs();
+
_gdsScene->runPreTickOps();
_scene->runPreTickOps();
@@ -341,6 +343,7 @@ Common::Error DgdsEngine::run() {
}
// Note: Hard-coded logic for DRAGON, check others
+ // FIXME; This doesn't work how I expect it should..
//if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
// _gdsScene->runPostTickOps();
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 958d7a7607a..9252193632d 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -111,7 +111,7 @@ void Dialog::drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
drawFindSelectionTxtOffset();
} else {
- _state->_loc = DgdsRect(x + 3, y + 3, w - 3, h - 3);
+ _state->_loc = DgdsRect(x + 3, y + 3, w - 6, h - 6);
drawForeground(dst, _bgColor, _str);
}
}
@@ -132,7 +132,7 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
}
if (stage == kDlgDrawStageBackground) {
- _state->_loc = DgdsRect(_rect.x + 6, _rect.y + 6, _rect.width - 6, _rect.height - 6);
+ _state->_loc = DgdsRect(_rect.x + 6, _rect.y + 6, _rect.width - 12, _rect.height - 12);
Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 986a6b26949..468f2dce460 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -525,23 +525,23 @@ void RequestData::drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, ui
const Common::SharedPtr<Graphics::ManagedSurface> *corners = cframes.data() + startNum;
for (int xoff = x + corners[0]->w; xoff < (x + width) - corners[2]->w; xoff += corners[1]->w)
- dst->blitFrom(*corners[1], Common::Point(xoff, y));
+ dst->transBlitFrom(*corners[1], Common::Point(xoff, y));
for (int xoff = x + corners[6]->w; xoff < (x + width) - corners[7]->w; xoff += corners[6]->w)
- dst->blitFrom(*corners[6], Common::Point(xoff, (y + height) - corners[6]->h));
+ dst->transBlitFrom(*corners[6], Common::Point(xoff, (y + height) - corners[6]->h));
for (int yoff = y + corners[0]->h; yoff < (y + height) - corners[5]->h; yoff += corners[3]->h) {
- dst->blitFrom(*corners[3], Common::Point(x, yoff));
+ dst->transBlitFrom(*corners[3], Common::Point(x, yoff));
}
for (int yoff = y + corners[2]->h; yoff < (y + height) - corners[7]->h; yoff += corners[4]->h) {
- dst->blitFrom(*corners[4], Common::Point((x + width) - corners[4]->w, yoff));
+ dst->transBlitFrom(*corners[4], Common::Point((x + width) - corners[4]->w, yoff));
}
- dst->blitFrom(*corners[0], Common::Point(x, y));
- dst->blitFrom(*corners[2], Common::Point((x + width) - corners[2]->w, y));
- dst->blitFrom(*corners[5], Common::Point(x, (y + height) - corners[5]->h));
- dst->blitFrom(*corners[7], Common::Point((x + width) - corners[7]->w, (y + height) - corners[7]->h));
+ dst->transBlitFrom(*corners[0], Common::Point(x, y));
+ dst->transBlitFrom(*corners[2], Common::Point((x + width) - corners[2]->w, y));
+ dst->transBlitFrom(*corners[5], Common::Point(x, (y + height) - corners[5]->h));
+ dst->transBlitFrom(*corners[7], Common::Point((x + width) - corners[7]->w, (y + height) - corners[7]->h));
}
/*static*/
@@ -576,29 +576,29 @@ void RequestData::drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, in
const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &corners = uiCorners->getFrames();
for (int xoff = _x + corners[0]->w; xoff < (_x + _width) - corners[3]->w; xoff += corners[2]->w) {
- dst->blitFrom(*corners[2], Common::Point(xoff, _y));
+ dst->transBlitFrom(*corners[2], Common::Point(xoff, _y));
}
for (int xoff = _x + 8 + corners[6]->w; xoff < (_x + 8 + _width - 16) - corners[8]->w; xoff += corners[7]->w) {
- dst->blitFrom(*corners[7], Common::Point(xoff, (_y + _height) - corners[7]->h));
+ dst->transBlitFrom(*corners[7], Common::Point(xoff, (_y + _height) - corners[7]->h));
}
for (int yoff = _y + corners[3]->h; yoff < (_y + sliderBgHeight) - corners[10]->h; yoff += corners[5]->h) {
- dst->blitFrom(*corners[5], Common::Point((_x + _width) - corners[5]->w, yoff));
+ dst->transBlitFrom(*corners[5], Common::Point((_x + _width) - corners[5]->w, yoff));
}
for (int yoff = _y + corners[1]->h; yoff < (_y + sliderBgHeight) - corners[9]->h; yoff += corners[4]->h) {
- dst->blitFrom(*corners[4], Common::Point(_x, yoff));
+ dst->transBlitFrom(*corners[4], Common::Point(_x, yoff));
}
for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[6]->h; yoff += corners[4]->h) {
- dst->blitFrom(*corners[4], Common::Point(_x + 8, yoff));
+ dst->transBlitFrom(*corners[4], Common::Point(_x + 8, yoff));
}
for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[8]->h; yoff += corners[5]->h) {
- dst->blitFrom(*corners[5], Common::Point((_x + 8 + _width - 16) - corners[5]->w, yoff));
+ dst->transBlitFrom(*corners[5], Common::Point((_x + 8 + _width - 16) - corners[5]->w, yoff));
}
- dst->blitFrom(*corners[1], Common::Point(_x, _y));
- dst->blitFrom(*corners[3], Common::Point((_x + _width) - corners[3]->w, _y));
- dst->blitFrom(*corners[6], Common::Point(_x + 8, (_y + _height) - corners[6]->h));
- dst->blitFrom(*corners[8], Common::Point((_x + _width - 8) - corners[8]->w, (_y + _height) - corners[8]->h));
- dst->blitFrom(*corners[9], Common::Point(_x, (_y + sliderBgHeight) - corners[9]->h));
- dst->blitFrom(*corners[10], Common::Point((_x + _width) - corners[10]->w, (_y + sliderBgHeight) - corners[10]->h));
+ dst->transBlitFrom(*corners[1], Common::Point(_x, _y));
+ dst->transBlitFrom(*corners[3], Common::Point((_x + _width) - corners[3]->w, _y));
+ dst->transBlitFrom(*corners[6], Common::Point(_x + 8, (_y + _height) - corners[6]->h));
+ dst->transBlitFrom(*corners[8], Common::Point((_x + _width - 8) - corners[8]->w, (_y + _height) - corners[8]->h));
+ dst->transBlitFrom(*corners[9], Common::Point(_x, (_y + sliderBgHeight) - corners[9]->h));
+ dst->transBlitFrom(*corners[10], Common::Point((_x + _width) - corners[10]->w, (_y + sliderBgHeight) - corners[10]->h));
drawHeader(dst, _x, _y, _width, 9, header);
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index cd1a6af8d30..1ee16202108 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -770,8 +770,9 @@ bool SDSScene::checkForClearedDialogs() {
bool result = false;
bool have8 = false;
for (auto &dlg : _dialogs) {
- if (!dlg.hasFlag(kDlgFlagHiFinished) && dlg.hasFlag(kDlgFlagLo8)) {
- have8 = true;
+ if (!dlg.hasFlag(kDlgFlagHiFinished)) {
+ if (dlg.hasFlag(kDlgFlagLo8))
+ have8 = true;
} else {
dlg.clear();
result = true;
Commit: 9b7f8d9bf3ce6f4c93bc2799a7e8538d1e2c08d9
https://github.com/scummvm/scummvm/commit/9b7f8d9bf3ce6f4c93bc2799a7e8538d1e2c08d9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix scene rendering a bit
The front and back buffers should only be combined after all scripts have
executed.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 32356cac36a..d75fccf95fa 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -61,6 +61,9 @@
#include "dgds/scripts.h"
#include "dgds/sound.h"
+// for frame contents debugging
+//#include "image/png.h"
+
namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
@@ -170,8 +173,16 @@ void DgdsEngine::setMouseCursor(uint num) {
return;
// TODO: Get mouse cursors from _gdsScene for hotspot info??
+ const Common::Array<MouseCursor> &cursors = _gdsScene->getCursorList();
+
+ if (num >= cursors.size())
+ error("Not enough cursor info, need %d have %d", num, cursors.size());
+
+ int hotx = cursors[num]._hotX;
+ int hoty = cursors[num]._hotY;
+
CursorMan.popAllCursors();
- CursorMan.pushCursor(*(_icons->getSurface(num)->surfacePtr()), 0, 0, 0, 0);
+ CursorMan.pushCursor(*(_icons->getSurface(num)->surfacePtr()), hotx, hoty, 0, 0);
CursorMan.showMouse(true);
}
@@ -351,6 +362,33 @@ Common::Error DgdsEngine::run() {
_scene->checkTriggers();
_scene->checkDialogActive();
+ _resData.blitFrom(_bottomBuffer);
+ _resData.transBlitFrom(_topBuffer);
+
+ /* For debugging, dump the frame contents..
+ {
+ Common::DumpFile outf;
+ uint32 now = g_engine->getTotalPlayTime();
+
+ byte palbuf[768];
+ g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
+
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-bottom.png", now)));
+ ::Image::writePNG(outf, *_bottomBuffer.surfacePtr(), palbuf);
+ outf.close();
+
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-top.png", now)));
+ ::Image::writePNG(outf, *_topBuffer.surfacePtr(), palbuf);
+ outf.close();
+
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-res.png", now)));
+ ::Image::writePNG(outf, *_resData.surfacePtr(), palbuf);
+ outf.close();
+ }
+ */
+
+ _topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+
_scene->drawAndUpdateDialogs(&_resData);
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 5ab53fe81cf..42ee09f6eb0 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -157,6 +157,8 @@ void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface
return;
}
+ _filename = filename;
+
surface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
DgdsChunkReader chunk(fileStream);
@@ -215,6 +217,8 @@ void Image::loadBitmap(const Common::String &filename) {
return;
}
+ _filename = filename;
+
int64 vqtpos = -1;
int64 scnpos = -1;
@@ -257,15 +261,11 @@ void Image::loadBitmap(const Common::String &filename) {
// TODO: Use mtxVals ?
} else if (chunk.isSection(ID_BIN)) {
for (auto & frame : _frames) {
- int32 tileOffset = 0;
- loadBitmap4(frame.get(), tileOffset, stream, false);
- tileOffset += frame->w * frame->h;
+ loadBitmap4(frame.get(), 0, stream, false);
}
} else if (chunk.isSection(ID_VGA)) {
for (auto & frame : _frames) {
- int32 tileOffset = 0;
- loadBitmap4(frame.get(), tileOffset, stream, true);
- tileOffset += frame->w * frame->h;
+ loadBitmap4(frame.get(), 0, stream, true);
}
} else if (chunk.isSection(ID_VQT)) {
// Postpone parsing this until we have the offsets, which come after.
@@ -296,17 +296,18 @@ void Image::loadBitmap(const Common::String &filename) {
nextOffset = ((nextOffset + 7) / 8) * 8;
}
} else {
- for (auto & frame : _frames) {
- uint32 subImgOffset = stream->readUint32LE();
- uint64 nextOffsetPos = stream->pos();
+ Common::Array<uint32> frameOffsets;
+ for (uint i = 0; i < _frames.size(); i++)
+ frameOffsets.push_back(stream->readUint32LE());
+
+ for (uint i = 0; i < _frames.size(); i++) {
if (vqtpos != -1) {
- fileStream->seek(vqtpos + subImgOffset);
- loadVQT(frame.get(), 0, fileStream);
+ fileStream->seek(vqtpos + frameOffsets[i]);
+ loadVQT(_frames[i].get(), 0, fileStream);
} else {
- fileStream->seek(scnpos + subImgOffset);
- loadSCN(frame.get(), fileStream);
+ fileStream->seek(scnpos + frameOffsets[i]);
+ loadSCN(_frames[i].get(), fileStream);
}
- stream->seek(nextOffsetPos);
}
}
// NOTE: This was proably the last chunk, but we don't check - should have
@@ -319,33 +320,43 @@ void Image::loadBitmap(const Common::String &filename) {
delete fileStream;
}
-void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &surface, bool flip) {
- Common::SharedPtr<Graphics::ManagedSurface> frame = _frames[frameno];
- const Common::Rect destRect(x, y, x + frame->w, y + frame->h);
+void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &destSurf, bool flip) const {
+ const Common::SharedPtr<Graphics::ManagedSurface> srcFrame = _frames[frameno];
+ const Common::Rect destRect(x, y, x + srcFrame->w, y + srcFrame->h);
Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
clippedDestRect.clip(destRect);
clippedDestRect.clip(drawWin);
- const Common::Point croppedBy(clippedDestRect.left - destRect.left, clippedDestRect.top - destRect.top);
+ Common::Point srcTopLeft(clippedDestRect.left - destRect.left, clippedDestRect.top - destRect.top);
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- const byte *src = (const byte *)frame->getPixels() + croppedBy.y * frame->pitch + croppedBy.x;
- byte *ptr = (byte *)surface.getBasePtr(clippedDestRect.left, clippedDestRect.top);
+ if (!rows or !columns) {
+ //debug("Draw at %d,%d frame %dx%d clipwin %d,%d-%d,%d gives null image area", x, y,
+ // srcFrame->w, srcFrame->h, drawWin.left, drawWin.top, drawWin.right, drawWin.bottom);
+ return;
+ }
+
+ // Flip should be applied before clip window
+ if (flip)
+ srcTopLeft.x = (srcFrame->w - srcTopLeft.x) - columns;
+
+ const byte *src = (const byte *)srcFrame->getBasePtr(srcTopLeft.x, srcTopLeft.y);
+ byte *dst = (byte *)destSurf.getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
if (flip) {
for (int j = 0; j < columns; ++j) {
if (src[columns - j - 1])
- ptr[j] = src[columns - j - 1];
+ dst[j] = src[columns - j - 1];
}
} else {
for (int j = 0; j < columns; ++j) {
if (src[j])
- ptr[j] = src[j];
+ dst[j] = src[j];
}
}
- ptr += surface.pitch;
- src += frame->pitch;
+ dst += destSurf.pitch;
+ src += srcFrame->pitch;
}
}
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index aad018b7864..6c79d554086 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -77,7 +77,7 @@ public:
void loadBitmap(const Common::String &filename);
int frameCount(const Common::String &filename);
- void drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &dst, bool flip = false);
+ void drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &dst, bool flip = false) const;
Common::SharedPtr<Graphics::ManagedSurface> getSurface(uint frameno);
@@ -88,6 +88,8 @@ public:
int loadedFrameCount() const { return _frames.size(); }
+ const Common::String &getFilename() const { return _filename; }
+
private:
void loadBitmap4(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream, bool highByte);
void loadBitmap8(Graphics::ManagedSurface *surf, uint32 toffset, Common::SeekableReadStream *stream);
@@ -97,6 +99,8 @@ private:
Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _frames;
ResourceManager *_resourceMan;
Decompressor *_decompressor;
+
+ Common::String _filename; // the file this was loaded from - only used for debugging
};
} // End of namespace Dgds
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 1ee16202108..123be7dce0c 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -946,9 +946,8 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
if (isVersionOver(" 1.208"))
readOpList(stream, _onChangeSceneOps);
readPerSceneGlobals(stream);
- Common::Array<struct MouseCursor> cursorList;
_iconFile = stream->readString();
- readMouseHotspotList(stream, cursorList);
+ readMouseHotspotList(stream, _cursorList);
readGameItemList(stream, _gameItems);
readStruct4List(stream, _struct4List2);
if (isVersionOver(" 1.205"))
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 0ce7866e5b9..09e6f3d6e3a 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -235,6 +235,8 @@ public:
int16 getGlobal(uint16 num);
int16 setGlobal(uint16 num, int16 val);
+ const Common::Array<struct MouseCursor> &getCursorList() { return _cursorList; }
+
private:
//byte _unk[32];
Common::String _iconFile;
@@ -242,6 +244,7 @@ private:
Common::Array<struct SceneOp> _startGameOps;
Common::Array<struct SceneOp> _quitGameOps;
Common::Array<struct SceneOp> _onChangeSceneOps;
+ Common::Array<struct MouseCursor> _cursorList;
Common::Array<struct PerSceneGlobal> _perSceneGlobals;
Common::Array<struct SceneStruct4> _struct4List1;
Common::Array<struct SceneStruct4> _struct4List2;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 9a87216f66c..e9c3905e5aa 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -159,10 +159,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->_soundPlayer->stopMusic();
break;
case 0x0ff0: { // REFRESH: void
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
- _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
- _vm->getTopBuffer().fillRect(bmpArea, 0);
} break;
case 0x1020: // SET DELAY: i:int [0..n]
// Delay of 240 should be 2 seconds, so this is in quarter-frames.
@@ -170,16 +166,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// in game frames, not millis.
_vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * 8.33));
break;
- case 0x1030: { // SET BRUSH: id:int [-1:n]
+ case 0x1030: // SET BRUSH: id:int [-1:n]
seq._brushNum = ivals[0];
- //if (seq._brushNum != -1) {
- // TODO: This is probably not the best place to load this - it would be far more
- // efficient to load all frames and pick during the draw.
- //if (!env._scriptShapes[seq._currentBmpId].empty())
- // _vm->_image->loadBitmap(env._scriptShapes[seq._currentBmpId], seq._brushNum);
- //}
break;
- }
case 0x1050: // SELECT BMP: id:int [0:n]
seq._currentBmpId = ivals[0];
break;
@@ -234,7 +223,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
}
case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
- // NOTE: params are x2/y2, NOT w/h
+ // NOTE: params are xmax/ymax, NOT w/h
seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
break;
case 0x4110: // FADE OUT: colorno,ncolors,targetcol,speed:byte
@@ -263,9 +252,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
// blt first?
_vm->_resData.blitFrom(_vm->getBottomBuffer());
- Graphics::Surface bmpSub = _vm->getTopBuffer().getSubArea(bmpArea);
- _vm->_resData.transBlitFrom(bmpSub, Common::Point(bmpArea.left, bmpArea.top));
- _vm->getTopBuffer().fillRect(bmpArea, 0);
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ _vm->getTopBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -298,9 +286,11 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
Common::Rect rect = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
env._getPutAreas[seq._currentGetPutId] = rect;
- // TODO: Check which buffer this should get things from
- Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getTopBuffer().format);
- surf->blitFrom(_vm->getTopBuffer(), rect, Common::Rect(0, 0, rect.width(), rect.height()));
+ // TODO: Check which buffer this should get things from .. composed buffer?
+ _vm->_resData.blitFrom(_vm->getBottomBuffer());
+ _vm->_resData.transBlitFrom(_vm->getTopBuffer());
+ Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_resData.format);
+ surf->blitFrom(_vm->_resData, rect, Common::Rect(0, 0, rect.width(), rect.height()));
env._getPutSurfaces[seq._currentGetPutId].reset(surf);
break;
}
@@ -929,7 +919,7 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
- debug(" ADSOP: 0x%04x", code);
+ debug(10, " ADSOP: 0x%04x", code);
switch (code) {
case 0x0001:
Commit: 01525c55b500cb8d82d9405e9f6cfe45d4499f48
https://github.com/scummvm/scummvm/commit/01525c55b500cb8d82d9405e9f6cfe45d4499f48
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add code to draw game clock
Always on for now, but can be easily changed to turn on and off.
Changed paths:
A engines/dgds/clock.cpp
A engines/dgds/clock.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/image.cpp
engines/dgds/module.mk
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
new file mode 100644
index 00000000000..e9cd825a618
--- /dev/null
+++ b/engines/dgds/clock.cpp
@@ -0,0 +1,131 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dgds/clock.h"
+#include "dgds/globals.h"
+#include "dgds/dgds.h"
+#include "dgds/font.h"
+#include "dgds/includes.h"
+#include "dgds/request.h"
+
+namespace Dgds {
+
+
+////////////////////////////////
+
+class DragonTimeGlobal : public ReadWriteGlobal<int16> {
+public:
+ DragonTimeGlobal(uint16 num, int16 *val, Clock &clock) : ReadWriteGlobal<int16>(num, val), _clock(clock) {}
+ int16 set(int16 val) override {
+ if (val != ReadWriteGlobal::get()) {
+ ReadWriteGlobal::set(val);
+ // notify that the time changed
+ _clock.addGameTime(0);
+ }
+ return val;
+ }
+
+private:
+ Clock &_clock;
+};
+
+Clock::Clock() : _visibleUser(true), _visibleScript(true), _days(0), _days2(0),
+ _hours(0), _mins(0), _gameMinsAdded(0) {
+}
+
+Global *Clock::getDaysGlobal(uint16 num) {
+ return new DragonTimeGlobal(num, &_days, *this);
+}
+
+Global *Clock::getDays2Global(uint16 num) {
+ return new ReadWriteGlobal<int16>(num, &_days2);
+}
+
+Global *Clock::getHoursGlobal(uint16 num) {
+ return new DragonTimeGlobal(num, &_hours, *this);
+}
+
+Global *Clock::getMinsGlobal(uint16 num) {
+ return new DragonTimeGlobal(num, &_mins, *this);
+}
+
+Global *Clock::getGameMinsAddedGlobal(uint16 num) {
+ return new ReadOnlyGlobal<int16>(num, &_gameMinsAdded);
+}
+
+static int16 DAYS_PER_MONTH[] = {
+ 31, 28, 31, 30,
+ 31, 30, 31, 31,
+ 30, 31, 30, 31
+};
+
+void Clock::addGameTime(int mins) {
+ _gameMinsAdded += mins;
+ int nhours = (_mins + mins) / 60;
+ _mins = (_mins + mins) % 60;
+ if (_mins < 0) {
+ _mins += 0x3c;
+ nhours--;
+ }
+ int ndays = (_hours + nhours) / 24;
+ _hours = (_hours + nhours) % 24;
+ if (_hours < 0) {
+ _hours += 24;
+ _days -= 1;
+ }
+ _days += ndays;
+ // TODO: if any change was made to days/hours/mins..
+ //if (plusmins + nhours + ndays != 0)
+ // UINT_39e5_0ffa = 0;
+}
+
+void Clock::draw(Graphics::ManagedSurface *surf) {
+ // FIXME: Temporarily ignore script visibility flag for testing.
+ if (!_visibleUser /*|| !_visibleScript*/)
+ return;
+
+ int month = 0;
+ int day = _days + _days2 + 1;
+ while (day > DAYS_PER_MONTH[month]) {
+ day -= DAYS_PER_MONTH[month];
+ month++;
+ if (month == ARRAYSIZE(DAYS_PER_MONTH))
+ month = 0;
+ }
+
+ Common::String clockStr = Common::String::format("%2d/%02d %2d:%02d", month + 1, day, _hours, _mins);
+
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const FontManager *fontman = engine->getFontMan();
+ const Font *font = fontman->getFont(FontManager::k4x5Font);
+ int width = font->getMaxCharWidth() * 12 + 3;
+ _drawPos.top = 0;
+ _drawPos.bottom = font->getFontHeight() + 6;
+ _drawPos.right = SCREEN_WIDTH;
+ _drawPos.left = SCREEN_WIDTH - width;
+
+ RequestData::fillBackground(surf, _drawPos.left + 2, _drawPos.top + 2, _drawPos.width() - 4, _drawPos.height() - 4, 65);
+ font->drawString(surf, clockStr, _drawPos.left + 3, _drawPos.top + 3, _drawPos.width(), 0);
+}
+
+
+
+} // end namespace Dgds
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
new file mode 100644
index 00000000000..f76a978d0c6
--- /dev/null
+++ b/engines/dgds/clock.h
@@ -0,0 +1,77 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_CLOCK_H
+#define DGDS_CLOCK_H
+
+#include "common/types.h"
+#include "common/rect.h"
+
+namespace Graphics {
+class ManagedSurface;
+}
+
+namespace Dgds {
+
+class Global;
+
+/* The game clock - drawn to the screen in Rise of the Dragon */
+class Clock {
+public:
+ Clock();
+ void addGameTime(int mins);
+
+ void setTime(int16 month, int16 day, int16 hour, int16 minute);
+
+ void draw(Graphics::ManagedSurface *surf);
+ void setVisibleUser(bool val) { _visibleUser = val; }
+ void setVisibleScript(bool val) { _visibleScript = val; }
+
+ void update();
+
+ Global *getMinsGlobal(uint16 num);
+ Global *getHoursGlobal(uint16 num);
+ Global *getDaysGlobal(uint16 num);
+ Global *getDays2Global(uint16 num);
+ Global *getGameMinsAddedGlobal(uint16 num);
+
+ const Common::Rect &getPos() const { return _drawPos; }
+
+private:
+
+ int16 _gameMinsAdded;
+
+ int16 _days;
+ int16 _days2;
+ int16 _hours;
+ int16 _mins;
+
+ Common::Rect _drawPos;
+
+ // Clock is shown if both are true;
+ bool _visibleScript;
+ bool _visibleUser;
+
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_CLOCK_H
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index d75fccf95fa..b8aadfc558e 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -70,8 +70,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
: Engine(syst), _fontManager(nullptr), _console(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
- _detailLevel(kDgdsDetailHigh), _showClockUser(false), _showClockScript(false),
- _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false), _random("dgds") {
+ _detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
+ _random("dgds") {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -186,6 +186,10 @@ void DgdsEngine::setMouseCursor(uint num) {
CursorMan.showMouse(true);
}
+void DgdsEngine::setShowClock(bool val) {
+ _clock.setVisibleScript(val);
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -219,8 +223,7 @@ Common::Error DgdsEngine::run() {
if (getGameId() == GID_DRAGON) {
_soundPlayer->loadSFX("SOUNDS.SNG");
- _gameGlobals = new DragonGlobals();
- _showClockUser = true;
+ _gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
@@ -360,6 +363,7 @@ Common::Error DgdsEngine::run() {
_scene->runPostTickOps();
_scene->checkTriggers();
+ _clock.draw(&_topBuffer);
_scene->checkDialogActive();
_resData.blitFrom(_bottomBuffer);
@@ -409,86 +413,4 @@ Common::SeekableReadStream *DgdsEngine::getResource(const Common::String &name,
return _resource->getResource(name, ignorePatches);
}
-
-
-// Parts of the old parse file code, kept temporarily for reference
-#if 0
-void DgdsEngine::parseFileInner(Common::Platform platform, Common::SeekableReadStream &file, const char *name) {
- const char *dot;
- DGDS_EX ex = 0;
-
- if ((dot = strrchr(name, '.'))) {
- ex = MKTAG24(dot[1], dot[2], dot[3]);
- }
-
- uint parent = 0;
-
- if (ex == EX_VIN || ex == EX_AMG) {
- Common::String line = file.readLine();
- while (!file.eos()) {
- if (!line.empty())
- debug(" \"%s\"", line.c_str());
- line = file.readLine();
- }
- } else {
- DgdsChunkReader chunk(&file);
- while (chunk.readNextHeader(ex, name)) {
- if (chunk.isContainer()) {
- parent = chunk.getId();
- continue;
- }
-
- chunk.readContent(_decompressor);
- Common::SeekableReadStream *stream = chunk.getContent();
-
- switch (ex) {
- case EX_TDS:
- /* Heart of China. */
- if (chunk.isSection(ID_THD)) {
- uint32 mark = stream->readUint32LE();
- debug(" 0x%X", mark);
-
- char version[7];
- stream->read(version, sizeof(version));
- debug(" \"%s\"", version);
-
- byte ch;
- Common::String bmpName;
- while ((ch = stream->readByte()))
- bmpName += ch;
- debug(" \"%s\"", bmpName.c_str());
-
- Common::String personName;
- while ((ch = stream->readByte()))
- personName += ch;
- debug(" \"%s\"", personName.c_str());
- }
- break;
- case EX_DDS:
- /* Heart of China. */
- if (chunk.isSection(ID_DDS)) {
- uint32 mark;
-
- mark = stream->readUint32LE();
- debug(" 0x%X", mark);
-
- char version[7];
- stream->read(version, sizeof(version));
- debug(" \"%s\"", version);
-
- byte ch;
- Common::String tag;
- while ((ch = stream->readByte()))
- tag += ch;
- debug(" \"%s\"", tag.c_str());
- }
- break;
- default:
- break;
- }
- }
- }
-}
-#endif
-
} // End of namespace Dgds
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 8157dac2634..3f1e7cb4b19 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -37,6 +37,7 @@
#include "gui/debugger.h"
#include "dgds/resource.h"
+#include "dgds/clock.h"
namespace Dgds {
@@ -97,16 +98,14 @@ private:
DgdsDetailLevel _detailLevel;
int _textSpeed;
- // Clock is shown if both are true;
- bool _showClockUser;
- bool _showClockScript;
-
bool _justChangedScene1;
bool _justChangedScene2;
Common::RandomSource _random;
Common::Point _lastMouse; // originals start mouse at 0,0.
+ Clock _clock;
+
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
virtual ~DgdsEngine();
@@ -132,13 +131,15 @@ public:
DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
int getTextSpeed() const { return _textSpeed; }
- void setShowClock(bool val) { _showClockScript = val; }
+ void setShowClock(bool val);
ADSInterpreter *adsInterpreter() { return _adsInterp; }
bool justChangedScene1() const { return _justChangedScene1; }
bool justChangedScene2() const { return _justChangedScene2; }
Common::RandomSource &getRandom() { return _random; }
Common::Point getLastMouse() const { return _lastMouse; }
+ Clock &getClock() { return _clock; }
+
private:
void loadCorners(const Common::String &filename);
void loadIcons();
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 9252193632d..3ffe8bb9489 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -557,7 +557,7 @@ Common::String Dialog::dump(const Common::String &indent) const {
Common::String DialogState::dump(const Common::String &indent) const {
return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>",
indent.c_str(), _hideTime, _loc.dump("").c_str(), _lastMouseX, _lastMouseY, _charWidth,
- _charHeight, _strMouseLoc, _selectedAction);
+ _charHeight, _strMouseLoc, (void *)_selectedAction);
}
Common::String DialogAction::dump(const Common::String &indent) const {
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 2a9b0123065..1df84baf95f 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -24,23 +24,6 @@
namespace Dgds {
-template<typename T> class ReadOnlyGlobal : public Global {
-public:
- ReadOnlyGlobal(uint16 num, const T *val) : Global(num), _val(val) {}
- int16 get() override { return *_val; }
- int16 set(int16 val) override { return *_val; }
-private:
- const T *_val;
-};
-
-template<typename T> class ReadWriteGlobal : public Global {
-public:
- ReadWriteGlobal(uint16 num, T *val) : Global(num), _val(val) {}
- int16 get() override { return *_val; }
- int16 set(int16 val) override { *_val = val; return *_val; }
-private:
- T *_val;
-};
typedef ReadOnlyGlobal<int16> ROI16Global;
typedef ReadWriteGlobal<int16> RWI16Global;
@@ -130,78 +113,27 @@ private:
////////////////////////////////
-class DragonTimeGlobal : public ReadWriteGlobal<int> {
-public:
- DragonTimeGlobal(uint16 num, int *val, DragonGameTime &time) : ReadWriteGlobal<int>(num, val), _time(time) {}
- int16 set(int16 val) override {
- if (val != ReadWriteGlobal::get()) {
- ReadWriteGlobal::set(val);
- _time.addGameTime(0);
- }
- return val;
- }
-
-private:
- DragonGameTime &_time;
-};
-
-DragonGameTime::DragonGameTime() : _gameTimeDays(0), _gameTimeMins(0), _gameTimeHours(0), _gameMinsAdded(0) {}
-
-Global *DragonGameTime::getDaysGlobal(uint16 num) {
- return new DragonTimeGlobal(num, &_gameTimeDays, *this);
-}
-
-Global *DragonGameTime::getHoursGlobal(uint16 num) {
- return new DragonTimeGlobal(num, &_gameTimeHours, *this);
-}
-
-Global *DragonGameTime::getMinsGlobal(uint16 num) {
- return new DragonTimeGlobal(num, &_gameTimeMins, *this);
-}
-
-void DragonGameTime::addGameTime(int mins) {
- _gameMinsAdded += mins;
- int nhours = (_gameTimeMins + mins) / 60;
- _gameTimeMins = (_gameTimeMins + mins) % 60;
- if (_gameTimeMins < 0) {
- _gameTimeMins += 0x3c;
- nhours--;
- }
- int ndays = (_gameTimeHours + nhours) / 24;
- _gameTimeHours = (_gameTimeHours + nhours) % 24;
- if (_gameTimeHours < 0) {
- _gameTimeHours += 24;
- _gameTimeDays -= 1;
- }
- _gameTimeDays += ndays;
- // TODO: if any change was made to days/hours/mins..
- //if (plusmins + nhours + ndays != 0)
- // UINT_39e5_0ffa = 0;
-}
-
-////////////////////////////////
-
-DragonGlobals::DragonGlobals() : Globals(),
+DragonGlobals::DragonGlobals(Clock &_clock) : Globals(),
_gameCounterTicksUp(0), _gameCounterTicksDown(0), _lastOpcode1SceneChageNum(0),
_sceneOp12SceneNum(0), _currentSelectedItem(0), _gameMinsToAdd_1(0), _gameMinsToAdd_2(0),
-_gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0), _gameDays2(0),
+_gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0),
_sceneOpcode15Flag(0), _sceneOpcode15Val(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
- _globals.push_back(new ROI16Global(1, &_time._gameMinsAdded));
+ _globals.push_back(_clock.getGameMinsAddedGlobal(1));
_globals.push_back(new ROI16Global(0x64, &_gameCounterTicksUp));
_globals.push_back(new ROI16Global(0x62, &_lastOpcode1SceneChageNum));
_globals.push_back(new RWI16Global(0x61, &_sceneOp12SceneNum));
_globals.push_back(new RWI16Global(0x60, &_currentSelectedItem));
- _globals.push_back(_time.getDaysGlobal(0x5F));
- _globals.push_back(_time.getHoursGlobal(0x5E));
- _globals.push_back(_time.getMinsGlobal(0x5D));
+ _globals.push_back(_clock.getDaysGlobal(0x5F));
+ _globals.push_back(_clock.getHoursGlobal(0x5E));
+ _globals.push_back(_clock.getMinsGlobal(0x5D));
_globals.push_back(new RWI16Global(0x5C, &_gameMinsToAdd_1));
_globals.push_back(new RWI16Global(0x5B, &_gameMinsToAdd_2));
_globals.push_back(new RWI16Global(0x5A, &_gameMinsToAdd_3));
_globals.push_back(new RWI16Global(0x59, &_gameMinsToAdd_4));
_globals.push_back(new RWI16Global(0x58, &_gameMinsToAdd_5));
_globals.push_back(new RWI16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
- _globals.push_back(new RWI16Global(0x56, &_gameDays2));
+ _globals.push_back(_clock.getDays2Global(0x56));
_globals.push_back(new RWI16Global(0x55, &_sceneOpcode15Flag));
_globals.push_back(new RWI16Global(0x54, &_sceneOpcode15Val));
_globals.push_back(new RWI16Global(0x20, &_sceneOpcode100Var));
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 04fcc38672d..2e8b461892c 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -29,6 +29,8 @@
namespace Dgds {
+class Clock;
+
/**
* The original game uses a struct here with 3 entries:
* 1. global variable num (uint16)
@@ -49,6 +51,24 @@ public:
virtual uint16 getNum() const { return _num; }
};
+template<typename T> class ReadOnlyGlobal : public Global {
+public:
+ ReadOnlyGlobal(uint16 num, const T *val) : Global(num), _val(val) {}
+ int16 get() override { return *_val; }
+ int16 set(int16 val) override { return *_val; }
+private:
+ const T *_val;
+};
+
+template<typename T> class ReadWriteGlobal : public Global {
+public:
+ ReadWriteGlobal(uint16 num, T *val) : Global(num), _val(val) {}
+ int16 get() override { return *_val; }
+ int16 set(int16 val) override { *_val = val; return *_val; }
+private:
+ T *_val;
+};
+
class Globals {
public:
@@ -77,26 +97,10 @@ private:
int getOffsetForVal(uint16 val);
};
-class DragonGameTime {
-public:
- DragonGameTime();
- void addGameTime(int mins);
-
- Global *getMinsGlobal(uint16 num);
- Global *getHoursGlobal(uint16 num);
- Global *getDaysGlobal(uint16 num);
-
- int16 _gameMinsAdded;
-
-private:
- int _gameTimeDays;
- int _gameTimeHours;
- int _gameTimeMins;
-};
class DragonGlobals : public Globals {
public:
- DragonGlobals();
+ DragonGlobals(Clock &clock);
private:
int16 _gameCounterTicksUp;
@@ -110,14 +114,13 @@ private:
int16 _gameMinsToAdd_4;
int16 _gameMinsToAdd_5;
int16 _gameGlobal0x57;
- int16 _gameDays2;
int16 _sceneOpcode15Flag;
int16 _sceneOpcode15Val;
int16 _sceneOpcode100Var;
int16 _arcadeModeFlag_3cdc;
int16 _opcode106EndMinutes;
DragonDataTable _table;
- DragonGameTime _time;
+ // Clock _clock; // kept in the engine
// uint16 _detailSliderSetting; // kept in the engine
};
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 42ee09f6eb0..dea53c562d4 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -331,7 +331,7 @@ void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin,
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- if (!rows or !columns) {
+ if (!rows || !columns) {
//debug("Draw at %d,%d frame %dx%d clipwin %d,%d-%d,%d gives null image area", x, y,
// srcFrame->w, srcFrame->h, drawWin.left, drawWin.top, drawWin.right, drawWin.bottom);
return;
@@ -535,13 +535,13 @@ uint32 Image::loadVQT(Graphics::ManagedSurface *surf, uint32 toffset, Common::Se
// Ref: https://moddingwiki.shikadi.net/wiki/The_Incredible_Machine_Image_Format
//
bool Image::loadSCN(Graphics::ManagedSurface *surf, Common::SeekableReadStream *stream) {
- uint32 tw = surf->w;
- uint32 th = surf->h;
+ int32 tw = surf->w;
+ int32 th = surf->h;
assert(th != 0);
byte *dst = (byte *)surf->getPixels();
- uint32 y = 0;
- uint32 x = 0;
+ int32 y = 0;
+ int32 x = 0;
const byte addVal = stream->readByte();
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index ce46714ed6f..581733fa6c5 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/dgds
MODULE_OBJS := \
+ clock.o \
console.o \
decompress.o \
dgds.o \
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 123be7dce0c..58f4a74632a 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -389,14 +389,6 @@ bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<Di
}
-void SDSScene::enableTrigger(uint16 num) {
- for (auto &trigger : _triggers) {
- if (trigger._num == num)
- trigger._enabled = true;
- }
-}
-
-
void Scene::segmentStateOps(const Common::Array<uint16> &args) {
ADSInterpreter *interp = static_cast<DgdsEngine *>(g_engine)->adsInterpreter();
@@ -591,6 +583,7 @@ bool SDSScene::load(const Common::String &filename, ResourceManager *resourceMan
return result;
}
+
bool SDSScene::parse(Common::SeekableReadStream *stream) {
_magic = stream->readUint32LE();
_version = stream->readString();
@@ -655,6 +648,14 @@ Common::String SDSScene::dump(const Common::String &indent) const {
return str;
}
+
+void SDSScene::enableTrigger(uint16 num) {
+ for (auto &trigger : _triggers) {
+ if (trigger._num == num)
+ trigger._enabled = true;
+ }
+}
+
void SDSScene::checkTriggers() {
// scene can change on these triggers. if that happens we stop.
int startSceneNum = _num;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 09e6f3d6e3a..313a1ae884b 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -64,6 +64,8 @@ struct HotArea {
Common::Array<struct SceneOp> opList2;
Common::Array<struct SceneOp> onLClickOps;
+ virtual ~HotArea() {}
+
virtual Common::String dump(const Common::String &indent) const;
};
Commit: 72535a9c61725bd9dff7995d35e372acb857b5bc
https://github.com/scummvm/scummvm/commit/72535a9c61725bd9dff7995d35e372acb857b5bc
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add inventory button
Still does nothing, but screen looks more correct now.
Changed paths:
engines/dgds/clock.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/includes.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index e9cd825a618..10b0b4a31d2 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -110,9 +110,9 @@ void Clock::draw(Graphics::ManagedSurface *surf) {
if (month == ARRAYSIZE(DAYS_PER_MONTH))
month = 0;
}
-
+
Common::String clockStr = Common::String::format("%2d/%02d %2d:%02d", month + 1, day, _hours, _mins);
-
+
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const FontManager *fontman = engine->getFontMan();
const Font *font = fontman->getFont(FontManager::k4x5Font);
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index b8aadfc558e..fa81be83b0b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -152,6 +152,9 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
setMouseCursor(0);
_scene->load(sceneFile, _resource, _decompressor);
+ // These are done inside the load function in the original.. cleaner here..
+ _scene->addInvButtonToHotAreaList();
+ setShowClock(true);
if (_scene->getMagic() != _gdsScene->getMagic())
error("Scene %s magic does (0x%08x) not match GDS magic (0x%08x)", sceneFile.c_str(), _scene->getMagic(), _gdsScene->getMagic());
@@ -190,6 +193,16 @@ void DgdsEngine::setShowClock(bool val) {
_clock.setVisibleScript(val);
}
+void DgdsEngine::checkDrawInventoryButton() {
+ if (_gdsScene->getCursorList().size() < 2 || _scene->getHotAreas().size() < 2 || _scene->getHotAreas()[0]._num != 0)
+ return;
+
+ int x = SCREEN_WIDTH - _icons->width(2) - 5;
+ int y = SCREEN_HEIGHT - _icons->height(2) - 5;
+ static const Common::Rect drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _icons->drawBitmap(2, x, y, drawWin, _topBuffer);
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -363,6 +376,7 @@ Common::Error DgdsEngine::run() {
_scene->runPostTickOps();
_scene->checkTriggers();
+ checkDrawInventoryButton();
_clock.draw(&_topBuffer);
_scene->checkDialogActive();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 3f1e7cb4b19..30e2fe5c2b2 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -124,6 +124,7 @@ public:
GDSScene *getGDSScene() { return _gdsScene; }
const FontManager *getFontMan() const { return _fontManager; }
const Common::SharedPtr<Image> &getUICorners() { return _corners; }
+ const Common::SharedPtr<Image> &getIcons() { return _icons; }
bool changeScene(int sceneNum, bool runChangeOps);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
@@ -143,6 +144,7 @@ public:
private:
void loadCorners(const Common::String &filename);
void loadIcons();
+ void checkDrawInventoryButton();
};
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
index 17bf44773aa..d4f0ea72760 100644
--- a/engines/dgds/includes.h
+++ b/engines/dgds/includes.h
@@ -90,4 +90,4 @@ namespace Dgds {
} // End of namespace Dgds
-#endif // DGDS_MOVIES_H
+#endif // DGDS_INCLUDES_H
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 58f4a74632a..50eb1d4350d 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -38,6 +38,7 @@
#include "dgds/scripts.h"
#include "dgds/font.h"
#include "dgds/globals.h"
+#include "dgds/image.h"
namespace Dgds {
@@ -121,6 +122,8 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpHideMouse: return "sceneOpHideMouse";
case kSceneOpMeanwhile: return "meanwhile";
case kSceneOpOpenPlaySkipIntroMenu: return "openPlaySkipIntroMovie";
+ case kSceneOpShowInvButton: return "showInvButton";
+ case kSceneOpHideInvButton: return "hideInvButton";
default:
return Common::String::format("sceneOp%d", (int)code);
}
@@ -484,8 +487,11 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpMeanwhile:
warning("TODO: Implement meanwhile screen");
break;
- case kSceneOp10:
- warning("TODO: Implement scene op 10 (find SDS hot spot?)");
+ case kSceneOpShowInvButton:
+ static_cast<DgdsEngine *>(g_engine)->getScene()->addInvButtonToHotAreaList();
+ break;
+ case kSceneOpHideInvButton:
+ static_cast<DgdsEngine *>(g_engine)->getScene()->removeInvButtonFromHotAreaList();
break;
case kSceneOpOpenPlaySkipIntroMenu:
warning("TODO: Implement scene op 107 (inject key code 0xfc, open menu to play intro or not)");
@@ -887,6 +893,31 @@ HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
return nullptr;
}
+void SDSScene::addInvButtonToHotAreaList() {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::Array<MouseCursor> &cursors = engine->getGDSScene()->getCursorList();
+ const Common::SharedPtr<Image> &icons = engine->getIcons();
+
+ if (cursors.empty() || !icons || icons->loadedFrameCount() <= 2 || _num == 2)
+ return;
+
+ HotArea area;
+ area._num = 0;
+ area._cursorNum = 0;
+ area.rect.width = icons->width(2);
+ area.rect.height = icons->height(2);
+ area.rect.x = SCREEN_WIDTH - area.rect.width;
+ area.rect.y = SCREEN_HEIGHT - area.rect.height;
+
+ _hotAreaList.insert_at(0, area);
+}
+
+void SDSScene::removeInvButtonFromHotAreaList() {
+ if (_hotAreaList.size() && _hotAreaList[0]._num == 0)
+ _hotAreaList.remove_at(0);
+}
+
+
GDSScene::GDSScene() {
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 313a1ae884b..1d6c9e3daac 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -79,8 +79,8 @@ enum SceneOpCode {
kSceneOpGiveItem = 6, // args: item num. give item?
kSceneOp7 = 7, // args: none.
kSceneOpShowDlg = 8, // args: dialogue number. show dialogue?
- kSceneOp9 = 9, // args: none.
- kSceneOp10 = 10, // args: none. Clean up the hot area list?
+ kSceneOpShowInvButton = 9, // args: none.
+ kSceneOpHideInvButton = 10, // args: none.
kSceneOpEnableTrigger = 11, // args: trigger num
kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
kSceneOp13 = 13, // args: none.
@@ -279,6 +279,11 @@ public:
void mouseLClicked(const Common::Point &pt);
void mouseRClicked(const Common::Point &pt);
+ void addInvButtonToHotAreaList();
+ void removeInvButtonFromHotAreaList();
+
+ const Common::Array<struct HotArea> &getHotAreas() { return _hotAreaList; }
+
private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
void enableTrigger(uint16 num) override;
Commit: a84fa4f99862e8bf1a117cc9f05bcd9e34769e44
https://github.com/scummvm/scummvm/commit/a84fa4f99862e8bf1a117cc9f05bcd9e34769e44
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start to implement inventory and item stuff
Changed paths:
A engines/dgds/inventory.cpp
A engines/dgds/inventory.h
engines/dgds/clock.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/module.mk
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index f76a978d0c6..3c6b6364018 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -42,7 +42,7 @@ public:
void setTime(int16 month, int16 day, int16 hour, int16 minute);
void draw(Graphics::ManagedSurface *surf);
- void setVisibleUser(bool val) { _visibleUser = val; }
+ void toggleVisibleUser() { _visibleUser = !_visibleUser; }
void setVisibleScript(bool val) { _visibleScript = val; }
void update();
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index fa81be83b0b..7326c7c7c3a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -54,6 +54,7 @@
#include "dgds/globals.h"
#include "dgds/image.h"
#include "dgds/includes.h"
+#include "dgds/inventory.h"
#include "dgds/menu.h"
#include "dgds/parser.h"
#include "dgds/request.h"
@@ -67,7 +68,7 @@
namespace Dgds {
DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
- : Engine(syst), _fontManager(nullptr), _console(nullptr),
+ : Engine(syst), _fontManager(nullptr), _console(nullptr), _inventory(nullptr),
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
@@ -100,6 +101,7 @@ DgdsEngine::~DgdsEngine() {
delete _soundPlayer;
delete _fontManager;
delete _menu;
+ delete _inventory;
_icons.reset();
_corners.reset();
@@ -194,7 +196,8 @@ void DgdsEngine::setShowClock(bool val) {
}
void DgdsEngine::checkDrawInventoryButton() {
- if (_gdsScene->getCursorList().size() < 2 || _scene->getHotAreas().size() < 2 || _scene->getHotAreas()[0]._num != 0)
+ if (_gdsScene->getCursorList().size() < 2 || _icons->loadedFrameCount() < 2 ||
+ _scene->getHotAreas().size() < 1 || _scene->getHotAreas()[0]._num != 0)
return;
int x = SCREEN_WIDTH - _icons->width(2) - 5;
@@ -216,6 +219,7 @@ Common::Error DgdsEngine::run() {
_fontManager = new FontManager();
_menu = new Menu();
_adsInterp = new ADSInterpreter(this);
+ _inventory = new Inventory();
setDebugger(_console);
@@ -307,6 +311,9 @@ Common::Error DgdsEngine::run() {
case Common::KEYCODE_F5:
triggerMenu = true;
break;
+ case Common::KEYCODE_c:
+ _clock.toggleVisibleUser();
+ break;
default:
break;
}
@@ -376,7 +383,12 @@ Common::Error DgdsEngine::run() {
_scene->runPostTickOps();
_scene->checkTriggers();
- checkDrawInventoryButton();
+ if (_inventory->isOpen()) {
+ _inventory->draw(_topBuffer);
+ } else {
+ _gdsScene->drawItems(_topBuffer);
+ checkDrawInventoryButton();
+ }
_clock.draw(&_topBuffer);
_scene->checkDialogActive();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 30e2fe5c2b2..023b2dd70d1 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -47,6 +47,7 @@ class Decompressor;
class Image;
class GamePalettes;
class FontManager;
+class Inventory;
class SDSScene;
class GDSScene;
class Sound;
@@ -89,6 +90,7 @@ private:
ADSInterpreter *_adsInterp;
GamePalettes *_gamePals;
Globals *_gameGlobals;
+ Inventory *_inventory;
FontManager *_fontManager;
Common::SharedPtr<Image> _corners;
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
new file mode 100644
index 00000000000..c09ef4b7215
--- /dev/null
+++ b/engines/dgds/inventory.cpp
@@ -0,0 +1,34 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "graphics/managed_surface.h"
+#include "dgds/inventory.h"
+
+namespace Dgds {
+
+Inventory::Inventory() : _isOpen(false) {
+}
+
+void Inventory::draw(Graphics::ManagedSurface &surf) {
+ // TODO: Implement me.
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
new file mode 100644
index 00000000000..60f28d5d6bd
--- /dev/null
+++ b/engines/dgds/inventory.h
@@ -0,0 +1,44 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_INVENTORY_H
+#define DGDS_INVENTORY_H
+
+namespace Graphics {
+class ManagedSurface;
+}
+
+namespace Dgds {
+
+class Inventory {
+public:
+ Inventory();
+
+ bool isOpen() const { return _isOpen; }
+ void draw(Graphics::ManagedSurface &surf);
+
+private:
+ bool _isOpen;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_INVENTORY_H
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 581733fa6c5..6ac27bc0751 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS := \
font.o \
globals.o \
image.o \
+ inventory.o \
menu.o \
metaengine.o \
music.o \
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 50eb1d4350d..d006461092a 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -112,6 +112,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
case kSceneOpSetItemAttr: return "setitemattr?";
case kSceneOpGiveItem: return "giveitem?";
+ case kSceneOpOpenInventory: return "openInventory";
case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
@@ -156,7 +157,7 @@ Common::String GameItem::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
"%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d flags %d unk14 %d",
indent.c_str(), super.c_str(), indent.c_str(), field10_0x24,
- _iconNum, field12_0x28, _flags, field14_0x2c);
+ _iconNum, _inSceneNum, _flags, field14_0x2c);
str += _dumpStructList(indent, "opList4", opList4);
str += _dumpStructList(indent, "opList5", opList5);
str += "\n";
@@ -250,7 +251,7 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
}
for (GameItem &dst : list) {
dst._iconNum = s->readUint16LE();
- dst.field12_0x28 = s->readUint16LE();
+ dst._inSceneNum = s->readUint16LE();
dst.field14_0x2c = s->readUint16LE();
if (!isVersionUnder(" 1.211"))
dst._flags = s->readUint16LE() & 0xfffe;
@@ -456,6 +457,15 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpSegmentStateOps:
segmentStateOps(op._args);
break;
+ case kSceneOpSetItemAttr:
+ warning("TODO: Implement set item attr(?) scene op");
+ break;
+ case kSceneOpGiveItem:
+ warning("TODO: Implement give item(?) scene op");
+ break;
+ case kSceneOpOpenInventory:
+ warning("TODO: Implement open inventory scene op");
+ break;
case kSceneOpShowDlg:
showDialog(op._args[0]);
break;
@@ -901,6 +911,9 @@ void SDSScene::addInvButtonToHotAreaList() {
if (cursors.empty() || !icons || icons->loadedFrameCount() <= 2 || _num == 2)
return;
+ if (_hotAreaList[0]._num == 0)
+ return;
+
HotArea area;
area._num = 0;
area._cursorNum = 0;
@@ -1057,5 +1070,34 @@ int16 GDSScene::setGlobal(uint16 num, int16 val) {
return gameGlobals->setGlobal(num, val);
}
+void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::SharedPtr<Image> &icons = engine->getIcons();
+ int currentScene = engine->getScene()->getNum();
+ if (icons->loadedFrameCount() < 3)
+ return;
+
+ int xoff = 20;
+ const Common::Rect screenWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ // Don't overlap the inventory icon.
+ const int maxx = SCREEN_WIDTH - (icons->width(2) + 10);
+ for (auto &item : _gameItems) {
+ if (item._inSceneNum == currentScene /* TODO: && item != draggingItem*/) {
+ if (!(item._flags & 1)) {
+ // Dropped item.
+ if (xoff + item.rect.width > maxx)
+ xoff = 20;
+ int yoff = SCREEN_HEIGHT - (item.rect.height + 2);
+ item.rect.x = xoff;
+ item.rect.y = yoff;
+ icons->drawBitmap(item._iconNum, xoff, yoff, screenWin, surf);
+ xoff += (item.rect.width + 6);
+ } else {
+ icons->drawBitmap(item._iconNum, item.rect.x, item.rect.y, screenWin, surf);
+ }
+ }
+ }
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 1d6c9e3daac..8e460975fce 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -77,8 +77,8 @@ enum SceneOpCode {
kSceneOpSegmentStateOps = 4, // args: array of uint pairs [op seg, op seg], term with 0,0 that modify segment states
kSceneOpSetItemAttr = 5, // args: [item num, item param 0x28, item param 0x2c]. set item attrs?
kSceneOpGiveItem = 6, // args: item num. give item?
- kSceneOp7 = 7, // args: none.
- kSceneOpShowDlg = 8, // args: dialogue number. show dialogue?
+ kSceneOpOpenInventory = 7, // args: none.
+ kSceneOpShowDlg = 8, // args: dialogue number.
kSceneOpShowInvButton = 9, // args: none.
kSceneOpHideInvButton = 10, // args: none.
kSceneOpEnableTrigger = 11, // args: trigger num
@@ -116,7 +116,7 @@ struct GameItem : public HotArea {
Common::Array<struct SceneOp> opList5;
uint16 field10_0x24;
uint16 _iconNum;
- uint16 field12_0x28;
+ uint16 _inSceneNum;
uint16 _flags;
uint16 field14_0x2c;
@@ -238,6 +238,7 @@ public:
int16 setGlobal(uint16 num, int16 val);
const Common::Array<struct MouseCursor> &getCursorList() { return _cursorList; }
+ void drawItems(Graphics::ManagedSurface &surf);
private:
//byte _unk[32];
Commit: 2f44f3f1a214a884772942a8be3f700b8a7ceb04
https://github.com/scummvm/scummvm/commit/2f44f3f1a214a884772942a8be3f700b8a7ceb04
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Start to implement Inventory screen
Changed paths:
engines/dgds/clock.cpp
engines/dgds/clock.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index 10b0b4a31d2..d933756542b 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -97,11 +97,7 @@ void Clock::addGameTime(int mins) {
// UINT_39e5_0ffa = 0;
}
-void Clock::draw(Graphics::ManagedSurface *surf) {
- // FIXME: Temporarily ignore script visibility flag for testing.
- if (!_visibleUser /*|| !_visibleScript*/)
- return;
-
+Common::String Clock::getTimeStr() const {
int month = 0;
int day = _days + _days2 + 1;
while (day > DAYS_PER_MONTH[month]) {
@@ -111,7 +107,15 @@ void Clock::draw(Graphics::ManagedSurface *surf) {
month = 0;
}
- Common::String clockStr = Common::String::format("%2d/%02d %2d:%02d", month + 1, day, _hours, _mins);
+ return Common::String::format("%2d/%02d %2d:%02d", month + 1, day, _hours, _mins);
+}
+
+void Clock::draw(Graphics::ManagedSurface *surf) {
+ // FIXME: Temporarily ignore script visibility flag for testing.
+ if (!_visibleUser /*|| !_visibleScript*/)
+ return;
+
+ const Common::String clockStr = getTimeStr();
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const FontManager *fontman = engine->getFontMan();
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index 3c6b6364018..b908e9e8991 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -41,6 +41,7 @@ public:
void setTime(int16 month, int16 day, int16 hour, int16 minute);
+ Common::String getTimeStr() const;
void draw(Graphics::ManagedSurface *surf);
void toggleVisibleUser() { _visibleUser = !_visibleUser; }
void setVisibleScript(bool val) { _visibleScript = val; }
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7326c7c7c3a..bde3fc93250 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -72,7 +72,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds") {
+ _random("dgds"), _currentCursor(-1) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -177,6 +177,9 @@ void DgdsEngine::setMouseCursor(uint num) {
if (!_icons || (int)num >= _icons->loadedFrameCount())
return;
+ if ((int)num == _currentCursor)
+ return;
+
// TODO: Get mouse cursors from _gdsScene for hotspot info??
const Common::Array<MouseCursor> &cursors = _gdsScene->getCursorList();
@@ -189,6 +192,8 @@ void DgdsEngine::setMouseCursor(uint num) {
CursorMan.popAllCursors();
CursorMan.pushCursor(*(_icons->getSurface(num)->surfacePtr()), hotx, hoty, 0, 0);
CursorMan.showMouse(true);
+
+ _currentCursor = num;
}
void DgdsEngine::setShowClock(bool val) {
@@ -203,7 +208,7 @@ void DgdsEngine::checkDrawInventoryButton() {
int x = SCREEN_WIDTH - _icons->width(2) - 5;
int y = SCREEN_HEIGHT - _icons->height(2) - 5;
static const Common::Rect drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- _icons->drawBitmap(2, x, y, drawWin, _topBuffer);
+ _icons->drawBitmap(2, x, y, drawWin, _resData);
}
Common::Error DgdsEngine::run() {
@@ -287,9 +292,11 @@ Common::Error DgdsEngine::run() {
loadIcons();
setMouseCursor(0);
+ _inventory->setRequestData(invRequestData);
+
//getDebugger()->attach();
- //debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
+ debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
//debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
@@ -361,18 +368,32 @@ Common::Error DgdsEngine::run() {
_scene->drawActiveDialogBgs(&_resData);
+ if (moveToNext && _inventory->isOpen()) {
+ _inventory->close();
+ moveToNext = false;
+ }
+
if (moveToNext || !_adsInterp->run()) {
moveToNext = false;
}
if (mouseMoved) {
- _scene->mouseMoved(_lastMouse);
+ if (_inventory->isOpen())
+ _inventory->mouseMoved(_lastMouse);
+ else
+ _scene->mouseMoved(_lastMouse);
mouseMoved = false;
} else if (mouseLClicked) {
- _scene->mouseLClicked(_lastMouse);
+ if (_inventory->isOpen())
+ _inventory->mouseLClicked(_lastMouse);
+ else
+ _scene->mouseLClicked(_lastMouse);
mouseLClicked = false;
} else if (mouseRClicked) {
- _scene->mouseRClicked(_lastMouse);
+ if (_inventory->isOpen())
+ _inventory->mouseRClicked(_lastMouse);
+ else
+ _scene->mouseRClicked(_lastMouse);
mouseRClicked = false;
}
@@ -383,15 +404,8 @@ Common::Error DgdsEngine::run() {
_scene->runPostTickOps();
_scene->checkTriggers();
- if (_inventory->isOpen()) {
- _inventory->draw(_topBuffer);
- } else {
- _gdsScene->drawItems(_topBuffer);
- checkDrawInventoryButton();
- }
- _clock.draw(&_topBuffer);
- _scene->checkDialogActive();
+ // Now we start to assemble the rendered scene.
_resData.blitFrom(_bottomBuffer);
_resData.transBlitFrom(_topBuffer);
@@ -419,6 +433,16 @@ Common::Error DgdsEngine::run() {
_topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ if (_inventory->isOpen()) {
+ int invCount = _gdsScene->countItemsInScene2();
+ _inventory->draw(_resData, invCount);
+ } else {
+ _gdsScene->drawItems(_resData);
+ checkDrawInventoryButton();
+ }
+ _clock.draw(&_resData);
+ _scene->checkDialogActive();
+
_scene->drawAndUpdateDialogs(&_resData);
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 023b2dd70d1..76f67c85c86 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -105,6 +105,7 @@ private:
Common::RandomSource _random;
Common::Point _lastMouse; // originals start mouse at 0,0.
+ int _currentCursor;
Clock _clock;
@@ -130,6 +131,7 @@ public:
bool changeScene(int sceneNum, bool runChangeOps);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
+ Inventory *getInventory() { return _inventory; }
void setMouseCursor(uint num);
DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 1df84baf95f..cf55d1b192c 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -117,7 +117,7 @@ DragonGlobals::DragonGlobals(Clock &_clock) : Globals(),
_gameCounterTicksUp(0), _gameCounterTicksDown(0), _lastOpcode1SceneChageNum(0),
_sceneOp12SceneNum(0), _currentSelectedItem(0), _gameMinsToAdd_1(0), _gameMinsToAdd_2(0),
_gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0),
-_sceneOpcode15Flag(0), _sceneOpcode15Val(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
+_sceneOpcode15FromScene(0), _sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
_globals.push_back(_clock.getGameMinsAddedGlobal(1));
_globals.push_back(new ROI16Global(0x64, &_gameCounterTicksUp));
@@ -134,8 +134,8 @@ _opcode106EndMinutes(0) {
_globals.push_back(new RWI16Global(0x58, &_gameMinsToAdd_5));
_globals.push_back(new RWI16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
_globals.push_back(_clock.getDays2Global(0x56));
- _globals.push_back(new RWI16Global(0x55, &_sceneOpcode15Flag));
- _globals.push_back(new RWI16Global(0x54, &_sceneOpcode15Val));
+ _globals.push_back(new RWI16Global(0x55, &_sceneOpcode15FromScene));
+ _globals.push_back(new RWI16Global(0x54, &_sceneOpcode15ToScene));
_globals.push_back(new RWI16Global(0x20, &_sceneOpcode100Var));
_globals.push_back(new RWI16Global(0x21, &_arcadeModeFlag_3cdc));
_globals.push_back(new RWI16Global(0x22, &_opcode106EndMinutes));
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 2e8b461892c..c7b7df0e3e6 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -114,8 +114,8 @@ private:
int16 _gameMinsToAdd_4;
int16 _gameMinsToAdd_5;
int16 _gameGlobal0x57;
- int16 _sceneOpcode15Flag;
- int16 _sceneOpcode15Val;
+ int16 _sceneOpcode15FromScene;
+ int16 _sceneOpcode15ToScene;
int16 _sceneOpcode100Var;
int16 _arcadeModeFlag_3cdc;
int16 _opcode106EndMinutes;
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index c09ef4b7215..998ce43f2df 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -21,14 +21,131 @@
#include "graphics/managed_surface.h"
#include "dgds/inventory.h"
+#include "dgds/dgds.h"
+#include "dgds/scene.h"
+#include "dgds/image.h"
namespace Dgds {
-Inventory::Inventory() : _isOpen(false) {
+Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nullptr),
+ _invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _highlightItemNo(-1),
+ _itemOffset(0)
+{
}
-void Inventory::draw(Graphics::ManagedSurface &surf) {
- // TODO: Implement me.
+void Inventory::setRequestData(const REQFileData &data) {
+ _requestData = data;
+ assert(_requestData._requests.size() > 0);
+ RequestData *req = _requestData._requests.data();
+ _prevPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(14));
+ _nextPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(15));
+ _invClock = dynamic_cast<TextAreaGadget *>(req->findGadgetByNumWithFlags3Not0x40(23));
+ _itemZoomBox = req->findGadgetByNumWithFlags3Not0x40(9);
+ _exitButton = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(17));
+ if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton)
+ error("Didn't get all expected inventory gadgets");
}
+void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (engine->getScene()->getNum() == 2)
+ return;
+
+ ImageGadget *itemImgArea = dynamic_cast<ImageGadget *>(_requestData._requests[0].findGadgetByNumWithFlags3Not0x40(8));
+ if (isRestarting) {
+ warning("TODO: Handle inventory redraw on restart");
+ } else {
+ _itemZoomBox->_flags3 &= 0x40;
+ }
+
+ if (!itemImgArea)
+ error("Couldn't get img area for inventory");
+
+ //
+ // Decide whether the nextpage/prevpage buttons should be visible
+ //
+ if ((itemImgArea->_width / itemImgArea->_gadget8_i1) *
+ (itemImgArea->_height / itemImgArea->_gadget8_i2) > itemCount) {
+ warning("TODO: Enable prev page / next page buttons in inventory");
+ }
+
+ _requestData._requests[0].drawInvType(&surf);
+
+ drawTime(surf);
+
+ drawItems(surf, itemImgArea);
+}
+
+void Inventory::drawTime(Graphics::ManagedSurface &surf) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ _invClock->_buttonName = engine->getClock().getTimeStr();
+ _invClock->draw(surf.surfacePtr());
+}
+
+void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ const Common::SharedPtr<Image> &icons = engine->getIcons();
+ int x = 0;
+ int y = 0;
+
+ const int xstep = imgArea->_gadget8_i1;
+ const int ystep = imgArea->_gadget8_i2;
+
+ Common::Rect itemRect(Common::Point(imgArea->_parentX + imgArea->_x, imgArea->_parentY + imgArea->_y), imgArea->_width, imgArea->_height);
+ surf.fillRect(itemRect, (byte)imgArea->_field15_0x22);
+
+ if (!icons)
+ return;
+
+ // TODO: does this need to be adjusted ever?
+ const Common::Rect drawMask(0, 0, 320, 200);
+ int offset = _itemOffset;
+ for (const auto & item: items) {
+ if (item._inSceneNum != 2 || !(item._flags & 4))
+ continue;
+
+ if (offset) {
+ offset--;
+ continue;
+ }
+
+ if (item._num == _highlightItemNo) {
+ // draw highlighted
+ Common::Rect highlightRect(Common::Point(x, y), xstep, ystep);
+ surf.fillRect(highlightRect, 4);
+ }
+
+ // draw offset for the image
+ int xoff = x + (xstep - item.rect.width) / 2;
+ int yoff = y + (ystep - item.rect.height) / 2;
+
+ icons->drawBitmap(item._iconNum, xoff, yoff, drawMask, surf);
+
+ x += xstep;
+ if (x > imgArea->_x + imgArea->_width) {
+ x = 0;
+ y += ystep;
+ }
+ if (y > imgArea->_x + imgArea->_width) {
+ break;
+ }
+ }
+
+}
+
+void Inventory::mouseMoved(const Common::Point &pt) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->setMouseCursor(0);
+}
+
+void Inventory::mouseLClicked(const Common::Point &pt) {
+
+}
+
+void Inventory::mouseRClicked(const Common::Point &pt) {
+
+}
+
+
} // end namespace Dgds
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 60f28d5d6bd..0b62b48d60b 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -22,6 +22,8 @@
#ifndef DGDS_INVENTORY_H
#define DGDS_INVENTORY_H
+#include "dgds/request.h"
+
namespace Graphics {
class ManagedSurface;
}
@@ -33,10 +35,29 @@ public:
Inventory();
bool isOpen() const { return _isOpen; }
- void draw(Graphics::ManagedSurface &surf);
+ void open() { _isOpen = true; }
+ void close() { _isOpen = false; }
+ void draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting = false);
+ void drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea);
+ void drawTime(Graphics::ManagedSurface &surf);
+
+ void mouseMoved(const Common::Point &pt);
+ void mouseLClicked(const Common::Point &pt);
+ void mouseRClicked(const Common::Point &pt);
+
+ void setRequestData(const REQFileData &data);
private:
bool _isOpen;
+ ButtonGadget *_prevPageBtn;
+ ButtonGadget *_nextPageBtn;
+ TextAreaGadget *_invClock;
+ Gadget *_itemZoomBox;
+ ButtonGadget *_exitButton;
+
+ REQFileData _requestData;
+ int _highlightItemNo; // -1 means no item highlighted.
+ int _itemOffset; // for scrolling through the item list
};
} // end namespace Dgds
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 91626dfbd5b..b16a1eabea8 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -138,7 +138,7 @@ void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
Graphics::Surface *dst = g_system->lockScreen();
Graphics::ManagedSurface managed(dst, DisposeAfterUse::NO);
- vcrRequestData._requests[_curMenu].draw(&managed);
+ vcrRequestData._requests[_curMenu].drawBg(&managed);
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 468f2dce460..a7ed2b5198b 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -223,8 +223,9 @@ bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int
data._y = str->readUint16LE();
data._width = str->readUint16LE();
data._height = str->readUint16LE();
- for (int i = 0; i < 3; i++)
- data._vals[i] = str->readUint16LE();
+ data._col1 = str->readUint16LE();
+ data._col2 = str->readUint16LE();
+ data._flags = str->readUint16LE();
uint16 numTextItems = str->readUint16LE();
data._textItemList.resize(numTextItems);
@@ -238,13 +239,16 @@ bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int
dst._txt = str->readString();
}
- uint16 numStruct2 = str->readUint16LE();
- data._struct2List.resize(numStruct2);
- for (int i = 0; i < numStruct2; i++) {
- RequestStruct2 &dst = data._struct2List[i];
- for (int j = 0; j < 6; j++) {
- dst._vals[j] = str->readUint16LE();
- }
+ uint16 numFillAreas = str->readUint16LE();
+ data._fillAreaList.resize(numFillAreas);
+ for (int i = 0; i < numFillAreas; i++) {
+ RequestFillArea &dst = data._fillAreaList[i];
+ dst._x = str->readUint16LE();
+ dst._y = str->readUint16LE();
+ dst._width = str->readUint16LE();
+ dst._height = str->readUint16LE();
+ dst._col1 = str->readUint16LE();
+ dst._col2 = str->readUint16LE();
}
return str->err();
@@ -466,18 +470,18 @@ Common::String ImageGadget::dump() const {
}
void ImageGadget::draw(Graphics::Surface *dst) const {
- error("TODO: Implement ImageGadget::draw");
+ warning("TODO: Implement ImageGadget::draw");
}
Common::String RequestData::dump() const {
- Common::String ret = Common::String::format("RequestData<file %d pos (%d,%d) size (%d, %d) %d %d %d\n",
- _fileNum, _x, _y, _width, _height, _vals[0], _vals[1], _vals[2]);
- for (const auto &s1 : _textItemList)
- ret += Common::String::format(" TextItem<'%s' pos (%d,%d) %d %d>\n", s1._txt.c_str(),
- s1._x, s1._y, s1._vals[0], s1._vals[1]);
- for (const auto &s2 : _struct2List)
- ret += Common::String::format(" RequestStruct2<%d %d %d %d %d %d>\n", s2._vals[0], s2._vals[1],
- s2._vals[2], s2._vals[3], s2._vals[4], s2._vals[5]);
+ Common::String ret = Common::String::format("RequestData<file %d pos (%d,%d) size (%d, %d) c1 %d c2 %d flg %d\n",
+ _fileNum, _x, _y, _width, _height, _col1, _col2, _flags);
+ for (const auto &t : _textItemList)
+ ret += Common::String::format(" TextItem<'%s' pos (%d,%d) %d %d>\n", t._txt.c_str(),
+ t._x, t._y, t._vals[0], t._vals[1]);
+ for (const auto &f : _fillAreaList)
+ ret += Common::String::format(" FillArea<x %d y %d w %d h %d c1 %d c2 %d>\n", f._x, f._y,
+ f._width, f._height, f._col1, f._col2);
for (const auto &g : _gadgets)
ret += Common::String::format(" %s\n", g->dump().c_str());
ret += ">";
@@ -485,7 +489,7 @@ Common::String RequestData::dump() const {
return ret;
}
-void RequestData::draw(Graphics::ManagedSurface *dst) const {
+void RequestData::drawBg(Graphics::ManagedSurface *dst) const {
int slidery = 0;
for (const auto &gadget : _gadgets) {
const SliderGadget *slider = dynamic_cast<const SliderGadget *>(gadget.get());
@@ -504,6 +508,34 @@ void RequestData::draw(Graphics::ManagedSurface *dst) const {
drawBackgroundNoSliders(dst, header);
}
+void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
+ if (_flags & 0x40)
+ return;
+
+ drawBackgroundNoSliders(dst, "");
+ for (const auto &fillArea : _fillAreaList) {
+ Common::Rect r(Common::Point(_x + fillArea._x, _y + fillArea._y), fillArea._width, fillArea._height);
+ dst->fillRect(r, fillArea._col1);
+ }
+
+ for (const auto &textItem : _textItemList) {
+ if (!textItem._txt.empty())
+ error("TODO: RequestData::drawInvType: Implement support for drawing text item.");
+
+ }
+
+ for (auto &gadget : _gadgets)
+ gadget->_flags3 |= 0x100;
+
+ for (auto &gadget : _gadgets) {
+ if (!(gadget->_flags3 & 0x40)) {
+ gadget->draw(dst->surfacePtr());
+ }
+ }
+
+ _flags |= 4;
+}
+
/*static*/
const Font *RequestData::getMenuFont() {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
@@ -639,6 +671,14 @@ void RequestData::fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16
}
}
+Gadget *RequestData::findGadgetByNumWithFlags3Not0x40(int16 num) {
+ for (auto &gadget : _gadgets) {
+ if (gadget->_gadgetNo == num && (gadget->_flags3 & 0x40) == 0)
+ return gadget.get();
+ }
+ return nullptr;
+}
+
Common::String REQFileData::dump() const {
Common::String ret("REQFileData<\n");
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 9db81033333..42f799c8d4b 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -42,8 +42,13 @@ struct TextItem {
// This struct is defined in the code, but seems
// to not be used in any of the games?
-struct RequestStruct2 {
- uint16 _vals[6];
+struct RequestFillArea {
+ uint16 _x;
+ uint16 _y;
+ uint16 _width;
+ uint16 _height;
+ uint16 _col1;
+ uint16 _col2;
};
enum GadgetType {
@@ -142,13 +147,16 @@ public:
uint16 _y;
uint16 _width;
uint16 _height;
- uint16 _vals[3];
+ uint16 _col1;
+ uint16 _col2;
+ uint16 _flags;
Common::Array<TextItem> _textItemList;
- Common::Array<RequestStruct2> _struct2List;
+ Common::Array<RequestFillArea> _fillAreaList;
Common::Array<Common::SharedPtr<Gadget>> _gadgets;
Common::String dump() const;
- void draw(Graphics::ManagedSurface *dst) const;
+ void drawBg(Graphics::ManagedSurface *dst) const;
+ void drawInvType(Graphics::ManagedSurface *dst);
static const Font *getMenuFont();
const Image *getCorners();
@@ -156,6 +164,7 @@ public:
static void fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
static void drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
static void drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header);
+ Gadget *findGadgetByNumWithFlags3Not0x40(int16 num);
private:
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index d006461092a..6357f6aae14 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -39,6 +39,7 @@
#include "dgds/font.h"
#include "dgds/globals.h"
#include "dgds/image.h"
+#include "dgds/inventory.h"
namespace Dgds {
@@ -64,14 +65,14 @@ Common::String _sceneConditionStr(SceneCondition cflag) {
if (cflag & kSceneCondSceneState)
ret += "state|";
- if (cflag & kSceneCondNeedItemField12)
- ret += "item12|";
+ if (cflag & kSceneCondNeedItemSceneNum)
+ ret += "itemsnum|";
if (cflag & kSceneCondNeedItemField14)
ret += "item14|";
- if ((cflag & (kSceneCondSceneState | kSceneCondNeedItemField12 | kSceneCondNeedItemField14)) == 0)
+ if ((cflag & (kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemField14)) == 0)
ret += "global|";
- cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemField12 | kSceneCondNeedItemField14));
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemField14));
if (cflag == kSceneCondNone)
ret += "nocond";
if (cflag & kSceneCondLessThan)
@@ -116,6 +117,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
+ case kSceneOpMoveItemsBetweenScenes: return "moveItemsBetweenScenes";
case kSceneOpRestartGame: return "restartGame";
case kSceneOpShowClock: return "sceneOpShowClock";
case kSceneOpHideClock: return "sceneOpHideClock";
@@ -464,7 +466,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
warning("TODO: Implement give item(?) scene op");
break;
case kSceneOpOpenInventory:
- warning("TODO: Implement open inventory scene op");
+ engine->getInventory()->open();
break;
case kSceneOpShowDlg:
showDialog(op._args[0]);
@@ -482,6 +484,11 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpRestartGame:
error("TODO: Implement restart game scene op");
break;
+ case kSceneOpMoveItemsBetweenScenes:
+ // Move all items from source scene to the dest scene.
+ // scene numbers are in globals.
+ error("TODO: Implement move items between scenes op");
+ break;
case kSceneOpShowClock:
engine->setShowClock(true);
break;
@@ -536,10 +543,17 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
refval = 0;
cflag = kSceneCondEqual;
- } else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemField12) {
- debug("TODO: Check game item attribute for scene condition");
- // TODO: Get game item c._num and check value from item attributes
- checkval = 0;
+ } else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemSceneNum) {
+ const Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
+ for (const auto &item : items) {
+ if (item._num == c._num) {
+ if (cflag & kSceneCondNeedItemSceneNum)
+ checkval = item._inSceneNum;
+ else // cflag & kSceneCondNeedItemField14
+ checkval = item.field14_0x2c;
+ break;
+ }
+ }
} else {
checkval = globals->getGlobal(c._num);
if (!(cflag & kSceneCondAbsVal))
@@ -547,7 +561,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
}
bool result = false;
- cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemField12 | kSceneCondNeedItemField14));
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemField14));
if (cflag == kSceneCondNone)
cflag = static_cast<SceneCondition>(kSceneCondEqual | kSceneCondNegate);
if ((cflag & kSceneCondLessThan) && checkval < refval)
@@ -882,7 +896,10 @@ void SDSScene::mouseLClicked(const Common::Point &pt) {
HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
- runOps(area->onLClickOps);
+ if (area->_num == 0)
+ static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
+ else
+ runOps(area->onLClickOps);
}
void SDSScene::mouseRClicked(const Common::Point &pt) {
@@ -1099,5 +1116,14 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
}
}
+int GDSScene::countItemsInScene2() const {
+ int result = 0;
+ for (const auto &item : _gameItems) {
+ if (item._inSceneNum == 2)
+ result++;
+ }
+ return result;
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 8e460975fce..4e1e3ea912a 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -43,7 +43,7 @@ enum SceneCondition {
kSceneCondAbsVal = 8,
kSceneCondAlwaysTrue = 0x10,
kSceneCondNeedItemField14 = 0x20,
- kSceneCondNeedItemField12 = 0x40,
+ kSceneCondNeedItemSceneNum = 0x40,
kSceneCondSceneState = 0x80
};
@@ -85,7 +85,7 @@ enum SceneOpCode {
kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
kSceneOp13 = 13, // args: none.
kSceneOpRestartGame = 14, // args: none.
- kSceneOp15 = 15, // args: none.
+ kSceneOpMoveItemsBetweenScenes = 15, // args: none.
kSceneOpShowClock = 16, // args: none. set some clock-related globals
kSceneOpHideClock = 17, // args: none. set some clock-related values.
kSceneOpShowMouse = 18, // args: none.
@@ -237,8 +237,10 @@ public:
int16 getGlobal(uint16 num);
int16 setGlobal(uint16 num, int16 val);
- const Common::Array<struct MouseCursor> &getCursorList() { return _cursorList; }
+ const Common::Array<struct MouseCursor> &getCursorList() const { return _cursorList; }
void drawItems(Graphics::ManagedSurface &surf);
+ const Common::Array<struct GameItem> &getGameItems() const { return _gameItems; }
+ int countItemsInScene2() const;
private:
//byte _unk[32];
@@ -283,7 +285,7 @@ public:
void addInvButtonToHotAreaList();
void removeInvButtonFromHotAreaList();
- const Common::Array<struct HotArea> &getHotAreas() { return _hotAreaList; }
+ const Common::Array<struct HotArea> &getHotAreas() const { return _hotAreaList; }
private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index e9c3905e5aa..1d384e8de69 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -919,7 +919,7 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
- debug(10, " ADSOP: 0x%04x", code);
+ debug(" ADSOP: 0x%04x", code);
switch (code) {
case 0x0001:
Commit: 70322958280b25560e38e53bd4cc947b7b6d4f58
https://github.com/scummvm/scummvm/commit/70322958280b25560e38e53bd4cc947b7b6d4f58
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More inventory implementation
Changed paths:
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 998ce43f2df..b1bdbb4c851 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -24,6 +24,8 @@
#include "dgds/dgds.h"
#include "dgds/scene.h"
#include "dgds/image.h"
+#include "dgds/font.h"
+#include "dgds/request.h"
namespace Dgds {
@@ -34,9 +36,9 @@ Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nul
}
void Inventory::setRequestData(const REQFileData &data) {
- _requestData = data;
- assert(_requestData._requests.size() > 0);
- RequestData *req = _requestData._requests.data();
+ _reqData = data;
+ assert(_reqData._requests.size() > 0);
+ RequestData *req = _reqData._requests.data();
_prevPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(14));
_nextPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(15));
_invClock = dynamic_cast<TextAreaGadget *>(req->findGadgetByNumWithFlags3Not0x40(23));
@@ -46,12 +48,31 @@ void Inventory::setRequestData(const REQFileData &data) {
error("Didn't get all expected inventory gadgets");
}
+void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
+ // This really should be a text area, but it's hard-coded in the game.
+ const Font *font = RequestData::getMenuFont();
+ const RequestData &r = _reqData._requests[0];
+
+ static const char *title = "INVENTORY";
+ int titleWidth = font->getStringWidth(title);
+ int y1 = r._y + 7;
+ int x1 = r._x + 112;
+ font->drawString(&surf, title, x1 + 4, y1 + 2, titleWidth, 0);
+
+ int x2 = x1 + titleWidth + 6;
+ int y2 = y1 + font->getFontHeight();
+ surf.drawLine(x1, y1, x2, y1, 0xdf);
+ surf.drawLine(x2, y1 + 1, x2, y2, 0xdf);
+ surf.drawLine(x1, y1 + 1, x1, y2, 0xff);
+ surf.drawLine(x1 + 1, y2, x1 + titleWidth + 5, y2, 0xff);
+}
+
void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (engine->getScene()->getNum() == 2)
return;
- ImageGadget *itemImgArea = dynamic_cast<ImageGadget *>(_requestData._requests[0].findGadgetByNumWithFlags3Not0x40(8));
+ ImageGadget *itemImgArea = dynamic_cast<ImageGadget *>(_reqData._requests[0].findGadgetByNumWithFlags3Not0x40(8));
if (isRestarting) {
warning("TODO: Handle inventory redraw on restart");
} else {
@@ -64,12 +85,19 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isResta
//
// Decide whether the nextpage/prevpage buttons should be visible
//
- if ((itemImgArea->_width / itemImgArea->_gadget8_i1) *
- (itemImgArea->_height / itemImgArea->_gadget8_i2) > itemCount) {
- warning("TODO: Enable prev page / next page buttons in inventory");
+ if ((itemImgArea->_width / itemImgArea->_xStep) *
+ (itemImgArea->_height / itemImgArea->_yStep) > itemCount) {
+ // not visible.
+ _prevPageBtn->_flags3 |= 0x40;
+ _nextPageBtn->_flags3 |= 0x40;
+ } else {
+ // clear flag 0x40 - visible.
+ _prevPageBtn->_flags3 &= ~0x40;
+ _nextPageBtn->_flags3 &= ~0x40;
}
+ _reqData._requests[0].drawInvType(&surf);
- _requestData._requests[0].drawInvType(&surf);
+ drawHeader(surf);
drawTime(surf);
@@ -78,8 +106,13 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isResta
void Inventory::drawTime(Graphics::ManagedSurface &surf) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- _invClock->_buttonName = engine->getClock().getTimeStr();
- _invClock->draw(surf.surfacePtr());
+ const Font *font = RequestData::getMenuFont();
+ const Common::String timeStr = engine->getClock().getTimeStr();
+ Common::Point clockpos = Common::Point(_invClock->_x + _invClock->_parentX, _invClock->_y + _invClock->_parentY);
+ surf.fillRect(Common::Rect(clockpos, _invClock->_width, _invClock->_height), 0);
+ RequestData::drawCorners(&surf, 19, clockpos.x - 2, clockpos.y - 2,
+ _invClock->_width + 4, _invClock->_height + 4);
+ font->drawString(&surf, timeStr, clockpos.x, clockpos.y, font->getStringWidth(timeStr), _invClock->_col3);
}
void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea) {
@@ -89,11 +122,12 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea)
int x = 0;
int y = 0;
- const int xstep = imgArea->_gadget8_i1;
- const int ystep = imgArea->_gadget8_i2;
+ const int xstep = imgArea->_xStep;
+ const int ystep = imgArea->_yStep;
- Common::Rect itemRect(Common::Point(imgArea->_parentX + imgArea->_x, imgArea->_parentY + imgArea->_y), imgArea->_width, imgArea->_height);
- surf.fillRect(itemRect, (byte)imgArea->_field15_0x22);
+ Common::Point pos(imgArea->_parentX + imgArea->_x, imgArea->_parentY + imgArea->_y);
+ Common::Rect itemRect(pos, imgArea->_width, imgArea->_height);
+ //surf.fillRect(itemRect, (byte)imgArea->_col1);
if (!icons)
return;
@@ -131,7 +165,6 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea)
break;
}
}
-
}
void Inventory::mouseMoved(const Common::Point &pt) {
@@ -140,7 +173,10 @@ void Inventory::mouseMoved(const Common::Point &pt) {
}
void Inventory::mouseLClicked(const Common::Point &pt) {
-
+ if (_exitButton->containsPoint(pt)) {
+ close();
+ return;
+ }
}
void Inventory::mouseRClicked(const Common::Point &pt) {
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 0b62b48d60b..c6780473c74 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -40,6 +40,7 @@ public:
void draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting = false);
void drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea);
void drawTime(Graphics::ManagedSurface &surf);
+ void drawHeader(Graphics::ManagedSurface &surf);
void mouseMoved(const Common::Point &pt);
void mouseLClicked(const Common::Point &pt);
@@ -55,7 +56,7 @@ private:
Gadget *_itemZoomBox;
ButtonGadget *_exitButton;
- REQFileData _requestData;
+ REQFileData _reqData;
int _highlightItemNo; // -1 means no item highlighted.
int _itemOffset; // for scrolling through the item list
};
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index b16a1eabea8..e1dd59af197 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -184,12 +184,7 @@ int16 Menu::getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseC
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider) {
- int16 x = gadget->_x + gadget->_parentX;
- int16 y = gadget->_y + gadget->_parentY;
- int16 right = x + gadget->_width;
- int16 bottom = (y + gadget->_height) - 1;
- Common::Rect gadgetRect(x, y, right, bottom);
- if (gadgetRect.contains(mouseClick))
+ if (gadget->containsPoint(mouseClick))
return (int16)gadget->_gadgetNo;
}
}
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index a7ed2b5198b..d591d66d345 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -115,10 +115,10 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
gptr->_gadgetType = gadgetType;
gptr->_flags2 = vals[6];
gptr->_flags3 = vals[7];
- gptr->_field14_0x20 = vals[8];
- gptr->_field15_0x22 = vals[9];
- gptr->_field15_0x22 = vals[10];
- gptr->_field16_0x24 = vals[11];
+ gptr->_fontNo = vals[8];
+ gptr->_col1 = vals[9];
+ gptr->_col2 = vals[10];
+ gptr->_col3 = vals[11];
gptr->_parentX = data._x;
gptr->_parentY = data._y;
}
@@ -163,9 +163,8 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
uint16 i2 = str->readUint16LE();
if (gptr) {
TextAreaGadget *g1 = static_cast<TextAreaGadget *>(gptr.get());
- // TODO: These fields might actually be shared with other gadget types?
- g1->_gadget1_i1 = i1;
- g1->_gadget1_i2 = i2;
+ g1->_textGadget_i1 = i1;
+ g1->_bufLen = i2;
}
break;
}
@@ -194,8 +193,8 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
uint16 i2 = str->readUint16LE();
if (gptr) {
ImageGadget *g8 = static_cast<ImageGadget *>(gptr.get());
- g8->_gadget8_i1 = i1;
- g8->_gadget8_i2 = i2;
+ g8->_xStep = i1;
+ g8->_yStep = i2;
}
break;
}
@@ -304,6 +303,15 @@ Common::String Gadget::dump() const {
void Gadget::draw(Graphics::Surface *dst) const {}
+bool Gadget::containsPoint(const Common::Point &pt) {
+ int16 x = _x + _parentX;
+ int16 y = _y + _parentY;
+ int16 right = x + _width;
+ int16 bottom = (y + _height) - 1;
+ Common::Rect gadgetRect(x, y, right, bottom);
+ return gadgetRect.contains(pt);
+}
+
void ButtonGadget::draw(Graphics::Surface *dst) const {
// TODO: Bounds calculation here might depend on parent.
@@ -396,7 +404,7 @@ void ButtonGadget::toggle(bool enable) {
Common::String TextAreaGadget::dump() const {
const Common::String base = Gadget::dump();
- return Common::String::format("TextArea<%s, %d %d>", base.c_str(), _gadget1_i1, _gadget1_i2);
+ return Common::String::format("TextArea<%s, %d buflen %d>", base.c_str(), _textGadget_i1, _bufLen);
}
void TextAreaGadget::draw(Graphics::Surface *dst) const {
@@ -466,10 +474,44 @@ void SliderGadget::draw(Graphics::Surface *dst) const {
Common::String ImageGadget::dump() const {
const Common::String base = Gadget::dump();
- return Common::String::format("Image<%s, %d %d>", base.c_str(), _gadget8_i1, _gadget8_i2);
+ return Common::String::format("Image<%s, xStep %d yStep %d>", base.c_str(), _xStep, _yStep);
+}
+
+static void _drawFrame(Graphics::Surface *dst, int16 x, int16 y, int16 w, int16 h, byte col1, byte col2) {
+ const int xmax = x + w - 1;
+ const int ymax = y + h - 1;
+ bool filled = true;
+ if (filled) {
+ for (int yy = y; yy < ymax; yy++) {
+ for (int xx = x; xx < xmax; xx = xx + 1) {
+ dst->setPixel(xx, yy, (byte)dst->getPixel(xx, yy) ^ col2);
+ }
+ }
+ }
+ for (int yy = y; yy <= ymax; yy++) {
+ dst->setPixel(x, yy, (byte)dst->getPixel(x, yy) ^ col1);
+ dst->setPixel(xmax, yy, (byte)dst->getPixel(xmax, yy) ^ col1);
+ }
+ for (int xx = x; xx < xmax; xx++) {
+ dst->setPixel(xx, y, (byte)dst->getPixel(xx, y) ^ col1);
+ dst->setPixel(xx, ymax, (byte)dst->getPixel(xx, ymax) ^ col1);
+ }
}
void ImageGadget::draw(Graphics::Surface *dst) const {
+ int xstep = _xStep;
+ int ystep = _yStep;
+
+ if (!xstep || !ystep)
+ return;
+
+ int xoff = _x + _parentX;
+ int yoff = _y + _parentY;
+ Common::Rect drawRect(Common::Point(xoff, yoff), _width, _height);
+ dst->fillRect(drawRect, _col1);
+ // Note: not quite the same as the original logic here, but gets the same result.
+ _drawFrame(dst, xoff, yoff, _width, _height, _sval1I, _sval1I);
+
warning("TODO: Implement ImageGadget::draw");
}
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 42f799c8d4b..0bfed2fb31e 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -85,10 +85,10 @@ public:
Common::String _buttonName;
// some other fields..
- uint16 _field14_0x20;
- uint16 _field15_0x22;
- uint16 _field16_0x24;
- uint16 _field17_0x26;
+ uint16 _fontNo;
+ uint16 _col1;
+ uint16 _col2;
+ uint16 _col3;
uint16 _field20_0x28;
uint16 _field21_0x2a;
@@ -99,6 +99,8 @@ public:
virtual Common::String dump() const;
virtual void draw(Graphics::Surface *dst) const;
virtual void toggle(bool enable) {}
+
+ bool containsPoint(const Common::Point &pt);
};
// Button gadget has no additional fields, but some behavior differences.
@@ -111,8 +113,8 @@ public:
// extended gadget type 1 is 62 (0x3e) bytes
class TextAreaGadget : public Gadget {
public:
- uint16 _gadget1_i1;
- uint16 _gadget1_i2;
+ uint16 _textGadget_i1;
+ uint16 _bufLen;
Common::String dump() const override;
void draw(Graphics::Surface *dst) const override;
@@ -133,8 +135,8 @@ public:
// extended gadget type 8 is 68 (0x44) bytes
class ImageGadget : public Gadget {
public:
- uint16 _gadget8_i1;
- uint16 _gadget8_i2;
+ uint16 _xStep;
+ uint16 _yStep;
Common::String dump() const override;
void draw(Graphics::Surface *dst) const override;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 6357f6aae14..479624686d5 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -530,8 +530,8 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
Globals *globals = engine->getGameGlobals();
for (const auto &c : conds) {
- uint16 refval = c._val;
- uint16 checkval;
+ int16 refval = c._val;
+ int16 checkval = -1;
SceneCondition cflag = c._flags;
if (cflag & kSceneCondAlwaysTrue)
return true;
Commit: f3b7165fd6d9290dd7ea22dd7e85135895dba376
https://github.com/scummvm/scummvm/commit/f3b7165fd6d9290dd7ea22dd7e85135895dba376
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Incrementally implement inventory interactions
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index bde3fc93250..5dcbe8514ab 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -301,11 +301,9 @@ Common::Error DgdsEngine::run() {
bool moveToNext = false;
bool triggerMenu = false;
- bool mouseLClicked = false;
- bool mouseRClicked = false;
- bool mouseMoved = false;
while (!shouldQuit()) {
+ Common::EventType mouseEvent = Common::EVENT_INVALID;
while (eventMan->pollEvent(ev)) {
if (ev.type == Common::EVENT_KEYDOWN) {
switch (ev.kbd.keycode) {
@@ -324,14 +322,9 @@ Common::Error DgdsEngine::run() {
default:
break;
}
- } else if (ev.type == Common::EVENT_LBUTTONUP) {
- mouseLClicked = true;
- _lastMouse = ev.mouse;
- } else if (ev.type == Common::EVENT_RBUTTONUP) {
- mouseRClicked = true;
- _lastMouse = ev.mouse;
- } else if (ev.type == Common::EVENT_MOUSEMOVE) {
- mouseMoved = true;
+ } else if (ev.type == Common::EVENT_LBUTTONDOWN || ev.type == Common::EVENT_LBUTTONUP
+ || ev.type == Common::EVENT_RBUTTONUP || ev.type == Common::EVENT_MOUSEMOVE) {
+ mouseEvent = ev.type;
_lastMouse = ev.mouse;
}
}
@@ -351,9 +344,9 @@ Common::Error DgdsEngine::run() {
}
if (_menu->menuShown()) {
- if (mouseLClicked) {
+ if (mouseEvent == Common::EVENT_LBUTTONUP) {
_menu->handleMenu(vcrRequestData, _lastMouse);
- mouseLClicked = false;
+ mouseEvent = Common::EVENT_INVALID;
}
g_system->updateScreen();
g_system->delayMillis(10);
@@ -377,24 +370,42 @@ Common::Error DgdsEngine::run() {
moveToNext = false;
}
- if (mouseMoved) {
- if (_inventory->isOpen())
- _inventory->mouseMoved(_lastMouse);
- else
- _scene->mouseMoved(_lastMouse);
- mouseMoved = false;
- } else if (mouseLClicked) {
- if (_inventory->isOpen())
- _inventory->mouseLClicked(_lastMouse);
- else
- _scene->mouseLClicked(_lastMouse);
- mouseLClicked = false;
- } else if (mouseRClicked) {
- if (_inventory->isOpen())
- _inventory->mouseRClicked(_lastMouse);
- else
- _scene->mouseRClicked(_lastMouse);
- mouseRClicked = false;
+ if (mouseEvent != Common::EVENT_INVALID) {
+ if (_inventory->isOpen()) {
+ switch (mouseEvent) {
+ case Common::EVENT_MOUSEMOVE:
+ _inventory->mouseMoved(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _inventory->mouseLDown(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _inventory->mouseLUp(_lastMouse);
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _inventory->mouseRUp(_lastMouse);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (mouseEvent) {
+ case Common::EVENT_MOUSEMOVE:
+ _scene->mouseMoved(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _scene->mouseLDown(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _scene->mouseLUp(_lastMouse);
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _scene->mouseRUp(_lastMouse);
+ break;
+ default:
+ break;
+ }
+ }
}
// Note: Hard-coded logic for DRAGON, check others
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index b1bdbb4c851..4d025d33638 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -30,8 +30,8 @@
namespace Dgds {
Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nullptr),
- _invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _highlightItemNo(-1),
- _itemOffset(0)
+ _invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _clockSkipMinBtn(nullptr),
+ _clockSkipHrBtn(nullptr), _dropBtn(nullptr), _highlightItemNo(-1), _itemOffset(0)
{
}
@@ -42,8 +42,14 @@ void Inventory::setRequestData(const REQFileData &data) {
_prevPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(14));
_nextPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(15));
_invClock = dynamic_cast<TextAreaGadget *>(req->findGadgetByNumWithFlags3Not0x40(23));
+ _itemBox = req->findGadgetByNumWithFlags3Not0x40(8);
_itemZoomBox = req->findGadgetByNumWithFlags3Not0x40(9);
_exitButton = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(17));
+
+ _clockSkipMinBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(24));
+ _clockSkipHrBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(25));
+ _dropBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(16));
+
if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton)
error("Didn't get all expected inventory gadgets");
}
@@ -172,14 +178,32 @@ void Inventory::mouseMoved(const Common::Point &pt) {
engine->setMouseCursor(0);
}
-void Inventory::mouseLClicked(const Common::Point &pt) {
+void Inventory::mouseLDown(const Common::Point &pt) {
+ if (_itemBox && _itemBox->containsPoint(pt)) {
+ debug("TODO: Handle drag events inside inventory.");
+ }
+}
+
+void Inventory::mouseLUp(const Common::Point &pt) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (_exitButton->containsPoint(pt)) {
close();
return;
+ } else if (_nextPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
+ debug("TODO: next inventory page");
+ } else if (_prevPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
+ debug("TODO: prev inventory page");
+ } else if (_clockSkipMinBtn && _clockSkipMinBtn->containsPoint(pt)) {
+ engine->getClock().addGameTime(1);
+ } else if (_clockSkipHrBtn && _clockSkipHrBtn->containsPoint(pt)) {
+ engine->getClock().addGameTime(60);
+ } else if (_dropBtn && _dropBtn->containsPoint(pt)) {
+ if (_highlightItemNo >= 0)
+ debug("TODO: drop button");
}
}
-void Inventory::mouseRClicked(const Common::Point &pt) {
+void Inventory::mouseRUp(const Common::Point &pt) {
}
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index c6780473c74..ea9a194072a 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -43,8 +43,9 @@ public:
void drawHeader(Graphics::ManagedSurface &surf);
void mouseMoved(const Common::Point &pt);
- void mouseLClicked(const Common::Point &pt);
- void mouseRClicked(const Common::Point &pt);
+ void mouseLDown(const Common::Point &pt);
+ void mouseLUp(const Common::Point &pt);
+ void mouseRUp(const Common::Point &pt);
void setRequestData(const REQFileData &data);
@@ -54,7 +55,11 @@ private:
ButtonGadget *_nextPageBtn;
TextAreaGadget *_invClock;
Gadget *_itemZoomBox;
+ Gadget *_itemBox;
ButtonGadget *_exitButton;
+ ButtonGadget *_clockSkipMinBtn;
+ ButtonGadget *_clockSkipHrBtn;
+ ButtonGadget *_dropBtn;
REQFileData _reqData;
int _highlightItemNo; // -1 means no item highlighted.
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 479624686d5..d1a5be570cb 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -67,12 +67,12 @@ Common::String _sceneConditionStr(SceneCondition cflag) {
ret += "state|";
if (cflag & kSceneCondNeedItemSceneNum)
ret += "itemsnum|";
- if (cflag & kSceneCondNeedItemField14)
- ret += "item14|";
- if ((cflag & (kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemField14)) == 0)
+ if (cflag & kSceneCondNeedItemQuality)
+ ret += "quality|";
+ if ((cflag & (kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemQuality)) == 0)
ret += "global|";
- cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemField14));
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemQuality));
if (cflag == kSceneCondNone)
ret += "nocond";
if (cflag & kSceneCondLessThan)
@@ -157,9 +157,9 @@ Common::String GameItem::dump(const Common::String &indent) const {
Common::String super = HotArea::dump(indent + " ");
Common::String str = Common::String::format(
- "%sGameItem<\n%s\n%sunk10 %d icon %d unk12 %d flags %d unk14 %d",
- indent.c_str(), super.c_str(), indent.c_str(), field10_0x24,
- _iconNum, _inSceneNum, _flags, field14_0x2c);
+ "%sGameItem<\n%s\n%saltCursor %d icon %d sceneNum %d flags %d quality %d",
+ indent.c_str(), super.c_str(), indent.c_str(), altCursor,
+ _iconNum, _inSceneNum, _flags, _quality);
str += _dumpStructList(indent, "opList4", opList4);
str += _dumpStructList(indent, "opList5", opList5);
str += "\n";
@@ -254,11 +254,11 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
for (GameItem &dst : list) {
dst._iconNum = s->readUint16LE();
dst._inSceneNum = s->readUint16LE();
- dst.field14_0x2c = s->readUint16LE();
+ dst._quality = s->readUint16LE();
if (!isVersionUnder(" 1.211"))
dst._flags = s->readUint16LE() & 0xfffe;
if (!isVersionUnder(" 1.204")) {
- dst.field10_0x24 = s->readUint16LE();
+ dst.altCursor = s->readUint16LE();
readOpList(s, dst.opList4);
readOpList(s, dst.opList5);
}
@@ -543,14 +543,14 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
refval = 0;
cflag = kSceneCondEqual;
- } else if (cflag & kSceneCondNeedItemField14 || cflag & kSceneCondNeedItemSceneNum) {
+ } else if (cflag & kSceneCondNeedItemQuality || cflag & kSceneCondNeedItemSceneNum) {
const Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
for (const auto &item : items) {
if (item._num == c._num) {
if (cflag & kSceneCondNeedItemSceneNum)
checkval = item._inSceneNum;
else // cflag & kSceneCondNeedItemField14
- checkval = item.field14_0x2c;
+ checkval = item._quality;
break;
}
}
@@ -561,7 +561,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
}
bool result = false;
- cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemField14));
+ cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemQuality));
if (cflag == kSceneCondNone)
cflag = static_cast<SceneCondition>(kSceneCondEqual | kSceneCondNegate);
if ((cflag & kSceneCondLessThan) && checkval < refval)
@@ -892,7 +892,19 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
engine->setMouseCursor(area ? area->_cursorNum : 0);
}
-void SDSScene::mouseLClicked(const Common::Point &pt) {
+void SDSScene::mouseLDown(const Common::Point &pt) {
+ HotArea *area = findAreaUnderMouse(pt);
+ if (!area)
+ return;
+
+ GameItem *item = dynamic_cast<GameItem *>(area);
+ if (!item)
+ return;
+
+ debug("TODO: Implement drag in scene for item %d", item->_num);
+}
+
+void SDSScene::mouseLUp(const Common::Point &pt) {
HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
@@ -902,7 +914,7 @@ void SDSScene::mouseLClicked(const Common::Point &pt) {
runOps(area->onLClickOps);
}
-void SDSScene::mouseRClicked(const Common::Point &pt) {
+void SDSScene::mouseRUp(const Common::Point &pt) {
HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
@@ -910,6 +922,16 @@ void SDSScene::mouseRClicked(const Common::Point &pt) {
}
HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
+ for (auto &item : engine->getGDSScene()->getGameItems()) {
+ if (item._inSceneNum == _num && checkConditions(item.enableConditions) &&
+ item.rect.x < pt.x && (item.rect.x + item.rect.width) > pt.x
+ && item.rect.y < pt.y && (item.rect.y + item.rect.height) > pt.y) {
+ return &item;
+ }
+ }
+
for (auto &area : _hotAreaList) {
if (checkConditions(area.enableConditions) &&
area.rect.x < pt.x && (area.rect.x + area.rect.width) > pt.x
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 4e1e3ea912a..b9902a09ffe 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -42,7 +42,7 @@ enum SceneCondition {
kSceneCondNegate = 4,
kSceneCondAbsVal = 8,
kSceneCondAlwaysTrue = 0x10,
- kSceneCondNeedItemField14 = 0x20,
+ kSceneCondNeedItemQuality = 0x20,
kSceneCondNeedItemSceneNum = 0x40,
kSceneCondSceneState = 0x80
};
@@ -114,11 +114,11 @@ struct SceneOp {
struct GameItem : public HotArea {
Common::Array<struct SceneOp> opList4;
Common::Array<struct SceneOp> opList5;
- uint16 field10_0x24;
+ uint16 altCursor;
uint16 _iconNum;
uint16 _inSceneNum;
uint16 _flags;
- uint16 field14_0x2c;
+ uint16 _quality;
Common::String dump(const Common::String &indent) const override;
};
@@ -239,7 +239,7 @@ public:
const Common::Array<struct MouseCursor> &getCursorList() const { return _cursorList; }
void drawItems(Graphics::ManagedSurface &surf);
- const Common::Array<struct GameItem> &getGameItems() const { return _gameItems; }
+ Common::Array<struct GameItem> &getGameItems() { return _gameItems; }
int countItemsInScene2() const;
private:
@@ -279,8 +279,9 @@ public:
void globalOps(const Common::Array<uint16> &args) override;
void mouseMoved(const Common::Point &pt);
- void mouseLClicked(const Common::Point &pt);
- void mouseRClicked(const Common::Point &pt);
+ void mouseLDown(const Common::Point &pt);
+ void mouseLUp(const Common::Point &pt);
+ void mouseRUp(const Common::Point &pt);
void addInvButtonToHotAreaList();
void removeInvButtonFromHotAreaList();
Commit: 87fa1a848291c94231c1d3510e86d03483e9322e
https://github.com/scummvm/scummvm/commit/87fa1a848291c94231c1d3510e86d03483e9322e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Improve clock and scene condition evaluation
Changed paths:
engines/dgds/clock.cpp
engines/dgds/clock.h
engines/dgds/dgds.cpp
engines/dgds/globals.cpp
engines/dgds/inventory.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index d933756542b..440698a5896 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -28,9 +28,6 @@
namespace Dgds {
-
-////////////////////////////////
-
class DragonTimeGlobal : public ReadWriteGlobal<int16> {
public:
DragonTimeGlobal(uint16 num, int16 *val, Clock &clock) : ReadWriteGlobal<int16>(num, val), _clock(clock) {}
@@ -48,7 +45,9 @@ private:
};
Clock::Clock() : _visibleUser(true), _visibleScript(true), _days(0), _days2(0),
- _hours(0), _mins(0), _gameMinsAdded(0) {
+ _hours(0), _mins(0), _gameMinsAdded(0), _gameTicksUp(0), _gameTicksDown(0),
+ _lastPlayTime(0), _millis(0)
+{
}
Global *Clock::getDaysGlobal(uint16 num) {
@@ -71,6 +70,14 @@ Global *Clock::getGameMinsAddedGlobal(uint16 num) {
return new ReadOnlyGlobal<int16>(num, &_gameMinsAdded);
}
+Global *Clock::getGameTicksUpGlobal(uint16 num) {
+ return new ReadOnlyGlobal<int16>(num, &_gameTicksUp);
+}
+
+Global *Clock::getGameTicksDownGlobal(uint16 num) {
+ return new ReadOnlyGlobal<int16>(num, &_gameTicksDown);
+}
+
static int16 DAYS_PER_MONTH[] = {
31, 28, 31, 30,
31, 30, 31, 31,
@@ -110,7 +117,7 @@ Common::String Clock::getTimeStr() const {
return Common::String::format("%2d/%02d %2d:%02d", month + 1, day, _hours, _mins);
}
-void Clock::draw(Graphics::ManagedSurface *surf) {
+void Clock::draw(Graphics::ManagedSurface &surf) {
// FIXME: Temporarily ignore script visibility flag for testing.
if (!_visibleUser /*|| !_visibleScript*/)
return;
@@ -126,10 +133,35 @@ void Clock::draw(Graphics::ManagedSurface *surf) {
_drawPos.right = SCREEN_WIDTH;
_drawPos.left = SCREEN_WIDTH - width;
- RequestData::fillBackground(surf, _drawPos.left + 2, _drawPos.top + 2, _drawPos.width() - 4, _drawPos.height() - 4, 65);
- font->drawString(surf, clockStr, _drawPos.left + 3, _drawPos.top + 3, _drawPos.width(), 0);
+ RequestData::fillBackground(&surf, _drawPos.left + 2, _drawPos.top + 2, _drawPos.width() - 4, _drawPos.height() - 4, 65);
+ font->drawString(&surf, clockStr, _drawPos.left + 3, _drawPos.top + 3, _drawPos.width(), 0);
}
+// TODO: This is approximate, work out the exact conversion factor here for better game accuracy.
+static const int MILLIS_PER_GAME_MIN = 5000;
+static const int MILLIS_PER_TIMER_TICK = 60;
+
+void Clock::update(bool gameRunning) {
+ uint32 playTimeNow = g_engine->getTotalPlayTime();
+ // These timers are updated whether or not the game is running
+ _gameTicksUp = playTimeNow / MILLIS_PER_TIMER_TICK;
+ // Is there any reason to make this variable anything other than negative the other one??
+ // There seems to be no other way to set them as the are RO globals.
+ _gameTicksDown = -_gameTicksUp;
+
+ uint32 lastLastPlayTime = _lastPlayTime;
+ _lastPlayTime = playTimeNow;
+
+ if (lastLastPlayTime == 0 || !gameRunning)
+ return;
+
+ _millis += playTimeNow - lastLastPlayTime;
+ int16 mins_to_add = _millis / MILLIS_PER_GAME_MIN;
+ _millis = _millis % MILLIS_PER_GAME_MIN;
+
+ if (mins_to_add)
+ addGameTime(mins_to_add);
+}
} // end namespace Dgds
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index b908e9e8991..7b88dcd6ba2 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -42,23 +42,29 @@ public:
void setTime(int16 month, int16 day, int16 hour, int16 minute);
Common::String getTimeStr() const;
- void draw(Graphics::ManagedSurface *surf);
+ void draw(Graphics::ManagedSurface &surf);
void toggleVisibleUser() { _visibleUser = !_visibleUser; }
void setVisibleScript(bool val) { _visibleScript = val; }
- void update();
+ void update(bool gameRunning);
Global *getMinsGlobal(uint16 num);
Global *getHoursGlobal(uint16 num);
Global *getDaysGlobal(uint16 num);
Global *getDays2Global(uint16 num);
Global *getGameMinsAddedGlobal(uint16 num);
+ Global *getGameTicksUpGlobal(uint16 num);
+ Global *getGameTicksDownGlobal(uint16 num);
const Common::Rect &getPos() const { return _drawPos; }
private:
+ uint32 _lastPlayTime;
+ uint32 _millis;
int16 _gameMinsAdded;
+ int16 _gameTicksUp;
+ int16 _gameTicksDown;
int16 _days;
int16 _days2;
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 5dcbe8514ab..cfc1b6ce730 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -451,10 +451,14 @@ Common::Error DgdsEngine::run() {
_gdsScene->drawItems(_resData);
checkDrawInventoryButton();
}
- _clock.draw(&_resData);
- _scene->checkDialogActive();
+ _clock.draw(_resData);
+ bool haveActiveDialog = _scene->checkDialogActive();
_scene->drawAndUpdateDialogs(&_resData);
+
+ bool gameRunning = (!haveActiveDialog && _gameGlobals->getGlobal(0x57) /* TODO: && _dragItem == nullptr*/);
+ _clock.update(gameRunning);
+
} else if (getGameId() == GID_BEAMISH) {
if (!_adsInterp->run())
return Common::kNoError;
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index cf55d1b192c..a8a26faeb4b 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -121,6 +121,7 @@ _sceneOpcode15FromScene(0), _sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _ar
_opcode106EndMinutes(0) {
_globals.push_back(_clock.getGameMinsAddedGlobal(1));
_globals.push_back(new ROI16Global(0x64, &_gameCounterTicksUp));
+ _globals.push_back(new ROI16Global(0x63, &_gameCounterTicksDown));
_globals.push_back(new ROI16Global(0x62, &_lastOpcode1SceneChageNum));
_globals.push_back(new RWI16Global(0x61, &_sceneOp12SceneNum));
_globals.push_back(new RWI16Global(0x60, &_currentSelectedItem));
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 4d025d33638..ea22de3b957 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -191,7 +191,7 @@ void Inventory::mouseLUp(const Common::Point &pt) {
return;
} else if (_nextPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
debug("TODO: next inventory page");
- } else if (_prevPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
+ } else if (_prevPageBtn->containsPoint(pt) && !(_prevPageBtn->_flags3 & 0x40)) {
debug("TODO: prev inventory page");
} else if (_clockSkipMinBtn && _clockSkipMinBtn->containsPoint(pt)) {
engine->getClock().addGameTime(1);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index d1a5be570cb..38aede162fe 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -60,8 +60,8 @@ template<class S> Common::String _dumpStructList(const Common::String &indent, c
Common::String _sceneConditionStr(SceneCondition cflag) {
Common::String ret;
- if (cflag & kSceneCondAlwaysTrue)
- return "true";
+ if (cflag & kSceneCondOr)
+ return "or";
if (cflag & kSceneCondSceneState)
ret += "state|";
@@ -444,7 +444,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
for (const SceneOp &op : ops) {
if (!checkConditions(op._conditionList))
continue;
- //debug("Exec %s", op.dump("").c_str());
+ debug("Exec %s", op.dump("").c_str());
switch(op._opCode) {
case kSceneOpChangeScene:
if (engine->changeScene(op._args[0], true))
@@ -522,18 +522,16 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
}
bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds) {
- if (conds.empty())
- return true;
- uint truecount = 0;
-
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
Globals *globals = engine->getGameGlobals();
- for (const auto &c : conds) {
+ uint cnum = 0;
+ while (cnum < conds.size()) {
+ const struct SceneConditions &c = conds[cnum];
int16 refval = c._val;
int16 checkval = -1;
SceneCondition cflag = c._flags;
- if (cflag & kSceneCondAlwaysTrue)
+ if (cflag & kSceneCondOr)
return true;
if (cflag & kSceneCondSceneState) {
@@ -573,10 +571,16 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
debug("Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
- if (result)
- truecount++;
+ if (!result) {
+ // Skip to the next or, or the end.
+ while (cnum < conds.size() && !(conds[cnum]._flags & kSceneCondOr))
+ cnum++;
+ if (cnum >= conds.size())
+ return false;
+ }
+ cnum++;
}
- return truecount == conds.size();
+ return true;
}
@@ -887,7 +891,7 @@ void SDSScene::globalOps(const Common::Array<uint16> &args) {
}
void SDSScene::mouseMoved(const Common::Point &pt) {
- HotArea *area = findAreaUnderMouse(pt);
+ const HotArea *area = findAreaUnderMouse(pt);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
engine->setMouseCursor(area ? area->_cursorNum : 0);
}
@@ -905,7 +909,7 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
}
void SDSScene::mouseLUp(const Common::Point &pt) {
- HotArea *area = findAreaUnderMouse(pt);
+ const HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
if (area->_num == 0)
@@ -915,7 +919,7 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
}
void SDSScene::mouseRUp(const Common::Point &pt) {
- HotArea *area = findAreaUnderMouse(pt);
+ const HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
runOps(area->onRClickOps);
@@ -950,7 +954,7 @@ void SDSScene::addInvButtonToHotAreaList() {
if (cursors.empty() || !icons || icons->loadedFrameCount() <= 2 || _num == 2)
return;
- if (_hotAreaList[0]._num == 0)
+ if (_hotAreaList.size() && _hotAreaList[0]._num == 0)
return;
HotArea area;
@@ -1058,28 +1062,38 @@ Common::String GDSScene::dump(const Common::String &indent) const {
}
void GDSScene::globalOps(const Common::Array<uint16> &args) {
- for (uint i = 0; i < args.size() / 3; i++) {
- uint16 num = args[i * 3 + 0];
- uint16 op = args[i * 3 + 1];
- uint16 val = args[i * 3 + 2];
+ if (!args.size())
+ error("GDSScene::globalOps: Empty arg list");
+
+ // The arg list should be a first value giving the count of operations,
+ // then 3 values for each op (num, opcode, val).
+ uint nops = args.size() / 3;
+ uint nops_in_args = args[0];
+ if (args.size() != nops * 3 + 1 || nops != nops_in_args)
+ error("GDSScene::globalOps: Op list should be length 3*n+1");
+
+ for (uint i = 0; i < nops; i++) {
+ uint16 num = args[i * 3 + 1];
+ uint16 op = args[i * 3 + 2];
+ int16 val = args[i * 3 + 3];
// CHECK ME: The original uses a different function here, but the
// result appears to be the same as just calling getGlobal?
- num = getGlobal(num);
+ int16 num2 = getGlobal(num);
// Op bit 3 on means use absolute val of val.
// Off means val is another global to lookup
if (op & 8)
op = op & 0xfff7;
else
- val = getGlobal(val);
+ val = getGlobal((uint16)val);
if (op == 1)
- val = num + val;
+ val = num2 + val;
else if (op == 6)
val = (val == 0);
else if (op == 5)
- val = num - val;
+ val = num2 - val;
setGlobal(num, val);
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index b9902a09ffe..baab3296f37 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -41,7 +41,7 @@ enum SceneCondition {
kSceneCondEqual = 2,
kSceneCondNegate = 4,
kSceneCondAbsVal = 8,
- kSceneCondAlwaysTrue = 0x10,
+ kSceneCondOr = 0x10,
kSceneCondNeedItemQuality = 0x20,
kSceneCondNeedItemSceneNum = 0x40,
kSceneCondSceneState = 0x80
Commit: 1030ef3224b6396df51587b26f1531baa07167a4
https://github.com/scummvm/scummvm/commit/1030ef3224b6396df51587b26f1531baa07167a4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement more inventory stuff
Changed paths:
engines/dgds/globals.cpp
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/request.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index a8a26faeb4b..231364459cd 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -120,8 +120,8 @@ _gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0
_sceneOpcode15FromScene(0), _sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
_globals.push_back(_clock.getGameMinsAddedGlobal(1));
- _globals.push_back(new ROI16Global(0x64, &_gameCounterTicksUp));
- _globals.push_back(new ROI16Global(0x63, &_gameCounterTicksDown));
+ _globals.push_back(_clock.getGameTicksUpGlobal(0x64));
+ _globals.push_back(_clock.getGameTicksDownGlobal(0x63));
_globals.push_back(new ROI16Global(0x62, &_lastOpcode1SceneChageNum));
_globals.push_back(new RWI16Global(0x61, &_sceneOp12SceneNum));
_globals.push_back(new RWI16Global(0x60, &_currentSelectedItem));
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index ea22de3b957..57ffd91c4ad 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -31,7 +31,8 @@ namespace Dgds {
Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nullptr),
_invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _clockSkipMinBtn(nullptr),
- _clockSkipHrBtn(nullptr), _dropBtn(nullptr), _highlightItemNo(-1), _itemOffset(0)
+ _itemArea(nullptr), _clockSkipHrBtn(nullptr), _dropBtn(nullptr), _highlightItemNo(-1),
+ _itemOffset(0)
{
}
@@ -49,8 +50,9 @@ void Inventory::setRequestData(const REQFileData &data) {
_clockSkipMinBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(24));
_clockSkipHrBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(25));
_dropBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(16));
+ _itemArea = dynamic_cast<ImageGadget *>(_reqData._requests[0].findGadgetByNumWithFlags3Not0x40(8));
- if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton)
+ if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton || !_itemArea)
error("Didn't get all expected inventory gadgets");
}
@@ -78,21 +80,17 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isResta
if (engine->getScene()->getNum() == 2)
return;
- ImageGadget *itemImgArea = dynamic_cast<ImageGadget *>(_reqData._requests[0].findGadgetByNumWithFlags3Not0x40(8));
if (isRestarting) {
warning("TODO: Handle inventory redraw on restart");
} else {
_itemZoomBox->_flags3 &= 0x40;
}
- if (!itemImgArea)
- error("Couldn't get img area for inventory");
-
//
// Decide whether the nextpage/prevpage buttons should be visible
//
- if ((itemImgArea->_width / itemImgArea->_xStep) *
- (itemImgArea->_height / itemImgArea->_yStep) > itemCount) {
+ if ((_itemArea->_width / _itemArea->_xStep) *
+ (_itemArea->_height / _itemArea->_yStep) > itemCount) {
// not visible.
_prevPageBtn->_flags3 |= 0x40;
_nextPageBtn->_flags3 |= 0x40;
@@ -104,10 +102,8 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isResta
_reqData._requests[0].drawInvType(&surf);
drawHeader(surf);
-
drawTime(surf);
-
- drawItems(surf, itemImgArea);
+ drawItems(surf);
}
void Inventory::drawTime(Graphics::ManagedSurface &surf) {
@@ -121,18 +117,18 @@ void Inventory::drawTime(Graphics::ManagedSurface &surf) {
font->drawString(&surf, timeStr, clockpos.x, clockpos.y, font->getStringWidth(timeStr), _invClock->_col3);
}
-void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea) {
+void Inventory::drawItems(Graphics::ManagedSurface &surf) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
const Common::SharedPtr<Image> &icons = engine->getIcons();
int x = 0;
int y = 0;
- const int xstep = imgArea->_xStep;
- const int ystep = imgArea->_yStep;
+ const int xstep = _itemArea->_xStep;
+ const int ystep = _itemArea->_yStep;
+ const int imgAreaX = _itemArea->_parentX + _itemArea->_x;
+ const int imgAreaY = _itemArea->_parentY + _itemArea->_y;
- Common::Point pos(imgArea->_parentX + imgArea->_x, imgArea->_parentY + imgArea->_y);
- Common::Rect itemRect(pos, imgArea->_width, imgArea->_height);
+ Common::Rect itemRect(Common::Point(imgAreaX, imgAreaY), _itemArea->_width, _itemArea->_height);
//surf.fillRect(itemRect, (byte)imgArea->_col1);
if (!icons)
@@ -141,8 +137,9 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea)
// TODO: does this need to be adjusted ever?
const Common::Rect drawMask(0, 0, 320, 200);
int offset = _itemOffset;
+ const Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
for (const auto & item: items) {
- if (item._inSceneNum != 2 || !(item._flags & 4))
+ if (item._inSceneNum != 2) // || !(item._flags & 4))
continue;
if (offset) {
@@ -152,22 +149,22 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea)
if (item._num == _highlightItemNo) {
// draw highlighted
- Common::Rect highlightRect(Common::Point(x, y), xstep, ystep);
+ Common::Rect highlightRect(Common::Point(imgAreaX + x, imgAreaY + y), xstep, ystep);
surf.fillRect(highlightRect, 4);
}
// draw offset for the image
- int xoff = x + (xstep - item.rect.width) / 2;
- int yoff = y + (ystep - item.rect.height) / 2;
+ int drawX = imgAreaX + x + (xstep - item.rect.width) / 2;
+ int drawY = imgAreaY + y + (ystep - item.rect.height) / 2;
- icons->drawBitmap(item._iconNum, xoff, yoff, drawMask, surf);
+ icons->drawBitmap(item._iconNum, drawX, drawY, drawMask, surf);
x += xstep;
- if (x > imgArea->_x + imgArea->_width) {
+ if (x >= _itemArea->_width) {
x = 0;
y += ystep;
}
- if (y > imgArea->_x + imgArea->_width) {
+ if (y >= _itemArea->_height) {
break;
}
}
@@ -175,31 +172,86 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea)
void Inventory::mouseMoved(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- engine->setMouseCursor(0);
+ const GameItem *dragItem = engine->getScene()->getDragItem();
+ if (dragItem) {
+ const RequestData &req = _reqData._requests[0];
+ const Common::Rect bgsize(Common::Point(req._x, req._y), req._width, req._height);
+ if (!bgsize.contains(pt)) {
+ // dragged an item outside the inventory
+ close();
+ }
+ } else {
+ engine->setMouseCursor(0);
+ }
+}
+
+GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (!_itemArea || !_itemArea->containsPoint(pt))
+ return nullptr;
+
+ const int imgAreaX = _itemArea->_parentX + _itemArea->_x;
+ const int imgAreaY = _itemArea->_parentY + _itemArea->_y;
+ const int numacross = _itemArea->_width / _itemArea->_xStep;
+ const int itemrow = (pt.y - imgAreaY) / _itemArea->_yStep;
+ const int itemcol = (pt.x - imgAreaX) / _itemArea->_xStep;
+ int itemnum = numacross * itemrow + itemcol;
+
+ Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ for (auto &item: items) {
+ if (item._inSceneNum != 2) // || !(item._flags & 4))
+ continue;
+
+ if (itemnum) {
+ itemnum--;
+ continue;
+ }
+ return &item;
+ }
+ return nullptr;
}
void Inventory::mouseLDown(const Common::Point &pt) {
- if (_itemBox && _itemBox->containsPoint(pt)) {
- debug("TODO: Handle drag events inside inventory.");
+ GameItem *underMouse = itemUnderMouse(pt);
+ if (underMouse) {
+ _highlightItemNo = underMouse->_num;
}
+ debug("TODO: Inventory::mouseLDown: Bring up the item description");
}
void Inventory::mouseLUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ int itemsPerPage = (_itemArea->_width / _itemArea->_xStep) * (_itemArea->_height / _itemArea->_yStep);
if (_exitButton->containsPoint(pt)) {
close();
return;
} else if (_nextPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
- debug("TODO: next inventory page");
+ int numInvItems = 0;
+ Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ for (auto &item: items) {
+ if (item._inSceneNum == 2) // && item._flags & 4)
+ numInvItems++;
+ }
+ if (_itemOffset < numInvItems)
+ _itemOffset += itemsPerPage;
} else if (_prevPageBtn->containsPoint(pt) && !(_prevPageBtn->_flags3 & 0x40)) {
- debug("TODO: prev inventory page");
+ if (_itemOffset > 0)
+ _itemOffset -= itemsPerPage;
} else if (_clockSkipMinBtn && _clockSkipMinBtn->containsPoint(pt)) {
engine->getClock().addGameTime(1);
} else if (_clockSkipHrBtn && _clockSkipHrBtn->containsPoint(pt)) {
engine->getClock().addGameTime(60);
} else if (_dropBtn && _dropBtn->containsPoint(pt)) {
- if (_highlightItemNo >= 0)
- debug("TODO: drop button");
+ if (_highlightItemNo >= 0) {
+ Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ for (auto &item: items) {
+ if (item._num == _highlightItemNo) {
+ item._inSceneNum = engine->getScene()->getNum();
+ break;
+ }
+ }
+ _highlightItemNo = -1;
+ }
}
}
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index ea9a194072a..58f128375f6 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -30,6 +30,8 @@ class ManagedSurface;
namespace Dgds {
+class GameItem;
+
class Inventory {
public:
Inventory();
@@ -38,7 +40,7 @@ public:
void open() { _isOpen = true; }
void close() { _isOpen = false; }
void draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting = false);
- void drawItems(Graphics::ManagedSurface &surf, ImageGadget *imgArea);
+ void drawItems(Graphics::ManagedSurface &surf);
void drawTime(Graphics::ManagedSurface &surf);
void drawHeader(Graphics::ManagedSurface &surf);
@@ -50,6 +52,8 @@ public:
void setRequestData(const REQFileData &data);
private:
+ GameItem *itemUnderMouse(const Common::Point &pt);
+
bool _isOpen;
ButtonGadget *_prevPageBtn;
ButtonGadget *_nextPageBtn;
@@ -60,6 +64,7 @@ private:
ButtonGadget *_clockSkipMinBtn;
ButtonGadget *_clockSkipHrBtn;
ButtonGadget *_dropBtn;
+ ImageGadget *_itemArea;
REQFileData _reqData;
int _highlightItemNo; // -1 means no item highlighted.
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index d591d66d345..2cb8b762547 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -511,8 +511,6 @@ void ImageGadget::draw(Graphics::Surface *dst) const {
dst->fillRect(drawRect, _col1);
// Note: not quite the same as the original logic here, but gets the same result.
_drawFrame(dst, xoff, yoff, _width, _height, _sval1I, _sval1I);
-
- warning("TODO: Implement ImageGadget::draw");
}
Common::String RequestData::dump() const {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 38aede162fe..9df9d0dcf41 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -395,6 +395,47 @@ bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<Di
}
+void Scene::setItemAttrOp(const Common::Array<uint16> &args) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (args.size() < 3)
+ error("Expect 3 args for item attr opcode.");
+
+ for (auto &item : engine->getGDSScene()->getGameItems()) {
+ if (item._num != args[0])
+ continue;
+
+ if (args[1] != 0xffff) {
+ //bool doDraw = item._inSceneNum != args[1] && engine->getScene()->getNum() == args[1];
+ item._inSceneNum = args[1];
+ }
+
+ if (args[2])
+ item._quality = args[2];
+
+ break;
+ }
+}
+
+void Scene::setDragItemOp(const Common::Array<uint16> &args) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
+ for (auto &item : engine->getGDSScene()->getGameItems()) {
+ if (item._num != args[0])
+ continue;
+
+ bool inScene = (item._inSceneNum == engine->getScene()->getNum());
+ engine->getScene()->setDragItem(&item);
+ if (!inScene)
+ item._inSceneNum = engine->getScene()->getNum(); // else do some redraw??
+
+ Common::Point lastMouse = engine->getLastMouse();
+ item.rect.x = lastMouse.x;
+ item.rect.y = lastMouse.y;
+ // TODO: Update hot x/y here ?
+ engine->setMouseCursor(item._iconNum);
+ }
+}
+
void Scene::segmentStateOps(const Common::Array<uint16> &args) {
ADSInterpreter *interp = static_cast<DgdsEngine *>(g_engine)->adsInterpreter();
@@ -444,7 +485,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
for (const SceneOp &op : ops) {
if (!checkConditions(op._conditionList))
continue;
- debug("Exec %s", op.dump("").c_str());
+ debug(10, "Exec %s", op.dump("").c_str());
switch(op._opCode) {
case kSceneOpChangeScene:
if (engine->changeScene(op._args[0], true))
@@ -460,10 +501,10 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
segmentStateOps(op._args);
break;
case kSceneOpSetItemAttr:
- warning("TODO: Implement set item attr(?) scene op");
+ setItemAttrOp(op._args);
break;
case kSceneOpGiveItem:
- warning("TODO: Implement give item(?) scene op");
+ setDragItemOp(op._args);
break;
case kSceneOpOpenInventory:
engine->getInventory()->open();
@@ -523,7 +564,6 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- Globals *globals = engine->getGameGlobals();
uint cnum = 0;
while (cnum < conds.size()) {
@@ -531,6 +571,8 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
int16 refval = c._val;
int16 checkval = -1;
SceneCondition cflag = c._flags;
+ // Two "or"s in a row, or an "or" at the start means true
+ // (as one side is empty)
if (cflag & kSceneCondOr)
return true;
@@ -553,9 +595,9 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
}
}
} else {
- checkval = globals->getGlobal(c._num);
+ checkval = engine->getGDSScene()->getGlobal(c._num);
if (!(cflag & kSceneCondAbsVal))
- refval = globals->getGlobal(refval);
+ refval = engine->getGDSScene()->getGlobal((uint16)refval);
}
bool result = false;
@@ -569,7 +611,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (cflag & kSceneCondNegate)
result = !result;
- debug("Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
+ debug(10, "Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
if (!result) {
// Skip to the next or, or the end.
@@ -587,7 +629,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
bool SDSScene::_dlgWithFlagLo8IsClosing = false;;
DialogFlags SDSScene::_sceneDialogFlags = kDlgFlagNone;
-SDSScene::SDSScene() : _num(-1) {
+SDSScene::SDSScene() : _num(-1), _dragItem(nullptr) {
}
bool SDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
@@ -650,6 +692,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
void SDSScene::unload() {
_num = 0;
+ _dragItem = nullptr;
_enterSceneOps.clear();
_leaveSceneOps.clear();
_preTickOps.clear();
@@ -893,7 +936,17 @@ void SDSScene::globalOps(const Common::Array<uint16> &args) {
void SDSScene::mouseMoved(const Common::Point &pt) {
const HotArea *area = findAreaUnderMouse(pt);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- engine->setMouseCursor(area ? area->_cursorNum : 0);
+
+ int16 cursorNum = area ? area->_cursorNum : 0;
+ if (_dragItem)
+ cursorNum = _dragItem->_iconNum;
+
+ engine->setMouseCursor(cursorNum);
+
+ if (area && area->_num == 0) {
+ // Object dragged over the inventory button
+ // static_cast<DgdsEngine *>(g_engine)->getInventory()-> ...
+ }
}
void SDSScene::mouseLDown(const Common::Point &pt) {
@@ -901,21 +954,40 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
if (!area)
return;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ runOps(area->opList2);
GameItem *item = dynamic_cast<GameItem *>(area);
- if (!item)
- return;
-
- debug("TODO: Implement drag in scene for item %d", item->_num);
+ if (item) {
+ _dragItem = item;
+ if (item->_iconNum)
+ engine->setMouseCursor(item->_iconNum);
+ }
}
void SDSScene::mouseLUp(const Common::Point &pt) {
const HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
- if (area->_num == 0)
- static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
- else
+
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
+ if (area->_num == 0) {
+ if (_dragItem) {
+ _dragItem->_inSceneNum = 2;
+ } else {
+ static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
+ }
+ } else {
+ // TODO: Need to do something with the drag item - struct4s
+ // should give instructions what to do here.
runOps(area->onLClickOps);
+ }
+ _dragItem = nullptr;
+
+ if (!_dragItem)
+ engine->setMouseCursor(area->_cursorNum);
+ else
+ engine->setMouseCursor(_dragItem->_iconNum);
}
void SDSScene::mouseRUp(const Common::Point &pt) {
@@ -1135,7 +1207,7 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
// Don't overlap the inventory icon.
const int maxx = SCREEN_WIDTH - (icons->width(2) + 10);
for (auto &item : _gameItems) {
- if (item._inSceneNum == currentScene /* TODO: && item != draggingItem*/) {
+ if (item._inSceneNum == currentScene && &item != engine->getScene()->getDragItem()) {
if (!(item._flags & 1)) {
// Dropped item.
if (xoff + item.rect.width > maxx)
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index baab3296f37..e14752d3c56 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -208,6 +208,9 @@ protected:
void segmentStateOp11(uint16 arg);
void segmentStateOp12(uint16 arg);
+ void setItemAttrOp(const Common::Array<uint16> &args);
+ void setDragItemOp(const Common::Array<uint16> &args);
+
uint32 _magic;
Common::String _version;
@@ -288,6 +291,9 @@ public:
const Common::Array<struct HotArea> &getHotAreas() const { return _hotAreaList; }
+ const GameItem *getDragItem() const { return _dragItem; }
+ void setDragItem(GameItem *item) { _dragItem = item; }
+
private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
void enableTrigger(uint16 num) override;
@@ -308,6 +314,8 @@ private:
Common::Array<struct SceneTrigger> _triggers;
//uint _field15_0x33;
+ GameItem *_dragItem;
+
static bool _dlgWithFlagLo8IsClosing;
static DialogFlags _sceneDialogFlags;
};
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 1d384e8de69..30cd47e405f 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -443,7 +443,7 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
if (scr->pos() >= scr->size())
return false;
- debug("TTM: Run env %d seq %d frame %d (scr offset %d)", seq._enviro, seq._seqNum,
+ debug(10, "TTM: Run env %d seq %d frame %d (scr offset %d)", seq._enviro, seq._seqNum,
seq._currentFrame, (int)scr->pos());
uint16 code = 0;
while (code != 0x0ff0 && scr->pos() < scr->size()) {
@@ -456,7 +456,7 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
if (count > 8 && count != 0x0f)
error("Invalid TTM opcode %04x requires %d locals", code, count);
- debugN("\tOP: 0x%4.4x %2u ", op, count);
+ debugN(10, "\tOP: 0x%4.4x %2u ", op, count);
if (count == 0x0F) {
byte ch[2];
@@ -469,16 +469,16 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
sval += ch[1];
} while (ch[0] != 0 && ch[1] != 0);
- debugN("\"%s\"", sval.c_str());
+ debugN(10, "\"%s\"", sval.c_str());
} else {
for (byte i = 0; i < count; i++) {
ivals[i] = scr->readSint16LE();
if (i > 0)
- debugN(", ");
- debugN("%d", ivals[i]);
+ debugN(10, ", ");
+ debugN(10, "%d", ivals[i]);
}
}
- debug(" (%s)", ttmOpName(op));
+ debug(10, " (%s)", ttmOpName(op));
handleOperation(env, seq, op, count, ivals, sval);
}
@@ -635,7 +635,7 @@ bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
if (seq._timeInterval != 0) {
uint32 now = g_engine->getTotalPlayTime();
if (now < seq._timeNext) {
- debug("env %d seq %d not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
+ debug(10, "env %d seq %d not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
seq._seqNum, seq._currentFrame, now, seq._timeNext, seq._timeInterval);
return false;
}
@@ -644,11 +644,11 @@ bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
seq._executed = false;
if (seq._gotoFrame == -1) {
- debug("env %d seq %d advance to frame %d->%d (start %d last %d)", seq._enviro,
+ debug(10, "env %d seq %d advance to frame %d->%d (start %d last %d)", seq._enviro,
seq._seqNum, seq._currentFrame, seq._currentFrame + 1, seq._startFrame, seq._lastFrame);
seq._currentFrame++;
} else {
- debug("env %d seq %d goto to frame %d->%d (start %d last %d)", seq._enviro,
+ debug(10, "env %d seq %d goto to frame %d->%d (start %d last %d)", seq._enviro,
seq._seqNum, seq._currentFrame, seq._gotoFrame, seq._startFrame, seq._lastFrame);
seq._currentFrame = seq._gotoFrame;
seq._gotoFrame = -1;
@@ -803,25 +803,25 @@ void ADSInterpreter::findEndOrInitOp() {
bool ADSInterpreter::logicOpResult(uint16 code, const TTMSeq *seq) {
switch (code) {
case 0x1310: // IF runtype 5, 2 params
- debug("ADS: if runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunType5;
case 0x1320: // IF not runtype 5, 2 params
- debug("ADS: if not runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if not runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runFlag != kRunType5;
case 0x1330: // IF_NOT_PLAYED, 2 params
- debug("ADS: if not played env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if not played env %d seq %d", seq->_enviro, seq->_seqNum);
return !seq->_runPlayed;
case 0x1340: // IF_PLAYED, 2 params
- debug("ADS: if played env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if played env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runPlayed;
case 0x1350: // IF_FINISHED, 2 params
- debug("ADS: if finished env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if finished env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunTypeFinished;
case 0x1360: // IF_NOT_RUNNING, 2 params
- debug("ADS: if not running env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if not running env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunTypeStopped;
case 0x1370: // IF_RUNNING, 2 params
- debug("ADS: if running env %d seq %d", seq->_enviro, seq->_seqNum);
+ debug(10, "ADS: if running env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
default:
error("Not an ADS logic op: %04x, how did we get here?", code);
@@ -840,15 +840,20 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr
return false;
}
+ bool logicResult = logicOpResult(code, seq);
+
if (andor == 0x1420) // AND
- testval &= logicOpResult(code, seq);
+ testval &= logicResult;
else // OR
- testval |= logicOpResult(code, seq);
+ testval |= logicResult;
+
+ debug(10, " -> %s (overall %s)", logicResult ? "true" : "false", testval ? "true" : "false");
code = scr->readUint16LE();
if (code == 0x1420 || code == 0x1430) {
andor = code;
+ debug(10, " ADS %s", code == 0x1420 ? "AND" : "AND");
code = scr->readUint16LE();
// The next op should be another logic op
} else {
@@ -893,7 +898,7 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
int64 endpos = scr->pos();
- int16 randval = _vm->getRandom().getRandomNumber(max - 1);
+ int16 randval = _vm->getRandom().getRandomNumber(max - 1) + 1; // Random from 1-max.
scr->seek(startpos, SEEK_SET);
// Now find the random bit to jump to
@@ -919,7 +924,7 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
- debug(" ADSOP: 0x%04x", code);
+ debug(10, " ADSOP: 0x%04x", code);
switch (code) {
case 0x0001:
@@ -941,11 +946,11 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
_adsData._hitBranchOp = true;
return true;
case 0x1510: // PLAY_SCENE? 0 params
- debug("ADS: 0x%04x hit branch op true", code);
+ debug(10, "ADS: 0x%04x hit branch op true", code);
_adsData._hitBranchOp = true;
return true;
case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
- debug("ADS: 0x%04x hit branch op", code);
+ debug(10, "ADS: 0x%04x hit branch op", code);
_adsData._hitBranchOp = true;
return false;
@@ -955,7 +960,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seqnum = scr->readUint16LE();
int16 runCount = scr->readSint16LE();
uint16 unk = scr->readUint16LE();
- debug("ADS: add scene - env %d seq %d runCount %d unk %d", enviro, seqnum, runCount, unk);
+ debug(10, "ADS: add scene - env %d seq %d runCount %d unk %d", enviro, seqnum, runCount, unk);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (!seq)
@@ -984,7 +989,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug("ADS: stop seq env %d seq %d unk %d", enviro, seqnum, unk);
+ debug(10, "ADS: stop seq env %d seq %d unk %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
if (_currentTTMSeq)
_currentTTMSeq->_runFlag = kRunTypeStopped;
@@ -994,7 +999,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug("ADS: set runflag5 env %d seq %d unk %d", enviro, seqnum, unk);
+ debug(10, "ADS: set runflag5 env %d seq %d unk %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
if (_currentTTMSeq)
_currentTTMSeq->_runFlag = kRunType5;
@@ -1004,7 +1009,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug("ADS: reset scene env %d seq %d unk %d", enviro, seqnum, unk);
+ debug(10, "ADS: reset scene env %d seq %d unk %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
if (_currentTTMSeq)
_currentTTMSeq->reset();
Commit: c219ffd53e4e7705838aabc56c212c5376e08d6d
https://github.com/scummvm/scummvm/commit/c219ffd53e4e7705838aabc56c212c5376e08d6d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add object-object interactions
Changed paths:
engines/dgds/inventory.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 57ffd91c4ad..afad1039efd 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -137,8 +137,8 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
// TODO: does this need to be adjusted ever?
const Common::Rect drawMask(0, 0, 320, 200);
int offset = _itemOffset;
- const Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
- for (const auto & item: items) {
+ Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ for (auto & item: items) {
if (item._inSceneNum != 2) // || !(item._flags & 4))
continue;
@@ -159,6 +159,9 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
icons->drawBitmap(item._iconNum, drawX, drawY, drawMask, surf);
+ item.rect.x = drawX;
+ item.rect.y = drawY;
+
x += xstep;
if (x >= _itemArea->_width) {
x = 0;
@@ -174,6 +177,7 @@ void Inventory::mouseMoved(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const GameItem *dragItem = engine->getScene()->getDragItem();
if (dragItem) {
+ engine->setMouseCursor(dragItem->_iconNum);
const RequestData &req = _reqData._requests[0];
const Common::Rect bgsize(Common::Point(req._x, req._y), req._width, req._height);
if (!bgsize.contains(pt)) {
@@ -215,12 +219,33 @@ void Inventory::mouseLDown(const Common::Point &pt) {
GameItem *underMouse = itemUnderMouse(pt);
if (underMouse) {
_highlightItemNo = underMouse->_num;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->getScene()->setDragItem(underMouse);
}
- debug("TODO: Inventory::mouseLDown: Bring up the item description");
+ debug("TODO: Inventory::mouseLDown: Render the item description");
}
void Inventory::mouseLUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const GameItem *dragItem = engine->getScene()->getDragItem();
+ engine->getScene()->setDragItem(nullptr);
+ engine->setMouseCursor(0);
+
+ if (dragItem) {
+ GameItem *underMouse = itemUnderMouse(pt);
+ if (underMouse && dragItem && underMouse != dragItem) {
+ // TODO: This may not be the right list here?
+ const Common::Array<struct ObjectInteraction> &interactions = engine->getGDSScene()->getObjInteractions2();
+ for (const auto &i : interactions) {
+ if (i._droppedItemNum == dragItem->_num && i._targetItemNum == underMouse->_num) {
+ engine->getScene()->runOps(i.opList);
+ break;
+ }
+ }
+ }
+ return;
+ }
+
int itemsPerPage = (_itemArea->_width / _itemArea->_xStep) * (_itemArea->_height / _itemArea->_yStep);
if (_exitButton->containsPoint(pt)) {
close();
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 9df9d0dcf41..220fd16636a 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -173,8 +173,8 @@ Common::String MouseCursor::dump(const Common::String &indent) const {
}
-Common::String SceneStruct4::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sSceneStruct4<%d %d", indent.c_str(), val1, val2);
+Common::String ObjectInteraction::dump(const Common::String &indent) const {
+ Common::String str = Common::String::format("%sObjectInteraction<dropped %d target %d", indent.c_str(), _droppedItemNum, _targetItemNum);
str += _dumpStructList(indent, "opList", opList);
str += "\n";
@@ -277,16 +277,16 @@ bool Scene::readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<Mo
}
-bool Scene::readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const {
+bool Scene::readObjInteractionList(Common::SeekableReadStream *s, Common::Array<ObjectInteraction> &list) const {
list.resize(s->readUint16LE());
- for (SceneStruct4 &dst : list) {
+ for (ObjectInteraction &dst : list) {
if (!isVersionOver(" 1.205")) {
- dst.val2 = s->readUint16LE();
- dst.val1 = s->readUint16LE();
- dst.val2 += s->readUint16LE();
+ dst._targetItemNum = s->readUint16LE();
+ dst._droppedItemNum = s->readUint16LE();
+ dst._targetItemNum += s->readUint16LE();
} else {
- dst.val1 = s->readUint16LE();
- dst.val2 = s->readUint16LE();
+ dst._droppedItemNum = s->readUint16LE();
+ dst._targetItemNum = s->readUint16LE();
}
readOpList(s, dst.opList);
}
@@ -479,7 +479,6 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
}
}
-
bool Scene::runOps(const Common::Array<SceneOp> &ops) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
@@ -678,9 +677,9 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
_field6_0x14 = stream->readUint16LE();
_adsFile = stream->readString();
readHotAreaList(stream, _hotAreaList);
- readStruct4List(stream, _struct4List1);
+ readObjInteractionList(stream, _objInteractions1);
if (isVersionOver(" 1.205")) {
- readStruct4List(stream, _struct4List2);
+ readObjInteractionList(stream, _objInteractions2);
}
readDialogList(stream, _dialogs);
if (isVersionOver(" 1.203")) {
@@ -700,8 +699,8 @@ void SDSScene::unload() {
_field6_0x14 = 0;
_adsFile.clear();
_hotAreaList.clear();
- _struct4List1.clear();
- _struct4List2.clear();
+ _objInteractions1.clear();
+ _objInteractions2.clear();
_dialogs.clear();
_triggers.clear();
_sceneDialogFlags = kDlgFlagNone;
@@ -715,8 +714,8 @@ Common::String SDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "preTickOps", _preTickOps);
str += _dumpStructList(indent, "postTickOps", _postTickOps);
str += _dumpStructList(indent, "hotAreaList", _hotAreaList);
- str += _dumpStructList(indent, "struct4List1", _struct4List1);
- str += _dumpStructList(indent, "struct4List2", _struct4List2);
+ str += _dumpStructList(indent, "objInteractions1", _objInteractions1);
+ str += _dumpStructList(indent, "objInteractions2", _objInteractions2);
str += _dumpStructList(indent, "dialogues", _dialogs);
str += _dumpStructList(indent, "triggers", _triggers);
@@ -971,23 +970,34 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->setMouseCursor(area->_cursorNum);
+
if (area->_num == 0) {
+ // dropped on the inventory button
if (_dragItem) {
_dragItem->_inSceneNum = 2;
} else {
static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
}
} else {
- // TODO: Need to do something with the drag item - struct4s
- // should give instructions what to do here.
- runOps(area->onLClickOps);
+ if (_dragItem) {
+ const GameItem *targetItem = dynamic_cast<const GameItem *>(area);
+ // Dropping one item on another -> use interactions from GDS
+ // Dropping item on an area -> interactions are in SDS
+ const Common::Array<struct ObjectInteraction> &interactions =
+ targetItem ? engine->getGDSScene()->getObjInteractions2()
+ : engine->getScene()->getObjInteractions1();
+ for (const auto &i : interactions) {
+ if (i._droppedItemNum == _dragItem->_num && i._targetItemNum == targetItem->_num) {
+ runOps(i.opList);
+ break;
+ }
+ }
+ } else {
+ runOps(area->onLClickOps);
+ }
}
_dragItem = nullptr;
-
- if (!_dragItem)
- engine->setMouseCursor(area->_cursorNum);
- else
- engine->setMouseCursor(_dragItem->_iconNum);
}
void SDSScene::mouseRUp(const Common::Point &pt) {
@@ -1109,9 +1119,9 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
_iconFile = stream->readString();
readMouseHotspotList(stream, _cursorList);
readGameItemList(stream, _gameItems);
- readStruct4List(stream, _struct4List2);
+ readObjInteractionList(stream, _objInteractions2);
if (isVersionOver(" 1.205"))
- readStruct4List(stream, _struct4List1);
+ readObjInteractionList(stream, _objInteractions1);
return !stream->err();
}
@@ -1125,8 +1135,8 @@ Common::String GDSScene::dump(const Common::String &indent) const {
str += _dumpStructList(indent, "postTickOps", _postTickOps);
str += _dumpStructList(indent, "onChangeSceneOps", _onChangeSceneOps);
str += _dumpStructList(indent, "perSceneGlobals", _perSceneGlobals);
- str += _dumpStructList(indent, "struct4List1", _struct4List1);
- str += _dumpStructList(indent, "struct4List2", _struct4List2);
+ str += _dumpStructList(indent, "objInteractions1", _objInteractions1);
+ str += _dumpStructList(indent, "objInteractions2", _objInteractions2);
str += "\n";
str += indent + ">";
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index e14752d3c56..27b5d9d4151 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -133,9 +133,10 @@ struct MouseCursor {
Common::String dump(const Common::String &indent) const;
};
-struct SceneStruct4 {
- uint16 val1;
- uint16 val2;
+// Interactions between two objects when one is dropped on the other
+struct ObjectInteraction {
+ uint16 _droppedItemNum;
+ uint16 _targetItemNum;
Common::Array<struct SceneOp> opList;
Common::String dump(const Common::String &indent) const;
@@ -184,19 +185,20 @@ public:
void mouseMoved(const Common::Point pt);
void mouseClicked(const Common::Point pt);
+ bool runOps(const Common::Array<SceneOp> &ops);
+
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
bool readHotArea(Common::SeekableReadStream *s, HotArea &dst) const;
bool readHotAreaList(Common::SeekableReadStream *s, Common::Array<HotArea> &list) const;
bool readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
- bool readStruct4List(Common::SeekableReadStream *s, Common::Array<SceneStruct4> &list) const;
+ bool readObjInteractionList(Common::SeekableReadStream *s, Common::Array<ObjectInteraction> &list) const;
bool readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const;
bool readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list) const;
bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const;
- bool runOps(const Common::Array<SceneOp> &ops);
bool checkConditions(const Common::Array<struct SceneConditions> &cond);
virtual void enableTrigger(uint16 num) {}
@@ -245,6 +247,9 @@ public:
Common::Array<struct GameItem> &getGameItems() { return _gameItems; }
int countItemsInScene2() const;
+ const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
+ const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+
private:
//byte _unk[32];
Common::String _iconFile;
@@ -254,8 +259,8 @@ private:
Common::Array<struct SceneOp> _onChangeSceneOps;
Common::Array<struct MouseCursor> _cursorList;
Common::Array<struct PerSceneGlobal> _perSceneGlobals;
- Common::Array<struct SceneStruct4> _struct4List1;
- Common::Array<struct SceneStruct4> _struct4List2;
+ Common::Array<struct ObjectInteraction> _objInteractions1;
+ Common::Array<struct ObjectInteraction> _objInteractions2;
};
class SDSScene : public Scene {
@@ -294,6 +299,9 @@ public:
const GameItem *getDragItem() const { return _dragItem; }
void setDragItem(GameItem *item) { _dragItem = item; }
+ const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
+ const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+
private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
void enableTrigger(uint16 num) override;
@@ -307,8 +315,8 @@ private:
Common::String _adsFile;
//uint _field8_0x23;
Common::Array<struct HotArea> _hotAreaList;
- Common::Array<struct SceneStruct4> _struct4List1;
- Common::Array<struct SceneStruct4> _struct4List2;
+ Common::Array<struct ObjectInteraction> _objInteractions1;
+ Common::Array<struct ObjectInteraction> _objInteractions2;
//uint _field12_0x2b;
Common::Array<class Dialog> _dialogs;
Common::Array<struct SceneTrigger> _triggers;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 30cd47e405f..b7c404d2134 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -180,7 +180,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
case 0x1070: // SELECT FONT i:int
seq._currentFontId = ivals[0];
- warning("TODO: Implement TTM 0x1070 select font %d", ivals[0]);
break;
case 0x1090: // SELECT SONG: id:int [0]
seq._currentSongId = ivals[0];
@@ -317,6 +316,19 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, seq._drawColFG);
_vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, seq._drawColFG);
break;
+ case 0xa200:
+ case 0xa210:
+ case 0xa220:
+ case 0xa230: {
+ uint strnum = (op & 0x70) >> 4;
+ const Common::String &str = env._strings[strnum];
+ const FontManager *mgr = _vm->getFontMan();
+ // TODO: Probably not this font?
+ const Font *font = mgr->getFont(FontManager::kDefaultFont);
+ // Note: ignore the y-height argument (ivals[3]) for now.
+ font->drawString(&(_vm->getTopBuffer()), str, ivals[0], ivals[1], ivals[2], seq._drawColFG);
+ break;
+ }
case 0xa510:
// DRAW SPRITE x,y:int .. how different from 0xa500??
// FALL THROUGH
@@ -404,6 +416,14 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
break;
+ case 0xf100:
+ case 0xf110:
+ case 0xf120:
+ case 0xf130: {
+ uint strnum = (op & 0x70) >> 4;
+ env._strings[strnum] = sval;
+ break;
+ }
// Unimplemented / unknown
case 0x0010: // (one-shot) ??
@@ -415,7 +435,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x2010: // SET FRAME?? x,y
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
- case 0xa424: // DRAW EMPTY CIRCLE
+ case 0xa420: // DRAW EMPTY CIRCLE
// From here on are not implemented in DRAGON
case 0xb000: // ? (0 args) - found in HoC intro
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 0214b066435..f952b728095 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -55,6 +55,7 @@ public:
Common::Array<Common::Rect> _getPutAreas;
Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _getPutSurfaces;
int _scriptPals[6];
+ Common::String _strings[6];
};
enum TTMRunType {
Commit: 98185eb48b281b24b0cfe7f113808d7400c232a3
https://github.com/scummvm/scummvm/commit/98185eb48b281b24b0cfe7f113808d7400c232a3
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Hack in some dialog stuff
Changed paths:
engines/dgds/dialog.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 3ffe8bb9489..6fe9be80a78 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -152,8 +152,6 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
RequestData::drawCorners(dst, 19, _state->_loc.x - 2, _state->_loc.y - 2,
_state->_loc.width + 4, _state->_loc.height + 4);
- _state->_loc.x += 8;
- _state->_loc.y -= 8;
} else if (stage == kDlgDrawFindSelectionPointXY) {
drawFindSelectionXY();
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
@@ -168,7 +166,7 @@ static void _filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface
Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, _drawPixel, dst);
}
-// Comic tought box made up of circles with 2 circles going up to it.
+// Comic thought box made up of circles with 2 circles going up to it.
// Draw circles with 5/4 more pixels in x because the pixels are not square.
void Dialog::drawType3(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
@@ -409,7 +407,6 @@ void Dialog::drawFindSelectionTxtOffset() {
}
void Dialog::drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const Common::String &txt) {
- // TODO: some more text calcuations happen here.
// This is where we actually draw the text.
// For now do the simplest wrapping, no highlighting.
assert(_state);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 220fd16636a..42d74e6bf14 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -111,8 +111,8 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpNoop: return "noop";
case kSceneOpGlobal: return "global";
case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
- case kSceneOpSetItemAttr: return "setitemattr?";
- case kSceneOpGiveItem: return "giveitem?";
+ case kSceneOpSetItemAttr: return "setItemAttr";
+ case kSceneOpSetDragItem: return "setDragItem";
case kSceneOpOpenInventory: return "openInventory";
case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
@@ -502,7 +502,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
case kSceneOpSetItemAttr:
setItemAttrOp(op._args);
break;
- case kSceneOpGiveItem:
+ case kSceneOpSetDragItem:
setDragItemOp(op._args);
break;
case kSceneOpOpenInventory:
@@ -883,6 +883,11 @@ bool SDSScene::drawAndUpdateDialogs(Graphics::ManagedSurface *dst) {
}
} else if (!dlg.hasFlag(kDlgFlagOpening)) {
dlg.draw(dst, kDlgDrawStageBackground);
+ // HACK: always draw foreground here too..??? The original doesn't but we never
+ // seem to end up calling the foreground draw function..
+ dlg.draw(dst, kDlgDrawFindSelectionPointXY);
+ dlg.draw(dst, kDlgDrawFindSelectionTxtOffset);
+ dlg.draw(dst, kDlgDrawStageForeground);
if (dlg.hasFlag(kDlgFlagHi20)) {
// Reset the dialog time and selected action
int delay = -1;
@@ -933,10 +938,11 @@ void SDSScene::globalOps(const Common::Array<uint16> &args) {
}
void SDSScene::mouseMoved(const Common::Point &pt) {
+ Dialog *dlg = getVisibleDialog();
const HotArea *area = findAreaUnderMouse(pt);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- int16 cursorNum = area ? area->_cursorNum : 0;
+ int16 cursorNum = (!dlg && area) ? area->_cursorNum : 0;
if (_dragItem)
cursorNum = _dragItem->_iconNum;
@@ -949,6 +955,14 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
}
void SDSScene::mouseLDown(const Common::Point &pt) {
+ Dialog *dlg = getVisibleDialog();
+ if (dlg) {
+ // HACK: Check for dialog action selection! for now, just close
+ // it here to make game playable.
+ dlg->clear();
+ return;
+ }
+
HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
@@ -1001,12 +1015,29 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
}
void SDSScene::mouseRUp(const Common::Point &pt) {
+ Dialog *dlg = getVisibleDialog();
+ if (dlg) {
+ // HACK: Check for dialog action selection! for now, just close
+ // it here to make game playable.
+ dlg->clear();
+ return;
+ }
+
const HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
runOps(area->onRClickOps);
}
+Dialog *SDSScene::getVisibleDialog() {
+ for (auto &dlg : _dialogs) {
+ if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagOpening)) {
+ return &dlg;
+ }
+ }
+ return nullptr;
+}
+
HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 27b5d9d4151..3d48ed649cc 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -76,7 +76,7 @@ enum SceneOpCode {
kSceneOpGlobal = 3, // args: array of uints
kSceneOpSegmentStateOps = 4, // args: array of uint pairs [op seg, op seg], term with 0,0 that modify segment states
kSceneOpSetItemAttr = 5, // args: [item num, item param 0x28, item param 0x2c]. set item attrs?
- kSceneOpGiveItem = 6, // args: item num. give item?
+ kSceneOpSetDragItem = 6, // args: item num. give item?
kSceneOpOpenInventory = 7, // args: none.
kSceneOpShowDlg = 8, // args: dialogue number.
kSceneOpShowInvButton = 9, // args: none.
@@ -306,6 +306,7 @@ private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
void enableTrigger(uint16 num) override;
void showDialog(uint16 num) override;
+ Dialog *getVisibleDialog();
int _num;
Common::Array<struct SceneOp> _enterSceneOps;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index b7c404d2134..4d4e2432fab 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -298,6 +298,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l] (not in DRAGON)
// it works like a bitblit, but it doesn't write if there's something already at the destination?
+ // TODO: In dragon this seems to be a whole set of operations - 0xa0n4.
+ // Maybe there are up to 9 regions available?
_vm->_resData.blitFrom(_vm->getBottomBuffer());
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
_vm->getTopBuffer().copyFrom(_vm->_resData);
@@ -316,10 +318,16 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, seq._drawColFG);
_vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, seq._drawColFG);
break;
- case 0xa200:
+ case 0xa200: // 0xa2n0 DRAW STRING n: x,y,w,h:int - draw the nth string from the string table
case 0xa210:
case 0xa220:
- case 0xa230: {
+ case 0xa230:
+ case 0xa240:
+ case 0xa250:
+ case 0xa260:
+ case 0xa270:
+ case 0xa280:
+ case 0xa290: {
uint strnum = (op & 0x70) >> 4;
const Common::String &str = env._strings[strnum];
const FontManager *mgr = _vm->getFontMan();
@@ -415,12 +423,17 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->_soundPlayer->playMusic(seq._currentSongId);
}
break;
-
- case 0xf100:
+ case 0xf100: // 0xf1n0 - SET STRING n: s:str - set the nth string in the table
case 0xf110:
case 0xf120:
- case 0xf130: {
- uint strnum = (op & 0x70) >> 4;
+ case 0xf130:
+ case 0xf140:
+ case 0xf150:
+ case 0xf160:
+ case 0xf170:
+ case 0xf180:
+ case 0xf190: {
+ uint strnum = (op & 0xf0) >> 4;
env._strings[strnum] = sval;
break;
}
Commit: 272827e9d4b71e6d0c4c7aa7398331a6287e8f3a
https://github.com/scummvm/scummvm/commit/272827e9d4b71e6d0c4c7aa7398331a6287e8f3a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: support for multi-ads, inventory now sorta works
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index cfc1b6ce730..7ee5aa2ec45 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -409,17 +409,12 @@ Common::Error DgdsEngine::run() {
}
// Note: Hard-coded logic for DRAGON, check others
- // FIXME; This doesn't work how I expect it should..
- //if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
- // _gdsScene->runPostTickOps();
+ if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
+ _gdsScene->runPostTickOps();
_scene->runPostTickOps();
_scene->checkTriggers();
- // Now we start to assemble the rendered scene.
- _resData.blitFrom(_bottomBuffer);
- _resData.transBlitFrom(_topBuffer);
-
/* For debugging, dump the frame contents..
{
Common::DumpFile outf;
@@ -442,12 +437,18 @@ Common::Error DgdsEngine::run() {
}
*/
- _topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ // Now we start to assemble the rendered scene.
+ _resData.blitFrom(_bottomBuffer);
if (_inventory->isOpen()) {
int invCount = _gdsScene->countItemsInScene2();
_inventory->draw(_resData, invCount);
- } else {
+ }
+
+ _resData.transBlitFrom(_topBuffer);
+ _topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+
+ if (!_inventory->isOpen()) {
_gdsScene->drawItems(_resData);
checkDrawInventoryButton();
}
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index dea53c562d4..010dae0f2db 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -321,6 +321,11 @@ void Image::loadBitmap(const Common::String &filename) {
}
void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &destSurf, bool flip) const {
+ if (frameno >= _frames.size()) {
+ warning("drawBitmap: Trying to draw frame %d from a %d frame image %s!", frameno, _frames.size(), _filename.c_str());
+ return;
+ }
+
const Common::SharedPtr<Graphics::ManagedSurface> srcFrame = _frames[frameno];
const Common::Rect destRect(x, y, x + srcFrame->w, y + srcFrame->h);
Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index afad1039efd..6f6d16267d3 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -32,10 +32,28 @@ namespace Dgds {
Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nullptr),
_invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _clockSkipMinBtn(nullptr),
_itemArea(nullptr), _clockSkipHrBtn(nullptr), _dropBtn(nullptr), _highlightItemNo(-1),
- _itemOffset(0)
+ _itemOffset(0), _openedFromSceneNum(-1)
{
}
+void Inventory::open() {
+ if (_isOpen)
+ return;;
+ _isOpen = true;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ _openedFromSceneNum = engine->getScene()->getNum();
+ engine->changeScene(2, false);
+}
+
+void Inventory::close() {
+ if (!_isOpen)
+ return;;
+ _isOpen = false;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->changeScene(_openedFromSceneNum, false);
+ _openedFromSceneNum = -1;
+}
+
void Inventory::setRequestData(const REQFileData &data) {
_reqData = data;
assert(_reqData._requests.size() > 0);
@@ -76,9 +94,9 @@ void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
}
void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- if (engine->getScene()->getNum() == 2)
- return;
+ //DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ //_if (engine->getScene()->getNum() == 2)
+ // return;
if (isRestarting) {
warning("TODO: Handle inventory redraw on restart");
@@ -155,7 +173,7 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
// draw offset for the image
int drawX = imgAreaX + x + (xstep - item.rect.width) / 2;
- int drawY = imgAreaY + y + (ystep - item.rect.height) / 2;
+ int drawY = imgAreaY + y + (ystep - item.rect.height) / 2;
icons->drawBitmap(item._iconNum, drawX, drawY, drawMask, surf);
@@ -217,32 +235,23 @@ GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
void Inventory::mouseLDown(const Common::Point &pt) {
GameItem *underMouse = itemUnderMouse(pt);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (underMouse) {
_highlightItemNo = underMouse->_num;
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
engine->getScene()->setDragItem(underMouse);
+ if (underMouse->_iconNum)
+ engine->setMouseCursor(underMouse->_iconNum);
}
- debug("TODO: Inventory::mouseLDown: Render the item description");
}
void Inventory::mouseLUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const GameItem *dragItem = engine->getScene()->getDragItem();
- engine->getScene()->setDragItem(nullptr);
engine->setMouseCursor(0);
if (dragItem) {
- GameItem *underMouse = itemUnderMouse(pt);
- if (underMouse && dragItem && underMouse != dragItem) {
- // TODO: This may not be the right list here?
- const Common::Array<struct ObjectInteraction> &interactions = engine->getGDSScene()->getObjInteractions2();
- for (const auto &i : interactions) {
- if (i._droppedItemNum == dragItem->_num && i._targetItemNum == underMouse->_num) {
- engine->getScene()->runOps(i.opList);
- break;
- }
- }
- }
+ engine->getScene()->mouseLUp(pt);
+ // this will clear the drag item.
return;
}
@@ -271,7 +280,7 @@ void Inventory::mouseLUp(const Common::Point &pt) {
Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
for (auto &item: items) {
if (item._num == _highlightItemNo) {
- item._inSceneNum = engine->getScene()->getNum();
+ item._inSceneNum = _openedFromSceneNum;
break;
}
}
@@ -281,7 +290,11 @@ void Inventory::mouseLUp(const Common::Point &pt) {
}
void Inventory::mouseRUp(const Common::Point &pt) {
-
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ GameItem *underMouse = itemUnderMouse(pt);
+ if (underMouse) {
+ engine->getScene()->runOps(underMouse->onRClickOps);
+ }
}
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 58f128375f6..31e1282c88e 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -37,8 +37,8 @@ public:
Inventory();
bool isOpen() const { return _isOpen; }
- void open() { _isOpen = true; }
- void close() { _isOpen = false; }
+ void open();
+ void close();
void draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting = false);
void drawItems(Graphics::ManagedSurface &surf);
void drawTime(Graphics::ManagedSurface &surf);
@@ -54,6 +54,8 @@ public:
private:
GameItem *itemUnderMouse(const Common::Point &pt);
+ uint16 _openedFromSceneNum;
+
bool _isOpen;
ButtonGadget *_prevPageBtn;
ButtonGadget *_nextPageBtn;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 42d74e6bf14..5f66497eaa9 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -118,7 +118,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
case kSceneOpMoveItemsBetweenScenes: return "moveItemsBetweenScenes";
- case kSceneOpRestartGame: return "restartGame";
+ case kSceneOpLeaveSceneAndOpenInventory: return "leaveSceneOpenInventory";
case kSceneOpShowClock: return "sceneOpShowClock";
case kSceneOpHideClock: return "sceneOpHideClock";
case kSceneOpShowMouse: return "sceneOpShowMouse";
@@ -521,8 +521,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
return false;
break;
}
- case kSceneOpRestartGame:
- error("TODO: Implement restart game scene op");
+ case kSceneOpLeaveSceneAndOpenInventory:
+ engine->getInventory()->open();
+ warning("TODO: Check leave scene and open inventory scene op");
break;
case kSceneOpMoveItemsBetweenScenes:
// Move all items from source scene to the dest scene.
@@ -979,22 +980,28 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
void SDSScene::mouseLUp(const Common::Point &pt) {
const HotArea *area = findAreaUnderMouse(pt);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
+ GameItem *dragItem = _dragItem;
+ _dragItem = nullptr;
+
+ if (dragItem && !area)
+ engine->setMouseCursor(0);
+
if (!area)
return;
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
-
engine->setMouseCursor(area->_cursorNum);
if (area->_num == 0) {
// dropped on the inventory button
- if (_dragItem) {
- _dragItem->_inSceneNum = 2;
+ if (dragItem) {
+ dragItem->_inSceneNum = 2;
} else {
static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
}
} else {
- if (_dragItem) {
+ if (dragItem) {
const GameItem *targetItem = dynamic_cast<const GameItem *>(area);
// Dropping one item on another -> use interactions from GDS
// Dropping item on an area -> interactions are in SDS
@@ -1002,7 +1009,7 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
targetItem ? engine->getGDSScene()->getObjInteractions2()
: engine->getScene()->getObjInteractions1();
for (const auto &i : interactions) {
- if (i._droppedItemNum == _dragItem->_num && i._targetItemNum == targetItem->_num) {
+ if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area->_num) {
runOps(i.opList);
break;
}
@@ -1011,7 +1018,6 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
runOps(area->onLClickOps);
}
}
- _dragItem = nullptr;
}
void SDSScene::mouseRUp(const Common::Point &pt) {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 3d48ed649cc..d35c861e3cf 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -42,8 +42,8 @@ enum SceneCondition {
kSceneCondNegate = 4,
kSceneCondAbsVal = 8,
kSceneCondOr = 0x10,
- kSceneCondNeedItemQuality = 0x20,
- kSceneCondNeedItemSceneNum = 0x40,
+ kSceneCondNeedItemSceneNum = 0x20,
+ kSceneCondNeedItemQuality = 0x40,
kSceneCondSceneState = 0x80
};
@@ -84,7 +84,7 @@ enum SceneOpCode {
kSceneOpEnableTrigger = 11, // args: trigger num
kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
kSceneOp13 = 13, // args: none.
- kSceneOpRestartGame = 14, // args: none.
+ kSceneOpLeaveSceneAndOpenInventory = 14, // args: none.
kSceneOpMoveItemsBetweenScenes = 15, // args: none.
kSceneOpShowClock = 16, // args: none. set some clock-related globals
kSceneOpHideClock = 17, // args: none. set some clock-related values.
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 4d4e2432fab..2c818725616 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -592,13 +592,15 @@ void TTMSeq::reset() {
_drawWin = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
-ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _currentTTMSeq(nullptr) {
+ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _currentTTMSeq(nullptr), _adsData(nullptr) {
_ttmInterpreter = new TTMInterpreter(_vm);
}
ADSInterpreter::~ADSInterpreter() {
delete _ttmInterpreter;
_ttmInterpreter = nullptr;
+ for (auto &data : _adsTexts)
+ delete data._value.scr;
}
bool ADSInterpreter::load(const Common::String &filename) {
@@ -615,45 +617,52 @@ bool ADSInterpreter::load(const Common::String &filename) {
detailfile = filename;
debug("ADSInterpreter: load %s", detailfile.c_str());
+ if (_adsTexts.contains(detailfile)) {
+ _adsData = &(_adsTexts.getVal(detailfile));
+ return true;
+ }
+
+ _adsTexts.setVal(detailfile, ADSData());
+ _adsData = &(_adsTexts.getVal(detailfile));
ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- dgds.parse(&_adsData, detailfile);
+ dgds.parse(_adsData, detailfile);
- for (const auto &file : _adsData._scriptNames) {
- _adsData._scriptEnvs.resize(_adsData._scriptEnvs.size() + 1);
- TTMEnviro &data = _adsData._scriptEnvs.back();
- data._enviro = _adsData._scriptEnvs.size();
+ for (const auto &file : _adsData->_scriptNames) {
+ _adsData->_scriptEnvs.resize(_adsData->_scriptEnvs.size() + 1);
+ TTMEnviro &data = _adsData->_scriptEnvs.back();
+ data._enviro = _adsData->_scriptEnvs.size();
_ttmInterpreter->load(file, data);
- _ttmInterpreter->findAndAddSequences(data, _adsData._ttmSeqs);
+ _ttmInterpreter->findAndAddSequences(data, _adsData->_ttmSeqs);
}
- _adsData.scr->seek(0);
+ _adsData->scr->seek(0);
uint16 opcode = 0;
int segcount = 0;
findUsedSequencesForSegment(0);
- _adsData._segments[0] = 0;
- opcode = _adsData.scr->readUint16LE();
- while (_adsData.scr->pos() < _adsData.scr->size()) {
+ _adsData->_segments[0] = 0;
+ opcode = _adsData->scr->readUint16LE();
+ while (_adsData->scr->pos() < _adsData->scr->size()) {
if (opcode == 0xffff) {
segcount++;
- _adsData._segments[segcount] = _adsData.scr->pos();
+ _adsData->_segments[segcount] = _adsData->scr->pos();
findUsedSequencesForSegment(segcount);
} else {
- _adsData.scr->skip(numArgs(opcode) * 2);
+ _adsData->scr->skip(numArgs(opcode) * 2);
}
- opcode = _adsData.scr->readUint16LE();
+ opcode = _adsData->scr->readUint16LE();
}
- for (uint i = segcount + 1; i < ARRAYSIZE(_adsData._segments); i++)
- _adsData._segments[i] = -1;
+ for (uint i = segcount + 1; i < ARRAYSIZE(_adsData->_segments); i++)
+ _adsData->_segments[i] = -1;
- _adsData._maxSegments = segcount + 1;
- _adsData.filename = filename;
+ _adsData->_maxSegments = segcount + 1;
+ _adsData->filename = filename;
- for (uint i = 0; i < ARRAYSIZE(_adsData._state); i++)
- _adsData._state[i] = 8;
- for (auto &seq : _adsData._ttmSeqs)
+ for (uint i = 0; i < ARRAYSIZE(_adsData->_state); i++)
+ _adsData->_state[i] = 8;
+ for (auto &seq : _adsData->_ttmSeqs)
seq.reset();
return true;
@@ -691,46 +700,45 @@ bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
}
void ADSInterpreter::findUsedSequencesForSegment(int segno) {
- _adsData._usedSeqs[segno].clear();
- int64 startoff = _adsData.scr->pos();
+ _adsData->_usedSeqs[segno].clear();
+ int64 startoff = _adsData->scr->pos();
uint16 opcode = 0;
// Skip the segment number.
- _adsData.scr->readUint16LE();
- while (opcode != 0xffff && _adsData.scr->pos() < _adsData.scr->size()) {
- opcode = _adsData.scr->readUint16LE();
+ _adsData->scr->readUint16LE();
+ while (opcode != 0xffff && _adsData->scr->pos() < _adsData->scr->size()) {
+ opcode = _adsData->scr->readUint16LE();
for (uint16 o : ADS_SEQ_OPCODES) {
if (opcode == o) {
- int16 envno = _adsData.scr->readSint16LE();
- int16 seqno = _adsData.scr->readSint16LE();
+ int16 envno = _adsData->scr->readSint16LE();
+ int16 seqno = _adsData->scr->readSint16LE();
TTMSeq *seq = findTTMSeq(envno, seqno);
if (!seq) {
warning("ADS opcode %04x at offset %d references unknown seq %d %d",
- opcode, (int)_adsData.scr->pos(), envno, seqno);
+ opcode, (int)_adsData->scr->pos(), envno, seqno);
} else {
bool already_added = false;
- for (TTMSeq *s : _adsData._usedSeqs[segno]) {
+ for (TTMSeq *s : _adsData->_usedSeqs[segno]) {
if (s == seq) {
already_added = true;
break;
}
}
if (!already_added)
- _adsData._usedSeqs[segno].push_back(seq);
+ _adsData->_usedSeqs[segno].push_back(seq);
}
// Rewind as we will go forward again outside this loop.
- _adsData.scr->seek(-4, SEEK_CUR);
+ _adsData->scr->seek(-4, SEEK_CUR);
break;
}
}
- _adsData.scr->skip(numArgs(opcode) * 2);
+ _adsData->scr->skip(numArgs(opcode) * 2);
}
- _adsData.scr->seek(startoff);
+ _adsData->scr->seek(startoff);
}
void ADSInterpreter::unload() {
- delete _adsData.scr;
- _adsData = ADSData();
+ _adsData = nullptr;
_currentTTMSeq = nullptr;
}
@@ -742,12 +750,12 @@ bool ADSInterpreter::playScene() {
if (!env)
error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
- _adsData._gotoTarget = -1;
+ _adsData->_gotoTarget = -1;
return _ttmInterpreter->run(*env, *_currentTTMSeq);
}
bool ADSInterpreter::skipSceneLogicBranch() {
- Common::SeekableReadStream *scr = _adsData.scr;
+ Common::SeekableReadStream *scr = _adsData->scr;
bool result = true;
while (scr->pos() < scr->size()) {
uint16 op = scr->readUint16LE();
@@ -768,7 +776,7 @@ bool ADSInterpreter::skipSceneLogicBranch() {
}
bool ADSInterpreter::skipToEndIf() {
- Common::SeekableReadStream *scr = _adsData.scr;
+ Common::SeekableReadStream *scr = _adsData->scr;
bool result = skipSceneLogicBranch();
if (result) {
uint16 op = scr->readUint16LE();
@@ -782,7 +790,7 @@ bool ADSInterpreter::skipToEndIf() {
}
TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
- for (auto & env : _adsData._scriptEnvs) {
+ for (auto & env : _adsData->_scriptEnvs) {
if (env._enviro == enviro)
return &env;
}
@@ -790,7 +798,7 @@ TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
}
TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seq) {
- for (auto & ttm : _adsData._ttmSeqs) {
+ for (auto & ttm : _adsData->_ttmSeqs) {
if (ttm._enviro == enviro && ttm._seqNum == seq)
return &ttm;
}
@@ -800,8 +808,8 @@ TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seq) {
void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
int idx = getArrIndexOfSegNum(seg);
if (idx >= 0) {
- _adsData._charWhile[idx] = 0;
- _adsData._state[idx] = (_adsData._state[idx] & 8) | val;
+ _adsData->_charWhile[idx] = 0;
+ _adsData->_state[idx] = (_adsData->_state[idx] & 8) | val;
}
}
@@ -809,14 +817,14 @@ void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
int idx = getArrIndexOfSegNum(seg);
if (idx >= 0) {
- _adsData._charWhile[idx] = 0;
- if (_adsData._state[idx] != 8)
- _adsData._state[idx] = val;
+ _adsData->_charWhile[idx] = 0;
+ if (_adsData->_state[idx] != 8)
+ _adsData->_state[idx] = val;
}
}
void ADSInterpreter::findEndOrInitOp() {
- Common::SeekableReadStream *scr = _adsData.scr;
+ Common::SeekableReadStream *scr = _adsData->scr;
int32 startoff = scr->pos();
while (scr->pos() < scr->size()) {
uint16 opcode = scr->readUint16LE();
@@ -976,15 +984,15 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1500: // ? IF ?, 0 params
debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
//sceneLogicOps();
- _adsData._hitBranchOp = true;
+ _adsData->_hitBranchOp = true;
return true;
case 0x1510: // PLAY_SCENE? 0 params
debug(10, "ADS: 0x%04x hit branch op true", code);
- _adsData._hitBranchOp = true;
+ _adsData->_hitBranchOp = true;
return true;
case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
debug(10, "ADS: 0x%04x hit branch op", code);
- _adsData._hitBranchOp = true;
+ _adsData->_hitBranchOp = true;
return false;
case 0x2000:
@@ -1065,17 +1073,17 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
// This is O(N) but the N is small and it's not called often.
TTMSeq seq;
bool success = false;
- for (uint i = 0; i < _adsData._ttmSeqs.size(); i++) {
- if (_adsData._ttmSeqs[i]._enviro == enviro && _adsData._ttmSeqs[i]._seqNum == seqnum) {
- seq = _adsData._ttmSeqs[i];
- _adsData._ttmSeqs.remove_at(i);
+ for (uint i = 0; i < _adsData->_ttmSeqs.size(); i++) {
+ if (_adsData->_ttmSeqs[i]._enviro == enviro && _adsData->_ttmSeqs[i]._seqNum == seqnum) {
+ seq = _adsData->_ttmSeqs[i];
+ _adsData->_ttmSeqs.remove_at(i);
success = true;
break;
}
}
if (success)
- _adsData._ttmSeqs.insert_at(0, seq);
+ _adsData->_ttmSeqs.insert_at(0, seq);
else
warning("ADS: 0x4000 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
@@ -1089,17 +1097,17 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
// This is O(N) but the N is small and it's not called often.
TTMSeq seq;
bool success = false;
- for (uint i = 0; i < _adsData._ttmSeqs.size(); i++) {
- if (_adsData._ttmSeqs[i]._enviro == enviro && _adsData._ttmSeqs[i]._seqNum == seqnum) {
- seq = _adsData._ttmSeqs[i];
- _adsData._ttmSeqs.remove_at(i);
+ for (uint i = 0; i < _adsData->_ttmSeqs.size(); i++) {
+ if (_adsData->_ttmSeqs[i]._enviro == enviro && _adsData->_ttmSeqs[i]._seqNum == seqnum) {
+ seq = _adsData->_ttmSeqs[i];
+ _adsData->_ttmSeqs.remove_at(i);
success = true;
break;
}
}
if (success)
- _adsData._ttmSeqs.push_back(seq);
+ _adsData->_ttmSeqs.push_back(seq);
else
warning("ADS: 0x4010 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
@@ -1107,19 +1115,19 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
}
case 0xF000:
- if (_adsData._runningSegmentIdx != -1)
- _adsData._state[_adsData._runningSegmentIdx] = 2;
+ if (_adsData->_runningSegmentIdx != -1)
+ _adsData->_state[_adsData->_runningSegmentIdx] = 2;
return false;
case 0xF010: {// FADE_OUT, 1 param
int16 segment = scr->readSint16LE();
- int16 idx = _adsData._runningSegmentIdx;
+ int16 idx = _adsData->_runningSegmentIdx;
if (segment >= 0)
idx = getArrIndexOfSegNum(segment);
debug("ADS: set state 2, segment param %d (idx %d)", segment, idx);
if (idx >= 0)
- _adsData._state[idx] = 2;
- if (idx == _adsData._runningSegmentIdx)
+ _adsData->_state[idx] = 2;
+ if (idx == _adsData->_runningSegmentIdx)
return false;
else
return true;
@@ -1159,8 +1167,8 @@ int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
int idx = getArrIndexOfSegNum(segnum);
if (idx < 0)
return 0;
- if (!(_adsData._state[idx] & 4)) {
- for (auto *seq : _adsData._usedSeqs[idx]) {
+ if (!(_adsData->_state[idx] & 4)) {
+ for (auto *seq : _adsData->_usedSeqs[idx]) {
if (!seq)
return 0;
if (seq->_runFlag != kRunTypeStopped && !seq->_selfLoop)
@@ -1173,28 +1181,28 @@ int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
int ADSInterpreter::getArrIndexOfSegNum(uint16 segnum) {
- int32 startoff = _adsData.scr->pos();
+ int32 startoff = _adsData->scr->pos();
int result = -1;
- for (int i = 0; i < _adsData._maxSegments; i++) {
- _adsData.scr->seek(_adsData._segments[i]);
- int16 seg = _adsData.scr->readSint16LE();
+ for (int i = 0; i < _adsData->_maxSegments; i++) {
+ _adsData->scr->seek(_adsData->_segments[i]);
+ int16 seg = _adsData->scr->readSint16LE();
if (seg == segnum) {
result = i;
break;
}
}
- _adsData.scr->seek(startoff);
+ _adsData->scr->seek(startoff);
return result;
}
bool ADSInterpreter::run() {
- if (_adsData._ttmSeqs.empty())
+ if (_adsData->_ttmSeqs.empty())
return false;
- for (int i = 0; i < _adsData._maxSegments; i++) {
- int16 flag = _adsData._state[i] & 0xfff7;
- for (auto seq : _adsData._usedSeqs[i]) {
+ for (int i = 0; i < _adsData->_maxSegments; i++) {
+ int16 flag = _adsData->_state[i] & 0xfff7;
+ for (auto seq : _adsData->_usedSeqs[i]) {
if (flag == 3) {
seq->reset();
} else {
@@ -1203,39 +1211,39 @@ bool ADSInterpreter::run() {
}
}
- for (int i = 0; i < _adsData._maxSegments; i++) {
- int16 state = _adsData._state[i];
- int32 offset = _adsData._segments[i];
- _adsData.scr->seek(offset);
+ for (int i = 0; i < _adsData->_maxSegments; i++) {
+ int16 state = _adsData->_state[i];
+ int32 offset = _adsData->_segments[i];
+ _adsData->scr->seek(offset);
// skip over the segment num
offset += 2;
- /*int16 segnum =*/ _adsData.scr->readSint16LE();
+ /*int16 segnum =*/ _adsData->scr->readSint16LE();
if (state & 8) {
state &= 0xfff7;
- _adsData._state[i] = state;
+ _adsData->_state[i] = state;
} else {
findEndOrInitOp();
- offset = _adsData.scr->pos();
+ offset = _adsData->scr->pos();
}
- if (_adsData._charWhile[i])
- offset = _adsData._charWhile[i];
+ if (_adsData->_charWhile[i])
+ offset = _adsData->_charWhile[i];
if (state == 3 || state == 4) {
- _adsData._state[i] = 1;
+ _adsData->_state[i] = 1;
state = 1;
}
- _adsData._runningSegmentIdx = i;
- if (_adsData.scr && state == 1) {
- _adsData.scr->seek(offset);
- //debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData._maxSegments);
+ _adsData->_runningSegmentIdx = i;
+ if (_adsData->scr && state == 1) {
+ _adsData->scr->seek(offset);
+ //debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData->_maxSegments);
runUntilBranchOpOrEnd();
}
}
bool result = false;
- for (auto &seq : _adsData._ttmSeqs) {
+ for (auto &seq : _adsData->_ttmSeqs) {
_currentTTMSeq = &seq;
seq._lastFrame = -1;
int sflag = seq._scriptFlag;
@@ -1247,8 +1255,8 @@ bool ADSInterpreter::run() {
} else {
int16 curframe = seq._currentFrame;
TTMEnviro *env = findTTMEnviro(seq._enviro);
- _adsData._hitTTMOp0110 = false;
- _adsData._scriptDelay = -1;
+ _adsData->_hitTTMOp0110 = false;
+ _adsData->_scriptDelay = -1;
bool scriptresult = false;
// Next few lines of code in a separate function in the original..
if (curframe < env->_totalFrames && curframe > -1 && env->_frameOffsets[curframe] > -1) {
@@ -1260,17 +1268,17 @@ bool ADSInterpreter::run() {
seq._executed = true;
seq._lastFrame = seq._currentFrame;
result = true;
- if (_adsData._scriptDelay != -1 && seq._timeInterval != _adsData._scriptDelay) {
+ if (_adsData->_scriptDelay != -1 && seq._timeInterval != _adsData->_scriptDelay) {
uint32 now = g_engine->getTotalPlayTime();
- seq._timeNext = now + _adsData._scriptDelay;
- seq._timeInterval = _adsData._scriptDelay;
+ seq._timeNext = now + _adsData->_scriptDelay;
+ seq._timeInterval = _adsData->_scriptDelay;
}
- if (!_adsData._hitTTMOp0110) {
- if (_adsData._gotoTarget != -1) {
- seq._gotoFrame = _adsData._gotoTarget;
- if (seq._currentFrame == _adsData._gotoTarget)
- seq._selfLoop = true;
+ if (!_adsData->_hitTTMOp0110) {
+ if (_adsData->_gotoTarget != -1) {
+ seq._gotoFrame = _adsData->_gotoTarget;
+ if (seq._currentFrame == _adsData->_gotoTarget)
+ seq._selfLoop = true;
}
if (seq._runFlag != kRunType5)
updateSeqTimeAndFrame(seq);
@@ -1305,7 +1313,7 @@ bool ADSInterpreter::run() {
}
bool ADSInterpreter::runUntilBranchOpOrEnd() {
- Common::SeekableReadStream *scr = _adsData.scr;
+ Common::SeekableReadStream *scr = _adsData->scr;
if (!scr || scr->pos() >= scr->size())
return false;
@@ -1315,19 +1323,19 @@ bool ADSInterpreter::runUntilBranchOpOrEnd() {
if (code == 0xffff)
return false;
more = handleOperation(code, scr);
- } while (!_adsData._hitBranchOp && more && scr->pos() < scr->size());
+ } while (!_adsData->_hitBranchOp && more && scr->pos() < scr->size());
- _adsData._hitBranchOp = false;
+ _adsData->_hitBranchOp = false;
return more;
}
void ADSInterpreter::setHitTTMOp0110() {
- _adsData._hitTTMOp0110 = true;
+ _adsData->_hitTTMOp0110 = true;
}
void ADSInterpreter::setGotoTarget(int32 target) {
- _adsData._gotoTarget = target;
+ _adsData->_gotoTarget = target;
}
int ADSInterpreter::numArgs(uint16 opcode) const {
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index f952b728095..64b9eb6dee5 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -168,7 +168,7 @@ public:
void setHitTTMOp0110(); // TODO: better name for this global?
void setGotoTarget(int32 target);
int16 getStateForSceneOp(uint16 segnum);
- void setScriptDelay(int16 delay) { _adsData._scriptDelay = delay; }
+ void setScriptDelay(int16 delay) { _adsData->_scriptDelay = delay; }
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
@@ -189,7 +189,8 @@ protected:
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
- ADSData _adsData;
+ Common::HashMap<Common::String, ADSData> _adsTexts;
+ ADSData *_adsData;
TTMSeq *_currentTTMSeq;
};
Commit: a3097b46289a2d552d33ce38b1da4b578fb1c985
https://github.com/scummvm/scummvm/commit/a3097b46289a2d552d33ce38b1da4b578fb1c985
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement minimal ops to make HoC boot
Changed paths:
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 5f66497eaa9..a8a9193129d 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -340,6 +340,10 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
dst._frameType = static_cast<DialogFrameType>(s->readUint16LE());
dst._time = s->readUint16LE();
+ if (isVersionOver(" 1.215")) {
+ s->readUint16LE();
+ error("TODO: what is this extra int in dialog action list?");
+ }
if (isVersionOver(" 1.207")) {
dst._nextDialogNum = s->readUint16LE();
}
@@ -663,8 +667,8 @@ bool SDSScene::load(const Common::String &filename, ResourceManager *resourceMan
bool SDSScene::parse(Common::SeekableReadStream *stream) {
_magic = stream->readUint32LE();
_version = stream->readString();
- if (isVersionOver(" 1.211")) {
- //if (isVersionOver(" 1.216")) { // HoC
+ //if (isVersionOver(" 1.211")) { // Dragon
+ if (isVersionOver(" 1.216")) { // HoC
//if (isVersionOver(" 1.224")) { // Beamish
error("Unsupported scene version '%s'", _version.c_str());
}
@@ -682,7 +686,9 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
if (isVersionOver(" 1.205")) {
readObjInteractionList(stream, _objInteractions2);
}
- readDialogList(stream, _dialogs);
+ if (isVersionUnder(" 1.214")) {
+ readDialogList(stream, _dialogs);
+ }
if (isVersionOver(" 1.203")) {
readTriggerList(stream, _triggers);
}
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 2c818725616..02c8c3507ec 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -763,10 +763,10 @@ bool ADSInterpreter::skipSceneLogicBranch() {
scr->seek(-2, SEEK_CUR);
return true;
} else if (op == 0 || op == 0xffff) {
+ // end of segment
return false;
} else if ((op & 0xff0f) == 0x1300) {
// a 0x13x0 logic op
- scr->seek(-2, SEEK_CUR);
result = handleOperation(op, scr);
} else {
scr->skip(numArgs(op) * 2);
@@ -784,7 +784,6 @@ bool ADSInterpreter::skipToEndIf() {
result = runUntilBranchOpOrEnd();
}
// don't rewind - the calls to this should always return ptr+2
- //scr->seek(-2, SEEK_CUR);
}
return result;
}
@@ -864,6 +863,10 @@ bool ADSInterpreter::logicOpResult(uint16 code, const TTMSeq *seq) {
case 0x1370: // IF_RUNNING, 2 params
debug(10, "ADS: if running env %d seq %d", seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
+ case 0x1380: // IF_???????, 0 params
+ case 0x1390: // IF_???????, 0 params
+ warning("Unimplemented IF operation 0x%x", code);
+ return false;
default:
error("Not an ADS logic op: %04x, how did we get here?", code);
}
@@ -873,12 +876,21 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr
bool testval = true;
uint16 andor = 0x1420; // start with "true" AND..
while (scr->pos() < scr->size()) {
- uint16 enviro = scr->readUint16LE();
- uint16 seqnum = scr->readUint16LE();
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (!seq) {
- warning("ADS if op referenced non-existant env %d seq %d", enviro, seqnum);
- return false;
+ uint16 enviro;
+ uint16 seqnum;
+ TTMSeq *seq = nullptr;
+
+ if (code != 0x1380 && code != 0x1390) {
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ seq = findTTMSeq(enviro, seqnum);
+ if (!seq) {
+ warning("ADS if op referenced non-existant env %d seq %d", enviro, seqnum);
+ return false;
+ }
+ } else {
+ // not actually enviro I think? for now just read it.
+ enviro = scr->readUint16LE();
}
bool logicResult = logicOpResult(code, seq);
@@ -980,6 +992,8 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1350: // IF_FINISHED, 2 params
case 0x1360: // IF_NOT_RUNNING, 2 params
case 0x1370: // IF_RUNNING, 2 params
+ case 0x1380: // IF_??????, 1 param (HOC+ only)
+ case 0x1390: // IF_??????, 1 param (HOC+ only)
return handleLogicOp(code, scr);
case 0x1500: // ? IF ?, 0 params
debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
@@ -1342,6 +1356,8 @@ int ADSInterpreter::numArgs(uint16 opcode) const {
// TODO: This list is from DRAGON, there may be more entries in newer games.
switch (opcode) {
case 0x1080:
+ case 0x1380:
+ case 0x1390:
case 0x3020:
case 0xF010:
case 0xF200:
Commit: 3c091686ede23f82597c4d3f5c2d311b229b20d5
https://github.com/scummvm/scummvm/commit/3c091686ede23f82597c4d3f5c2d311b229b20d5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix more rendering and execution issues
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
engines/dgds/sound.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7ee5aa2ec45..ab9630527c6 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -72,7 +72,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds"), _currentCursor(-1) {
+ _random("dgds"), _currentCursor(-1), _topBufferUsed(false) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -134,6 +134,10 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
warning("Tried to change from scene %d to itself, doing nothing.", sceneNum);
return false;
}
+
+ if (sceneNum != 2 && _scene->getNum() != 2 && _inventory->isOpen()) {
+ _inventory->close();
+ }
const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
if (!_resource->hasResource(sceneFile)) {
@@ -211,6 +215,14 @@ void DgdsEngine::checkDrawInventoryButton() {
_icons->drawBitmap(2, x, y, drawWin, _resData);
}
+Graphics::ManagedSurface &DgdsEngine::getTopBuffer() {
+ if (_topBufferUsed) {
+ _topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _topBufferUsed = false;
+ }
+ return _topBuffer;
+}
+
Common::Error DgdsEngine::run() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -297,7 +309,7 @@ Common::Error DgdsEngine::run() {
//getDebugger()->attach();
debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
- //debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
+ debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
bool moveToNext = false;
bool triggerMenu = false;
@@ -446,7 +458,7 @@ Common::Error DgdsEngine::run() {
}
_resData.transBlitFrom(_topBuffer);
- _topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _topBufferUsed = true;
if (!_inventory->isOpen()) {
_gdsScene->drawItems(_resData);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 76f67c85c86..bf3d59c1d20 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -83,6 +83,7 @@ private:
DgdsGameId _gameId;
Graphics::ManagedSurface _bottomBuffer;
Graphics::ManagedSurface _topBuffer;
+ bool _topBufferUsed;
SDSScene *_scene;
GDSScene *_gdsScene;
Menu *_menu;
@@ -117,7 +118,8 @@ public:
DgdsGameId getGameId() { return _gameId; }
- Graphics::ManagedSurface &getTopBuffer() { return _topBuffer; }
+ Graphics::ManagedSurface &getTopBuffer();
+ const Graphics::ManagedSurface &getTopBuffer() const { return _topBuffer; }
Graphics::ManagedSurface &getBottomBuffer() { return _bottomBuffer; }
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 6fe9be80a78..840f4dbc391 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -127,6 +127,9 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (colonpos != Common::String::npos) {
title = _str.substr(0, colonpos);
txt = _str.substr(colonpos + 1);
+ // Most have a CR after the colon? trim it to remove a blank line.
+ if (txt.size() && txt[0] == '\r')
+ txt = txt.substr(1);
} else {
txt = _str;
}
@@ -139,6 +142,7 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!title.empty()) {
// TODO: Maybe should measure the font?
_state->_loc.y += 10;
+ _state->_loc.height -= 10;
RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
}
@@ -152,6 +156,9 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
RequestData::drawCorners(dst, 19, _state->_loc.x - 2, _state->_loc.y - 2,
_state->_loc.width + 4, _state->_loc.height + 4);
+ _state->_loc.x += 8;
+ _state->_loc.width -= 16;
+
} else if (stage == kDlgDrawFindSelectionPointXY) {
drawFindSelectionXY();
} else if (stage == kDlgDrawFindSelectionTxtOffset) {
@@ -416,7 +423,7 @@ void Dialog::drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const
const int h = font->getFontHeight();
font->wordWrapText(txt, _state->_loc.width, lines);
- int ystart = _state->_loc.y + (_state->_loc.height - lines.size() * h) / 2;
+ int ystart = _state->_loc.y + (_state->_loc.height - (int)lines.size() * h) / 2;
int x = _state->_loc.x;
if (hasFlag(kDlgFlagLeftJust)) {
@@ -509,7 +516,10 @@ struct DialogAction *Dialog::pickAction(bool isClosing) {
struct DialogAction *retval = nullptr;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (/* some game flags?? && */isClosing) {
- return &_action[engine->getRandom().getRandomNumber(_action.size() - 1)];
+ if (_action.empty())
+ return nullptr;
+ else
+ return &_action[engine->getRandom().getRandomNumber(_action.size() - 1)];
}
assert(_state);
const Common::Point lastMouse = engine->getLastMouse();
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index a8a9193129d..f5aad0804dd 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -529,11 +529,15 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
engine->getInventory()->open();
warning("TODO: Check leave scene and open inventory scene op");
break;
- case kSceneOpMoveItemsBetweenScenes:
- // Move all items from source scene to the dest scene.
- // scene numbers are in globals.
- error("TODO: Implement move items between scenes op");
+ case kSceneOpMoveItemsBetweenScenes: {
+ int16 fromScene = engine->getGameGlobals()->getGlobal(0x55);
+ int16 toScene = engine->getGameGlobals()->getGlobal(0x54);
+ for (auto &item : engine->getGDSScene()->getGameItems()) {
+ if (item._inSceneNum == fromScene)
+ item._inSceneNum = toScene;
+ }
break;
+ }
case kSceneOpShowClock:
engine->setShowClock(true);
break;
@@ -633,7 +637,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
bool SDSScene::_dlgWithFlagLo8IsClosing = false;;
DialogFlags SDSScene::_sceneDialogFlags = kDlgFlagNone;
-SDSScene::SDSScene() : _num(-1), _dragItem(nullptr) {
+SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false) {
}
bool SDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
@@ -787,7 +791,8 @@ bool SDSScene::checkDialogActive() {
_sceneDialogFlags = kDlgFlagNone;
- bool someFlag = true; // ((g_gameStateFlag_41f6 | UINT_39e5_41f8) & 6) != 0); ??
+ bool clearDlgFlag = _shouldClearDlg; // ((g_gameStateFlag_41f6 | UINT_39e5_41f8) & 6) != 0); ??
+ _shouldClearDlg = false;
for (auto &dlg : _dialogs) {
if (!dlg.hasFlag(kDlgFlagVisible))
@@ -796,9 +801,12 @@ bool SDSScene::checkDialogActive() {
if (!dlg._state)
dlg._state.reset(new DialogState());
+ // FIXME: double-check this logic.
+ // Mark finished if we are manually clearing *or* the timer has expired.
bool finished = false;
- if (dlg._state->_hideTime && dlg._state->_hideTime < timeNow) {
- finished = someFlag;
+ if (dlg._state->_hideTime &&
+ ((dlg._state->_hideTime < timeNow && clearDlgFlag) || timeNow > dlg._state->_hideTime)) {
+ finished = true;
}
bool no_options = false;
@@ -842,10 +850,12 @@ bool SDSScene::checkDialogActive() {
void SDSScene::drawActiveDialogBgs(Graphics::ManagedSurface *dst) {
for (auto &dlg : _dialogs) {
if (dlg.hasFlag(kDlgFlagVisible) && !dlg.hasFlag(kDlgFlagOpening)) {
- assert(dlg._state);
dlg.draw(dst, kDlgDrawStageBackground);
- dlg.clearFlag(kDlgFlagHi20);
- dlg.setFlag(kDlgFlagHi40);
+ // FIXME: Original clears Hi20 and sets Hi40 here, but with our
+ // call sequence that means the time never works right in
+ // drawAndUpdateDialogs??
+ //dlg.clearFlag(kDlgFlagHi20);
+ //dlg.setFlag(kDlgFlagHi40);
}
}
}
@@ -964,9 +974,7 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
void SDSScene::mouseLDown(const Common::Point &pt) {
Dialog *dlg = getVisibleDialog();
if (dlg) {
- // HACK: Check for dialog action selection! for now, just close
- // it here to make game playable.
- dlg->clear();
+ _shouldClearDlg = true;
return;
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index d35c861e3cf..d2404b479a1 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -95,12 +95,12 @@ enum SceneOpCode {
kSceneOp100 = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOp102 = 102, // args: none.
- kSceneOp103 = 103, // args: none.
+ kSceneOp103 = 103, // args: none. Something about "boy am I tired"?
kSceneOp104 = 104, // args: none.
kSceneOp105 = 105, // args: none. Draw some number at 141, 56
kSceneOp106 = 106, // args: none. Draw some number at 42, 250
- kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. Show the "Play Introduction" / "Skip Introduction" menu. Dragon only??
- kSceneOp108 = 108, // args: none.
+ kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. DRAGON: Show menu 50, the "Play Introduction" / "Skip Introduction" menu.
+ kSceneOp108 = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
};
struct SceneOp {
@@ -324,6 +324,7 @@ private:
//uint _field15_0x33;
GameItem *_dragItem;
+ bool _shouldClearDlg;
static bool _dlgWithFlagLo8IsClosing;
static DialogFlags _sceneDialogFlags;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 02c8c3507ec..e7963febe2f 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -158,8 +158,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
_vm->_soundPlayer->stopMusic();
break;
- case 0x0ff0: { // REFRESH: void
- } break;
+ case 0x0ff0: // REFRESH: void
+ break;
case 0x1020: // SET DELAY: i:int [0..n]
// Delay of 240 should be 2 seconds, so this is in quarter-frames.
// TODO: Probably should do this accounting (as well as timeCut and dialogs)
@@ -195,7 +195,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
seq._currentGetPutId = ivals[0];
break;
case 0x1200: // GOTO
- _vm->adsInterpreter()->setGotoTarget(ivals[0]);
+ _vm->adsInterpreter()->setGotoTarget(findGOTOTarget(env, seq, ivals[0]));
break;
case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
if (seq._executed) // this is a one-shot op.
@@ -235,11 +235,10 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// bring that down a bit to use less cpu.
// Speed 4 should complete fade in 2 seconds (eg, Dynamix logo fade)
- // TODO: this is a pretty bad way to do it - maybe should pump messages at least.
+ // TODO: this is a pretty bad way to do it - should pump messages in this loop?
for (int i = 0; i < 320; i += ivals[3]) {
int fade = MIN(i / 5, 63);
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g_system->updateScreen();
g_system->delayMillis(5);
}
@@ -249,10 +248,10 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
break;
- // blt first?
+ // blt first to make the initial fade-in work
_vm->_resData.blitFrom(_vm->getBottomBuffer());
_vm->_resData.transBlitFrom(_vm->getTopBuffer());
- _vm->getTopBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -260,7 +259,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
for (int i = 320; i > 0; i -= ivals[3]) {
int fade = MAX(0, MIN(i / 5, 63));
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g_system->updateScreen();
g_system->delayMillis(5);
}
@@ -384,9 +382,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xf010: { // LOAD SCR: filename:str
if (seq._executed) // this is a one-shot op
break;
- Image *tmp = new Image(_vm->getResourceManager(), _vm->getDecompressor());
- tmp->drawScreen(sval, _vm->getBottomBuffer());
- delete tmp;
+ Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
+ tmp.drawScreen(sval, _vm->getBottomBuffer());
break;
}
case 0xf020: // LOAD BMP: filename:str
@@ -519,8 +516,12 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
return true;
}
-int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq) {
- error("TODO: implement TTMInterpreter::findGOTOTarget");
+int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame) {
+ for (int32 i = 0; i < (int)env._frameOffsets.size(); i++) {
+ if (env._frameOffsets[i] == frame)
+ return i;
+ }
+ return -1;
}
void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &seqArray) {
@@ -1030,7 +1031,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
} else if (runCount < 0) {
// Negative run count sets the cut time
seq->_timeCut = g_engine->getTotalPlayTime() + runCount;
- // Should this be *10 like delays?
+ // TODO: Should this be *10 like delays?
warning("TODO: check handling of negative runcount %d", runCount);
seq->_runFlag = kRunTypeTimeLimited;
} else {
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 64b9eb6dee5..c555cdb9951 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -55,7 +55,7 @@ public:
Common::Array<Common::Rect> _getPutAreas;
Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _getPutSurfaces;
int _scriptPals[6];
- Common::String _strings[6];
+ Common::String _strings[10];
};
enum TTMRunType {
@@ -148,7 +148,7 @@ public:
protected:
void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
- int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq);
+ int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);
DgdsEngine *_vm;
};
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 20ba3e2b7de..9f587ee2340 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -265,7 +265,6 @@ void Sound::playPCSound(uint num, const Common::Array<uint32> &sizeArray, const
} else {
warning("Sound: Requested to play %d but only have %d tracks", num, dataArray.size());
}
-
}
void Sound::stopMusic() {
Commit: 3b41518ecc4b4812af4e3c02431156b69d431187
https://github.com/scummvm/scummvm/commit/3b41518ecc4b4812af4e3c02431156b69d431187
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix some implicit scene change crashes for inventory
Changed paths:
engines/dgds/scene.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index f5aad0804dd..b9b668a2942 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -511,7 +511,8 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
break;
case kSceneOpOpenInventory:
engine->getInventory()->open();
- break;
+ // This implicitly changes scene num
+ return false;
case kSceneOpShowDlg:
showDialog(op._args[0]);
break;
@@ -527,8 +528,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
}
case kSceneOpLeaveSceneAndOpenInventory:
engine->getInventory()->open();
+ // This implicitly changes scene num
warning("TODO: Check leave scene and open inventory scene op");
- break;
+ return false;
case kSceneOpMoveItemsBetweenScenes: {
int16 fromScene = engine->getGameGlobals()->getGlobal(0x55);
int16 toScene = engine->getGameGlobals()->getGlobal(0x54);
Commit: 6abe2cd0b356d294d53cca804eb32d75ec9542ac
https://github.com/scummvm/scummvm/commit/6abe2cd0b356d294d53cca804eb32d75ec9542ac
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix mouse on inv drop
Changed paths:
engines/dgds/scene.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index b9b668a2942..bd4c02b470c 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -1012,8 +1012,11 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
if (area->_num == 0) {
// dropped on the inventory button
if (dragItem) {
+ debug("Item %d dropped on inventory.", dragItem->_num);
dragItem->_inSceneNum = 2;
+ engine->setMouseCursor(0);
} else {
+ debug("Mouseup on inventory.");
static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
}
} else {
Commit: c0d78c7ded494235f79bc288a421750e2e0dec5d
https://github.com/scummvm/scummvm/commit/c0d78c7ded494235f79bc288a421750e2e0dec5d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Rename buffers to make it more understandable
Also properly fix GOTO opcode this time. This fixes a bunch of things in the
shower at the start of the game.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index ab9630527c6..1b8fb5b27c5 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -72,7 +72,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds"), _currentCursor(-1), _topBufferUsed(false) {
+ _random("dgds"), _currentCursor(-1) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -106,9 +106,10 @@ DgdsEngine::~DgdsEngine() {
_icons.reset();
_corners.reset();
- _resData.free();
- _topBuffer.free();
- _bottomBuffer.free();
+ _compositionBuffer.free();
+ _foregroundBuffer.free();
+ _storedAreaBuffer.free();
+ _backgroundBuffer.free();
}
@@ -134,7 +135,7 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
warning("Tried to change from scene %d to itself, doing nothing.", sceneNum);
return false;
}
-
+
if (sceneNum != 2 && _scene->getNum() != 2 && _inventory->isOpen()) {
_inventory->close();
}
@@ -190,11 +191,21 @@ void DgdsEngine::setMouseCursor(uint num) {
if (num >= cursors.size())
error("Not enough cursor info, need %d have %d", num, cursors.size());
- int hotx = cursors[num]._hotX;
- int hoty = cursors[num]._hotY;
+ uint16 hotX = cursors[num]._hotX;
+ uint16 hotY = cursors[num]._hotY;
+
+ /*
+ // Adjust mouse location so hot pixel is in the same place as before?
+ uint16 lastHotX = _currentCursor >= 0 ? cursors[_currentCursor]._hotX : 0;
+ uint16 lastHotY = _currentCursor >= 0 ? cursors[_currentCursor]._hotY : 0;
+
+ int16 newMouseX = _lastMouse.x - lastHotX + hotX;
+ int16 newMouseY = _lastMouse.y - lastHotY + hotY;
- CursorMan.popAllCursors();
- CursorMan.pushCursor(*(_icons->getSurface(num)->surfacePtr()), hotx, hoty, 0, 0);
+ g_system->warpMouse(newMouseX, newMouseY);
+ */
+
+ CursorMan.replaceCursor(*(_icons->getSurface(num)->surfacePtr()), hotX, hotY, 0, 0);
CursorMan.showMouse(true);
_currentCursor = num;
@@ -212,15 +223,11 @@ void DgdsEngine::checkDrawInventoryButton() {
int x = SCREEN_WIDTH - _icons->width(2) - 5;
int y = SCREEN_HEIGHT - _icons->height(2) - 5;
static const Common::Rect drawWin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- _icons->drawBitmap(2, x, y, drawWin, _resData);
+ _icons->drawBitmap(2, x, y, drawWin, _compositionBuffer);
}
-Graphics::ManagedSurface &DgdsEngine::getTopBuffer() {
- if (_topBufferUsed) {
- _topBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _topBufferUsed = false;
- }
- return _topBuffer;
+Graphics::ManagedSurface &DgdsEngine::getForegroundBuffer() {
+ return _foregroundBuffer;
}
Common::Error DgdsEngine::run() {
@@ -240,9 +247,10 @@ Common::Error DgdsEngine::run() {
setDebugger(_console);
- _bottomBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- _topBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- _resData.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _backgroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _storedAreaBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _foregroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ _compositionBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
g_system->fillScreen(0);
@@ -371,7 +379,7 @@ Common::Error DgdsEngine::run() {
_gdsScene->runPreTickOps();
_scene->runPreTickOps();
- _scene->drawActiveDialogBgs(&_resData);
+ _scene->drawActiveDialogBgs(&_compositionBuffer);
if (moveToNext && _inventory->isOpen()) {
_inventory->close();
@@ -427,6 +435,16 @@ Common::Error DgdsEngine::run() {
_scene->runPostTickOps();
_scene->checkTriggers();
+ // Now we start to assemble the rendered scene.
+ _compositionBuffer.blitFrom(_backgroundBuffer);
+ _compositionBuffer.transBlitFrom(_storedAreaBuffer);
+
+ if (_inventory->isOpen()) {
+ int invCount = _gdsScene->countItemsInScene2();
+ _inventory->draw(_compositionBuffer, invCount);
+ }
+
+ _compositionBuffer.transBlitFrom(_foregroundBuffer);
/* For debugging, dump the frame contents..
{
Common::DumpFile outf;
@@ -446,28 +464,18 @@ Common::Error DgdsEngine::run() {
outf.open(Common::Path(Common::String::format("/tmp/%07d-res.png", now)));
::Image::writePNG(outf, *_resData.surfacePtr(), palbuf);
outf.close();
- }
- */
-
- // Now we start to assemble the rendered scene.
- _resData.blitFrom(_bottomBuffer);
-
- if (_inventory->isOpen()) {
- int invCount = _gdsScene->countItemsInScene2();
- _inventory->draw(_resData, invCount);
- }
+ }*/
- _resData.transBlitFrom(_topBuffer);
- _topBufferUsed = true;
+ _foregroundBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
if (!_inventory->isOpen()) {
- _gdsScene->drawItems(_resData);
+ _gdsScene->drawItems(_compositionBuffer);
checkDrawInventoryButton();
}
- _clock.draw(_resData);
+ _clock.draw(_compositionBuffer);
bool haveActiveDialog = _scene->checkDialogActive();
- _scene->drawAndUpdateDialogs(&_resData);
+ _scene->drawAndUpdateDialogs(&_compositionBuffer);
bool gameRunning = (!haveActiveDialog && _gameGlobals->getGlobal(0x57) /* TODO: && _dragItem == nullptr*/);
_clock.update(gameRunning);
@@ -477,7 +485,7 @@ Common::Error DgdsEngine::run() {
return Common::kNoError;
}
- g_system->copyRectToScreen(_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ g_system->copyRectToScreen(_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g_system->updateScreen();
g_system->delayMillis(10);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index bf3d59c1d20..0626b51803c 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -72,7 +72,7 @@ class DgdsEngine : public Engine {
public:
Common::Platform _platform;
Sound *_soundPlayer;
- Graphics::ManagedSurface _resData;
+ Graphics::ManagedSurface _compositionBuffer;
private:
Console *_console;
@@ -81,9 +81,9 @@ private:
Decompressor *_decompressor;
DgdsGameId _gameId;
- Graphics::ManagedSurface _bottomBuffer;
- Graphics::ManagedSurface _topBuffer;
- bool _topBufferUsed;
+ Graphics::ManagedSurface _backgroundBuffer;
+ Graphics::ManagedSurface _storedAreaBuffer;
+ Graphics::ManagedSurface _foregroundBuffer;
SDSScene *_scene;
GDSScene *_gdsScene;
Menu *_menu;
@@ -118,9 +118,10 @@ public:
DgdsGameId getGameId() { return _gameId; }
- Graphics::ManagedSurface &getTopBuffer();
- const Graphics::ManagedSurface &getTopBuffer() const { return _topBuffer; }
- Graphics::ManagedSurface &getBottomBuffer() { return _bottomBuffer; }
+ Graphics::ManagedSurface &getForegroundBuffer();
+ const Graphics::ManagedSurface &getForegroundBuffer() const { return _foregroundBuffer; }
+ Graphics::ManagedSurface &getBackgroundBuffer() { return _backgroundBuffer; }
+ Graphics::ManagedSurface &getStoredAreaBuffer() { return _storedAreaBuffer; }
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index e7963febe2f..049ab1aa41b 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -88,7 +88,15 @@ static const char *ttmOpName(uint16 op) {
case 0x4200: return "STORE AREA";
case 0x4210: return "SAVE GETPUT REGION";
case 0xa000: return "DRAW PIXEL";
+ case 0xa010: return "SAVE REGION 10?????";
+ case 0xa020: return "SAVE REGION 20?????";
+ case 0xa030: return "SAVE REGION 30?????";
+ case 0xa040: return "SAVE REGION 40?????";
case 0xa050: return "SAVE REGION";
+ case 0xa060: return "SAVE REGION FLIPPED??";
+ case 0xa070: return "SAVE REGION 70?????";
+ case 0xa080: return "SAVE REGION 80?????";
+ case 0xa090: return "SAVE REGION 90?????";
case 0xa0a0: return "DRAW LINE";
case 0xa100: return "DRAW FILLED RECT";
case 0xa110: return "DRAW EMPTY RECT";
@@ -124,23 +132,21 @@ static const char *ttmOpName(uint16 op) {
}
void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
- Common::Rect bmpArea(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-
switch (op) {
case 0x0000: // FINISH: void
break;
case 0x0020: // SAVE (free?) BACKGROUND
if (seq._executed) // this is a one-shot op
break;
- _vm->getBottomBuffer().copyFrom(_vm->getTopBuffer());
+ _vm->getBackgroundBuffer().copyFrom(_vm->getForegroundBuffer());
break;
case 0x0070: // FREE PALETTE
if (seq._executed) // this is a one-shot op
break;
error("TODO: Implement me: free palette (current pal)");
break;
- case 0x0080: // FREE SHAPE // DRAW BACKGROUND??
- _vm->getTopBuffer().copyFrom(_vm->getBottomBuffer());
+ case 0x0080: // FREE SHAPE
+ env._scriptShapes[seq._currentBmpId].reset();
break;
case 0x0090: // FREE FONT
if (seq._executed) // this is a one-shot op
@@ -150,6 +156,12 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x00B0:
// Does nothing?
break;
+ case 0x00C0: // (one-shot) FREE GETPUT (free getput item pointed to by _currentGetPutId)
+ if (seq._executed) // this is a one-shot op
+ break;
+ env._getPutSurfaces[seq._currentGetPutId].reset();
+ env._getPutAreas[seq._currentGetPutId] = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ break;
case 0x0110: // PURGE void
_vm->adsInterpreter()->setHitTTMOp0110();
break;
@@ -243,15 +255,16 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
g_system->delayMillis(5);
}
}
- _vm->getBottomBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getBackgroundBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
break;
// blt first to make the initial fade-in work
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- g_system->copyRectToScreen(_vm->_resData.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
+ _vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
+ _vm->_compositionBuffer.transBlitFrom(_vm->getForegroundBuffer());
+ g_system->copyRectToScreen(_vm->_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -265,13 +278,11 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
break;
}
- case 0x4200: { // STORE AREA: x,y,w,h:int [0..n] ; it makes this area of bmpData persist in the next frames.
+ case 0x4200: { // STORE AREA: x,y,w,h:int [0..n] ; makes this area of foreground persist in the next frames.
if (seq._executed) // this is a one-shot op
break;
- const Common::Rect destRect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- _vm->getBottomBuffer().copyRectToSurface(_vm->_resData, destRect.left, destRect.top, destRect);
+ const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->getStoredAreaBuffer().transBlitFrom(_vm->getForegroundBuffer(), rect, rect);
break;
}
case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
@@ -281,41 +292,51 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
env._getPutAreas.resize(seq._currentGetPutId + 1);
env._getPutSurfaces.resize(seq._currentGetPutId + 1);
}
- Common::Rect rect = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
env._getPutAreas[seq._currentGetPutId] = rect;
- // TODO: Check which buffer this should get things from .. composed buffer?
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_resData.format);
- surf->blitFrom(_vm->_resData, rect, Common::Rect(0, 0, rect.width(), rect.height()));
+
+ // Getput reads an area from the front buffer.
+ Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getForegroundBuffer().format);
+ surf->blitFrom(_vm->getForegroundBuffer(), rect, Common::Point(0, 0));
env._getPutSurfaces[seq._currentGetPutId].reset(surf);
break;
}
case 0xa000: // DRAW PIXEL x,y:int
- _vm->getTopBuffer().setPixel(ivals[0], ivals[1], seq._drawColFG);
+ _vm->getForegroundBuffer().setPixel(ivals[0], ivals[1], seq._drawColFG);
break;
- case 0xa050: // SAVE REGION i,j,k,l:int [i<k,j<l] (not in DRAGON)
+ case 0xa050: {// SAVE REGION x,y,w,h:int (not used in DRAGON?)
// it works like a bitblit, but it doesn't write if there's something already at the destination?
- // TODO: In dragon this seems to be a whole set of operations - 0xa0n4.
- // Maybe there are up to 9 regions available?
- _vm->_resData.blitFrom(_vm->getBottomBuffer());
- _vm->_resData.transBlitFrom(_vm->getTopBuffer());
- _vm->getTopBuffer().copyFrom(_vm->_resData);
+ // TODO: This is part of a whole set of operations - 0xa0n4.
+ // They do various flips etc.
+ warning("TODO: Fix implementation of SAVE REGION (0xa050)");
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
+ _vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
+ _vm->_compositionBuffer.transBlitFrom(_vm->getForegroundBuffer());
+ _vm->getForegroundBuffer().blitFrom(_vm->_compositionBuffer, r, r);
+ break;
+ }
+ case 0xa060: { // RESTORE REGION
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->getStoredAreaBuffer().fillRect(r, 0);
break;
+ }
case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->getTopBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
+ _vm->getForegroundBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
break;
- case 0xa100: // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
- bmpArea = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getTopBuffer().fillRect(bmpArea, seq._drawColFG);
+ case 0xa100: { // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->getForegroundBuffer().fillRect(r, seq._drawColFG);
break;
- case 0xa110: // DRAW EMPTY RECT x1,y1,x2,y2:int
- bmpArea = Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.right, bmpArea.top, seq._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.bottom, bmpArea.right, bmpArea.bottom, seq._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.left, bmpArea.top, bmpArea.left, bmpArea.bottom, seq._drawColFG);
- _vm->getTopBuffer().drawLine(bmpArea.right, bmpArea.top, bmpArea.right, bmpArea.bottom, seq._drawColFG);
+ }
+ case 0xa110: { // DRAW EMPTY RECT x1,y1,x2,y2:int
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->getForegroundBuffer().drawLine(r.left, r.top, r.right, r.top, seq._drawColFG);
+ _vm->getForegroundBuffer().drawLine(r.left, r.bottom, r.right, r.bottom, seq._drawColFG);
+ _vm->getForegroundBuffer().drawLine(r.left, r.top, r.left, r.bottom, seq._drawColFG);
+ _vm->getForegroundBuffer().drawLine(r.right, r.top, r.right, r.bottom, seq._drawColFG);
break;
+ }
case 0xa200: // 0xa2n0 DRAW STRING n: x,y,w,h:int - draw the nth string from the string table
case 0xa210:
case 0xa220:
@@ -332,7 +353,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// TODO: Probably not this font?
const Font *font = mgr->getFont(FontManager::kDefaultFont);
// Note: ignore the y-height argument (ivals[3]) for now.
- font->drawString(&(_vm->getTopBuffer()), str, ivals[0], ivals[1], ivals[2], seq._drawColFG);
+ font->drawString(&(_vm->getForegroundBuffer()), str, ivals[0], ivals[1], ivals[2], seq._drawColFG);
break;
}
case 0xa510:
@@ -361,7 +382,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// DRAW BMP: x,y:int [-n,+n] (RISE)
Common::SharedPtr<Image> img = env._scriptShapes[seq._currentBmpId];
if (img)
- img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->getTopBuffer(), op == 0xa520);
+ img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->getForegroundBuffer(), op == 0xa520);
else
warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
break;
@@ -375,15 +396,16 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
}
const Common::Rect &r = env._getPutAreas[i];
- _vm->getTopBuffer().copyRectToSurface(*(env._getPutSurfaces[i]->surfacePtr()),
- r.left, r.top, Common::Rect(0, 0, r.width(), r.height()));
+ _vm->getForegroundBuffer().transBlitFrom(*(env._getPutSurfaces[i].get()),
+ Common::Point(r.left, r.top));
break;
}
case 0xf010: { // LOAD SCR: filename:str
if (seq._executed) // this is a one-shot op
break;
Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
- tmp.drawScreen(sval, _vm->getBottomBuffer());
+ tmp.drawScreen(sval, _vm->getBackgroundBuffer());
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
}
case 0xf020: // LOAD BMP: filename:str
@@ -437,12 +459,18 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// Unimplemented / unknown
case 0x0010: // (one-shot) ??
- case 0x00C0: // (one-shot) FREE GETPUT (free getput item pointed to by _currentGetPutId)
case 0x0230: // (one-shot) reset current music? (0 args) - found in HoC intro. Sets params about current music.
case 0x0400: // (one-shot) set palette??
case 0x1040: // Sets some global? i:int
case 0x10B0: // null op?
case 0x2010: // SET FRAME?? x,y
+ case 0xa010: // SAVE REGION ????
+ case 0xa020: // SAVE REGION ????
+ case 0xa030: // SAVE REGION ????
+ case 0xa040: // SAVE REGION ????
+ case 0xa070: // SAVE REGION ????
+ case 0xa080: // SAVE REGION ????
+ case 0xa090: // SAVE REGION ????
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa420: // DRAW EMPTY CIRCLE
@@ -516,12 +544,22 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
return true;
}
-int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame) {
+int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 targetFrame) {
+ int64 startpos = env.scr->pos();
+ int32 retval = -1;
for (int32 i = 0; i < (int)env._frameOffsets.size(); i++) {
- if (env._frameOffsets[i] == frame)
- return i;
+ env.scr->seek(env._frameOffsets[i]);
+ uint16 op = env.scr->readUint16LE();
+ if (op == 0x1101 || op == 0x1111) {
+ uint16 frameno = env.scr->readUint16LE();
+ if (frameno == targetFrame) {
+ retval = i;
+ break;
+ }
+ }
}
- return -1;
+ env.scr->seek(startpos);
+ return retval;
}
void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &seqArray) {
Commit: 33057f412e7ec735102ea1df362a3cef1c6276cc
https://github.com/scummvm/scummvm/commit/33057f412e7ec735102ea1df362a3cef1c6276cc
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Improve debug, fix store opcode.
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 049ab1aa41b..e80fec0ed4d 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -100,6 +100,16 @@ static const char *ttmOpName(uint16 op) {
case 0xa0a0: return "DRAW LINE";
case 0xa100: return "DRAW FILLED RECT";
case 0xa110: return "DRAW EMPTY RECT";
+ case 0xa200: return "DRAW STRING 0";
+ case 0xa210: return "DRAW STRING 1";
+ case 0xa220: return "DRAW STRING 2";
+ case 0xa230: return "DRAW STRING 3";
+ case 0xa240: return "DRAW STRING 4";
+ case 0xa250: return "DRAW STRING 5";
+ case 0xa260: return "DRAW STRING 6";
+ case 0xa270: return "DRAW STRING 7";
+ case 0xa280: return "DRAW STRING 8";
+ case 0xa290: return "DRAW STRING 9";
case 0xa500: return "DRAW BMP";
case 0xa520: return "DRAW SPRITE FLIP";
case 0xa530: return "DRAW BMP4";
@@ -109,6 +119,16 @@ static const char *ttmOpName(uint16 op) {
case 0xf040: return "LOAD FONT";
case 0xf050: return "LOAD PAL";
case 0xf060: return "LOAD SONG";
+ case 0xf100: return "SET STRING 0";
+ case 0xf110: return "SET STRING 1";
+ case 0xf120: return "SET STRING 2";
+ case 0xf130: return "SET STRING 3";
+ case 0xf140: return "SET STRING 4";
+ case 0xf150: return "SET STRING 5";
+ case 0xf160: return "SET STRING 6";
+ case 0xf170: return "SET STRING 7";
+ case 0xf180: return "SET STRING 8";
+ case 0xf190: return "SET STRING 9";
case 0x0220: return "STOP CURRENT MUSIC";
case 0x00C0: return "FREE BACKGROUND";
@@ -282,7 +302,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op
break;
const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getStoredAreaBuffer().transBlitFrom(_vm->getForegroundBuffer(), rect, rect);
+ _vm->getStoredAreaBuffer().blitFrom(_vm->getForegroundBuffer(), rect, rect);
break;
}
case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
@@ -756,7 +776,7 @@ void ADSInterpreter::findUsedSequencesForSegment(int segno) {
opcode, (int)_adsData->scr->pos(), envno, seqno);
} else {
bool already_added = false;
- for (TTMSeq *s : _adsData->_usedSeqs[segno]) {
+ for (const TTMSeq *s : _adsData->_usedSeqs[segno]) {
if (s == seq) {
already_added = true;
break;
Commit: 487586681f711ec002e1b44a516be467e949a4f4
https://github.com/scummvm/scummvm/commit/487586681f711ec002e1b44a516be467e949a4f4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix compile with new palette
Changed paths:
engines/dgds/console.cpp
engines/dgds/image.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 0935652c30e..090e5a8cc28 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -24,6 +24,7 @@
#include "common/system.h"
#include "graphics/palette.h"
+#include "graphics/paletteman.h"
#include "image/png.h"
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 010dae0f2db..1356e0af32a 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -29,6 +29,7 @@
#include "common/platform.h"
#include "graphics/managed_surface.h"
#include "graphics/palette.h"
+#include "graphics/paletteman.h"
#include "graphics/surface.h"
#include "dgds/dgds.h"
#include "dgds/font.h"
Commit: affe5bf0b85121ea9193af46cc885d29fe860704
https://github.com/scummvm/scummvm/commit/affe5bf0b85121ea9193af46cc885d29fe860704
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add initial load/save code
Changed paths:
engines/dgds/clock.cpp
engines/dgds/clock.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index 440698a5896..45f9530e77d 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -164,4 +164,27 @@ void Clock::update(bool gameRunning) {
addGameTime(mins_to_add);
}
+Common::Error Clock::syncState(Common::Serializer &s) {
+ s.syncAsUint32LE(_lastPlayTime);
+ s.syncAsUint32LE(_millis);
+
+ s.syncAsSint16LE(_gameMinsAdded);
+ s.syncAsSint16LE(_gameTicksUp);
+ s.syncAsSint16LE(_gameTicksDown);
+ s.syncAsSint16LE(_days);
+ s.syncAsSint16LE(_days2);
+ s.syncAsSint16LE(_hours);
+ s.syncAsSint16LE(_mins);
+
+ s.syncAsSint16LE(_drawPos.left);
+ s.syncAsSint16LE(_drawPos.top);
+ s.syncAsSint16LE(_drawPos.right);
+ s.syncAsSint16LE(_drawPos.bottom);
+
+ s.syncAsByte(_visibleScript);
+ s.syncAsByte(_visibleUser);
+
+ return Common::kNoError;
+}
+
} // end namespace Dgds
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index 7b88dcd6ba2..f7c8b4dec5d 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -24,6 +24,7 @@
#include "common/types.h"
#include "common/rect.h"
+#include "common/serializer.h"
namespace Graphics {
class ManagedSurface;
@@ -58,6 +59,8 @@ public:
const Common::Rect &getPos() const { return _drawPos; }
+ Common::Error syncState(Common::Serializer &s);
+
private:
uint32 _lastPlayTime;
uint32 _millis;
@@ -76,7 +79,6 @@ private:
// Clock is shown if both are true;
bool _visibleScript;
bool _visibleUser;
-
};
} // end namespace Dgds
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 1b8fb5b27c5..eab23a0f630 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -146,7 +146,8 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
return false;
}
- _scene->runLeaveSceneOps();
+ if (runChangeOps)
+ _scene->runLeaveSceneOps();
// store the last scene num
_gameGlobals->setGlobal(0x61, _scene->getNum());
@@ -154,7 +155,8 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_scene->unload();
_soundPlayer->unloadMusic();
- _gdsScene->runChangeSceneOps();
+ if (runChangeOps)
+ _gdsScene->runChangeSceneOps();
setMouseCursor(0);
@@ -230,7 +232,7 @@ Graphics::ManagedSurface &DgdsEngine::getForegroundBuffer() {
return _foregroundBuffer;
}
-Common::Error DgdsEngine::run() {
+void DgdsEngine::init() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
_console = new Console(this);
@@ -253,10 +255,9 @@ Common::Error DgdsEngine::run() {
_compositionBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
g_system->fillScreen(0);
+}
- Common::EventManager *eventMan = g_system->getEventManager();
- Common::Event ev;
-
+void DgdsEngine::loadGameFiles() {
REQFileData invRequestData;
REQFileData vcrRequestData;
RequestParser reqParser(_resource, _decompressor);
@@ -313,11 +314,20 @@ Common::Error DgdsEngine::run() {
setMouseCursor(0);
_inventory->setRequestData(invRequestData);
+ _menu->setRequestData(vcrRequestData);
//getDebugger()->attach();
debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
+}
+
+Common::Error DgdsEngine::run() {
+ init();
+ loadGameFiles();
+
+ Common::EventManager *eventMan = g_system->getEventManager();
+ Common::Event ev;
bool moveToNext = false;
bool triggerMenu = false;
@@ -354,7 +364,7 @@ Common::Error DgdsEngine::run() {
_menu->setScreenBuffer();
CursorMan.showMouse(true);
- _menu->drawMenu(vcrRequestData);
+ _menu->drawMenu();
} else {
_menu->hideMenu();
CursorMan.showMouse(false);
@@ -365,7 +375,7 @@ Common::Error DgdsEngine::run() {
if (_menu->menuShown()) {
if (mouseEvent == Common::EVENT_LBUTTONUP) {
- _menu->handleMenu(vcrRequestData, _lastMouse);
+ _menu->handleMenu(_lastMouse);
mouseEvent = Common::EVENT_INVALID;
}
g_system->updateScreen();
@@ -499,4 +509,71 @@ Common::SeekableReadStream *DgdsEngine::getResource(const Common::String &name,
return _resource->getResource(name, ignorePatches);
}
+
+bool DgdsEngine::canLoadGameStateCurrently(Common::U32String *msg /*= nullptr*/) {
+ return _gdsScene != nullptr;
+}
+
+
+bool DgdsEngine::canSaveGameStateCurrently(Common::U32String *msg /*= nullptr*/) {
+ return _gdsScene && _scene && _scene->getNum() != 2
+ && !_scene->hasVisibleDialog() && !_menu->menuShown()
+ && _scene->getDragItem() == nullptr;
+}
+
+
+Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
+ //
+ // Version history:
+ //
+ // 1: First version
+ //
+
+ assert(_scene && _gdsScene);
+
+ if (!s.syncVersion(1))
+ error("Save game version too new: %d", s.getVersion());
+
+ Common::Error result;
+
+ result = _gdsScene->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ int sceneNum = _scene->getNum();
+ s.syncAsUint16LE(sceneNum);
+ if (s.isLoading()) {
+ // load scene data before syncing state
+ const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
+ if (!_resource->hasResource(sceneFile))
+ error("Game references non-existant scene %d", sceneNum);
+
+ _scene->load(sceneFile, _resource, _decompressor);
+ }
+
+ result = _scene->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ result = _gameGlobals->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ result = _clock.syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ result = _inventory->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ result = _gamePals->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ result = _adsInterp->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+
+ s.syncAsSint16LE(_textSpeed);
+ s.syncAsByte(_justChangedScene1);
+ s.syncAsByte(_justChangedScene2);
+
+ return Common::kNoError;
+}
+
+
} // End of namespace Dgds
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 0626b51803c..6c4d047faf7 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -27,6 +27,7 @@
#include "common/events.h"
#include "common/platform.h"
#include "common/random.h"
+#include "common/serializer.h"
#include "graphics/surface.h"
#include "graphics/managed_surface.h"
@@ -148,11 +149,28 @@ public:
Clock &getClock() { return _clock; }
+ bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
+ bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+
+ Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override {
+ Common::Serializer s(nullptr, stream);
+ return syncGame(s);
+ }
+
+ Common::Error loadGameStream(Common::SeekableReadStream *stream) override {
+ Common::Serializer s(stream, nullptr);
+ return syncGame(s);
+ }
+
private:
+ Common::Error syncGame(Common::Serializer &s);
+
void loadCorners(const Common::String &filename);
void loadIcons();
void checkDrawInventoryButton();
+ void init();
+ void loadGameFiles();
};
} // End of namespace Dgds
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 840f4dbc391..52d9e9b7a5d 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -561,12 +561,43 @@ Common::String Dialog::dump(const Common::String &indent) const {
return str;
}
+Common::Error Dialog::syncState(Common::Serializer &s) {
+ s.syncAsUint32LE(_flags);
+ bool hasState = _state.get() != nullptr;
+ s.syncAsByte(hasState);
+ if (hasState) {
+ if (!_state)
+ _state.reset(new DialogState());
+ _state->syncState(s);
+ } else {
+ _state.reset();
+ }
+ return Common::kNoError;
+}
+
Common::String DialogState::dump(const Common::String &indent) const {
return Common::String::format("%sDialogState<hide %d loc %s lastmouse %d %d charsz %d %d mousestr %d selaction %p>",
indent.c_str(), _hideTime, _loc.dump("").c_str(), _lastMouseX, _lastMouseY, _charWidth,
_charHeight, _strMouseLoc, (void *)_selectedAction);
}
+Common::Error DialogState::syncState(Common::Serializer &s) {
+ s.syncAsUint32LE(_hideTime);
+ s.syncAsSint16LE(_lastMouseX);
+ s.syncAsSint16LE(_lastMouseY);
+ s.syncAsUint16LE(_charWidth);
+ s.syncAsUint16LE(_charHeight);
+ s.syncAsUint32LE(_strMouseLoc);
+
+ s.syncAsUint16LE(_loc.x);
+ s.syncAsUint16LE(_loc.y);
+ s.syncAsUint16LE(_loc.width);
+ s.syncAsUint16LE(_loc.height);
+
+ return Common::kNoError;
+}
+
+
Common::String DialogAction::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
str += _dumpStructList(indent, "opList", sceneOpList);
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 9c0311ece11..d30c0666e2c 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -25,6 +25,7 @@
#include "common/stream.h"
#include "common/array.h"
#include "common/rect.h"
+#include "common/serializer.h"
#include "dgds/dgds_rect.h"
@@ -93,6 +94,7 @@ public:
struct DialogAction *_selectedAction;
Common::String dump(const Common::String &indent) const;
+ Common::Error syncState(Common::Serializer &s);
};
class Dialog {
@@ -125,6 +127,8 @@ public:
Common::String dump(const Common::String &indent) const;
void clear();
+ Common::Error syncState(Common::Serializer &s);
+
private:
void drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage);
void drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage);
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 231364459cd..ab44cd00c1d 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -114,10 +114,10 @@ private:
////////////////////////////////
DragonGlobals::DragonGlobals(Clock &_clock) : Globals(),
-_gameCounterTicksUp(0), _gameCounterTicksDown(0), _lastOpcode1SceneChageNum(0),
-_sceneOp12SceneNum(0), _currentSelectedItem(0), _gameMinsToAdd_1(0), _gameMinsToAdd_2(0),
-_gameMinsToAdd_3(0), _gameMinsToAdd_4(0), _gameMinsToAdd_5(0), _gameGlobal0x57(0),
-_sceneOpcode15FromScene(0), _sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
+_lastOpcode1SceneChageNum(0), _sceneOp12SceneNum(0), _currentSelectedItem(0),
+_gameMinsToAdd_1(0), _gameMinsToAdd_2(0), _gameMinsToAdd_3(0), _gameMinsToAdd_4(0),
+_gameMinsToAdd_5(0), _gameGlobal0x57(0), _sceneOpcode15FromScene(0),
+_sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
_globals.push_back(_clock.getGameMinsAddedGlobal(1));
_globals.push_back(_clock.getGameTicksUpGlobal(0x64));
@@ -147,5 +147,28 @@ _opcode106EndMinutes(0) {
_globals.push_back(new DetailLevelROGlobal(0x27));
}
+Common::Error DragonGlobals::syncState(Common::Serializer &s) {
+ s.syncAsSint16LE(_lastOpcode1SceneChageNum);
+ s.syncAsSint16LE(_sceneOp12SceneNum);
+ s.syncAsSint16LE(_currentSelectedItem);
+ s.syncAsSint16LE(_gameMinsToAdd_1);
+ s.syncAsSint16LE(_gameMinsToAdd_2);
+ s.syncAsSint16LE(_gameMinsToAdd_3);
+ s.syncAsSint16LE(_gameMinsToAdd_4);
+ s.syncAsSint16LE(_gameMinsToAdd_5);
+ s.syncAsSint16LE(_gameGlobal0x57);
+ s.syncAsSint16LE(_sceneOpcode15FromScene);
+ s.syncAsSint16LE(_sceneOpcode15ToScene);
+ s.syncAsSint16LE(_sceneOpcode100Var);
+ s.syncAsSint16LE(_arcadeModeFlag_3cdc);
+ s.syncAsSint16LE(_opcode106EndMinutes);
+
+ s.syncAsSint16LE(_table._row);
+ s.syncAsSint16LE(_table._col);
+ s.syncAsSint16LE(_table._divBy4);
+ s.syncAsSint16LE(_table._output);
+
+ return Common::kNoError;
+}
} // end namespace Dgds
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index c7b7df0e3e6..ed11637bad2 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -78,6 +78,7 @@ public:
int16 getGlobal(uint16 num);
int16 setGlobal(uint16 num, int16 val);
+ virtual Common::Error syncState(Common::Serializer &s) { return Common::kNoError; };
protected:
Common::Array<Global *> _globals;
};
@@ -103,8 +104,6 @@ public:
DragonGlobals(Clock &clock);
private:
- int16 _gameCounterTicksUp;
- int16 _gameCounterTicksDown;
int16 _lastOpcode1SceneChageNum;
int16 _sceneOp12SceneNum;
int16 _currentSelectedItem;
@@ -122,6 +121,8 @@ private:
DragonDataTable _table;
// Clock _clock; // kept in the engine
// uint16 _detailSliderSetting; // kept in the engine
+
+ Common::Error syncState(Common::Serializer &s) override;
};
} // end namespace Dgds
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 1356e0af32a..7f1d8b30932 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -40,8 +40,7 @@
namespace Dgds {
-Palette::Palette() {
- memset(_palette, 0, 256 * 3);
+DgdsPal::DgdsPal() : Palette(256) {
}
GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor) : _curPalNum(0),
@@ -58,19 +57,18 @@ int GamePalettes::loadPalette(Common::String filename) {
_palettes.resize(_palettes.size() + 1);
- Palette &pal = _palettes.back();
+ DgdsPal &pal = _palettes.back();
DgdsChunkReader chunk(fileStream);
while (chunk.readNextHeader(EX_PAL, filename)) {
chunk.readContent(_decompressor);
Common::SeekableReadStream *chunkStream = chunk.getContent();
if (chunk.isSection(ID_VGA)) {
- chunkStream->read(pal._palette, 256 * 3);
-
- for (uint k = 0; k < 256 * 3; k += 3) {
- pal._palette[k + 0] <<= 2;
- pal._palette[k + 1] <<= 2;
- pal._palette[k + 2] <<= 2;
+ for (uint k = 0; k < 256; k++) {
+ byte r = chunkStream->readByte() << 2;
+ byte g = chunkStream->readByte() << 2;
+ byte b = chunkStream->readByte() << 2;
+ pal.set(k, r, g, b);
}
}
}
@@ -91,12 +89,12 @@ void GamePalettes::setPalette() {
error("request to set pal %d but only have %d pals", _curPalNum, _palettes.size());
_curPal = _palettes[_curPalNum];
- g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
+ g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
}
void GamePalettes::clearPalette() {
- _curPal = _blacks;
- g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
+ _curPal = DgdsPal();
+ g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
}
void GamePalettes::setFade(int col, int ncols, int targetcol, int fade) {
@@ -106,22 +104,46 @@ void GamePalettes::setFade(int col, int ncols, int targetcol, int fade) {
if (col + ncols > 256)
error("GamePalettes::setFade: request to fade past the end of the palette");
- Palette &pal = _palettes[_curPalNum];
+ const DgdsPal &pal = _palettes[_curPalNum];
- byte r2 = pal._palette[targetcol * 3 + 0];
- byte g2 = pal._palette[targetcol * 3 + 1];
- byte b2 = pal._palette[targetcol * 3 + 2];
+ byte r2, b2, g2;
+ pal.get(targetcol, r2, b2, g2);
for (int c = col; c < col + ncols; c++) {
- byte r = pal._palette[c * 3 + 0];
- byte g = pal._palette[c * 3 + 1];
- byte b = pal._palette[c * 3 + 2];
+ byte r, g, b;
+ pal.get(c, r, g, b);
+
+ _curPal.set(c,
+ r2 * fade / 255 + r * (255 - fade) / 255,
+ g2 * fade / 255 + g * (255 - fade) / 255,
+ b2 * fade / 255 + b * (255 - fade) / 255);
+ }
+ g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
+}
+
+Common::Error GamePalettes::syncState(Common::Serializer &s) {
+ s.syncAsUint16LE(_curPalNum);
+ uint npals = _palettes.size();
+ s.syncAsUint16LE(npals);
- _curPal._palette[c * 3 + 0] = r2 * fade / 255 + r * (255 - fade) / 255;
- _curPal._palette[c * 3 + 1] = g2 * fade / 255 + g * (255 - fade) / 255;
- _curPal._palette[c * 3 + 2] = b2 * fade / 255 + b * (255 - fade) / 255;
+ if (s.isLoading()) {
+ for (uint i = 0; i < npals; i++) {
+ Common::String name;
+ s.syncString(name);
+ loadPalette(name);
+ }
+ if (_curPalNum >= _palettes.size())
+ error("Current palette number %d greater than available palettes", _curPalNum);
+
+ setPalette();
+ } else {
+ for (uint i = 0; i < npals; i++) {
+ Common::String name = _palettes[i].getName();
+ s.syncString(name);
+ }
}
- g_system->getPaletteManager()->setPalette(_curPal._palette, 0, 256);
+
+ return Common::kNoError;
}
Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor) {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 6c79d554086..15c0d0ba4e5 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -24,6 +24,7 @@
#define DGDS_IMAGE_H
#include <common/ptr.h>
+#include <graphics/palette.h>
namespace Common {
class SeekableReadStream;
@@ -40,10 +41,13 @@ class Decompressor;
class DgdsChunkReader;
class ResourceManager;
-class Palette {
+class DgdsPal : public Graphics::Palette {
public:
- Palette();
- byte _palette[256 * 3];
+ DgdsPal();
+ const Common::String &getName() { return _name; }
+ void setName(const Common::String &name) { _name = name; }
+private:
+ Common::String _name;
};
class GamePalettes {
@@ -58,14 +62,15 @@ public:
// Add coloff to the result to move toward white.
void setFade(int col, int ncols, int coloff, int fade);
+ Common::Error syncState(Common::Serializer &s);
+
private:
ResourceManager *_resourceMan;
Decompressor *_decompressor;
- Palette _curPal;
+ DgdsPal _curPal;
uint _curPalNum;
- Common::Array<Palette> _palettes;
- Palette _blacks;
+ Common::Array<DgdsPal> _palettes;
};
class Image {
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 6f6d16267d3..842aaea4e57 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/util.h"
#include "graphics/managed_surface.h"
#include "dgds/inventory.h"
#include "dgds/dgds.h"
@@ -171,7 +172,15 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
surf.fillRect(highlightRect, 4);
}
- // draw offset for the image
+ // Update the icon bounds - Note: original doesn't do this here, but if we don't then
+ // the Napent in Dragon is weirdly offset in y because its rect has a large height?
+ Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
+ if (icon) {
+ item.rect.width = MIN((int)icon->w, item.rect.width);
+ item.rect.height = MIN((int)icon->h, item.rect.height);
+ }
+
+ // calculate draw offset for the image
int drawX = imgAreaX + x + (xstep - item.rect.width) / 2;
int drawY = imgAreaY + y + (ystep - item.rect.height) / 2;
@@ -297,5 +306,14 @@ void Inventory::mouseRUp(const Common::Point &pt) {
}
}
+Common::Error Inventory::syncState(Common::Serializer &s) {
+ s.syncAsUint16LE(_openedFromSceneNum);
+ s.syncAsByte(_isOpen);
+ s.syncAsSint16LE(_highlightItemNo);
+ s.syncAsSint16LE(_itemOffset);
+
+ return Common::kNoError;
+}
+
} // end namespace Dgds
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 31e1282c88e..716d2107f6a 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -22,6 +22,7 @@
#ifndef DGDS_INVENTORY_H
#define DGDS_INVENTORY_H
+#include "common/serializer.h"
#include "dgds/request.h"
namespace Graphics {
@@ -51,6 +52,8 @@ public:
void setRequestData(const REQFileData &data);
+ Common::Error syncState(Common::Serializer &s);
+
private:
GameItem *itemUnderMouse(const Common::Point &pt);
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index e1dd59af197..ae083784638 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -127,10 +127,10 @@ void Menu::setScreenBuffer() {
g_system->unlockScreen();
}
-void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
+void Menu::drawMenu(int16 menu) {
_curMenu = menu;
- Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
// Restore background when drawing submenus
g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
@@ -138,7 +138,7 @@ void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
Graphics::Surface *dst = g_system->lockScreen();
Graphics::ManagedSurface managed(dst, DisposeAfterUse::NO);
- vcrRequestData._requests[_curMenu].drawBg(&managed);
+ _reqData._requests[_curMenu].drawBg(&managed);
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
@@ -146,15 +146,15 @@ void Menu::drawMenu(REQFileData &vcrRequestData, int16 menu) {
gadget->draw(dst);
}
- drawMenuText(vcrRequestData, dst);
+ drawMenuText(dst);
g_system->unlockScreen();
g_system->updateScreen();
}
-void Menu::drawMenuText(REQFileData &vcrRequestData, Graphics::Surface *dst) {
- Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
- Common::Array<TextItem> textItems = vcrRequestData._requests[_curMenu]._textItemList;
+void Menu::drawMenuText(Graphics::Surface *dst) {
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
+ Common::Array<TextItem> textItems = _reqData._requests[_curMenu]._textItemList;
// TODO: Get the parent coordinates properly
uint16 parentX = gadgets[0].get()->_parentX;
@@ -175,11 +175,11 @@ void Menu::drawMenuText(REQFileData &vcrRequestData, Graphics::Surface *dst) {
}
}
-int16 Menu::getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick) {
+int16 Menu::getClickedMenuItem(Common::Point mouseClick) {
if (_curMenu < 0)
return -1;
- Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
@@ -192,16 +192,16 @@ int16 Menu::getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseC
return -1;
}
-void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
- const int16 clickedMenuItem = getClickedMenuItem(vcrRequestData, mouse);
+void Menu::handleMenu(Common::Point &mouse) {
+ const int16 clickedMenuItem = getClickedMenuItem(mouse);
// Click animation
// TODO: Handle on/off buttons
if (clickedMenuItem >= 0) {
- toggleGadget(vcrRequestData, clickedMenuItem, false);
- drawMenu(vcrRequestData, _curMenu);
+ toggleGadget(clickedMenuItem, false);
+ drawMenu(_curMenu);
g_system->delayMillis(500);
- toggleGadget(vcrRequestData, clickedMenuItem, true);
+ toggleGadget(clickedMenuItem, true);
}
switch (clickedMenuItem) {
@@ -216,22 +216,22 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
CursorMan.showMouse(false);
break;
case kMenuMainControls:
- drawMenu(vcrRequestData, kMenuControls);
+ drawMenu(kMenuControls);
break;
case kMenuMainOptions:
- drawMenu(vcrRequestData, kMenuOptions);
+ drawMenu(kMenuOptions);
break;
case kMenuMainCalibrate:
case kMenuJoystickCalibrationOK:
case kMenuMouseCalibrationCalibrate:
- drawMenu(vcrRequestData, kMenuCalibrate);
+ drawMenu(kMenuCalibrate);
break;
case kMenuMainFiles:
case kMenuSaveCancel:
- drawMenu(vcrRequestData, kMenuFiles);
+ drawMenu(kMenuFiles);
break;
case kMenuMainQuit:
- drawMenu(vcrRequestData, kMenuQuit);
+ drawMenu(kMenuQuit);
break;
case kMenuControlsVCR:
case kMenuOptionsVCR:
@@ -240,7 +240,7 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
case kMenuFilesVCR:
case kMenuQuitNo:
case kMenuRestartNo:
- drawMenu(vcrRequestData, kMenuMain);
+ drawMenu(kMenuMain);
break;
case kMenuOptionsJoystickOnOff:
case kMenuOptionsMouseOnOff:
@@ -250,21 +250,21 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
debug("Clicked option with ID %d", clickedMenuItem);
break;
case kMenuCalibrateJoystick:
- drawMenu(vcrRequestData, kMenuJoystick);
+ drawMenu(kMenuJoystick);
break;
case kMenuCalibrateMouse:
- drawMenu(vcrRequestData, kMenuMouse);
+ drawMenu(kMenuMouse);
break;
case kMenuFilesSave:
case kMenuChangeDirectoryCancel:
- drawMenu(vcrRequestData, kMenuSave);
+ drawMenu(kMenuSave);
break;
case kMenuFilesRestore:
// TODO
debug("Clicked Files - Restore %d", clickedMenuItem);
break;
case kMenuFilesRestart:
- drawMenu(vcrRequestData, kMenuRestart);
+ drawMenu(kMenuRestart);
break;
case kMenuSavePrevious:
case kMenuSaveNext:
@@ -273,7 +273,7 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
debug("Clicked Save - %d", clickedMenuItem);
break;
case kMenuSaveChangeDirectory:
- drawMenu(vcrRequestData, kMenuChangeDirectory);
+ drawMenu(kMenuChangeDirectory);
break;
case kMenuChangeDirectoryOK:
// TODO
@@ -292,8 +292,8 @@ void Menu::handleMenu(REQFileData &vcrRequestData, Common::Point &mouse) {
}
}
-void Menu::toggleGadget(REQFileData &vcrRequestData, int16 gadgetId, bool enable) {
- Common::Array<Common::SharedPtr<Gadget> > gadgets = vcrRequestData._requests[_curMenu]._gadgets;
+void Menu::toggleGadget(int16 gadgetId, bool enable) {
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 937a64d478e..e314bb9fbff 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -36,6 +36,7 @@
#include "gui/debugger.h"
#include "dgds/resource.h"
+#include "dgds/request.h"
namespace Dgds {
@@ -51,15 +52,20 @@ public:
virtual ~Menu();
void setScreenBuffer();
- void drawMenu(REQFileData &vcrRequestData, int16 menu = 0);
- void handleMenu(REQFileData &vcrRequestData, Common::Point &mouse);
+ void drawMenu(int16 menu = 0);
+ void handleMenu(Common::Point &mouse);
bool menuShown() const { return _curMenu >= 0; }
void hideMenu() { _curMenu = -1; }
+ void setRequestData(const REQFileData &data) {
+ _reqData = data;
+ }
+
private:
- int16 getClickedMenuItem(REQFileData &vcrRequestData, Common::Point mouseClick);
- void drawMenuText(REQFileData &vcrRequestData, Graphics::Surface *dst);
- void toggleGadget(REQFileData &vcrRequestData, int16 gadgetId, bool enable);
+ int16 getClickedMenuItem(Common::Point mouseClick);
+ void drawMenuText(Graphics::Surface *dst);
+ void toggleGadget(int16 gadgetId, bool enable);
+ REQFileData _reqData;
};
} // End of namespace Dgds
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index bd4c02b470c..b8fabe43f83 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -25,6 +25,7 @@
#include "common/file.h"
#include "common/rect.h"
#include "common/system.h"
+#include "common/util.h"
#include "graphics/cursorman.h"
#include "graphics/surface.h"
@@ -158,7 +159,7 @@ Common::String GameItem::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
"%sGameItem<\n%s\n%saltCursor %d icon %d sceneNum %d flags %d quality %d",
- indent.c_str(), super.c_str(), indent.c_str(), altCursor,
+ indent.c_str(), super.c_str(), indent.c_str(), _altCursor,
_iconNum, _inSceneNum, _flags, _quality);
str += _dumpStructList(indent, "opList4", opList4);
str += _dumpStructList(indent, "opList5", opList5);
@@ -258,7 +259,7 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
if (!isVersionUnder(" 1.211"))
dst._flags = s->readUint16LE() & 0xfffe;
if (!isVersionUnder(" 1.204")) {
- dst.altCursor = s->readUint16LE();
+ dst._altCursor = s->readUint16LE();
readOpList(s, dst.opList4);
readOpList(s, dst.opList5);
}
@@ -639,7 +640,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
bool SDSScene::_dlgWithFlagLo8IsClosing = false;;
DialogFlags SDSScene::_sceneDialogFlags = kDlgFlagNone;
-SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false) {
+SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false), _ignoreMouseUp(false) {
}
bool SDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
@@ -807,7 +808,7 @@ bool SDSScene::checkDialogActive() {
// Mark finished if we are manually clearing *or* the timer has expired.
bool finished = false;
if (dlg._state->_hideTime &&
- ((dlg._state->_hideTime < timeNow && clearDlgFlag) || timeNow > dlg._state->_hideTime)) {
+ ((dlg._state->_hideTime < timeNow && clearDlgFlag) || timeNow >= dlg._state->_hideTime)) {
finished = true;
}
@@ -909,7 +910,7 @@ bool SDSScene::drawAndUpdateDialogs(Graphics::ManagedSurface *dst) {
dlg.draw(dst, kDlgDrawStageForeground);
if (dlg.hasFlag(kDlgFlagHi20)) {
// Reset the dialog time and selected action
- int delay = -1;
+ int delay = 0xffff;
if (dlg._time)
delay = dlg._time;
@@ -977,6 +978,7 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
Dialog *dlg = getVisibleDialog();
if (dlg) {
_shouldClearDlg = true;
+ _ignoreMouseUp = true;
return;
}
@@ -995,6 +997,11 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
}
void SDSScene::mouseLUp(const Common::Point &pt) {
+ if (_ignoreMouseUp) {
+ _ignoreMouseUp = false;
+ return;
+ }
+
const HotArea *area = findAreaUnderMouse(pt);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
@@ -1063,6 +1070,10 @@ Dialog *SDSScene::getVisibleDialog() {
return nullptr;
}
+bool SDSScene::hasVisibleDialog() {
+ return getVisibleDialog() != nullptr;
+}
+
HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
@@ -1111,6 +1122,33 @@ void SDSScene::removeInvButtonFromHotAreaList() {
_hotAreaList.remove_at(0);
}
+Common::Error SDSScene::syncState(Common::Serializer &s) {
+ // num should be synced as part of the engine -
+ // at this point we are already loaded.
+ assert(_num);
+
+ // The dialogs and triggers are stateful, everthing else is stateless.
+ uint16 ndlgs = _dialogs.size();
+ s.syncAsUint16LE(ndlgs);
+ if (ndlgs != _dialogs.size()) {
+ error("Dialog count in save doesn't match count in game (%d vs %d)",
+ ndlgs, _dialogs.size());
+ }
+ for (auto &dlg : _dialogs) {
+ dlg.syncState(s);
+ }
+
+ uint16 ntrig = _triggers.size();
+ s.syncAsUint16LE(ntrig);
+ if (ntrig != _triggers.size()) {
+ error("Trigger count in save doesn't match count in game (%d vs %d)",
+ ntrig, _triggers.size());
+ }
+ for (auto &trg : _triggers)
+ s.syncAsByte(trg._enabled);
+
+ return Common::kNoError;
+}
GDSScene::GDSScene() {
}
@@ -1276,6 +1314,13 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
if (item._inSceneNum == currentScene && &item != engine->getScene()->getDragItem()) {
if (!(item._flags & 1)) {
// Dropped item.
+ // Update the rect for the icon - Note: original doesn't do this,
+ // but then the napent icon is offset??
+ Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
+ if (icon) {
+ item.rect.width = MIN((int)icon->w, item.rect.width);
+ item.rect.height = MIN((int)icon->h, item.rect.height);
+ }
if (xoff + item.rect.width > maxx)
xoff = 20;
int yoff = SCREEN_HEIGHT - (item.rect.height + 2);
@@ -1299,5 +1344,41 @@ int GDSScene::countItemsInScene2() const {
return result;
}
+Common::Error GDSScene::syncState(Common::Serializer &s) {
+ // Only items and globals are stateful - everything else is stateless.
+ // Game should already be loaded at this point so the lsits are already
+ // filled out.
+
+ assert(!_gameItems.empty());
+ assert(!_perSceneGlobals.empty());
+
+ // TODO: Maybe it would be nicer to save the item/global numbers
+ // with the values in case the order changed in some other version of the game data? This assumes they will be
+ // the same order.
+
+ uint16 nitems = _gameItems.size();
+ s.syncAsUint16LE(nitems);
+ if (nitems != _gameItems.size()) {
+ error("Item count in save doesn't match count in game (%d vs %d)",
+ nitems, _gameItems.size());
+ }
+ for (auto &item : _gameItems) {
+ s.syncAsUint16LE(item._inSceneNum);
+ s.syncAsUint16LE(item._quality);
+ }
+
+ uint16 nglobals = _perSceneGlobals.size();
+ s.syncAsUint16LE(nglobals);
+ if (nglobals != _perSceneGlobals.size()) {
+ error("Scene global count in save doesn't match count in game (%d vs %d)",
+ nglobals, _perSceneGlobals.size());
+ }
+ for (auto &glob : _perSceneGlobals) {
+ s.syncAsUint16LE(glob._val);
+ }
+
+ return Common::kNoError;
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index d2404b479a1..5b1363a3d6e 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -25,6 +25,7 @@
#include "common/stream.h"
#include "common/array.h"
+#include "common/serializer.h"
#include "dgds/dialog.h"
#include "dgds/dgds_rect.h"
@@ -114,7 +115,7 @@ struct SceneOp {
struct GameItem : public HotArea {
Common::Array<struct SceneOp> opList4;
Common::Array<struct SceneOp> opList5;
- uint16 altCursor;
+ uint16 _altCursor;
uint16 _iconNum;
uint16 _inSceneNum;
uint16 _flags;
@@ -186,6 +187,7 @@ public:
void mouseClicked(const Common::Point pt);
bool runOps(const Common::Array<SceneOp> &ops);
+ virtual Common::Error syncState(Common::Serializer &s) = 0;
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
@@ -250,6 +252,8 @@ public:
const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+ Common::Error syncState(Common::Serializer &s) override;
+
private:
//byte _unk[32];
Common::String _iconFile;
@@ -302,6 +306,9 @@ public:
const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+ bool hasVisibleDialog();
+ Common::Error syncState(Common::Serializer &s) override;
+
private:
HotArea *findAreaUnderMouse(const Common::Point &pt);
void enableTrigger(uint16 num) override;
@@ -325,6 +332,7 @@ private:
GameItem *_dragItem;
bool _shouldClearDlg;
+ bool _ignoreMouseUp;
static bool _dlgWithFlagLo8IsClosing;
static DialogFlags _sceneDialogFlags;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index e80fec0ed4d..230bbd9648b 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -43,6 +43,107 @@
namespace Dgds {
+Common::Error TTMEnviro::syncState(Common::Serializer &s) {
+ DgdsEngine *engine = dynamic_cast<DgdsEngine *>(g_engine);
+ for (auto &shape : _scriptShapes) {
+ bool hasShape = shape.get() != nullptr;
+ s.syncAsByte(hasShape);
+ if (hasShape) {
+ Common::String name;
+ if (s.isLoading()) {
+ s.syncString(name);
+ shape.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+ shape->loadBitmap(name);
+ } else {
+ name = shape->getFilename();
+ s.syncString(name);
+ }
+ }
+ }
+
+ uint16 ngetput = _getPutAreas.size();
+ s.syncAsUint16LE(ngetput);
+ _getPutAreas.resize(ngetput);
+ _getPutSurfaces.resize(ngetput);
+ for (uint i = 0; i < ngetput; i++) {
+ s.syncAsUint16LE(_getPutAreas[i].left);
+ s.syncAsUint16LE(_getPutAreas[i].top);
+ s.syncAsUint16LE(_getPutAreas[i].right);
+ s.syncAsUint16LE(_getPutAreas[i].bottom);
+ if (s.isLoading()) {
+ _getPutSurfaces[i].reset(new Graphics::ManagedSurface());
+ } else {
+ // TODO: Save the getput buffer contents here?
+ }
+ }
+ for (uint i = 0; i < ARRAYSIZE(_scriptPals); i++)
+ s.syncAsSint32LE(_scriptPals[i]);
+ for (uint i = 0; i < ARRAYSIZE(_strings); i++)
+ s.syncString(_strings[i]);
+
+ return Common::kNoError;
+}
+
+Common::Error TTMSeq::syncState(Common::Serializer &s) {
+ s.syncAsSint16LE(_gotoFrame);
+ s.syncAsSint16LE(_currentFrame);
+ s.syncAsSint16LE(_lastFrame);
+ s.syncAsByte(_selfLoop);
+ s.syncAsByte(_executed);
+ s.syncAsUint32LE(_timeNext);
+ s.syncAsUint32LE(_timeCut);
+
+ s.syncAsUint16LE(_drawWin.left);
+ s.syncAsUint16LE(_drawWin.top);
+ s.syncAsUint16LE(_drawWin.right);
+ s.syncAsUint16LE(_drawWin.bottom);
+
+ s.syncAsSint16LE(_currentFontId);
+ s.syncAsSint16LE(_currentPalId);
+ s.syncAsSint16LE(_currentSongId);
+ s.syncAsSint16LE(_currentBmpId);
+ s.syncAsSint16LE(_currentGetPutId);
+ s.syncAsSint16LE(_brushNum);
+ s.syncAsByte(_drawColFG);
+ s.syncAsByte(_drawColBG);
+ s.syncAsSint16LE(_runPlayed);
+ s.syncAsSint16LE(_runCount);
+ s.syncAsSint16LE(_timeInterval);
+ s.syncAsUint32LE(_runFlag);
+ s.syncAsSint16LE(_scriptFlag);
+
+ return Common::kNoError;
+}
+
+Common::Error ADSData::syncState(Common::Serializer &s) {
+ uint16 arrSize = ARRAYSIZE(_state);
+ s.syncAsUint16LE(arrSize);
+ if (arrSize != ARRAYSIZE(_state))
+ error("Expected fixed size state array");
+ for (uint i = 0; i < arrSize; i++)
+ s.syncAsSint16LE(_state[i]);
+
+ uint16 nenvs = _scriptEnvs.size();
+ s.syncAsUint16LE(nenvs);
+ // This should be the same on load as the data comes from the ADS/TTM files.
+ if (nenvs != _scriptEnvs.size())
+ error("Unexpected number of script envs (%d in save vs %d in ADS)", nenvs, _scriptEnvs.size());
+
+ for (auto &env : _scriptEnvs)
+ env.syncState(s);
+
+ uint16 nseqs = _ttmSeqs.size();
+ s.syncAsUint16LE(nseqs);
+ if (nseqs != _ttmSeqs.size())
+ error("Unexpected number of ttm seqeunces (%d in save vs %d in ADS)", nseqs, _ttmSeqs.size());
+
+ for (auto &seq : _ttmSeqs)
+ seq.syncState(s);
+
+ return Common::kNoError;
+}
+
+
TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
bool TTMInterpreter::load(const Common::String &filename, TTMEnviro &scriptData) {
@@ -158,7 +259,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0020: // SAVE (free?) BACKGROUND
if (seq._executed) // this is a one-shot op
break;
- _vm->getBackgroundBuffer().copyFrom(_vm->getForegroundBuffer());
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ //_vm->getBackgroundBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x0070: // FREE PALETTE
if (seq._executed) // this is a one-shot op
@@ -1455,5 +1557,34 @@ int ADSInterpreter::numArgs(uint16 opcode) const {
}
}
+Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
+ uint32 numTexts = _adsTexts.size();
+ s.syncAsUint32LE(numTexts);
+
+ Common::Array<Common::String> scriptNames;
+
+ if (s.isLoading()) {
+ for (uint32 i = 0; i < numTexts; i++) {
+ Common::String txtName;
+ s.syncString(txtName);
+ load(txtName);
+ scriptNames.push_back(txtName);
+ }
+ } else {
+ for (const auto &node : _adsTexts) {
+ Common::String txtName = node._key;
+ s.syncString(txtName);
+ scriptNames.push_back(txtName);
+ }
+ }
+
+ // Text order should be the same
+ for (const Common::String &name : scriptNames) {
+ _adsTexts[name].syncState(s);
+ }
+
+ return Common::kNoError;
+}
+
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index c555cdb9951..314bd7ea5a4 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -48,6 +48,9 @@ public:
TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
ARRAYCLEAR(_scriptPals);
}
+
+ Common::Error syncState(Common::Serializer &s);
+
uint16 _enviro;
uint16 _totalFrames;
Common::Array<int> _frameOffsets;
@@ -76,6 +79,7 @@ struct TTMSeq {
}
void reset();
+ Common::Error syncState(Common::Serializer &s);
int16 _enviro;
int16 _seqNum;
@@ -106,9 +110,8 @@ struct TTMSeq {
class ADSData : public ScriptParserData {
public:
- ADSData() : _initFlag(false), _maxSegments(0), _scriptDelay(-1),
- _hitTTMOp0110(false), _hitBranchOp(false), _gotoTarget(-1),
- _runningSegmentIdx(0) {
+ ADSData() : _maxSegments(0), _scriptDelay(-1), _hitTTMOp0110(false), _hitBranchOp(false),
+ _gotoTarget(-1), _runningSegmentIdx(0) {
for (int i = 0; i < ARRAYSIZE(_state); i++)
_state[i] = 8;
@@ -121,7 +124,6 @@ public:
Common::Array<Common::String> _scriptNames;
Common::Array<TTMEnviro> _scriptEnvs;
Common::Array<TTMSeq> _ttmSeqs;
- bool _initFlag;
int _maxSegments;
// TODO: replace these with dynamic arrays - fixed arrays inherited from original.
int _state[80];
@@ -135,6 +137,8 @@ public:
bool _hitTTMOp0110;
bool _hitBranchOp;
int16 _runningSegmentIdx;
+
+ Common::Error syncState(Common::Serializer &s);
};
class TTMInterpreter {
@@ -170,6 +174,8 @@ public:
int16 getStateForSceneOp(uint16 segnum);
void setScriptDelay(int16 delay) { _adsData->_scriptDelay = delay; }
+ Common::Error syncState(Common::Serializer &s);
+
protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
@@ -186,6 +192,7 @@ protected:
void findEndOrInitOp();
bool updateSeqTimeAndFrame(TTMSeq &seq);
int getArrIndexOfSegNum(uint16 segnum);
+
DgdsEngine *_vm;
TTMInterpreter *_ttmInterpreter;
Commit: e79b60a4d2ca467faca5fd94940d727df9609b19
https://github.com/scummvm/scummvm/commit/e79b60a4d2ca467faca5fd94940d727df9609b19
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add save/load dialogs. Fix skipping dialog
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.h
engines/dgds/scene.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index eab23a0f630..9a81b1c1f63 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -346,6 +346,14 @@ Common::Error DgdsEngine::run() {
case Common::KEYCODE_F5:
triggerMenu = true;
break;
+ case Common::KEYCODE_s:
+ if (ev.kbd.hasFlags(Common::KBD_CTRL))
+ saveGameDialog();
+ break;
+ case Common::KEYCODE_l:
+ if (ev.kbd.hasFlags(Common::KBD_CTRL))
+ loadGameDialog();
+ break;
case Common::KEYCODE_c:
_clock.toggleVisibleUser();
break;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 6c4d047faf7..d4d0b03d0db 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -162,6 +162,12 @@ public:
return syncGame(s);
}
+ bool hasFeature(EngineFeature f) const override {
+ return
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+ };
+
private:
Common::Error syncGame(Common::Serializer &s);
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 15c0d0ba4e5..bb31c386422 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -44,6 +44,7 @@ class ResourceManager;
class DgdsPal : public Graphics::Palette {
public:
DgdsPal();
+ virtual ~DgdsPal() {}
const Common::String &getName() { return _name; }
void setName(const Common::String &name) { _name = name; }
private:
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index b8fabe43f83..38cbeb6e604 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -808,7 +808,7 @@ bool SDSScene::checkDialogActive() {
// Mark finished if we are manually clearing *or* the timer has expired.
bool finished = false;
if (dlg._state->_hideTime &&
- ((dlg._state->_hideTime < timeNow && clearDlgFlag) || timeNow >= dlg._state->_hideTime)) {
+ ((dlg._state->_hideTime > timeNow && clearDlgFlag) || timeNow >= dlg._state->_hideTime)) {
finished = true;
}
Commit: 6f94da020a7ff3cc59c21d2418b141476d9239ea
https://github.com/scummvm/scummvm/commit/6f94da020a7ff3cc59c21d2418b141476d9239ea
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix dialog item selection
Changed paths:
engines/dgds/dialog.cpp
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 52d9e9b7a5d..9bb090fc62c 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -365,6 +365,28 @@ void Dialog::drawFindSelectionXY() {
}
}
+
+/**
+ * Get offsets into a string for a given set of wrapped lines.
+ *
+ * Font::wordWrapText will wrap the lines on a space or a CR, so each
+ * line's offset is the total chars from the previous line plus 1.
+ * each
+ *
+ * Returns one more value than the number of lines - the last one is
+ * s.size() for convenience.
+ */
+static Common::Array<int> _wrappedLineOffsets(const Common::String &s, const Common::Array<Common::String> &lines) {
+ Common::Array<int> ret;
+ int off = 0;
+ for (const Common::String &l : lines) {
+ ret.push_back(off);
+ off += l.size() + 1;
+ }
+ ret.push_back(s.size());
+ return ret;
+}
+
void Dialog::drawFindSelectionTxtOffset() {
if (!_state)
return;
@@ -379,18 +401,21 @@ void Dialog::drawFindSelectionTxtOffset() {
int dlgy = _state->_loc.y;
Common::Array<Common::String> lines;
- int maxWidth = font->wordWrapText(_str, dlgy, lines);
+ int maxWidth = font->wordWrapText(_str, _state->_loc.width, lines);
if (hasFlag(kDlgFlagLeftJust)) {
+ int textHeight = lines.size() * lineHeight;
dlgx += (_state->_loc.width - maxWidth - 1) / 2;
- dlgy += (_state->_loc.height - (lines.size() * lineHeight) - 1) / 2;
+ dlgy += (_state->_loc.height - textHeight - 1) / 2;
}
+ const Common::Array<int> lineOffs = _wrappedLineOffsets(_str, lines);
+
uint lineno;
uint totalchars = 0;
for (lineno = 0; lineno < lines.size() && dlgy + lineHeight < lastMouseY; lineno++) {
- totalchars += lines[lineno].size() + 1;
- dlgy = dlgy + lineHeight;
+ totalchars = lineOffs[lineno + 1];
+ dlgy += lineHeight;
}
int startx = dlgx;
@@ -426,25 +451,42 @@ void Dialog::drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const
int ystart = _state->_loc.y + (_state->_loc.height - (int)lines.size() * h) / 2;
int x = _state->_loc.x;
+
+ int highlightStart = INT_MAX;
+ int highlightEnd = INT_MAX;
+ if (_state->_selectedAction) {
+ // find the txt in the full dlg string, as action offsets include the heading
+ int txtoffset = _str.find(txt);
+ highlightStart = (int)_state->_selectedAction->strStart - txtoffset;
+ highlightEnd = (int)_state->_selectedAction->strEnd - txtoffset;
+ }
+
+ const Common::Array<int> lineOffs = _wrappedLineOffsets(txt, lines);
+
+ Graphics::TextAlign align;
+ int xwidth;
if (hasFlag(kDlgFlagLeftJust)) {
+ int maxlen = 0;
// each line left-aligned, but overall block is still centered
- int maxlen = -1;
for (const auto &line : lines)
maxlen = MAX(maxlen, font->getStringWidth(line));
-
x += (_state->_loc.width - maxlen) / 2;
-
- for (uint i = 0; i < lines.size(); i++)
- font->drawString(dst, lines[i], x, ystart + i * h, maxlen, fontcol, Graphics::kTextAlignLeft);
+ align = Graphics::kTextAlignLeft;
+ xwidth = maxlen;
} else {
- // center each line
- for (uint i = 0; i < lines.size(); i++)
- font->drawString(dst, lines[i], x, ystart + i * h, _state->_loc.width, fontcol, Graphics::kTextAlignCenter);
+ align = Graphics::kTextAlignCenter;
+ xwidth = _state->_loc.width;
}
- if (_state->_selectedAction) {
- warning("TODO: Draw highlight on selected action.");
+ for (uint i = 0; i < lines.size(); i++) {
+ font->drawString(dst, lines[i], x, ystart + i * h, xwidth, fontcol, align);
+ if (highlightStart < lineOffs[i + 1] && highlightEnd > lineOffs[i]) {
+ // highlight on this line
+ // TODO: What if it's only a partial line??
+ font->drawString(dst, lines[i], x, ystart + i * h, xwidth, _selectonFontCol, align);
+ }
}
+
}
void Dialog::setFlag(DialogFlags flg) {
@@ -524,9 +566,9 @@ struct DialogAction *Dialog::pickAction(bool isClosing) {
assert(_state);
const Common::Point lastMouse = engine->getLastMouse();
if (_state->_loc.x <= lastMouse.x &&
- _state->_loc.x + _state->_loc.width <= lastMouse.x &&
+ _state->_loc.x + _state->_loc.width >= lastMouse.x &&
_state->_loc.y <= lastMouse.y &&
- _state->_loc.y + _state->_loc.height <= lastMouse.y) {
+ _state->_loc.y + _state->_loc.height >= lastMouse.y) {
_state->_lastMouseX = lastMouse.x;
_state->_lastMouseY = lastMouse.y;
draw(nullptr, kDlgDrawFindSelectionTxtOffset);
Commit: c028ebf8ce047d69698fc7c60063f9c7ebf83180
https://github.com/scummvm/scummvm/commit/c028ebf8ce047d69698fc7c60063f9c7ebf83180
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix dragging out of inventory
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/inventory.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 9a81b1c1f63..3a60d60ab5a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -137,7 +137,9 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
}
if (sceneNum != 2 && _scene->getNum() != 2 && _inventory->isOpen()) {
+ // not going to or from inventory, ensure it's closed and clear drag item.
_inventory->close();
+ _scene->setDragItem(nullptr);
}
const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
@@ -158,7 +160,8 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
if (runChangeOps)
_gdsScene->runChangeSceneOps();
- setMouseCursor(0);
+ if (!_scene->getDragItem())
+ setMouseCursor(0);
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 842aaea4e57..0db8bc053f7 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -202,13 +202,14 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
void Inventory::mouseMoved(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const GameItem *dragItem = engine->getScene()->getDragItem();
+ GameItem *dragItem = engine->getScene()->getDragItem();
if (dragItem) {
engine->setMouseCursor(dragItem->_iconNum);
const RequestData &req = _reqData._requests[0];
const Common::Rect bgsize(Common::Point(req._x, req._y), req._width, req._height);
if (!bgsize.contains(pt)) {
// dragged an item outside the inventory
+ dragItem->_inSceneNum = _openedFromSceneNum;
close();
}
} else {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 38cbeb6e604..f76c172f1e4 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -705,7 +705,6 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
void SDSScene::unload() {
_num = 0;
- _dragItem = nullptr;
_enterSceneOps.clear();
_leaveSceneOps.clear();
_preTickOps.clear();
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 5b1363a3d6e..f9c5ef8bdbb 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -301,6 +301,7 @@ public:
const Common::Array<struct HotArea> &getHotAreas() const { return _hotAreaList; }
const GameItem *getDragItem() const { return _dragItem; }
+ GameItem *getDragItem() { return _dragItem; }
void setDragItem(GameItem *item) { _dragItem = item; }
const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 230bbd9648b..782b2e2e24e 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -957,10 +957,10 @@ TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
return nullptr;
}
-TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seq) {
- for (auto & ttm : _adsData->_ttmSeqs) {
- if (ttm._enviro == enviro && ttm._seqNum == seq)
- return &ttm;
+TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seqno) {
+ for (auto &seq : _adsData->_ttmSeqs) {
+ if (seq._enviro == enviro && seq._seqNum == seqno)
+ return &seq;
}
return nullptr;
}
@@ -1241,7 +1241,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
handleRandomOp(code, scr);
break;
- case 0x4000: { // MOVE SEQ TO FRONT
+ case 0x4000: { // MOVE SEQ TO BACK
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
/*uint16 unk = */scr->readUint16LE();
@@ -1258,14 +1258,14 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
}
if (success)
- _adsData->_ttmSeqs.insert_at(0, seq);
+ _adsData->_ttmSeqs.push_back(seq);
else
warning("ADS: 0x4000 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
break;
}
- case 0x4010: { // MOVE SEQ TO BACK
+ case 0x4010: { // MOVE SEQ TO FRONT
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
/*uint16 unk = */scr->readUint16LE();
@@ -1282,7 +1282,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
}
if (success)
- _adsData->_ttmSeqs.push_back(seq);
+ _adsData->_ttmSeqs.insert_at(0, seq);
else
warning("ADS: 0x4010 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
Commit: 0516a3e3ac9b870d940fc3311bdf9bc7d89f702a
https://github.com/scummvm/scummvm/commit/0516a3e3ac9b870d940fc3311bdf9bc7d89f702a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Mostly fix save/load of games
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/metaengine.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 3a60d60ab5a..9fdb1a326b3 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -558,6 +558,7 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
if (!_resource->hasResource(sceneFile))
error("Game references non-existant scene %d", sceneNum);
+ _scene->unload();
_scene->load(sceneFile, _resource, _decompressor);
}
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 7f1d8b30932..226e01bce63 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -47,7 +47,7 @@ GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompres
_resourceMan(resourceMan), _decompressor(decompressor) {
}
-int GamePalettes::loadPalette(Common::String filename) {
+int GamePalettes::loadPalette(const Common::String &filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream) {
// Happens in the Amiga version of Dragon
@@ -72,6 +72,7 @@ int GamePalettes::loadPalette(Common::String filename) {
}
}
}
+ pal.setName(filename);
delete fileStream;
selectPalNum(_palettes.size() - 1);
@@ -133,7 +134,8 @@ Common::Error GamePalettes::syncState(Common::Serializer &s) {
loadPalette(name);
}
if (_curPalNum >= _palettes.size())
- error("Current palette number %d greater than available palettes", _curPalNum);
+ error("Current palette number %d greater than available palettes %d",
+ _curPalNum, _palettes.size());
setPalette();
} else {
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index bb31c386422..92c3f17dec7 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -54,7 +54,7 @@ private:
class GamePalettes {
public:
GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor);
- int loadPalette(Common::String filename);
+ int loadPalette(const Common::String &filename);
void selectPalNum(int num);
void setPalette();
void clearPalette();
diff --git a/engines/dgds/metaengine.cpp b/engines/dgds/metaengine.cpp
index e3b85741547..83a3c4e8711 100644
--- a/engines/dgds/metaengine.cpp
+++ b/engines/dgds/metaengine.cpp
@@ -37,7 +37,8 @@ public:
};
bool DgdsMetaEngine::hasFeature(MetaEngineFeature f) const {
- return (f == kSupportsListSaves) ||
+ return checkExtendedSaves(f) ||
+ (f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
Commit: 1a714adcd8f489ff0d10aed9bd8d4549b8d46899
https://github.com/scummvm/scummvm/commit/1a714adcd8f489ff0d10aed9bd8d4549b8d46899
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix dialog selection
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/scene.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 9fdb1a326b3..724899428d8 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -163,6 +163,8 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
if (!_scene->getDragItem())
setMouseCursor(0);
+ _foregroundBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
_scene->addInvButtonToHotAreaList();
@@ -232,6 +234,11 @@ void DgdsEngine::checkDrawInventoryButton() {
}
Graphics::ManagedSurface &DgdsEngine::getForegroundBuffer() {
+ if (_usedForegroundBuffer) {
+ _foregroundBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _usedForegroundBuffer = false;
+ }
+
return _foregroundBuffer;
}
@@ -332,7 +339,6 @@ Common::Error DgdsEngine::run() {
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
- bool moveToNext = false;
bool triggerMenu = false;
while (!shouldQuit()) {
@@ -341,10 +347,7 @@ Common::Error DgdsEngine::run() {
if (ev.type == Common::EVENT_KEYDOWN) {
switch (ev.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
- if (_menu->menuShown())
- triggerMenu = true;
- else
- moveToNext = true;
+ triggerMenu = true;
break;
case Common::KEYCODE_F5:
triggerMenu = true;
@@ -371,10 +374,13 @@ Common::Error DgdsEngine::run() {
}
if (triggerMenu) {
- if (!_menu->menuShown()) {
+ if (_inventory->isOpen()) {
+ _inventory->close();
+ } else if (!_menu->menuShown()) {
_menu->setScreenBuffer();
CursorMan.showMouse(true);
+ setMouseCursor(0);
_menu->drawMenu();
} else {
_menu->hideMenu();
@@ -402,14 +408,7 @@ Common::Error DgdsEngine::run() {
_scene->drawActiveDialogBgs(&_compositionBuffer);
- if (moveToNext && _inventory->isOpen()) {
- _inventory->close();
- moveToNext = false;
- }
-
- if (moveToNext || !_adsInterp->run()) {
- moveToNext = false;
- }
+ _adsInterp->run();
if (mouseEvent != Common::EVENT_INVALID) {
if (_inventory->isOpen()) {
@@ -487,7 +486,7 @@ Common::Error DgdsEngine::run() {
outf.close();
}*/
- _foregroundBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _usedForegroundBuffer = true;
if (!_inventory->isOpen()) {
_gdsScene->drawItems(_compositionBuffer);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index d4d0b03d0db..e4d1c39b04d 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -104,6 +104,7 @@ private:
bool _justChangedScene1;
bool _justChangedScene2;
+ bool _usedForegroundBuffer;
Common::RandomSource _random;
Common::Point _lastMouse; // originals start mouse at 0,0.
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 9bb090fc62c..75671dcfdff 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -554,10 +554,10 @@ void Dialog::updateSelectedAction(int delta) {
}
}
-struct DialogAction *Dialog::pickAction(bool isClosing) {
+struct DialogAction *Dialog::pickAction(bool isClosing, bool isForceClose) {
struct DialogAction *retval = nullptr;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- if (/* some game flags?? && */isClosing) {
+ if (!isForceClose && isClosing) {
if (_action.empty())
return nullptr;
else
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index d30c0666e2c..c1e0eeb9f0d 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -123,7 +123,7 @@ public:
void flipFlag(DialogFlags flg);
bool hasFlag(DialogFlags flg) const;
void updateSelectedAction(int delta);
- struct DialogAction *pickAction(bool isClosing);
+ struct DialogAction *pickAction(bool isClosing, bool isForceClose);
Common::String dump(const Common::String &indent) const;
void clear();
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index ae083784638..96621a025ff 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -135,24 +135,28 @@ void Menu::drawMenu(int16 menu) {
// Restore background when drawing submenus
g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
- Graphics::Surface *dst = g_system->lockScreen();
-
- Graphics::ManagedSurface managed(dst, DisposeAfterUse::NO);
+ // This is not very efficient, but it only happens once when the menu is opened.
+ Graphics::Surface *screen = g_system->lockScreen();
+ Graphics::ManagedSurface managed(screen->w, screen->h, screen->format);
+ managed.blitFrom(*screen);
_reqData._requests[_curMenu].drawBg(&managed);
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider)
- gadget->draw(dst);
+ gadget->draw(managed.surfacePtr());
}
- drawMenuText(dst);
+ drawMenuText(managed);
+
+ // Can't use transparent blit here as the font is often color 0.
+ screen->copyRectToSurface(*managed.surfacePtr(), 0, 0, Common::Rect(screen->w, screen->h));
g_system->unlockScreen();
g_system->updateScreen();
}
-void Menu::drawMenuText(Graphics::Surface *dst) {
+void Menu::drawMenuText(Graphics::ManagedSurface &dst) {
Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
Common::Array<TextItem> textItems = _reqData._requests[_curMenu]._textItemList;
@@ -170,7 +174,7 @@ void Menu::drawMenuText(Graphics::Surface *dst) {
const Font *font = RequestData::getMenuFont();
int w = font->getStringWidth(textItem._txt);
- font->drawString(dst, textItem._txt, parentX + textItem._x, parentY + textItem._y, w, 0);
+ font->drawString(dst.surfacePtr(), textItem._txt, parentX + textItem._x, parentY + textItem._y, w, 0);
pos++;
}
}
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index e314bb9fbff..f5d21be97db 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -63,7 +63,7 @@ public:
private:
int16 getClickedMenuItem(Common::Point mouseClick);
- void drawMenuText(Graphics::Surface *dst);
+ void drawMenuText(Graphics::ManagedSurface &dst);
void toggleGadget(int16 gadgetId, bool enable);
REQFileData _reqData;
};
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index f76c172f1e4..889ff84f580 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -622,7 +622,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (cflag & kSceneCondNegate)
result = !result;
- debug(10, "Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
+ debug(11, "Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
if (!result) {
// Skip to the next or, or the end.
@@ -817,7 +817,7 @@ bool SDSScene::checkDialogActive() {
if ((!finished && !no_options) || dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40)) {
if (!finished && dlg._action.size() > 1 && !dlg.hasFlag(kDlgFlagHiFinished)) {
- struct DialogAction *action = dlg.pickAction(false);
+ struct DialogAction *action = dlg.pickAction(false, clearDlgFlag);
if (dlg._state->_selectedAction != action) {
dlg._state->_selectedAction = action;
dlg.clearFlag(kDlgFlagHi10);
@@ -827,7 +827,7 @@ bool SDSScene::checkDialogActive() {
} else {
// this dialog is finished - call the ops and maybe show the next one
_dlgWithFlagLo8IsClosing = dlg.hasFlag(kDlgFlagLo8);
- struct DialogAction *action = dlg.pickAction(true);
+ struct DialogAction *action = dlg.pickAction(true, clearDlgFlag);
if (action || dlg._action.empty()) {
dlg.setFlag(kDlgFlagHiFinished);
if (action) {
@@ -920,7 +920,7 @@ bool SDSScene::drawAndUpdateDialogs(Graphics::ManagedSurface *dst) {
dlg._state->_selectedAction = nullptr;
dlg.updateSelectedAction(0);
if (dlg._action.size() > 1 && !dlg._state->_selectedAction) {
- dlg._state->_selectedAction = dlg.pickAction(false);
+ dlg._state->_selectedAction = dlg.pickAction(false, false);
if (dlg._state->_selectedAction)
dlg.draw(dst, kDlgDrawStageForeground);
}
Commit: 48ce6e938ba9623aaae82f9841d1376d8f709347
https://github.com/scummvm/scummvm/commit/48ce6e938ba9623aaae82f9841d1376d8f709347
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix some drag-drop, dialog, and resource loading issues
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/image.cpp
engines/dgds/inventory.cpp
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 090e5a8cc28..f23a7ab6139 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -105,7 +105,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
size = 0;
if ((dot = strrchr(fileName.c_str(), '.'))) {
- ex = MKTAG24(dot[1], dot[2], dot[3]);
+ ex = MKTAG24(toupper(dot[1]), toupper(dot[2]), toupper(dot[3]));
}
DgdsChunkReader chunk(resStream);
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 724899428d8..c77e9ab33b0 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -128,7 +128,7 @@ void DgdsEngine::loadIcons() {
_icons->loadBitmap(iconFileName);
}
-bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
+bool DgdsEngine::changeScene(int sceneNum) {
assert(_scene && _adsInterp);
if (sceneNum == _scene->getNum()) {
@@ -148,8 +148,11 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
return false;
}
- if (runChangeOps)
- _scene->runLeaveSceneOps();
+ // Save the current foreground in case we are going to the inventory or
+ // a scene which doesn't draw its own
+ _backgroundBuffer.blitFrom(_compositionBuffer);
+
+ _scene->runLeaveSceneOps();
// store the last scene num
_gameGlobals->setGlobal(0x61, _scene->getNum());
@@ -157,8 +160,7 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
_scene->unload();
_soundPlayer->unloadMusic();
- if (runChangeOps)
- _gdsScene->runChangeSceneOps();
+ _gdsScene->runChangeSceneOps();
if (!_scene->getDragItem())
setMouseCursor(0);
@@ -175,6 +177,8 @@ bool DgdsEngine::changeScene(int sceneNum, bool runChangeOps) {
if (!_scene->getAdsFile().empty())
_adsInterp->load(_scene->getAdsFile());
+ else
+ _adsInterp->unload();
_scene->runEnterSceneOps();
debug("%s", _scene->dump("").c_str());
@@ -289,7 +293,7 @@ void DgdsEngine::loadGameFiles() {
_gdsScene->runStartGameOps();
// To skip credits for testing
- changeScene(6, true);
+ changeScene(5);
} else if (getGameId() == GID_CHINA) {
_gameGlobals = new Globals();
@@ -378,13 +382,12 @@ Common::Error DgdsEngine::run() {
_inventory->close();
} else if (!_menu->menuShown()) {
_menu->setScreenBuffer();
-
+ // force mouse on
CursorMan.showMouse(true);
setMouseCursor(0);
_menu->drawMenu();
} else {
_menu->hideMenu();
- CursorMan.showMouse(false);
}
triggerMenu = false;
@@ -448,7 +451,7 @@ Common::Error DgdsEngine::run() {
}
}
- // Note: Hard-coded logic for DRAGON, check others
+ // TODO: Hard-coded logic to match Rise of the Dragon, check others
if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
_gdsScene->runPostTickOps();
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index e4d1c39b04d..f77ff09f7e0 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -133,7 +133,7 @@ public:
const FontManager *getFontMan() const { return _fontManager; }
const Common::SharedPtr<Image> &getUICorners() { return _corners; }
const Common::SharedPtr<Image> &getIcons() { return _icons; }
- bool changeScene(int sceneNum, bool runChangeOps);
+ bool changeScene(int sceneNum);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
Inventory *getInventory() { return _inventory; }
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 75671dcfdff..9fc92a9f8f3 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -555,7 +555,6 @@ void Dialog::updateSelectedAction(int delta) {
}
struct DialogAction *Dialog::pickAction(bool isClosing, bool isForceClose) {
- struct DialogAction *retval = nullptr;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (!isForceClose && isClosing) {
if (_action.empty())
@@ -586,7 +585,13 @@ struct DialogAction *Dialog::pickAction(bool isClosing, bool isForceClose) {
}
}
}
- return retval;
+
+ // Note: maybe not in original, but if we are closing and
+ // there is only one action, always do that action.
+ if (isClosing && _action.size() == 1)
+ return &_action[0];
+
+ return nullptr;
}
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 226e01bce63..2ead89af1ed 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -171,7 +171,7 @@ void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface
error("Couldn't get image resource %s", filename.c_str());
if ((dot = strrchr(filename.c_str(), '.'))) {
- ex = MKTAG24(dot[1], dot[2], dot[3]);
+ ex = MKTAG24(toupper(dot[1]), toupper(dot[2]), toupper(dot[3]));
} else {
ex = 0;
}
@@ -231,7 +231,7 @@ void Image::loadBitmap(const Common::String &filename) {
const char *dot;
if ((dot = strrchr(filename.c_str(), '.'))) {
- ex = MKTAG24(dot[1], dot[2], dot[3]);
+ ex = MKTAG24(toupper(dot[1]), toupper(dot[2]), toupper(dot[3]));
} else {
ex = 0;
}
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 0db8bc053f7..e426e7c802c 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -38,20 +38,25 @@ Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nul
}
void Inventory::open() {
- if (_isOpen)
- return;;
+ // Allow double-open becuase that's how the inventory shows item
+ // descriptions.r
_isOpen = true;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- _openedFromSceneNum = engine->getScene()->getNum();
- engine->changeScene(2, false);
+ int curScene = engine->getScene()->getNum();
+ if (curScene != 2) {
+ _openedFromSceneNum = curScene;
+ engine->changeScene(2);
+ } else {
+ engine->getScene()->runEnterSceneOps();
+ }
}
void Inventory::close() {
if (!_isOpen)
- return;;
+ return;
_isOpen = false;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- engine->changeScene(_openedFromSceneNum, false);
+ engine->changeScene(_openedFromSceneNum);
_openedFromSceneNum = -1;
}
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 96621a025ff..d261d9c0368 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -144,7 +144,7 @@ void Menu::drawMenu(int16 menu) {
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider)
- gadget->draw(managed.surfacePtr());
+ gadget->draw(&managed);
}
drawMenuText(managed);
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 2cb8b762547..de0d5cff55e 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -301,7 +301,7 @@ Common::String Gadget::dump() const {
_buttonName.c_str(), _parentX, _parentY);
}
-void Gadget::draw(Graphics::Surface *dst) const {}
+void Gadget::draw(Graphics::ManagedSurface *dst) const {}
bool Gadget::containsPoint(const Common::Point &pt) {
int16 x = _x + _parentX;
@@ -312,7 +312,7 @@ bool Gadget::containsPoint(const Common::Point &pt) {
return gadgetRect.contains(pt);
}
-void ButtonGadget::draw(Graphics::Surface *dst) const {
+void ButtonGadget::draw(Graphics::ManagedSurface *dst) const {
// TODO: Bounds calculation here might depend on parent.
int16 x = _x + _parentX;
@@ -407,7 +407,7 @@ Common::String TextAreaGadget::dump() const {
return Common::String::format("TextArea<%s, %d buflen %d>", base.c_str(), _textGadget_i1, _bufLen);
}
-void TextAreaGadget::draw(Graphics::Surface *dst) const {
+void TextAreaGadget::draw(Graphics::ManagedSurface *dst) const {
const Font *font = RequestData::getMenuFont();
font->drawString(dst, _buttonName, _x + _parentX, _y + _parentY, 0, 0);
}
@@ -440,7 +440,7 @@ static const char *_sliderLabelsForGadget(uint16 num) {
}
}
-void SliderGadget::draw(Graphics::Surface *dst) const {
+void SliderGadget::draw(Graphics::ManagedSurface *dst) const {
const Font *font = RequestData::getMenuFont();
int16 x = _x + _parentX;
@@ -477,7 +477,7 @@ Common::String ImageGadget::dump() const {
return Common::String::format("Image<%s, xStep %d yStep %d>", base.c_str(), _xStep, _yStep);
}
-static void _drawFrame(Graphics::Surface *dst, int16 x, int16 y, int16 w, int16 h, byte col1, byte col2) {
+static void _drawFrame(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 w, int16 h, byte col1, byte col2) {
const int xmax = x + w - 1;
const int ymax = y + h - 1;
bool filled = true;
@@ -498,7 +498,7 @@ static void _drawFrame(Graphics::Surface *dst, int16 x, int16 y, int16 w, int16
}
}
-void ImageGadget::draw(Graphics::Surface *dst) const {
+void ImageGadget::draw(Graphics::ManagedSurface *dst) const {
int xstep = _xStep;
int ystep = _yStep;
@@ -511,6 +511,9 @@ void ImageGadget::draw(Graphics::Surface *dst) const {
dst->fillRect(drawRect, _col1);
// Note: not quite the same as the original logic here, but gets the same result.
_drawFrame(dst, xoff, yoff, _width, _height, _sval1I, _sval1I);
+
+ // NOTE: This only get done in inventory in original?
+ RequestData::drawCorners(dst, 19, xoff - 2, yoff - 2, _width + 4, _height + 4);
}
Common::String RequestData::dump() const {
@@ -569,7 +572,7 @@ void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
for (auto &gadget : _gadgets) {
if (!(gadget->_flags3 & 0x40)) {
- gadget->draw(dst->surfacePtr());
+ gadget->draw(dst);
}
}
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 0bfed2fb31e..023840c6f6d 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -97,7 +97,7 @@ public:
uint16 _parentY;
virtual Common::String dump() const;
- virtual void draw(Graphics::Surface *dst) const;
+ virtual void draw(Graphics::ManagedSurface *dst) const;
virtual void toggle(bool enable) {}
bool containsPoint(const Common::Point &pt);
@@ -106,7 +106,7 @@ public:
// Button gadget has no additional fields, but some behavior differences.
class ButtonGadget : public Gadget {
public:
- void draw(Graphics::Surface *dst) const override;
+ void draw(Graphics::ManagedSurface *dst) const override;
void toggle(bool enable) override;
};
@@ -117,7 +117,7 @@ public:
uint16 _bufLen;
Common::String dump() const override;
- void draw(Graphics::Surface *dst) const override;
+ void draw(Graphics::ManagedSurface *dst) const override;
};
// extended gadget type 2 is 74 (0x4a) bytes
@@ -129,7 +129,7 @@ public:
uint16 _gadget2_i4;
Common::String dump() const override;
- void draw(Graphics::Surface *dst) const override;
+ void draw(Graphics::ManagedSurface *dst) const override;
};
// extended gadget type 8 is 68 (0x44) bytes
@@ -139,7 +139,7 @@ public:
uint16 _yStep;
Common::String dump() const override;
- void draw(Graphics::Surface *dst) const override;
+ void draw(Graphics::ManagedSurface *dst) const override;
};
class RequestData {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 889ff84f580..07f644eefa5 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -97,7 +97,7 @@ Common::String HotArea::dump(const Common::String &indent) const {
indent.c_str(), rect.dump("").c_str(), _num, _cursorNum);
str += _dumpStructList(indent, "enableConditions", enableConditions);
str += _dumpStructList(indent, "onRClickOps", onRClickOps);
- str += _dumpStructList(indent, "opList2", opList2);
+ str += _dumpStructList(indent, "onLDownOps", onLDownOps);
str += _dumpStructList(indent, "onLClickOps", onLClickOps);
str += "\n";
str += indent + ">";
@@ -232,7 +232,7 @@ bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
dst._cursorNum = s->readUint16LE();
readConditionList(s, dst.enableConditions);
readOpList(s, dst.onRClickOps);
- readOpList(s, dst.opList2);
+ readOpList(s, dst.onLDownOps);
readOpList(s, dst.onLClickOps);
return !s->err();
}
@@ -492,7 +492,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
debug(10, "Exec %s", op.dump("").c_str());
switch(op._opCode) {
case kSceneOpChangeScene:
- if (engine->changeScene(op._args[0], true))
+ if (engine->changeScene(op._args[0]))
// This probably reset the list - stop now.
return false;
break;
@@ -522,7 +522,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
break;
case kSceneOpChangeSceneToStored: {
uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
- if (engine->changeScene(sceneNo, true))
+ if (engine->changeScene(sceneNo))
// This probably reset the list - stop now.
return false;
break;
@@ -582,8 +582,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
int16 refval = c._val;
int16 checkval = -1;
SceneCondition cflag = c._flags;
- // Two "or"s in a row, or an "or" at the start means true
- // (as one side is empty)
+ // Hit an "or" here means the last result was true.
if (cflag & kSceneCondOr)
return true;
@@ -600,7 +599,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (item._num == c._num) {
if (cflag & kSceneCondNeedItemSceneNum)
checkval = item._inSceneNum;
- else // cflag & kSceneCondNeedItemField14
+ else // cflag & kSceneCondNeedItemQuality
checkval = item._quality;
break;
}
@@ -625,7 +624,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
debug(11, "Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
if (!result) {
- // Skip to the next or, or the end.
+ // Skip just past the next or, or to the end.
while (cnum < conds.size() && !(conds[cnum]._flags & kSceneCondOr))
cnum++;
if (cnum >= conds.size())
@@ -806,8 +805,7 @@ bool SDSScene::checkDialogActive() {
// FIXME: double-check this logic.
// Mark finished if we are manually clearing *or* the timer has expired.
bool finished = false;
- if (dlg._state->_hideTime &&
- ((dlg._state->_hideTime > timeNow && clearDlgFlag) || timeNow >= dlg._state->_hideTime)) {
+ if (clearDlgFlag || (dlg._state->_hideTime && timeNow >= dlg._state->_hideTime)) {
finished = true;
}
@@ -831,6 +829,7 @@ bool SDSScene::checkDialogActive() {
if (action || dlg._action.empty()) {
dlg.setFlag(kDlgFlagHiFinished);
if (action) {
+ debug("Dialog closing: run action %d op list (%d ops)", action->val, action->sceneOpList.size());
if (!runOps(action->sceneOpList)) {
_dlgWithFlagLo8IsClosing = false;
return true;
@@ -966,11 +965,6 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
cursorNum = _dragItem->_iconNum;
engine->setMouseCursor(cursorNum);
-
- if (area && area->_num == 0) {
- // Object dragged over the inventory button
- // static_cast<DgdsEngine *>(g_engine)->getInventory()-> ...
- }
}
void SDSScene::mouseLDown(const Common::Point &pt) {
@@ -985,8 +979,11 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
if (!area)
return;
+ debug(9, "Mouse LDown on area %d (%d,%d,%d,%d) cursor %d", area->_num, area->rect.x, area->rect.y,
+ area->rect.width, area->rect.height, area->_cursorNum);
+
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- runOps(area->opList2);
+ runOps(area->onLDownOps);
GameItem *item = dynamic_cast<GameItem *>(area);
if (item) {
_dragItem = item;
@@ -1001,50 +998,85 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
return;
}
+ if (_dragItem) {
+ onDragFinish(pt);
+ return;
+ }
+
const HotArea *area = findAreaUnderMouse(pt);
+ if (!area)
+ return;
+
+ debug(9, "Mouse LUp on area %d (%d,%d,%d,%d) cursor %d", area->_num, area->rect.x, area->rect.y,
+ area->rect.width, area->rect.height, area->_cursorNum);
+
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->setMouseCursor(area->_cursorNum);
+
+ if (area && area->_num == 0) {
+ debug("Mouseup on inventory.");
+ static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
+ } else {
+ debug(" --> exec %d click ops for area %d", area->onLClickOps.size(), area->_num);
+ runOps(area->onLClickOps);
+ }
+}
+
+static bool _isInRect(const Common::Point &pt, const DgdsRect rect) {
+ return rect.x <= pt.x && (rect.x + rect.width) > pt.x
+ && rect.y <= pt.y && (rect.y + rect.height) > pt.y;
+}
+
+void SDSScene::onDragFinish(const Common::Point &pt) {
+ assert(_dragItem);
+
+ // Unlike a click operation, this runs the drop event for *all* areas
+ // and items, ignoring enable condition.
GameItem *dragItem = _dragItem;
_dragItem = nullptr;
- if (dragItem && !area)
- engine->setMouseCursor(0);
+ runOps(dragItem->opList4);
- if (!area)
- return;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ engine->setMouseCursor(0);
- engine->setMouseCursor(area->_cursorNum);
+ // TODO: Both these loops are very similar.. there should be a cleaner way.
- if (area->_num == 0) {
- // dropped on the inventory button
- if (dragItem) {
+ for (const auto &item : engine->getGDSScene()->getGameItems()) {
+ if (item._inSceneNum == _num && _isInRect(pt, item.rect)) {
+ debug("Dragged item %d onto item %d", dragItem->_num, item._num);
+ for (const auto &i : engine->getGDSScene()->getObjInteractions2()) {
+ if (i._droppedItemNum == dragItem->_num && i._targetItemNum == item._num) {
+ debug(" --> exec item %d drag ops", i.opList.size());
+ runOps(i.opList);
+ break;
+ }
+ }
+ }
+ }
+
+ for (const auto &area : _hotAreaList) {
+ if (!_isInRect(pt, area.rect))
+ continue;
+
+ if (area._num == 0) {
debug("Item %d dropped on inventory.", dragItem->_num);
dragItem->_inSceneNum = 2;
- engine->setMouseCursor(0);
} else {
- debug("Mouseup on inventory.");
- static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
- }
- } else {
- if (dragItem) {
- const GameItem *targetItem = dynamic_cast<const GameItem *>(area);
- // Dropping one item on another -> use interactions from GDS
- // Dropping item on an area -> interactions are in SDS
- const Common::Array<struct ObjectInteraction> &interactions =
- targetItem ? engine->getGDSScene()->getObjInteractions2()
- : engine->getScene()->getObjInteractions1();
- for (const auto &i : interactions) {
- if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area->_num) {
+ debug("Dragged item %d onto area %d", dragItem->_num, area._num);
+ for (const auto &i : engine->getScene()->getObjInteractions1()) {
+ if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area._num) {
+ debug(" --> exec area %d drag ops", i.opList.size());
runOps(i.opList);
break;
}
}
- } else {
- runOps(area->onLClickOps);
}
}
}
+
void SDSScene::mouseRUp(const Common::Point &pt) {
Dialog *dlg = getVisibleDialog();
if (dlg) {
@@ -1077,17 +1109,14 @@ HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (auto &item : engine->getGDSScene()->getGameItems()) {
- if (item._inSceneNum == _num && checkConditions(item.enableConditions) &&
- item.rect.x < pt.x && (item.rect.x + item.rect.width) > pt.x
- && item.rect.y < pt.y && (item.rect.y + item.rect.height) > pt.y) {
+ if (item._inSceneNum == _num && checkConditions(item.enableConditions)
+ && _isInRect(pt, item.rect)) {
return &item;
}
}
for (auto &area : _hotAreaList) {
- if (checkConditions(area.enableConditions) &&
- area.rect.x < pt.x && (area.rect.x + area.rect.width) > pt.x
- && area.rect.y < pt.y && (area.rect.y + area.rect.height) > pt.y) {
+ if (checkConditions(area.enableConditions) && _isInRect(pt, area.rect)) {
return &area;
}
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index f9c5ef8bdbb..865c392b424 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -62,7 +62,7 @@ struct HotArea {
uint16 _cursorNum;
Common::Array<struct SceneConditions> enableConditions;
Common::Array<struct SceneOp> onRClickOps;
- Common::Array<struct SceneOp> opList2;
+ Common::Array<struct SceneOp> onLDownOps;
Common::Array<struct SceneOp> onLClickOps;
virtual ~HotArea() {}
@@ -233,8 +233,6 @@ public:
const Common::String &getIconFile() const { return _iconFile; }
bool readPerSceneGlobals(Common::SeekableReadStream *s);
- uint16 getGlobal(uint num);
-
Common::String dump(const Common::String &indent) const;
void runStartGameOps() { runOps(_startGameOps); }
@@ -315,6 +313,7 @@ private:
void enableTrigger(uint16 num) override;
void showDialog(uint16 num) override;
Dialog *getVisibleDialog();
+ void onDragFinish(const Common::Point &pt);
int _num;
Common::Array<struct SceneOp> _enterSceneOps;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 782b2e2e24e..4160919d94b 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -765,7 +765,8 @@ ADSInterpreter::~ADSInterpreter() {
}
bool ADSInterpreter::load(const Common::String &filename) {
- unload();
+ // Don't clear current _adsData, we reset that below.
+ _currentTTMSeq = nullptr;
// For high detail, replace extension ADS with ADH. Low detail is ADL.
Common::String detailfile = filename.substr(0, filename.size() - 1);
@@ -778,10 +779,11 @@ bool ADSInterpreter::load(const Common::String &filename) {
detailfile = filename;
debug("ADSInterpreter: load %s", detailfile.c_str());
+ /* FIXME: quick hack - never reuse data.
if (_adsTexts.contains(detailfile)) {
_adsData = &(_adsTexts.getVal(detailfile));
return true;
- }
+ }*/
_adsTexts.setVal(detailfile, ADSData());
_adsData = &(_adsTexts.getVal(detailfile));
Commit: 9c06c52e4f7d79a867ac21532a6cd9551195e457
https://github.com/scummvm/scummvm/commit/9c06c52e4f7d79a867ac21532a6cd9551195e457
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Load/save background image name
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index c77e9ab33b0..603027f5117 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -148,9 +148,11 @@ bool DgdsEngine::changeScene(int sceneNum) {
return false;
}
- // Save the current foreground in case we are going to the inventory or
- // a scene which doesn't draw its own
- _backgroundBuffer.blitFrom(_compositionBuffer);
+ // Save the current foreground if we are going to the inventory, clear it otherwise.
+ if (sceneNum == 2)
+ _backgroundBuffer.blitFrom(_compositionBuffer);
+ else
+ _backgroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_scene->runLeaveSceneOps();
@@ -165,7 +167,7 @@ bool DgdsEngine::changeScene(int sceneNum) {
if (!_scene->getDragItem())
setMouseCursor(0);
- _foregroundBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
@@ -239,7 +241,7 @@ void DgdsEngine::checkDrawInventoryButton() {
Graphics::ManagedSurface &DgdsEngine::getForegroundBuffer() {
if (_usedForegroundBuffer) {
- _foregroundBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_usedForegroundBuffer = false;
}
@@ -561,6 +563,7 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
error("Game references non-existant scene %d", sceneNum);
_scene->unload();
+ _adsInterp->unload();
_scene->load(sceneFile, _resource, _decompressor);
}
@@ -586,6 +589,16 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
s.syncAsByte(_justChangedScene1);
s.syncAsByte(_justChangedScene2);
+ // sync engine play time to ensure various events run correctly.
+ uint32 playtime = g_engine->getTotalPlayTime();
+ s.syncAsUint32LE(playtime);
+ g_engine->setTotalPlayTime(playtime);
+
+ s.syncString(_backgroundFile);
+ if (s.isLoading()) {
+ Image(_resource, _decompressor).drawScreen(_backgroundFile, _backgroundBuffer);
+ }
+
return Common::kNoError;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index f77ff09f7e0..fb17e1e06e9 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -83,6 +83,7 @@ private:
DgdsGameId _gameId;
Graphics::ManagedSurface _backgroundBuffer;
+ Common::String _backgroundFile; // Record the background file name for save games.
Graphics::ManagedSurface _storedAreaBuffer;
Graphics::ManagedSurface _foregroundBuffer;
SDSScene *_scene;
@@ -169,6 +170,8 @@ public:
(f == kSupportsSavingDuringRuntime);
};
+ void setBackgroundFile(const Common::String &name) { _backgroundFile = name; }
+
private:
Common::Error syncGame(Common::Serializer &s);
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 2ead89af1ed..cfb6084498e 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -184,7 +184,7 @@ void Image::drawScreen(const Common::String &filename, Graphics::ManagedSurface
_filename = filename;
- surface.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ surface.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
DgdsChunkReader chunk(fileStream);
while (chunk.readNextHeader(ex, filename)) {
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 4160919d94b..966c35aa9df 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -259,8 +259,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0020: // SAVE (free?) BACKGROUND
if (seq._executed) // this is a one-shot op
break;
- _vm->getStoredAreaBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- //_vm->getBackgroundBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ //_vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x0070: // FREE PALETTE
if (seq._executed) // this is a one-shot op
@@ -282,7 +282,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op
break;
env._getPutSurfaces[seq._currentGetPutId].reset();
- env._getPutAreas[seq._currentGetPutId] = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ env._getPutAreas[seq._currentGetPutId] = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
break;
case 0x0110: // PURGE void
_vm->adsInterpreter()->setHitTTMOp0110();
@@ -377,7 +377,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
g_system->delayMillis(5);
}
}
- _vm->getBackgroundBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
@@ -527,7 +527,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
tmp.drawScreen(sval, _vm->getBackgroundBuffer());
- _vm->getStoredAreaBuffer().fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->setBackgroundFile(sval);
break;
}
case 0xf020: // LOAD BMP: filename:str
@@ -670,6 +671,8 @@ int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 targetFr
int64 startpos = env.scr->pos();
int32 retval = -1;
for (int32 i = 0; i < (int)env._frameOffsets.size(); i++) {
+ if (env._frameOffsets[i] < 0)
+ continue;
env.scr->seek(env._frameOffsets[i]);
uint16 op = env.scr->readUint16LE();
if (op == 0x1101 || op == 0x1111) {
@@ -750,7 +753,7 @@ void TTMSeq::reset() {
_runFlag = kRunTypeStopped;
_scriptFlag = 0;
_selfLoop = false;
- _drawWin = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ _drawWin = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
}
ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _currentTTMSeq(nullptr), _adsData(nullptr) {
@@ -903,6 +906,7 @@ void ADSInterpreter::findUsedSequencesForSegment(int segno) {
void ADSInterpreter::unload() {
_adsData = nullptr;
_currentTTMSeq = nullptr;
+ _adsTexts.clear();
}
bool ADSInterpreter::playScene() {
Commit: b6406e76111d0688c507c6a2e13193913807b042
https://github.com/scummvm/scummvm/commit/b6406e76111d0688c507c6a2e13193913807b042
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Clear stored and foreground buffer on load
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 603027f5117..682ae30316f 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -597,6 +597,8 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
s.syncString(_backgroundFile);
if (s.isLoading()) {
Image(_resource, _decompressor).drawScreen(_backgroundFile, _backgroundBuffer);
+ _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _storedAreaBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
}
return Common::kNoError;
Commit: c263922adf40b279e03baac5cbda991372ff4d47
https://github.com/scummvm/scummvm/commit/c263922adf40b279e03baac5cbda991372ff4d47
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Load active script on save/load
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 966c35aa9df..6a293d3b978 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -1564,10 +1564,13 @@ int ADSInterpreter::numArgs(uint16 opcode) const {
}
Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
+ //TODO: Currently sync all states then set the active one,
+ // do we need to load/save all?
uint32 numTexts = _adsTexts.size();
s.syncAsUint32LE(numTexts);
Common::Array<Common::String> scriptNames;
+ Common::String activeScript;
if (s.isLoading()) {
for (uint32 i = 0; i < numTexts; i++) {
@@ -1581,6 +1584,8 @@ Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
Common::String txtName = node._key;
s.syncString(txtName);
scriptNames.push_back(txtName);
+ if (&node._value == _adsData)
+ activeScript = txtName;
}
}
@@ -1589,6 +1594,10 @@ Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
_adsTexts[name].syncState(s);
}
+ s.syncString(activeScript);
+ assert(_adsTexts.contains(activeScript));
+ _adsData = &_adsTexts[activeScript];
+
return Common::kNoError;
}
Commit: fcf43ac0f7561616b42243029aa58b3ea221be30
https://github.com/scummvm/scummvm/commit/fcf43ac0f7561616b42243029aa58b3ea221be30
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Stop processing drag ops if scene changed
Changed paths:
engines/dgds/scene.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 07f644eefa5..c99a0d91046 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -1049,7 +1049,8 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
for (const auto &i : engine->getGDSScene()->getObjInteractions2()) {
if (i._droppedItemNum == dragItem->_num && i._targetItemNum == item._num) {
debug(" --> exec item %d drag ops", i.opList.size());
- runOps(i.opList);
+ if (!runOps(i.opList))
+ return;
break;
}
}
@@ -1068,7 +1069,8 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
for (const auto &i : engine->getScene()->getObjInteractions1()) {
if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area._num) {
debug(" --> exec area %d drag ops", i.opList.size());
- runOps(i.opList);
+ if (!runOps(i.opList))
+ return;
break;
}
}
Commit: faa70e545fb819e27df6a3fce08ee10c33ddd9be
https://github.com/scummvm/scummvm/commit/faa70e545fb819e27df6a3fce08ee10c33ddd9be
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Load game from launcher if set
Changed paths:
engines/dgds/dgds.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 682ae30316f..018ce48f51f 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -342,6 +342,11 @@ Common::Error DgdsEngine::run() {
init();
loadGameFiles();
+ // If a savegame was selected from the launcher, load it now.
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot != -1)
+ loadGameState(saveSlot);
+
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
Commit: c79b6d898278ebe6fb5b523e98e2341b17820514
https://github.com/scummvm/scummvm/commit/c79b6d898278ebe6fb5b523e98e2341b17820514
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix dragging in inventory a bit
Changed paths:
engines/dgds/inventory.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index e426e7c802c..3b1ab841f8c 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -46,9 +46,8 @@ void Inventory::open() {
if (curScene != 2) {
_openedFromSceneNum = curScene;
engine->changeScene(2);
- } else {
- engine->getScene()->runEnterSceneOps();
}
+ engine->getScene()->runEnterSceneOps();
}
void Inventory::close() {
@@ -224,56 +223,61 @@ void Inventory::mouseMoved(const Common::Point &pt) {
GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- if (!_itemArea || !_itemArea->containsPoint(pt))
+ if (!_itemArea)
return nullptr;
- const int imgAreaX = _itemArea->_parentX + _itemArea->_x;
- const int imgAreaY = _itemArea->_parentY + _itemArea->_y;
- const int numacross = _itemArea->_width / _itemArea->_xStep;
- const int itemrow = (pt.y - imgAreaY) / _itemArea->_yStep;
- const int itemcol = (pt.x - imgAreaX) / _itemArea->_xStep;
- int itemnum = numacross * itemrow + itemcol;
-
Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
- for (auto &item: items) {
- if (item._inSceneNum != 2) // || !(item._flags & 4))
- continue;
+ if (_itemArea->containsPoint(pt)) {
+ const int imgAreaX = _itemArea->_parentX + _itemArea->_x;
+ const int imgAreaY = _itemArea->_parentY + _itemArea->_y;
+ const int numacross = _itemArea->_width / _itemArea->_xStep;
+ const int itemrow = (pt.y - imgAreaY) / _itemArea->_yStep;
+ const int itemcol = (pt.x - imgAreaX) / _itemArea->_xStep;
+ int itemnum = numacross * itemrow + itemcol;
- if (itemnum) {
- itemnum--;
- continue;
+ for (auto &item: items) {
+ if (item._inSceneNum != 2) // || !(item._flags & 4))
+ continue;
+
+ if (itemnum) {
+ itemnum--;
+ continue;
+ }
+ return &item;
}
- return &item;
}
return nullptr;
}
void Inventory::mouseLDown(const Common::Point &pt) {
- GameItem *underMouse = itemUnderMouse(pt);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- if (underMouse) {
- _highlightItemNo = underMouse->_num;
- engine->getScene()->setDragItem(underMouse);
- if (underMouse->_iconNum)
- engine->setMouseCursor(underMouse->_iconNum);
+ if (_itemBox->containsPoint(pt)) {
+ GameItem *underMouse = itemUnderMouse(pt);
+ if (underMouse) {
+ _highlightItemNo = underMouse->_num;
+ engine->getScene()->runOps(underMouse->onLDownOps);
+ engine->getScene()->setDragItem(underMouse);
+ if (underMouse->_iconNum)
+ engine->setMouseCursor(underMouse->_iconNum);
+ }
+ } else {
+ return engine->getScene()->mouseLDown(pt);
}
}
void Inventory::mouseLUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const GameItem *dragItem = engine->getScene()->getDragItem();
+ GameItem *dragItem = engine->getScene()->getDragItem();
engine->setMouseCursor(0);
if (dragItem) {
- engine->getScene()->mouseLUp(pt);
- // this will clear the drag item.
+ engine->getScene()->onDragFinish(pt);
return;
}
int itemsPerPage = (_itemArea->_width / _itemArea->_xStep) * (_itemArea->_height / _itemArea->_yStep);
if (_exitButton->containsPoint(pt)) {
close();
- return;
} else if (_nextPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
int numInvItems = 0;
Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
@@ -306,9 +310,13 @@ void Inventory::mouseLUp(const Common::Point &pt) {
void Inventory::mouseRUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- GameItem *underMouse = itemUnderMouse(pt);
- if (underMouse) {
- engine->getScene()->runOps(underMouse->onRClickOps);
+ if (_itemBox->containsPoint(pt)) {
+ GameItem *underMouse = itemUnderMouse(pt);
+ if (underMouse) {
+ engine->getScene()->runOps(underMouse->onRClickOps);
+ }
+ } else {
+ engine->getScene()->mouseRUp(pt);
}
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index c99a0d91046..88f45f543e5 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -161,7 +161,7 @@ Common::String GameItem::dump(const Common::String &indent) const {
"%sGameItem<\n%s\n%saltCursor %d icon %d sceneNum %d flags %d quality %d",
indent.c_str(), super.c_str(), indent.c_str(), _altCursor,
_iconNum, _inSceneNum, _flags, _quality);
- str += _dumpStructList(indent, "opList4", opList4);
+ str += _dumpStructList(indent, "onDragFinishedOps", onDragFinishedOps);
str += _dumpStructList(indent, "opList5", opList5);
str += "\n";
str += indent + ">";
@@ -260,7 +260,7 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
dst._flags = s->readUint16LE() & 0xfffe;
if (!isVersionUnder(" 1.204")) {
dst._altCursor = s->readUint16LE();
- readOpList(s, dst.opList4);
+ readOpList(s, dst.onDragFinishedOps);
readOpList(s, dst.opList5);
}
}
@@ -1036,7 +1036,7 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
GameItem *dragItem = _dragItem;
_dragItem = nullptr;
- runOps(dragItem->opList4);
+ runOps(dragItem->onDragFinishedOps);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
engine->setMouseCursor(0);
@@ -1411,4 +1411,3 @@ Common::Error GDSScene::syncState(Common::Serializer &s) {
}
} // End of namespace Dgds
-
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 865c392b424..0da4923baef 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -113,7 +113,7 @@ struct SceneOp {
};
struct GameItem : public HotArea {
- Common::Array<struct SceneOp> opList4;
+ Common::Array<struct SceneOp> onDragFinishedOps;
Common::Array<struct SceneOp> opList5;
uint16 _altCursor;
uint16 _iconNum;
@@ -306,14 +306,18 @@ public:
const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
bool hasVisibleDialog();
+
Common::Error syncState(Common::Serializer &s) override;
-private:
+ void onDragFinish(const Common::Point &pt);
+
+protected:
HotArea *findAreaUnderMouse(const Common::Point &pt);
+
+private:
void enableTrigger(uint16 num) override;
void showDialog(uint16 num) override;
Dialog *getVisibleDialog();
- void onDragFinish(const Common::Point &pt);
int _num;
Common::Array<struct SceneOp> _enterSceneOps;
Commit: ccdfdb683d934123e6e6d2cd817be53b84130d99
https://github.com/scummvm/scummvm/commit/ccdfdb683d934123e6e6d2cd817be53b84130d99
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement opening menu from script
Changed paths:
engines/dgds/clock.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/scene.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index 45f9530e77d..7cefa10135f 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -44,7 +44,7 @@ private:
Clock &_clock;
};
-Clock::Clock() : _visibleUser(true), _visibleScript(true), _days(0), _days2(0),
+Clock::Clock() : _visibleUser(true), _visibleScript(false), _days(0), _days2(0),
_hours(0), _mins(0), _gameMinsAdded(0), _gameTicksUp(0), _gameTicksDown(0),
_lastPlayTime(0), _millis(0)
{
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 018ce48f51f..84561d2e10a 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -72,7 +72,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds"), _currentCursor(-1) {
+ _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -172,7 +172,6 @@ bool DgdsEngine::changeScene(int sceneNum) {
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
_scene->addInvButtonToHotAreaList();
- setShowClock(true);
if (_scene->getMagic() != _gdsScene->getMagic())
error("Scene %s magic does (0x%08x) not match GDS magic (0x%08x)", sceneFile.c_str(), _scene->getMagic(), _gdsScene->getMagic());
@@ -291,12 +290,6 @@ void DgdsEngine::loadGameFiles() {
loadCorners("DCORNERS.BMP");
reqParser.parse(&invRequestData, "DINV.REQ");
reqParser.parse(&vcrRequestData, "DVCR.REQ");
-
- _gdsScene->runStartGameOps();
-
- // To skip credits for testing
- changeScene(5);
-
} else if (getGameId() == GID_CHINA) {
_gameGlobals = new Globals();
_gamePals->loadPalette("HOC.PAL");
@@ -304,28 +297,24 @@ void DgdsEngine::loadGameFiles() {
//debug("%s", _gdsScene->dump("").c_str());
+ loadCorners("HCORNERS.BMP");
reqParser.parse(&invRequestData, "HINV.REQ");
reqParser.parse(&vcrRequestData, "HVCR.REQ");
-
- //_scene->load("S101.SDS", _resource, _decompressor);
- //_adsInterp->load("TITLE.ADS");
- _gdsScene->runStartGameOps();
-
- loadCorners("HCORNERS.BMP");
} else if (getGameId() == GID_BEAMISH) {
_gameGlobals = new Globals();
_gamePals->loadPalette("WILLY.PAL");
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
+ loadCorners("WCORNERS.BMP");
reqParser.parse(&invRequestData, "WINV.REQ");
reqParser.parse(&vcrRequestData, "WVCR.REQ");
//_scene->load("S34.SDS", _resource, _decompressor);
_adsInterp->load("TITLE.ADS");
- loadCorners("WCORNERS.BMP");
}
+ _gdsScene->runStartGameOps();
loadIcons();
setMouseCursor(0);
@@ -350,18 +339,16 @@ Common::Error DgdsEngine::run() {
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
- bool triggerMenu = false;
-
while (!shouldQuit()) {
Common::EventType mouseEvent = Common::EVENT_INVALID;
while (eventMan->pollEvent(ev)) {
if (ev.type == Common::EVENT_KEYDOWN) {
switch (ev.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
- triggerMenu = true;
+ _menuToTrigger = kMenuMain;
break;
case Common::KEYCODE_F5:
- triggerMenu = true;
+ _menuToTrigger = kMenuMain;
break;
case Common::KEYCODE_s:
if (ev.kbd.hasFlags(Common::KBD_CTRL))
@@ -384,20 +371,20 @@ Common::Error DgdsEngine::run() {
}
}
- if (triggerMenu) {
+ if (_menuToTrigger != kMenuNone) {
if (_inventory->isOpen()) {
_inventory->close();
- } else if (!_menu->menuShown()) {
+ } else if (!_menu->menuShown()) {
_menu->setScreenBuffer();
// force mouse on
CursorMan.showMouse(true);
setMouseCursor(0);
- _menu->drawMenu();
+ _menu->drawMenu(_menuToTrigger);
} else {
_menu->hideMenu();
}
- triggerMenu = false;
+ _menuToTrigger = kMenuNone;
}
if (_menu->menuShown()) {
@@ -609,5 +596,4 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
return Common::kNoError;
}
-
} // End of namespace Dgds
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index fb17e1e06e9..f0aeaa17d4b 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -39,6 +39,7 @@
#include "dgds/resource.h"
#include "dgds/clock.h"
+#include "dgds/menu.h"
namespace Dgds {
@@ -113,6 +114,8 @@ private:
Clock _clock;
+ MenuId _menuToTrigger;
+
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
virtual ~DgdsEngine();
@@ -171,6 +174,7 @@ public:
};
void setBackgroundFile(const Common::String &name) { _backgroundFile = name; }
+ void setMenuToTrigger(MenuId menu) { _menuToTrigger = menu; }
private:
Common::Error syncGame(Common::Serializer &s);
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index d261d9c0368..194f61f53ea 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -36,30 +36,6 @@
namespace Dgds {
-enum MenuIds {
- kMenuNone = -1,
- kMenuMain = 0,
- kMenuControls = 1,
- kMenuOptions = 2,
- kMenuCalibrate = 3,
- kMenuRestart = 4,
- // 5: you cannot save your game right now
- // 6: game over
- kMenuFiles = 7,
- // 8: save game not saved because disk is full
- // 9: all game entries are full
- kMenuSave = 10,
- // 11: change directory - create directory
- // 12: change directory - invalid directory specified
- kMenuChangeDirectory = 13,
- kMenuJoystick = 14,
- kMenuMouse = 15,
- kMenuQuit = 16
- // 17: I'm frustrated - keep trying / win arcade
- // 18: skip introduction / play introduction
- // 19: save game before arcade
- // 20: replay arcade
-};
enum MenuButtonIds {
kMenuMainPlay = 120,
@@ -109,11 +85,14 @@ enum MenuButtonIds {
kMenuQuitYes = 134,
kMenuQuitNo = 133,
+ kMenuIntroSkip = 143,
+ kMenuIntroPlay = 144,
+
kMenuRestartYes = 163,
kMenuRestartNo = 164
};
-Menu::Menu() {
+Menu::Menu() : _curMenu(kMenuNone) {
_screenBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
}
@@ -127,7 +106,7 @@ void Menu::setScreenBuffer() {
g_system->unlockScreen();
}
-void Menu::drawMenu(int16 menu) {
+void Menu::drawMenu(MenuId menu) {
_curMenu = menu;
Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
@@ -180,7 +159,7 @@ void Menu::drawMenuText(Graphics::ManagedSurface &dst) {
}
int16 Menu::getClickedMenuItem(Common::Point mouseClick) {
- if (_curMenu < 0)
+ if (_curMenu == kMenuNone)
return -1;
Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
@@ -237,9 +216,15 @@ void Menu::handleMenu(Common::Point &mouse) {
case kMenuMainQuit:
drawMenu(kMenuQuit);
break;
+ case kMenuCalibrateVCR: // NOTE: same as kMenuIntroPlay
+ if (_curMenu == kMenuSkipPlayIntro) {
+ hideMenu();
+ } else {
+ drawMenu(kMenuMain);
+ }
+ break;
case kMenuControlsVCR:
case kMenuOptionsVCR:
- case kMenuCalibrateVCR:
case kMenuCalibrateVCRHoC:
case kMenuFilesVCR:
case kMenuQuitNo:
@@ -283,6 +268,10 @@ void Menu::handleMenu(Common::Point &mouse) {
// TODO
debug("Clicked change directory - %d", clickedMenuItem);
break;
+ case kMenuIntroSkip:
+ hideMenu();
+ static_cast<DgdsEngine *>(g_engine)->changeScene(5);
+ break;
case kMenuQuitYes:
g_engine->quitGame();
break;
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index f5d21be97db..19fc173fe8b 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -42,20 +42,45 @@ namespace Dgds {
class REQFileData;
+enum MenuId {
+ kMenuNone = -1,
+ kMenuMain = 0,
+ kMenuControls = 1,
+ kMenuOptions = 2,
+ kMenuCalibrate = 3,
+ kMenuRestart = 4,
+ // 5: you cannot save your game right now
+ // 6: game over
+ kMenuFiles = 7,
+ // 8: save game not saved because disk is full
+ // 9: all game entries are full
+ kMenuSave = 10,
+ // 11: change directory - create directory
+ // 12: change directory - invalid directory specified
+ kMenuChangeDirectory = 13,
+ kMenuJoystick = 14,
+ kMenuMouse = 15,
+ kMenuQuit = 16,
+ // 17: I'm frustrated - keep trying / win arcade
+ kMenuSkipPlayIntro = 18,
+ // 19: save game before arcade
+ // 20: replay arcade
+};
+
class Menu {
private:
Graphics::Surface _screenBuffer;
- int16 _curMenu = -1;
+ MenuId _curMenu = kMenuMain;
public:
Menu();
virtual ~Menu();
void setScreenBuffer();
- void drawMenu(int16 menu = 0);
+ void drawMenu(MenuId menu = kMenuMain);
void handleMenu(Common::Point &mouse);
- bool menuShown() const { return _curMenu >= 0; }
- void hideMenu() { _curMenu = -1; }
+ bool menuShown() const { return _curMenu != kMenuNone; }
+ void hideMenu() { _curMenu = kMenuNone; }
void setRequestData(const REQFileData &data) {
_reqData = data;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 88f45f543e5..acccb857ff2 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -37,6 +37,7 @@
#include "dgds/request.h"
#include "dgds/scene.h"
#include "dgds/scripts.h"
+#include "dgds/menu.h"
#include "dgds/font.h"
#include "dgds/globals.h"
#include "dgds/image.h"
@@ -563,7 +564,7 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops) {
static_cast<DgdsEngine *>(g_engine)->getScene()->removeInvButtonFromHotAreaList();
break;
case kSceneOpOpenPlaySkipIntroMenu:
- warning("TODO: Implement scene op 107 (inject key code 0xfc, open menu to play intro or not)");
+ static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuSkipPlayIntro);
break;
default:
warning("TODO: Implement scene op %d", op._opCode);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 6a293d3b978..bba454a553f 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -378,6 +378,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
}
_vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ // reset to previous palette.
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], 0);
break;
case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
Commit: 2b9f38ede1413b7c3af0f63d857ec5185d2e1abc
https://github.com/scummvm/scummvm/commit/2b9f38ede1413b7c3af0f63d857ec5185d2e1abc
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix script timing values to match original
Changed paths:
engines/dgds/scripts.cpp
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index bba454a553f..133459ab8ce 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -295,10 +295,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0ff0: // REFRESH: void
break;
case 0x1020: // SET DELAY: i:int [0..n]
- // Delay of 240 should be 2 seconds, so this is in quarter-frames.
// TODO: Probably should do this accounting (as well as timeCut and dialogs)
// in game frames, not millis.
- _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * 8.33));
+ _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * 16.667));
break;
case 0x1030: // SET BRUSH: id:int [-1:n]
seq._brushNum = ivals[0];
@@ -352,7 +351,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
// TODO: do same time fix as for 0x1020
- _vm->adsInterpreter()->setScriptDelay((int)(sleep * 8.33));
+ _vm->adsInterpreter()->setScriptDelay((int)(sleep * 16.667));
break;
}
case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
Commit: 46b90500b5cf604b6a1a0e8a91284f93b28d76b5
https://github.com/scummvm/scummvm/commit/46b90500b5cf604b6a1a0e8a91284f93b28d76b5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add minutes on various events
Changed paths:
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index ab44cd00c1d..785443eeba1 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -115,8 +115,8 @@ private:
DragonGlobals::DragonGlobals(Clock &_clock) : Globals(),
_lastOpcode1SceneChageNum(0), _sceneOp12SceneNum(0), _currentSelectedItem(0),
-_gameMinsToAdd_1(0), _gameMinsToAdd_2(0), _gameMinsToAdd_3(0), _gameMinsToAdd_4(0),
-_gameMinsToAdd_5(0), _gameGlobal0x57(0), _sceneOpcode15FromScene(0),
+_gameMinsToAddOnLClick(0), _gameMinsToAddOnStartDrag(0), _gameMinsToAddOnRClick(0), _gameMinsToAddOnDragFinished(0),
+_gameMinsToAddOnObjInteraction(0), _gameGlobal0x57(0), _sceneOpcode15FromScene(0),
_sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
_globals.push_back(_clock.getGameMinsAddedGlobal(1));
@@ -128,11 +128,11 @@ _opcode106EndMinutes(0) {
_globals.push_back(_clock.getDaysGlobal(0x5F));
_globals.push_back(_clock.getHoursGlobal(0x5E));
_globals.push_back(_clock.getMinsGlobal(0x5D));
- _globals.push_back(new RWI16Global(0x5C, &_gameMinsToAdd_1));
- _globals.push_back(new RWI16Global(0x5B, &_gameMinsToAdd_2));
- _globals.push_back(new RWI16Global(0x5A, &_gameMinsToAdd_3));
- _globals.push_back(new RWI16Global(0x59, &_gameMinsToAdd_4));
- _globals.push_back(new RWI16Global(0x58, &_gameMinsToAdd_5));
+ _globals.push_back(new RWI16Global(0x5C, &_gameMinsToAddOnLClick));
+ _globals.push_back(new RWI16Global(0x5B, &_gameMinsToAddOnStartDrag));
+ _globals.push_back(new RWI16Global(0x5A, &_gameMinsToAddOnRClick));
+ _globals.push_back(new RWI16Global(0x59, &_gameMinsToAddOnDragFinished));
+ _globals.push_back(new RWI16Global(0x58, &_gameMinsToAddOnObjInteraction));
_globals.push_back(new RWI16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
_globals.push_back(_clock.getDays2Global(0x56));
_globals.push_back(new RWI16Global(0x55, &_sceneOpcode15FromScene));
@@ -151,11 +151,11 @@ Common::Error DragonGlobals::syncState(Common::Serializer &s) {
s.syncAsSint16LE(_lastOpcode1SceneChageNum);
s.syncAsSint16LE(_sceneOp12SceneNum);
s.syncAsSint16LE(_currentSelectedItem);
- s.syncAsSint16LE(_gameMinsToAdd_1);
- s.syncAsSint16LE(_gameMinsToAdd_2);
- s.syncAsSint16LE(_gameMinsToAdd_3);
- s.syncAsSint16LE(_gameMinsToAdd_4);
- s.syncAsSint16LE(_gameMinsToAdd_5);
+ s.syncAsSint16LE(_gameMinsToAddOnLClick);
+ s.syncAsSint16LE(_gameMinsToAddOnStartDrag);
+ s.syncAsSint16LE(_gameMinsToAddOnRClick);
+ s.syncAsSint16LE(_gameMinsToAddOnDragFinished);
+ s.syncAsSint16LE(_gameMinsToAddOnObjInteraction);
s.syncAsSint16LE(_gameGlobal0x57);
s.syncAsSint16LE(_sceneOpcode15FromScene);
s.syncAsSint16LE(_sceneOpcode15ToScene);
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index ed11637bad2..866b0f30878 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -103,15 +103,21 @@ class DragonGlobals : public Globals {
public:
DragonGlobals(Clock &clock);
+ int16 getGameMinsToAddOnLClick() const { return _gameMinsToAddOnLClick; }
+ int16 getGameMinsToAddOnStartDrag() const { return _gameMinsToAddOnStartDrag; }
+ int16 getGameMinsToAddOnRClick() const { return _gameMinsToAddOnRClick; }
+ int16 getGameMinsToAddOnDragFinished() const { return _gameMinsToAddOnDragFinished; }
+ int16 getGameMinsToAddOnObjInteraction() const { return _gameMinsToAddOnObjInteraction; }
+
private:
int16 _lastOpcode1SceneChageNum;
int16 _sceneOp12SceneNum;
int16 _currentSelectedItem;
- int16 _gameMinsToAdd_1;
- int16 _gameMinsToAdd_2;
- int16 _gameMinsToAdd_3;
- int16 _gameMinsToAdd_4;
- int16 _gameMinsToAdd_5;
+ int16 _gameMinsToAddOnLClick;
+ int16 _gameMinsToAddOnStartDrag;
+ int16 _gameMinsToAddOnRClick;
+ int16 _gameMinsToAddOnDragFinished;
+ int16 _gameMinsToAddOnObjInteraction;
int16 _gameGlobal0x57;
int16 _sceneOpcode15FromScene;
int16 _sceneOpcode15ToScene;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index acccb857ff2..549ba77ac12 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -485,12 +485,16 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
}
}
-bool Scene::runOps(const Common::Array<SceneOp> &ops) {
+bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 */) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
if (!checkConditions(op._conditionList))
continue;
debug(10, "Exec %s", op.dump("").c_str());
+ if (addMinuites) {
+ engine->getClock().addGameTime(addMinuites);
+ addMinuites = 0;
+ }
switch(op._opCode) {
case kSceneOpChangeScene:
if (engine->changeScene(op._args[0]))
@@ -984,7 +988,8 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
area->rect.width, area->rect.height, area->_cursorNum);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- runOps(area->onLDownOps);
+ int16 addmins = static_cast<DragonGlobals *>(engine->getGameGlobals())->getGameMinsToAddOnStartDrag();
+ runOps(area->onLDownOps, addmins);
GameItem *item = dynamic_cast<GameItem *>(area);
if (item) {
_dragItem = item;
@@ -1019,7 +1024,8 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
} else {
debug(" --> exec %d click ops for area %d", area->onLClickOps.size(), area->_num);
- runOps(area->onLClickOps);
+ int16 addmins = static_cast<DragonGlobals *>(engine->getGameGlobals())->getGameMinsToAddOnLClick();
+ runOps(area->onLClickOps, addmins);
}
}
@@ -1037,9 +1043,11 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
GameItem *dragItem = _dragItem;
_dragItem = nullptr;
- runOps(dragItem->onDragFinishedOps);
-
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const DragonGlobals *globals = static_cast<DragonGlobals *>(engine->getGameGlobals());
+
+ runOps(dragItem->onDragFinishedOps, globals->getGameMinsToAddOnDragFinished());
+
engine->setMouseCursor(0);
// TODO: Both these loops are very similar.. there should be a cleaner way.
@@ -1050,7 +1058,7 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
for (const auto &i : engine->getGDSScene()->getObjInteractions2()) {
if (i._droppedItemNum == dragItem->_num && i._targetItemNum == item._num) {
debug(" --> exec item %d drag ops", i.opList.size());
- if (!runOps(i.opList))
+ if (!runOps(i.opList, globals->getGameMinsToAddOnObjInteraction()))
return;
break;
}
@@ -1070,7 +1078,7 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
for (const auto &i : engine->getScene()->getObjInteractions1()) {
if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area._num) {
debug(" --> exec area %d drag ops", i.opList.size());
- if (!runOps(i.opList))
+ if (!runOps(i.opList, globals->getGameMinsToAddOnObjInteraction()))
return;
break;
}
@@ -1092,7 +1100,10 @@ void SDSScene::mouseRUp(const Common::Point &pt) {
const HotArea *area = findAreaUnderMouse(pt);
if (!area)
return;
- runOps(area->onRClickOps);
+
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ int16 addmins = static_cast<DragonGlobals *>(engine->getGameGlobals())->getGameMinsToAddOnLClick();
+ runOps(area->onRClickOps, addmins);
}
Dialog *SDSScene::getVisibleDialog() {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 0da4923baef..bf2a8881750 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -186,7 +186,7 @@ public:
void mouseMoved(const Common::Point pt);
void mouseClicked(const Common::Point pt);
- bool runOps(const Common::Array<SceneOp> &ops);
+ bool runOps(const Common::Array<SceneOp> &ops, int16 addMinutes = 0);
virtual Common::Error syncState(Common::Serializer &s) = 0;
protected:
Commit: b593f026f72d2bac79263628e26b1cde11120ac5
https://github.com/scummvm/scummvm/commit/b593f026f72d2bac79263628e26b1cde11120ac5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix small things to make china not crash
Changed paths:
engines/dgds/clock.cpp
engines/dgds/dgds.cpp
engines/dgds/scripts.cpp
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index 7cefa10135f..cdd8cb3a0b9 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -118,8 +118,7 @@ Common::String Clock::getTimeStr() const {
}
void Clock::draw(Graphics::ManagedSurface &surf) {
- // FIXME: Temporarily ignore script visibility flag for testing.
- if (!_visibleUser /*|| !_visibleScript*/)
+ if (!_visibleUser || !_visibleScript)
return;
const Common::String clockStr = getTimeStr();
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 84561d2e10a..641db57d9e9 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -291,7 +291,8 @@ void DgdsEngine::loadGameFiles() {
reqParser.parse(&invRequestData, "DINV.REQ");
reqParser.parse(&vcrRequestData, "DVCR.REQ");
} else if (getGameId() == GID_CHINA) {
- _gameGlobals = new Globals();
+ // TODO: Create a better type for this..
+ _gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("HOC.PAL");
_gdsScene->load("HOC.GDS", _resource, _decompressor);
@@ -301,7 +302,8 @@ void DgdsEngine::loadGameFiles() {
reqParser.parse(&invRequestData, "HINV.REQ");
reqParser.parse(&vcrRequestData, "HVCR.REQ");
} else if (getGameId() == GID_BEAMISH) {
- _gameGlobals = new Globals();
+ // TODO: Create a better type for this..
+ _gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("WILLY.PAL");
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 133459ab8ce..561851618b9 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -265,7 +265,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0070: // FREE PALETTE
if (seq._executed) // this is a one-shot op
break;
- error("TODO: Implement me: free palette (current pal)");
+ warning("TODO: Implement me: free palette (current pal)");
+ seq._currentPalId = 0;
break;
case 0x0080: // FREE SHAPE
env._scriptShapes[seq._currentBmpId].reset();
@@ -1034,7 +1035,7 @@ bool ADSInterpreter::logicOpResult(uint16 code, const TTMSeq *seq) {
case 0x1380: // IF_???????, 0 params
case 0x1390: // IF_???????, 0 params
warning("Unimplemented IF operation 0x%x", code);
- return false;
+ return true;
default:
error("Not an ADS logic op: %04x, how did we get here?", code);
}
Commit: 723761ec2fe5733e02a2c8e02d1241e29d433321
https://github.com/scummvm/scummvm/commit/723761ec2fe5733e02a2c8e02d1241e29d433321
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix some inventory interactions
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 641db57d9e9..649eeea9ddb 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -168,6 +168,7 @@ bool DgdsEngine::changeScene(int sceneNum) {
setMouseCursor(0);
_foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _storedAreaBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
@@ -456,14 +457,15 @@ Common::Error DgdsEngine::run() {
// Now we start to assemble the rendered scene.
_compositionBuffer.blitFrom(_backgroundBuffer);
- _compositionBuffer.transBlitFrom(_storedAreaBuffer);
if (_inventory->isOpen()) {
int invCount = _gdsScene->countItemsInScene2();
_inventory->draw(_compositionBuffer, invCount);
}
+ _compositionBuffer.transBlitFrom(_storedAreaBuffer);
_compositionBuffer.transBlitFrom(_foregroundBuffer);
+
/* For debugging, dump the frame contents..
{
Common::DumpFile outf;
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 3b1ab841f8c..f77a7e5246b 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -33,7 +33,7 @@ namespace Dgds {
Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nullptr),
_invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _clockSkipMinBtn(nullptr),
_itemArea(nullptr), _clockSkipHrBtn(nullptr), _dropBtn(nullptr), _highlightItemNo(-1),
- _itemOffset(0), _openedFromSceneNum(-1)
+ _itemOffset(0), _openedFromSceneNum(-1), _showZoomBox(false), _fullWidth(-1)
{
}
@@ -46,8 +46,9 @@ void Inventory::open() {
if (curScene != 2) {
_openedFromSceneNum = curScene;
engine->changeScene(2);
+ } else {
+ engine->getScene()->runEnterSceneOps();
}
- engine->getScene()->runEnterSceneOps();
}
void Inventory::close() {
@@ -56,24 +57,27 @@ void Inventory::close() {
_isOpen = false;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
engine->changeScene(_openedFromSceneNum);
+ _showZoomBox = false;
_openedFromSceneNum = -1;
}
void Inventory::setRequestData(const REQFileData &data) {
_reqData = data;
assert(_reqData._requests.size() > 0);
- RequestData *req = _reqData._requests.data();
- _prevPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(14));
- _nextPageBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(15));
- _invClock = dynamic_cast<TextAreaGadget *>(req->findGadgetByNumWithFlags3Not0x40(23));
- _itemBox = req->findGadgetByNumWithFlags3Not0x40(8);
- _itemZoomBox = req->findGadgetByNumWithFlags3Not0x40(9);
- _exitButton = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(17));
-
- _clockSkipMinBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(24));
- _clockSkipHrBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(25));
- _dropBtn = dynamic_cast<ButtonGadget *>(req->findGadgetByNumWithFlags3Not0x40(16));
- _itemArea = dynamic_cast<ImageGadget *>(_reqData._requests[0].findGadgetByNumWithFlags3Not0x40(8));
+ RequestData &req = _reqData._requests[0];
+ _prevPageBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(14));
+ _nextPageBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(15));
+ _invClock = dynamic_cast<TextAreaGadget *>(req.findGadgetByNumWithFlags3Not0x40(23));
+ _itemBox = req.findGadgetByNumWithFlags3Not0x40(8);
+ _itemZoomBox = req.findGadgetByNumWithFlags3Not0x40(9);
+ _exitButton = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(17));
+
+ _clockSkipMinBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(24));
+ _clockSkipHrBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(25));
+ _dropBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(16));
+ _itemArea = dynamic_cast<ImageGadget *>(req.findGadgetByNumWithFlags3Not0x40(8));
+
+ _fullWidth = req._width;
if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton || !_itemArea)
error("Didn't get all expected inventory gadgets");
@@ -98,15 +102,17 @@ void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
surf.drawLine(x1 + 1, y2, x1 + titleWidth + 5, y2, 0xff);
}
-void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting) {
+void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount) {
//DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- //_if (engine->getScene()->getNum() == 2)
- // return;
- if (isRestarting) {
- warning("TODO: Handle inventory redraw on restart");
+ RequestData &boxreq = _reqData._requests[0];
+
+ if (_showZoomBox) {
+ _itemZoomBox->_flags3 &= ~0x40;
+ boxreq._width = _fullWidth;
} else {
- _itemZoomBox->_flags3 &= 0x40;
+ _itemZoomBox->_flags3 |= 0x40;
+ boxreq._width = _itemBox->_width + _itemBox->_x * 2;
}
//
@@ -122,7 +128,8 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount, bool isResta
_prevPageBtn->_flags3 &= ~0x40;
_nextPageBtn->_flags3 &= ~0x40;
}
- _reqData._requests[0].drawInvType(&surf);
+
+ boxreq.drawInvType(&surf);
drawHeader(surf);
drawTime(surf);
@@ -251,7 +258,9 @@ GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
void Inventory::mouseLDown(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- if (_itemBox->containsPoint(pt)) {
+ if (engine->getScene()->hasVisibleDialog() || !_itemBox->containsPoint(pt)) {
+ return engine->getScene()->mouseLDown(pt);
+ } else {
GameItem *underMouse = itemUnderMouse(pt);
if (underMouse) {
_highlightItemNo = underMouse->_num;
@@ -260,8 +269,6 @@ void Inventory::mouseLDown(const Common::Point &pt) {
if (underMouse->_iconNum)
engine->setMouseCursor(underMouse->_iconNum);
}
- } else {
- return engine->getScene()->mouseLDown(pt);
}
}
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 716d2107f6a..91f1da49e81 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -40,7 +40,7 @@ public:
bool isOpen() const { return _isOpen; }
void open();
void close();
- void draw(Graphics::ManagedSurface &surf, int itemCount, bool isRestarting = false);
+ void draw(Graphics::ManagedSurface &surf, int itemCount);
void drawItems(Graphics::ManagedSurface &surf);
void drawTime(Graphics::ManagedSurface &surf);
void drawHeader(Graphics::ManagedSurface &surf);
@@ -51,6 +51,7 @@ public:
void mouseRUp(const Common::Point &pt);
void setRequestData(const REQFileData &data);
+ void setShowZoomBox(bool val) { _showZoomBox = val; }
Common::Error syncState(Common::Serializer &s);
@@ -59,6 +60,7 @@ private:
uint16 _openedFromSceneNum;
+ bool _showZoomBox;
bool _isOpen;
ButtonGadget *_prevPageBtn;
ButtonGadget *_nextPageBtn;
@@ -74,6 +76,7 @@ private:
REQFileData _reqData;
int _highlightItemNo; // -1 means no item highlighted.
int _itemOffset; // for scrolling through the item list
+ int _fullWidth; // width of the box including zoom
};
} // end namespace Dgds
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 549ba77ac12..3fe2ced2fd4 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -120,7 +120,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
case kSceneOpMoveItemsBetweenScenes: return "moveItemsBetweenScenes";
- case kSceneOpLeaveSceneAndOpenInventory: return "leaveSceneOpenInventory";
+ case kSceneOpOpenInventoryZoom: return "openInventoryZoom";
case kSceneOpShowClock: return "sceneOpShowClock";
case kSceneOpHideClock: return "sceneOpHideClock";
case kSceneOpShowMouse: return "sceneOpShowMouse";
@@ -532,10 +532,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
return false;
break;
}
- case kSceneOpLeaveSceneAndOpenInventory:
+ case kSceneOpOpenInventoryZoom:
+ engine->getInventory()->setShowZoomBox(true);
engine->getInventory()->open();
- // This implicitly changes scene num
- warning("TODO: Check leave scene and open inventory scene op");
return false;
case kSceneOpMoveItemsBetweenScenes: {
int16 fromScene = engine->getGameGlobals()->getGlobal(0x55);
@@ -1021,7 +1020,7 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
if (area && area->_num == 0) {
debug("Mouseup on inventory.");
- static_cast<DgdsEngine *>(g_engine)->getInventory()->open();
+ engine->getInventory()->open();
} else {
debug(" --> exec %d click ops for area %d", area->onLClickOps.size(), area->_num);
int16 addmins = static_cast<DragonGlobals *>(engine->getGameGlobals())->getGameMinsToAddOnLClick();
@@ -1102,6 +1101,14 @@ void SDSScene::mouseRUp(const Common::Point &pt) {
return;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
+ if (area->_num == 0) {
+ debug("Right mouseup on inventory.");
+ engine->getInventory()->setShowZoomBox(true);
+ engine->getInventory()->open();
+ return;
+ }
+
int16 addmins = static_cast<DragonGlobals *>(engine->getGameGlobals())->getGameMinsToAddOnLClick();
runOps(area->onRClickOps, addmins);
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index bf2a8881750..a238ec9429e 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -85,7 +85,7 @@ enum SceneOpCode {
kSceneOpEnableTrigger = 11, // args: trigger num
kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
kSceneOp13 = 13, // args: none.
- kSceneOpLeaveSceneAndOpenInventory = 14, // args: none.
+ kSceneOpOpenInventoryZoom = 14, // args: none.
kSceneOpMoveItemsBetweenScenes = 15, // args: none.
kSceneOpShowClock = 16, // args: none. set some clock-related globals
kSceneOpHideClock = 17, // args: none. set some clock-related values.
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 561851618b9..cd69c93db27 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -259,13 +259,16 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0020: // SAVE (free?) BACKGROUND
if (seq._executed) // this is a one-shot op
break;
- _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ warning("TODO: Implement me: op 0x0020 save/free background?");
+ //_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
//_vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getBackgroundBuffer().transBlitFrom(_vm->getStoredAreaBuffer());
+ _vm->getBackgroundBuffer().transBlitFrom(_vm->getForegroundBuffer());
break;
case 0x0070: // FREE PALETTE
if (seq._executed) // this is a one-shot op
break;
- warning("TODO: Implement me: free palette (current pal)");
+ warning("TODO: Implement me: op 0x0070 free palette (current pal)");
seq._currentPalId = 0;
break;
case 0x0080: // FREE SHAPE
Commit: 8339a8de2aecd29070197c30434bcb883e2ac2b9
https://github.com/scummvm/scummvm/commit/8339a8de2aecd29070197c30434bcb883e2ac2b9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Don't run scripts during mini inventory
This matches the original behavior.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/inventory.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 649eeea9ddb..ae1c785c5e4 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -408,7 +408,8 @@ Common::Error DgdsEngine::run() {
_scene->drawActiveDialogBgs(&_compositionBuffer);
- _adsInterp->run();
+ if (!_inventory->isOpen() || _inventory->isZoomVisible())
+ _adsInterp->run();
if (mouseEvent != Common::EVENT_INVALID) {
if (_inventory->isOpen()) {
@@ -553,7 +554,7 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
int sceneNum = _scene->getNum();
s.syncAsUint16LE(sceneNum);
if (s.isLoading()) {
- // load scene data before syncing state
+ // load and prepare scene data before syncing the rest of the state
const Common::String sceneFile = Common::String::format("S%d.SDS", sceneNum);
if (!_resource->hasResource(sceneFile))
error("Game references non-existant scene %d", sceneNum);
@@ -561,6 +562,7 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
_scene->unload();
_adsInterp->unload();
_scene->load(sceneFile, _resource, _decompressor);
+ _scene->addInvButtonToHotAreaList();
}
result = _scene->syncState(s);
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 91f1da49e81..225e9b9cd67 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -52,6 +52,7 @@ public:
void setRequestData(const REQFileData &data);
void setShowZoomBox(bool val) { _showZoomBox = val; }
+ bool isZoomVisible() const { return _showZoomBox; }
Common::Error syncState(Common::Serializer &s);
Commit: 62b886874dcc8d46d650ad74154f3f5d9fbe670f
https://github.com/scummvm/scummvm/commit/62b886874dcc8d46d650ad74154f3f5d9fbe670f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Go back to just clearing foreground
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index ae1c785c5e4..180da8fbacf 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -239,15 +239,6 @@ void DgdsEngine::checkDrawInventoryButton() {
_icons->drawBitmap(2, x, y, drawWin, _compositionBuffer);
}
-Graphics::ManagedSurface &DgdsEngine::getForegroundBuffer() {
- if (_usedForegroundBuffer) {
- _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _usedForegroundBuffer = false;
- }
-
- return _foregroundBuffer;
-}
-
void DgdsEngine::init() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -488,7 +479,7 @@ Common::Error DgdsEngine::run() {
outf.close();
}*/
- _usedForegroundBuffer = true;
+ _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
if (!_inventory->isOpen()) {
_gdsScene->drawItems(_compositionBuffer);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index f0aeaa17d4b..93a9c564762 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -106,7 +106,6 @@ private:
bool _justChangedScene1;
bool _justChangedScene2;
- bool _usedForegroundBuffer;
Common::RandomSource _random;
Common::Point _lastMouse; // originals start mouse at 0,0.
@@ -124,10 +123,11 @@ public:
DgdsGameId getGameId() { return _gameId; }
- Graphics::ManagedSurface &getForegroundBuffer();
const Graphics::ManagedSurface &getForegroundBuffer() const { return _foregroundBuffer; }
+ Graphics::ManagedSurface &getForegroundBuffer() { return _foregroundBuffer; }
Graphics::ManagedSurface &getBackgroundBuffer() { return _backgroundBuffer; }
Graphics::ManagedSurface &getStoredAreaBuffer() { return _storedAreaBuffer; }
+
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
Commit: 7e27347b55c96fb8ff8c779c1cf4226acddb8a6e
https://github.com/scummvm/scummvm/commit/7e27347b55c96fb8ff8c779c1cf4226acddb8a6e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: More tweaking to rendering to match originals
This is still not quite right. I will need to add a mask layer it seems, as
running TTM opcode 0020 (save background) after drawing a color 0 rect is *not*
the same as running that opcode after just drawing a bmp on the foreground.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 180da8fbacf..a3a0f44e272 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -63,7 +63,12 @@
#include "dgds/sound.h"
// for frame contents debugging
-//#include "image/png.h"
+//#define DUMP_FRAME_DATA 1
+
+#ifdef DUMP_FRAME_DATA
+#include "graphics/paletteman.h"
+#include "image/png.h"
+#endif
namespace Dgds {
@@ -160,6 +165,7 @@ bool DgdsEngine::changeScene(int sceneNum) {
_gameGlobals->setGlobal(0x61, _scene->getNum());
_scene->unload();
+ _backgroundFile.clear();
_soundPlayer->unloadMusic();
_gdsScene->runChangeSceneOps();
@@ -325,6 +331,8 @@ Common::Error DgdsEngine::run() {
init();
loadGameFiles();
+ // changeScene(55); // to test DRAGON intro sequence (after credits)
+
// If a savegame was selected from the launcher, load it now.
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot != -1)
@@ -458,7 +466,8 @@ Common::Error DgdsEngine::run() {
_compositionBuffer.transBlitFrom(_storedAreaBuffer);
_compositionBuffer.transBlitFrom(_foregroundBuffer);
- /* For debugging, dump the frame contents..
+#ifdef DUMP_FRAME_DATA
+ /* For debugging, dump the frame contents.. */
{
Common::DumpFile outf;
uint32 now = g_engine->getTotalPlayTime();
@@ -466,18 +475,23 @@ Common::Error DgdsEngine::run() {
byte palbuf[768];
g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
- outf.open(Common::Path(Common::String::format("/tmp/%07d-bottom.png", now)));
- ::Image::writePNG(outf, *_bottomBuffer.surfacePtr(), palbuf);
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-back.png", now)));
+ ::Image::writePNG(outf, *_backgroundBuffer.surfacePtr(), palbuf);
outf.close();
- outf.open(Common::Path(Common::String::format("/tmp/%07d-top.png", now)));
- ::Image::writePNG(outf, *_topBuffer.surfacePtr(), palbuf);
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-fore.png", now)));
+ ::Image::writePNG(outf, *_foregroundBuffer.surfacePtr(), palbuf);
outf.close();
- outf.open(Common::Path(Common::String::format("/tmp/%07d-res.png", now)));
- ::Image::writePNG(outf, *_resData.surfacePtr(), palbuf);
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-stor.png", now)));
+ ::Image::writePNG(outf, *_storedAreaBuffer.surfacePtr(), palbuf);
outf.close();
- }*/
+
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-comp.png", now)));
+ ::Image::writePNG(outf, *_compositionBuffer.surfacePtr(), palbuf);
+ outf.close();
+ }
+#endif
_foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 93a9c564762..830a6eb6d5c 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -174,6 +174,7 @@ public:
};
void setBackgroundFile(const Common::String &name) { _backgroundFile = name; }
+ const Common::String &getBackgroundFile() const { return _backgroundFile; }
void setMenuToTrigger(MenuId menu) { _menuToTrigger = menu; }
private:
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index cd69c93db27..eb5b1b97a09 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -43,6 +43,12 @@
namespace Dgds {
+void GetPutRegion::reset() {
+ _area = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
+ _fgSurf.reset();
+ _storedSurf.reset();
+}
+
Common::Error TTMEnviro::syncState(Common::Serializer &s) {
DgdsEngine *engine = dynamic_cast<DgdsEngine *>(g_engine);
for (auto &shape : _scriptShapes) {
@@ -61,17 +67,17 @@ Common::Error TTMEnviro::syncState(Common::Serializer &s) {
}
}
- uint16 ngetput = _getPutAreas.size();
+ uint16 ngetput = _getPuts.size();
s.syncAsUint16LE(ngetput);
- _getPutAreas.resize(ngetput);
- _getPutSurfaces.resize(ngetput);
+ _getPuts.resize(ngetput);
for (uint i = 0; i < ngetput; i++) {
- s.syncAsUint16LE(_getPutAreas[i].left);
- s.syncAsUint16LE(_getPutAreas[i].top);
- s.syncAsUint16LE(_getPutAreas[i].right);
- s.syncAsUint16LE(_getPutAreas[i].bottom);
+ s.syncAsUint16LE(_getPuts[i]._area.left);
+ s.syncAsUint16LE(_getPuts[i]._area.top);
+ s.syncAsUint16LE(_getPuts[i]._area.right);
+ s.syncAsUint16LE(_getPuts[i]._area.bottom);
if (s.isLoading()) {
- _getPutSurfaces[i].reset(new Graphics::ManagedSurface());
+ _getPuts[i]._fgSurf.reset(new Graphics::ManagedSurface());
+ _getPuts[i]._storedSurf.reset(new Graphics::ManagedSurface());
} else {
// TODO: Save the getput buffer contents here?
}
@@ -259,10 +265,24 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0020: // SAVE (free?) BACKGROUND
if (seq._executed) // this is a one-shot op
break;
- warning("TODO: Implement me: op 0x0020 save/free background?");
- //_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- //_vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _vm->getBackgroundBuffer().transBlitFrom(_vm->getStoredAreaBuffer());
+ //
+ // This appears in the credits, intro sequence, and the
+ // "meanwhile" event with the factory in DRAGON. Seems it
+ // should reload the background image to clear any previous 0020
+ // event, and then save the current FG over it.
+ // Credits - (no scr loaded) Store large image on black bg after loading and before txt scroll
+ // Intro - (no scr loaded) After each screen change, draw and save the new comic frame as bg
+ // on "aaaaah" scene, called after only drawing the AAAH and calling store area
+ // Meanwhile - (scr loaded) Save the foreground people onto the background before walk animation
+ //
+ //warning("TODO: Implement me: op 0x0020 save/free background?");
+ if (_vm->getBackgroundFile().empty()) {
+ _vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ } else {
+ Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
+ tmp.drawScreen(_vm->getBackgroundFile(), _vm->getBackgroundBuffer());
+ }
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_vm->getBackgroundBuffer().transBlitFrom(_vm->getForegroundBuffer());
break;
case 0x0070: // FREE PALETTE
@@ -285,8 +305,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x00C0: // (one-shot) FREE GETPUT (free getput item pointed to by _currentGetPutId)
if (seq._executed) // this is a one-shot op
break;
- env._getPutSurfaces[seq._currentGetPutId].reset();
- env._getPutAreas[seq._currentGetPutId] = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
+ env._getPuts[seq._currentGetPutId].reset();
break;
case 0x0110: // PURGE void
_vm->adsInterpreter()->setHitTTMOp0110();
@@ -381,17 +400,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
}
_vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
// reset to previous palette.
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], 0);
break;
case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
if (seq._executed) // this is a one-shot op.
break;
- // blt first to make the initial fade-in work
- _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
- _vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
- _vm->_compositionBuffer.transBlitFrom(_vm->getForegroundBuffer());
- g_system->copyRectToScreen(_vm->_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
if (ivals[3] == 0) {
_vm->getGamePals()->setPalette();
@@ -399,6 +414,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
for (int i = 320; i > 0; i -= ivals[3]) {
int fade = MAX(0, MIN(i / 5, 63));
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
+ if (i == 320) {
+ // blt first to make the initial fade-in work
+ _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
+ _vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
+ _vm->_compositionBuffer.transBlitFrom(_vm->getForegroundBuffer());
+ g_system->copyRectToScreen(_vm->_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ }
g_system->updateScreen();
g_system->delayMillis(5);
}
@@ -409,23 +431,25 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op
break;
const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getStoredAreaBuffer().blitFrom(_vm->getForegroundBuffer(), rect, rect);
+ _vm->getStoredAreaBuffer().transBlitFrom(_vm->getForegroundBuffer(), rect, rect);
break;
}
case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
if (seq._executed) // this is a one-shot op.
break;
- if (seq._currentGetPutId >= (int)env._getPutAreas.size()) {
- env._getPutAreas.resize(seq._currentGetPutId + 1);
- env._getPutSurfaces.resize(seq._currentGetPutId + 1);
+ if (seq._currentGetPutId >= (int)env._getPuts.size()) {
+ env._getPuts.resize(seq._currentGetPutId + 1);
}
const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- env._getPutAreas[seq._currentGetPutId] = rect;
+ env._getPuts[seq._currentGetPutId]._area = rect;
// Getput reads an area from the front buffer.
Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getForegroundBuffer().format);
surf->blitFrom(_vm->getForegroundBuffer(), rect, Common::Point(0, 0));
- env._getPutSurfaces[seq._currentGetPutId].reset(surf);
+ env._getPuts[seq._currentGetPutId]._fgSurf.reset(surf);
+ Graphics::ManagedSurface *surf2 = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getForegroundBuffer().format);
+ surf->blitFrom(_vm->getStoredAreaBuffer(), rect, Common::Point(0, 0));
+ env._getPuts[seq._currentGetPutId]._storedSurf.reset(surf2);
break;
}
case 0xa000: // DRAW PIXEL x,y:int
@@ -435,7 +459,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// it works like a bitblit, but it doesn't write if there's something already at the destination?
// TODO: This is part of a whole set of operations - 0xa0n4.
// They do various flips etc.
- warning("TODO: Fix implementation of SAVE REGION (0xa050)");
+ //warning("TODO: Fix implementation of SAVE REGION (0xa050)");
const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
_vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
_vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
@@ -518,12 +542,15 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op.
break;
int16 i = ivals[0];
- if (i >= (int16)env._getPutAreas.size() || !env._getPutSurfaces[i]) {
+ if (i >= (int16)env._getPuts.size()) {
warning("Trying to put getput region %d we never got", i);
break;
}
- const Common::Rect &r = env._getPutAreas[i];
- _vm->getForegroundBuffer().transBlitFrom(*(env._getPutSurfaces[i].get()),
+ const Common::Rect &r = env._getPuts[i]._area;
+ // Getput should overwrite the contents
+ _vm->getForegroundBuffer().blitFrom(*(env._getPuts[i]._fgSurf.get()),
+ Common::Point(r.left, r.top));
+ _vm->getStoredAreaBuffer().blitFrom(*(env._getPuts[i]._storedSurf.get()),
Common::Point(r.left, r.top));
break;
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 314bd7ea5a4..29bd3aca5f2 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -43,6 +43,15 @@ public:
Common::HashMap<uint16, Common::String> _tags;
};
+class GetPutRegion {
+public:
+ Common::Rect _area;
+ Common::SharedPtr<Graphics::ManagedSurface> _fgSurf;
+ Common::SharedPtr<Graphics::ManagedSurface> _storedSurf;
+
+ void reset();
+};
+
class TTMEnviro : public ScriptParserData {
public:
TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
@@ -55,8 +64,7 @@ public:
uint16 _totalFrames;
Common::Array<int> _frameOffsets;
Common::SharedPtr<Image> _scriptShapes[6];
- Common::Array<Common::Rect> _getPutAreas;
- Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> _getPutSurfaces;
+ Common::Array<GetPutRegion> _getPuts;
int _scriptPals[6];
Common::String _strings[10];
};
Commit: 45cc070eb810aaa64a81ff8af759e420e0afb934
https://github.com/scummvm/scummvm/commit/45cc070eb810aaa64a81ff8af759e420e0afb934
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix wrapping with space padding
Changed paths:
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/scene.cpp
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 9fc92a9f8f3..6da563ec38c 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -595,6 +595,34 @@ struct DialogAction *Dialog::pickAction(bool isClosing, bool isForceClose) {
}
+void Dialog::fixupStringAndActions() {
+ //
+ // This is a slight HACK. The original seems to have accepted any number
+ // of trailing spaces before a CR when doing wrapping, but our wrapper
+ // will wrap the spaces. This creates too many blank lines.
+ // To correct this, remove sequences of blank before CRs -
+ // but we then have to fix up offsets of actions.
+ //
+ // This code is not efficient, but it only runs once on load and
+ // only on fairly short strings, so it's ok.
+ //
+ for (uint i = 0; i < _str.size(); i++) {
+ if (_str[i] == '\r') {
+ while (i > 0 && _str[i - 1] == ' ') {
+ _str.deleteChar(i - 1);
+ for (auto &action : _action) {
+ if (action.strStart > i)
+ action.strStart--;
+ if (action.strEnd > i)
+ action.strEnd--;
+ }
+ i--;
+ }
+ }
+ }
+}
+
+
Common::String Dialog::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
"%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index c1e0eeb9f0d..d9bc117e587 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -129,6 +129,8 @@ public:
Common::Error syncState(Common::Serializer &s);
+ void fixupStringAndActions();
+
private:
void drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage);
void drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 3fe2ced2fd4..8a4539270c1 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -366,6 +366,8 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
else
dst._fontColor = dst._fontColor ^ 8;
}
+
+ dst.fixupStringAndActions();
}
return !s->err();
Commit: 38185598b6bbd03f6ef534fdd5d289fb7a10a744
https://github.com/scummvm/scummvm/commit/38185598b6bbd03f6ef534fdd5d289fb7a10a744
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Remove foreground buffer
With this change, the rendering now seems to closely match the original in most
situations.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/inventory.cpp
engines/dgds/request.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index a3a0f44e272..eae5c189cb7 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -112,7 +112,6 @@ DgdsEngine::~DgdsEngine() {
_corners.reset();
_compositionBuffer.free();
- _foregroundBuffer.free();
_storedAreaBuffer.free();
_backgroundBuffer.free();
}
@@ -173,7 +172,6 @@ bool DgdsEngine::changeScene(int sceneNum) {
if (!_scene->getDragItem())
setMouseCursor(0);
- _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_storedAreaBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_scene->load(sceneFile, _resource, _decompressor);
@@ -264,7 +262,6 @@ void DgdsEngine::init() {
_backgroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_storedAreaBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
- _foregroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_compositionBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
g_system->fillScreen(0);
@@ -405,6 +402,15 @@ Common::Error DgdsEngine::run() {
_gdsScene->runPreTickOps();
_scene->runPreTickOps();
+ _compositionBuffer.blitFrom(_backgroundBuffer);
+
+ if (_inventory->isOpen()) {
+ int invCount = _gdsScene->countItemsInScene2();
+ _inventory->draw(_compositionBuffer, invCount);
+ }
+
+ _compositionBuffer.transBlitFrom(_storedAreaBuffer);
+
_scene->drawActiveDialogBgs(&_compositionBuffer);
if (!_inventory->isOpen() || _inventory->isZoomVisible())
@@ -455,17 +461,6 @@ Common::Error DgdsEngine::run() {
_scene->runPostTickOps();
_scene->checkTriggers();
- // Now we start to assemble the rendered scene.
- _compositionBuffer.blitFrom(_backgroundBuffer);
-
- if (_inventory->isOpen()) {
- int invCount = _gdsScene->countItemsInScene2();
- _inventory->draw(_compositionBuffer, invCount);
- }
-
- _compositionBuffer.transBlitFrom(_storedAreaBuffer);
- _compositionBuffer.transBlitFrom(_foregroundBuffer);
-
#ifdef DUMP_FRAME_DATA
/* For debugging, dump the frame contents.. */
{
@@ -479,10 +474,6 @@ Common::Error DgdsEngine::run() {
::Image::writePNG(outf, *_backgroundBuffer.surfacePtr(), palbuf);
outf.close();
- outf.open(Common::Path(Common::String::format("/tmp/%07d-fore.png", now)));
- ::Image::writePNG(outf, *_foregroundBuffer.surfacePtr(), palbuf);
- outf.close();
-
outf.open(Common::Path(Common::String::format("/tmp/%07d-stor.png", now)));
::Image::writePNG(outf, *_storedAreaBuffer.surfacePtr(), palbuf);
outf.close();
@@ -493,12 +484,11 @@ Common::Error DgdsEngine::run() {
}
#endif
- _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
-
if (!_inventory->isOpen()) {
_gdsScene->drawItems(_compositionBuffer);
checkDrawInventoryButton();
}
+
_clock.draw(_compositionBuffer);
bool haveActiveDialog = _scene->checkDialogActive();
@@ -600,7 +590,6 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
s.syncString(_backgroundFile);
if (s.isLoading()) {
Image(_resource, _decompressor).drawScreen(_backgroundFile, _backgroundBuffer);
- _foregroundBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_storedAreaBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 830a6eb6d5c..d708377f873 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -86,7 +86,6 @@ private:
Graphics::ManagedSurface _backgroundBuffer;
Common::String _backgroundFile; // Record the background file name for save games.
Graphics::ManagedSurface _storedAreaBuffer;
- Graphics::ManagedSurface _foregroundBuffer;
SDSScene *_scene;
GDSScene *_gdsScene;
Menu *_menu;
@@ -123,8 +122,6 @@ public:
DgdsGameId getGameId() { return _gameId; }
- const Graphics::ManagedSurface &getForegroundBuffer() const { return _foregroundBuffer; }
- Graphics::ManagedSurface &getForegroundBuffer() { return _foregroundBuffer; }
Graphics::ManagedSurface &getBackgroundBuffer() { return _backgroundBuffer; }
Graphics::ManagedSurface &getStoredAreaBuffer() { return _storedAreaBuffer; }
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index f77a7e5246b..7c1c247ad9b 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -103,8 +103,6 @@ void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
}
void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount) {
- //DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
-
RequestData &boxreq = _reqData._requests[0];
if (_showZoomBox) {
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index de0d5cff55e..192af33f9b1 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -564,7 +564,6 @@ void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
for (const auto &textItem : _textItemList) {
if (!textItem._txt.empty())
error("TODO: RequestData::drawInvType: Implement support for drawing text item.");
-
}
for (auto &gadget : _gadgets)
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index eb5b1b97a09..4b8c3e126f2 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -45,8 +45,7 @@ namespace Dgds {
void GetPutRegion::reset() {
_area = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
- _fgSurf.reset();
- _storedSurf.reset();
+ _surf.reset();
}
Common::Error TTMEnviro::syncState(Common::Serializer &s) {
@@ -76,8 +75,7 @@ Common::Error TTMEnviro::syncState(Common::Serializer &s) {
s.syncAsUint16LE(_getPuts[i]._area.right);
s.syncAsUint16LE(_getPuts[i]._area.bottom);
if (s.isLoading()) {
- _getPuts[i]._fgSurf.reset(new Graphics::ManagedSurface());
- _getPuts[i]._storedSurf.reset(new Graphics::ManagedSurface());
+ _getPuts[i]._surf.reset(new Graphics::ManagedSurface());
} else {
// TODO: Save the getput buffer contents here?
}
@@ -275,15 +273,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// on "aaaaah" scene, called after only drawing the AAAH and calling store area
// Meanwhile - (scr loaded) Save the foreground people onto the background before walk animation
//
- //warning("TODO: Implement me: op 0x0020 save/free background?");
- if (_vm->getBackgroundFile().empty()) {
- _vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- } else {
- Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
- tmp.drawScreen(_vm->getBackgroundFile(), _vm->getBackgroundBuffer());
- }
_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _vm->getBackgroundBuffer().transBlitFrom(_vm->getForegroundBuffer());
+ _vm->getBackgroundBuffer().blitFrom(_vm->_compositionBuffer);
break;
case 0x0070: // FREE PALETTE
if (seq._executed) // this is a one-shot op
@@ -399,8 +390,10 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
g_system->delayMillis(5);
}
}
+ // Clear all the buffers
_vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->_compositionBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
// reset to previous palette.
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], 0);
break;
@@ -415,10 +408,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
int fade = MAX(0, MIN(i / 5, 63));
_vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
if (i == 320) {
- // blt first to make the initial fade-in work
- _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
- _vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
- _vm->_compositionBuffer.transBlitFrom(_vm->getForegroundBuffer());
+ // update screen first to make the initial fade-in work
g_system->copyRectToScreen(_vm->_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
g_system->updateScreen();
@@ -431,7 +421,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op
break;
const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getStoredAreaBuffer().transBlitFrom(_vm->getForegroundBuffer(), rect, rect);
+ _vm->getStoredAreaBuffer().blitFrom(_vm->_compositionBuffer, rect, rect);
break;
}
case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
@@ -444,27 +434,26 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
env._getPuts[seq._currentGetPutId]._area = rect;
// Getput reads an area from the front buffer.
- Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getForegroundBuffer().format);
- surf->blitFrom(_vm->getForegroundBuffer(), rect, Common::Point(0, 0));
- env._getPuts[seq._currentGetPutId]._fgSurf.reset(surf);
- Graphics::ManagedSurface *surf2 = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->getForegroundBuffer().format);
- surf->blitFrom(_vm->getStoredAreaBuffer(), rect, Common::Point(0, 0));
- env._getPuts[seq._currentGetPutId]._storedSurf.reset(surf2);
+ Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_compositionBuffer.format);
+ surf->blitFrom(_vm->_compositionBuffer, rect, Common::Point(0, 0));
+ env._getPuts[seq._currentGetPutId]._surf.reset(surf);
break;
}
case 0xa000: // DRAW PIXEL x,y:int
- _vm->getForegroundBuffer().setPixel(ivals[0], ivals[1], seq._drawColFG);
+ _vm->_compositionBuffer.setPixel(ivals[0], ivals[1], seq._drawColFG);
break;
- case 0xa050: {// SAVE REGION x,y,w,h:int (not used in DRAGON?)
+ case 0xa050: {// SAVE REGION x,y,w,h:int
+ // This is used in DRAGON intro sequence to draw the AAAAH
// it works like a bitblit, but it doesn't write if there's something already at the destination?
// TODO: This is part of a whole set of operations - 0xa0n4.
// They do various flips etc.
- //warning("TODO: Fix implementation of SAVE REGION (0xa050)");
+ warning("TODO: Fix implementation of SAVE REGION (0xa050) (%d, %d, %d, %d)",
+ ivals[0], ivals[1], ivals[2], ivals[3]);
const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
- _vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
- _vm->_compositionBuffer.transBlitFrom(_vm->getForegroundBuffer());
- _vm->getForegroundBuffer().blitFrom(_vm->_compositionBuffer, r, r);
+ //_vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
+ //_vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
+ //_vm->_compositionBuffer.transBlitFrom(_vm->_compositionBuffer);
+ //_vm->_compositionBuffer.blitFrom(_vm->_compositionBuffer, r, r);
break;
}
case 0xa060: { // RESTORE REGION
@@ -473,19 +462,19 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
}
case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->getForegroundBuffer().drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
break;
case 0xa100: { // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getForegroundBuffer().fillRect(r, seq._drawColFG);
+ _vm->_compositionBuffer.fillRect(r, seq._drawColFG);
break;
}
case 0xa110: { // DRAW EMPTY RECT x1,y1,x2,y2:int
const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getForegroundBuffer().drawLine(r.left, r.top, r.right, r.top, seq._drawColFG);
- _vm->getForegroundBuffer().drawLine(r.left, r.bottom, r.right, r.bottom, seq._drawColFG);
- _vm->getForegroundBuffer().drawLine(r.left, r.top, r.left, r.bottom, seq._drawColFG);
- _vm->getForegroundBuffer().drawLine(r.right, r.top, r.right, r.bottom, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.left, r.top, r.right, r.top, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.left, r.bottom, r.right, r.bottom, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.left, r.top, r.left, r.bottom, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.right, r.top, r.right, r.bottom, seq._drawColFG);
break;
}
case 0xa200: // 0xa2n0 DRAW STRING n: x,y,w,h:int - draw the nth string from the string table
@@ -504,7 +493,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// TODO: Probably not this font?
const Font *font = mgr->getFont(FontManager::kDefaultFont);
// Note: ignore the y-height argument (ivals[3]) for now.
- font->drawString(&(_vm->getForegroundBuffer()), str, ivals[0], ivals[1], ivals[2], seq._drawColFG);
+ font->drawString(&(_vm->_compositionBuffer), str, ivals[0], ivals[1], ivals[2], seq._drawColFG);
break;
}
case 0xa510:
@@ -533,7 +522,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// DRAW BMP: x,y:int [-n,+n] (RISE)
Common::SharedPtr<Image> img = env._scriptShapes[seq._currentBmpId];
if (img)
- img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->getForegroundBuffer(), op == 0xa520);
+ img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->_compositionBuffer, op == 0xa520);
else
warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
break;
@@ -542,15 +531,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op.
break;
int16 i = ivals[0];
- if (i >= (int16)env._getPuts.size()) {
+ if (i >= (int16)env._getPuts.size() || !env._getPuts[i]._surf.get()) {
warning("Trying to put getput region %d we never got", i);
break;
}
const Common::Rect &r = env._getPuts[i]._area;
// Getput should overwrite the contents
- _vm->getForegroundBuffer().blitFrom(*(env._getPuts[i]._fgSurf.get()),
- Common::Point(r.left, r.top));
- _vm->getStoredAreaBuffer().blitFrom(*(env._getPuts[i]._storedSurf.get()),
+ _vm->_compositionBuffer.blitFrom(*(env._getPuts[i]._surf.get()),
Common::Point(r.left, r.top));
break;
}
@@ -559,6 +546,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
tmp.drawScreen(sval, _vm->getBackgroundBuffer());
+ _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_vm->setBackgroundFile(sval);
break;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 29bd3aca5f2..47ebdc4434f 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -46,8 +46,7 @@ public:
class GetPutRegion {
public:
Common::Rect _area;
- Common::SharedPtr<Graphics::ManagedSurface> _fgSurf;
- Common::SharedPtr<Graphics::ManagedSurface> _storedSurf;
+ Common::SharedPtr<Graphics::ManagedSurface> _surf;
void reset();
};
Commit: dddb5097cfb0bd3aec9d52befdef0c4de5a32d96
https://github.com/scummvm/scummvm/commit/dddb5097cfb0bd3aec9d52befdef0c4de5a32d96
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add sq5 demo detection
Changed paths:
engines/dgds/detection.cpp
engines/dgds/detection_tables.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/inventory.cpp
engines/dgds/resource.cpp
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/detection.cpp b/engines/dgds/detection.cpp
index aa1c7dafa8e..1719e7ce9fe 100644
--- a/engines/dgds/detection.cpp
+++ b/engines/dgds/detection.cpp
@@ -28,6 +28,7 @@ static const PlainGameDescriptor dgdsGames[] = {
{"rise", "Rise of the Dragon"},
{"china", "Heart of China"},
{"beamish", "The Adventures of Willy Beamish"},
+ {"sq5", "Space Quest V CES Demo"},
{0, 0}
};
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index c2e9b8d9cc7..112a974abc5 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -173,6 +173,20 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
+ // SQ5 demo
+ {
+ "sq5",
+ 0,
+ {
+ {"cesdemo.ads", 0, "8b5d56353aae62c69fe81a3ef80c3789", 2394},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+
AD_TABLE_END_MARKER
};
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index eae5c189cb7..0f7b03baa91 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -88,6 +88,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_gameId = GID_CHINA;
else if (!strcmp(gameDesc->gameId, "beamish"))
_gameId = GID_BEAMISH;
+ else if (!strcmp(gameDesc->gameId, "sq5"))
+ _gameId = GID_SQ5DEMO;
else
error("Unknown game ID");
@@ -309,6 +311,11 @@ void DgdsEngine::loadGameFiles() {
//_scene->load("S34.SDS", _resource, _decompressor);
_adsInterp->load("TITLE.ADS");
+ } else if (getGameId() == GID_SQ5DEMO) {
+ // TODO: Create a better type for this..
+ _gameGlobals = new DragonGlobals(_clock);
+ _gamePals->loadPalette("NORMAL.PAL");
+ _adsInterp->load("CESDEMO.ADS");
}
_gdsScene->runStartGameOps();
@@ -538,6 +545,8 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
assert(_scene && _gdsScene);
+ _menu->hideMenu();
+
if (!s.syncVersion(1))
error("Save game version too new: %d", s.getVersion());
@@ -554,6 +563,8 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
if (!_resource->hasResource(sceneFile))
error("Game references non-existant scene %d", sceneNum);
+ _soundPlayer->unloadMusic();
+ _soundPlayer->stopAllSfx();
_scene->unload();
_adsInterp->unload();
_scene->load(sceneFile, _resource, _decompressor);
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index d708377f873..9601fa290fe 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -62,7 +62,8 @@ class Globals;
enum DgdsGameId {
GID_DRAGON,
GID_CHINA,
- GID_BEAMISH
+ GID_BEAMISH,
+ GID_SQ5DEMO,
};
enum DgdsDetailLevel {
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 7c1c247ad9b..2e55f97c971 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -63,7 +63,10 @@ void Inventory::close() {
void Inventory::setRequestData(const REQFileData &data) {
_reqData = data;
- assert(_reqData._requests.size() > 0);
+ if (_reqData._requests.empty()) {
+ warning("No inventory request data to load");
+ return;
+ }
RequestData &req = _reqData._requests[0];
_prevPageBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(14));
_nextPageBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(15));
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 2b1408a299d..e8435dd3142 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -48,6 +48,11 @@ ResourceManager::ResourceManager() {
}
}
+ if (!indexFile.isOpen()) {
+ warning("No DGDS volume index file found to open.");
+ return;
+ }
+
indexFile.skip(4); // salt for file hash, TODO
int volumes = indexFile.readUint16LE();
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 9f587ee2340..314efea751b 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -78,6 +78,11 @@ void Sound::playAmigaSfx(const Common::String &filename, byte channel, byte volu
}
}
+void Sound::stopAllSfx() {
+ for (uint i = 0; i < ARRAYSIZE(_channels); i++)
+ stopSfx(i);
+}
+
void Sound::stopSfx(byte channel) {
if (_mixer->isSoundHandleActive(_channels[channel].handle)) {
_mixer->stopHandle(_channels[channel].handle);
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index a29f46aef9e..58dc89abfb6 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -56,6 +56,7 @@ public:
void playSFX(uint num);
void stopSfx(byte channel);
+ void stopAllSfx();
bool playPCM(const byte *data, uint32 size);
Commit: 1cef88c99e6575720475a940ad9a1dcc7c9af132
https://github.com/scummvm/scummvm/commit/1cef88c99e6575720475a940ad9a1dcc7c9af132
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Hook up save/load menu items
Changed paths:
engines/dgds/menu.cpp
engines/dgds/menu.h
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 194f61f53ea..5ac19f74645 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -89,7 +89,11 @@ enum MenuButtonIds {
kMenuIntroPlay = 144,
kMenuRestartYes = 163,
- kMenuRestartNo = 164
+ kMenuRestartNo = 164,
+
+ kMenuGameOverQuit = 169,
+ kMenuGameOverRestart = 168,
+ kMenuGameOverRestore = 170,
};
Menu::Menu() : _curMenu(kMenuNone) {
@@ -216,7 +220,7 @@ void Menu::handleMenu(Common::Point &mouse) {
case kMenuMainQuit:
drawMenu(kMenuQuit);
break;
- case kMenuCalibrateVCR: // NOTE: same as kMenuIntroPlay
+ case kMenuCalibrateVCR: // NOTE: same ID as kMenuIntroPlay
if (_curMenu == kMenuSkipPlayIntro) {
hideMenu();
} else {
@@ -244,22 +248,27 @@ void Menu::handleMenu(Common::Point &mouse) {
case kMenuCalibrateMouse:
drawMenu(kMenuMouse);
break;
- case kMenuFilesSave:
case kMenuChangeDirectoryCancel:
drawMenu(kMenuSave);
break;
case kMenuFilesRestore:
- // TODO
- debug("Clicked Files - Restore %d", clickedMenuItem);
+ case kMenuGameOverRestore:
+ if (g_engine->loadGameDialog())
+ hideMenu();
+ else
+ drawMenu(_curMenu);
break;
case kMenuFilesRestart:
drawMenu(kMenuRestart);
break;
+ case kMenuFilesSave: // TODO: Add an option to support original save/load dialogs?
case kMenuSavePrevious:
case kMenuSaveNext:
case kMenuSaveSave:
- // TODO
- debug("Clicked Save - %d", clickedMenuItem);
+ if (g_engine->saveGameDialog())
+ hideMenu();
+ else
+ drawMenu(_curMenu);
break;
case kMenuSaveChangeDirectory:
drawMenu(kMenuChangeDirectory);
@@ -279,6 +288,12 @@ void Menu::handleMenu(Common::Point &mouse) {
// TODO
debug("Clicked Restart - Yes %d", clickedMenuItem);
break;
+ case kMenuGameOverQuit:
+ drawMenu(kMenuQuit);
+ break;
+ case kMenuGameOverRestart:
+ drawMenu(kMenuRestart);
+ break;
default:
debug("Clicked ID %d", clickedMenuItem);
break;
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 19fc173fe8b..2c8f0d40b33 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -50,8 +50,8 @@ enum MenuId {
kMenuCalibrate = 3,
kMenuRestart = 4,
// 5: you cannot save your game right now
- // 6: game over
- kMenuFiles = 7,
+ kMenuGameOver = 6, // num 41
+ kMenuFiles = 7, // num 21
// 8: save game not saved because disk is full
// 9: all game entries are full
kMenuSave = 10,
Commit: a15c1cb1e16a15ffcd2cea287d24a71704b68c2b
https://github.com/scummvm/scummvm/commit/a15c1cb1e16a15ffcd2cea287d24a71704b68c2b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Various fixes to font and dialog handling
Changed paths:
engines/dgds/dialog.cpp
engines/dgds/font.cpp
engines/dgds/font.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 6da563ec38c..260f89f8e07 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -611,9 +611,9 @@ void Dialog::fixupStringAndActions() {
while (i > 0 && _str[i - 1] == ' ') {
_str.deleteChar(i - 1);
for (auto &action : _action) {
- if (action.strStart > i)
+ if (action.strStart >= i)
action.strStart--;
- if (action.strEnd > i)
+ if (action.strEnd >= i)
action.strEnd--;
}
i--;
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index cc22671f1d4..26526f57c88 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -202,7 +202,8 @@ const Font *FontManager::getFont(FontType type) const {
return _fonts.getVal(type);
}
-void FontManager::tryLoadFont(FontType ftype, const char *fname, ResourceManager *resMgr, Decompressor *decomp) {
+void FontManager::tryLoadFont(const char *fname, ResourceManager *resMgr, Decompressor *decomp) {
+ FontType ftype = fontTypeByName(fname);
Font *font = Font::load(fname, resMgr, decomp);
if (font)
_fonts.setVal(ftype, font);
@@ -210,23 +211,47 @@ void FontManager::tryLoadFont(FontType ftype, const char *fname, ResourceManager
error("Failed to load font %s", fname);
}
+FontManager::FontType FontManager::fontTypeByName(const Common::String &filename) const {
+ if (filename == "8X8.FNT") return k8x8Font;
+ if (filename == "6X6.FNT") return k6x6Font;
+ if (filename == "4x5.FNT") return k4x5Font;
+ if (filename == "DRAGON.FNT") return kGameFont;
+ if (filename == "7X8.FNT") return k7x8Font;
+ if (filename == "P6X6.FNT") return kGameDlgFont;
+ if (filename == "HOC.FNT") return kGameFont;
+ if (filename == "CHINA.FNT") return kChinaFont;
+ if (filename == "CHINESE.FNT") return kGameDlgFont;
+ if (filename == "WILLY.FNT") return kGameFont;
+ if (filename == "WVCR.FNT") return kWVCRFont;
+ if (filename == "COMIX_16.FNT") return kGameDlgFont;
+ return FontManager::kDefaultFont;
+}
+
void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompressor *decomp) {
- tryLoadFont(k8x8Font, "8X8.FNT", resMgr, decomp);
- tryLoadFont(k6x6Font, "6X6.FNT", resMgr, decomp);
- tryLoadFont(k4x5Font, "4x5.FNT", resMgr, decomp);
+ if (gameId == GID_SQ5DEMO) {
+ tryLoadFont("EXIT.FNT", resMgr, decomp);
+ //tryLoadFont("SSM1_12.FNT", resMgr, decomp);
+ //tryLoadFont("SSM1_15.FNT", resMgr, decomp);
+ //tryLoadFont("SSM1_30.FNT", resMgr, decomp);
+ return;
+ }
+
+ tryLoadFont("8X8.FNT", resMgr, decomp);
+ tryLoadFont("6X6.FNT", resMgr, decomp);
+ tryLoadFont("4x5.FNT", resMgr, decomp);
if (gameId == GID_DRAGON) {
- tryLoadFont(kGameFont, "DRAGON.FNT", resMgr, decomp);
- tryLoadFont(k7x8Font, "7X8.FNT", resMgr, decomp);
- tryLoadFont(kGameDlgFont, "P6X6.FNT", resMgr, decomp);
+ tryLoadFont("DRAGON.FNT", resMgr, decomp);
+ tryLoadFont("7X8.FNT", resMgr, decomp);
+ tryLoadFont("P6X6.FNT", resMgr, decomp);
} else if (gameId == GID_CHINA) {
- tryLoadFont(kGameFont, "HOC.FNT", resMgr, decomp);
- tryLoadFont(kChinaFont, "CHINA.FNT", resMgr, decomp);
- tryLoadFont(kGameDlgFont, "CHINESE.FNT", resMgr, decomp);
+ tryLoadFont("HOC.FNT", resMgr, decomp);
+ tryLoadFont("CHINA.FNT", resMgr, decomp);
+ tryLoadFont("CHINESE.FNT", resMgr, decomp);
} else if (gameId == GID_BEAMISH) {
- tryLoadFont(kGameFont, "WILLY.FNT", resMgr, decomp);
- tryLoadFont(kWVCRFont, "WVCR.FNT", resMgr, decomp);
- tryLoadFont(kGameDlgFont, "COMIX_16.FNT", resMgr, decomp);
+ tryLoadFont("WILLY.FNT", resMgr, decomp);
+ tryLoadFont("WVCR.FNT", resMgr, decomp);
+ tryLoadFont("COMIX_16.FNT", resMgr, decomp);
}
_fonts.setVal(kDefaultFont, _fonts.getVal(kGameFont));
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index 411467083e5..d00e221d855 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -114,10 +114,11 @@ public:
~FontManager();
const Font *getFont(FontType) const;
+ FontType fontTypeByName(const Common::String &filename) const;
void loadFonts(DgdsGameId gameId, ResourceManager *resourceManager, Decompressor *decompressor);
-private:
- void tryLoadFont(FontType type, const char *filename, ResourceManager *resourceManager, Decompressor *decompressor);
+private:
+ void tryLoadFont(const char *filename, ResourceManager *resourceManager, Decompressor *decompressor);
struct FontTypeHash {
Common::Hash<const char *> hash;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8a4539270c1..c195afade79 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -534,6 +534,14 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
return false;
break;
}
+ case kSceneOpAddFlagToDragItem: {
+ GameItem *item = engine->getScene()->getDragItem();
+ if (item) {
+ item->_flags |= 1;
+ // TODO: Also update position?
+ }
+ break;
+ }
case kSceneOpOpenInventoryZoom:
engine->getInventory()->setShowZoomBox(true);
engine->getInventory()->open();
@@ -568,6 +576,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
case kSceneOpHideInvButton:
static_cast<DgdsEngine *>(g_engine)->getScene()->removeInvButtonFromHotAreaList();
break;
+ case kSceneOpOpenGameOverMenu:
+ static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuGameOver);
+ break;
case kSceneOpOpenPlaySkipIntroMenu:
static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuSkipPlayIntro);
break;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index a238ec9429e..1c11ac1a29f 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -84,7 +84,7 @@ enum SceneOpCode {
kSceneOpHideInvButton = 10, // args: none.
kSceneOpEnableTrigger = 11, // args: trigger num
kSceneOpChangeSceneToStored = 12, // args: none. Change scene to stored number
- kSceneOp13 = 13, // args: none.
+ kSceneOpAddFlagToDragItem = 13, // args: none.
kSceneOpOpenInventoryZoom = 14, // args: none.
kSceneOpMoveItemsBetweenScenes = 15, // args: none.
kSceneOpShowClock = 16, // args: none. set some clock-related globals
@@ -95,7 +95,7 @@ enum SceneOpCode {
// From here on might be game-specific?
kSceneOp100 = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
- kSceneOp102 = 102, // args: none.
+ kSceneOpOpenGameOverMenu = 102, // args: none.
kSceneOp103 = 103, // args: none. Something about "boy am I tired"?
kSceneOp104 = 104, // args: none.
kSceneOp105 = 105, // args: none. Draw some number at 141, 56
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 4b8c3e126f2..540fa97609b 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -43,6 +43,8 @@
namespace Dgds {
+static const float MS_PER_FRAME = 16.667;
+
void GetPutRegion::reset() {
_area = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
_surf.reset();
@@ -85,6 +87,8 @@ Common::Error TTMEnviro::syncState(Common::Serializer &s) {
for (uint i = 0; i < ARRAYSIZE(_strings); i++)
s.syncString(_strings[i]);
+ // TODO: Save the font list.
+
return Common::kNoError;
}
@@ -288,7 +292,12 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x0090: // FREE FONT
if (seq._executed) // this is a one-shot op
break;
- error("TODO: Implement me: free font (current one)");
+ if (seq._currentFontId >= (int16)env._fonts.size()) {
+ warning("Request to free font not loaded %d", seq._currentFontId);
+ break;
+ }
+ env._fonts.remove_at(seq._currentFontId);
+ seq._currentFontId = 0;
break;
case 0x00B0:
// Does nothing?
@@ -311,7 +320,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x1020: // SET DELAY: i:int [0..n]
// TODO: Probably should do this accounting (as well as timeCut and dialogs)
// in game frames, not millis.
- _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * 16.667));
+ _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * MS_PER_FRAME));
break;
case 0x1030: // SET BRUSH: id:int [-1:n]
seq._brushNum = ivals[0];
@@ -365,7 +374,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
// TODO: do same time fix as for 0x1020
- _vm->adsInterpreter()->setScriptDelay((int)(sleep * 16.667));
+ _vm->adsInterpreter()->setScriptDelay((int)(sleep * MS_PER_FRAME));
break;
}
case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
@@ -487,13 +496,20 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa270:
case 0xa280:
case 0xa290: {
+ int16 fontno = seq._currentFontId;
+ if (fontno >= (int16)env._fonts.size()) {
+ warning("Trying to draw font no %d but only loaded %d", seq._currentFontId, env._fonts.size());
+ fontno = 0;
+ }
uint strnum = (op & 0x70) >> 4;
const Common::String &str = env._strings[strnum];
const FontManager *mgr = _vm->getFontMan();
- // TODO: Probably not this font?
- const Font *font = mgr->getFont(FontManager::kDefaultFont);
- // Note: ignore the y-height argument (ivals[3]) for now.
- font->drawString(&(_vm->_compositionBuffer), str, ivals[0], ivals[1], ivals[2], seq._drawColFG);
+ const Font *font = mgr->getFont(env._fonts[fontno]);
+ // Note: ignore the y-height argument (ivals[3]) for now. If width is 0, draw as much as we can.
+ int width = ivals[2];
+ if (width == 0)
+ width = SCREEN_WIDTH - ivals[0];
+ font->drawString(&(_vm->_compositionBuffer), str, ivals[0], ivals[1], width, seq._drawColFG);
break;
}
case 0xa510:
@@ -560,8 +576,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xf040: { // LOAD FONT: filename:str
if (seq._executed) // this is a one-shot op
break;
- //const FontManager *mgr = _vm->getFontMan();
- warning("TODO: Implement opcode 0xf040 load font %s", sval.c_str());
+ const FontManager *mgr = _vm->getFontMan();
+ env._fonts.push_back(mgr->fontTypeByName(sval));
+ seq._currentFontId = env._fonts.size() - 1;
break;
}
case 0xf050: { // LOAD PAL: filename:str
@@ -1029,27 +1046,36 @@ void ADSInterpreter::findEndOrInitOp() {
bool ADSInterpreter::logicOpResult(uint16 code, const TTMSeq *seq) {
switch (code) {
+ case 0x1010:
case 0x1310: // IF runtype 5, 2 params
- debug(10, "ADS: if runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if runtype 5 env %d seq %d", code, seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunType5;
+ case 0x1020:
case 0x1320: // IF not runtype 5, 2 params
- debug(10, "ADS: if not runtype 5 env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if not runtype 5 env %d seq %d", code, seq->_enviro, seq->_seqNum);
return seq->_runFlag != kRunType5;
+ case 0x1030:
case 0x1330: // IF_NOT_PLAYED, 2 params
- debug(10, "ADS: if not played env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if not played env %d seq %d", code, seq->_enviro, seq->_seqNum);
return !seq->_runPlayed;
+ case 0x1040:
case 0x1340: // IF_PLAYED, 2 params
- debug(10, "ADS: if played env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if played env %d seq %d", code, seq->_enviro, seq->_seqNum);
return seq->_runPlayed;
+ case 0x1050:
case 0x1350: // IF_FINISHED, 2 params
- debug(10, "ADS: if finished env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if finished env %d seq %d", code, seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunTypeFinished;
+ case 0x1060:
case 0x1360: // IF_NOT_RUNNING, 2 params
- debug(10, "ADS: if not running env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if not running env %d seq %d", code, seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunTypeStopped;
+ case 0x1070:
case 0x1370: // IF_RUNNING, 2 params
- debug(10, "ADS: if running env %d seq %d", seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: if running env %d seq %d", code, seq->_enviro, seq->_seqNum);
return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
+ case 0x1080:
+ case 0x1090:
case 0x1380: // IF_???????, 0 params
case 0x1390: // IF_???????, 0 params
warning("Unimplemented IF operation 0x%x", code);
@@ -1093,7 +1119,7 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr
if (code == 0x1420 || code == 0x1430) {
andor = code;
- debug(10, " ADS %s", code == 0x1420 ? "AND" : "AND");
+ debug(10, " ADS 0x%04x: %s", code, code == 0x1420 ? "AND" : "OR");
code = scr->readUint16LE();
// The next op should be another logic op
} else {
@@ -1109,9 +1135,11 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr
}
int16 ADSInterpreter::randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr) {
+ // Leaves the pointer at the same place it started
int argsize = numArgs(code) * 2;
if (argsize == 0)
error("Unexpected 0-arg ADS opcode 0x%04x inside random block", code);
+ // skip args before the random proportion
if (argsize > 2)
scr->seek(argsize - 2, SEEK_CUR);
int16 result = scr->readSint16LE();
@@ -1164,14 +1192,21 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
uint16 enviro, seqnum;
- debug(10, " ADSOP: 0x%04x", code);
-
switch (code) {
case 0x0001:
case 0x0005:
- //debug("ADS: init code 0x%04x", code);
+ debug(10, "ADS 0x%04x: init", code);
// "init". 0x0005 can be used for searching for next thing.
break;
+ case 0x1010: // unknown, 2 params
+ case 0x1020: // unknown, 2 params
+ case 0x1030: // unknown, 2 params
+ case 0x1040: // unknown, 2 params
+ case 0x1050: // unknown, 2 params
+ case 0x1060: // unknown, 2 params
+ case 0x1070: // unknown, 2 params
+ case 0x1080: // if current seq countdown??, 1 param
+ case 0x1090: // if ??? ???
case 0x1310: // IF runtype 5, 2 params
case 0x1320: // IF not runtype 5, 2 params
case 0x1330: // IF_NOT_PLAYED, 2 params
@@ -1183,16 +1218,17 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x1390: // IF_??????, 1 param (HOC+ only)
return handleLogicOp(code, scr);
case 0x1500: // ? IF ?, 0 params
- debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
- //sceneLogicOps();
+ //debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
+ debug(10, "ADS 0x%04x: skip to end if", code);
+ skipToEndIf();
_adsData->_hitBranchOp = true;
return true;
case 0x1510: // PLAY_SCENE? 0 params
- debug(10, "ADS: 0x%04x hit branch op true", code);
+ debug(10, "ADS 0x%04x: hit branch op true", code);
_adsData->_hitBranchOp = true;
return true;
case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
- debug(10, "ADS: 0x%04x hit branch op", code);
+ debug(10, "ADS 0x%04x: hit branch op", code);
_adsData->_hitBranchOp = true;
return false;
@@ -1201,8 +1237,8 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
int16 runCount = scr->readSint16LE();
- uint16 unk = scr->readUint16LE();
- debug(10, "ADS: add scene - env %d seq %d runCount %d unk %d", enviro, seqnum, runCount, unk);
+ uint16 unk = scr->readUint16LE(); // proportion
+ debug(10, "ADS 0x%04x: add scene - env %d seq %d runCount %d prop %d", code, enviro, seqnum, runCount, unk);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
if (!seq)
@@ -1216,9 +1252,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seq->_runFlag = kRunType1;
} else if (runCount < 0) {
// Negative run count sets the cut time
- seq->_timeCut = g_engine->getTotalPlayTime() + runCount;
- // TODO: Should this be *10 like delays?
- warning("TODO: check handling of negative runcount %d", runCount);
+ seq->_timeCut = g_engine->getTotalPlayTime() + (-runCount * MS_PER_FRAME);
seq->_runFlag = kRunTypeTimeLimited;
} else {
seq->_runFlag = kRunTypeMulti;
@@ -1227,49 +1261,52 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seq->_runPlayed++;
break;
}
- case 0x2010: { // STOP_SCENE, 3 params (ttmenv, ttmseq, ?)
+ case 0x2010: { // STOP_SCENE, 3 params (ttmenv, ttmseq, proportion)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug(10, "ADS: stop seq env %d seq %d unk %d", enviro, seqnum, unk);
+ debug(10, "ADS 0x2010: stop seq env %d seq %d prop %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
if (_currentTTMSeq)
_currentTTMSeq->_runFlag = kRunTypeStopped;
break;
}
- case 0x2015: { // SET RUNFLAG 5, 3 params (ttmenv, ttmseq, ?)
+ case 0x2015: { // SET RUNFLAG 5, 3 params (ttmenv, ttmseq, proportion)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug(10, "ADS: set runflag5 env %d seq %d unk %d", enviro, seqnum, unk);
+ debug(10, "ADS 0x2015: set runflag5 env %d seq %d prop %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
if (_currentTTMSeq)
_currentTTMSeq->_runFlag = kRunType5;
break;
}
- case 0x2020: { // RESET SEQ, 2 params (env, seq)
+ case 0x2020: { // RESET SEQ, 2 params (env, seq, proportion)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug(10, "ADS: reset scene env %d seq %d unk %d", enviro, seqnum, unk);
+ debug(10, "ADS 0x2020: reset scene env %d seq %d prop %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
if (_currentTTMSeq)
_currentTTMSeq->reset();
break;
}
- case 0x3020: // RANDOM_NOOP, 1 param (proportion)
- scr->readUint16LE();
+ case 0x3020: {// RANDOM_NOOP, 1 param (proportion)
+ uint16 unk = scr->readUint16LE();
+ debug(10, "ADS 0x3020: random noop? prop %d", unk);
return true;
-
+ }
case 0x3010: // RANDOM_START, 0 params
case 0x30FF: // RANDOM_END, 0 params
+ debug(10, "ADS 0x%04x: random %s", code, code == 0x3010 ? "start" : "end");
handleRandomOp(code, scr);
break;
case 0x4000: { // MOVE SEQ TO BACK
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
+ debug(10, "ADS 0x%04x: mov seq to back env %d seq %d", code, enviro, seqnum);
/*uint16 unk = */scr->readUint16LE();
// This is O(N) but the N is small and it's not called often.
TTMSeq seq;
@@ -1294,6 +1331,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
case 0x4010: { // MOVE SEQ TO FRONT
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
+ debug(10, "ADS 0x%04x: mov seq to front env %d seq %d", code, enviro, seqnum);
/*uint16 unk = */scr->readUint16LE();
// This is O(N) but the N is small and it's not called often.
TTMSeq seq;
@@ -1316,6 +1354,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
}
case 0xF000:
+ debug(10, "ADS 0x%04x: set state 2, current idx (%d)", code, _adsData->_runningSegmentIdx);
if (_adsData->_runningSegmentIdx != -1)
_adsData->_state[_adsData->_runningSegmentIdx] = 2;
return false;
@@ -1325,7 +1364,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
int16 idx = _adsData->_runningSegmentIdx;
if (segment >= 0)
idx = getArrIndexOfSegNum(segment);
- debug("ADS: set state 2, segment param %d (idx %d)", segment, idx);
+ debug(10, "ADS 0x%04x: set state 2, segment %d (idx %d)", code, segment, idx);
if (idx >= 0)
_adsData->_state[idx] = 2;
if (idx == _adsData->_runningSegmentIdx)
@@ -1334,27 +1373,40 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
return true;
}
+ case 0xF200: { // RUN_SCRIPT, 1 param
+ int16 segment = scr->readSint16LE();
+ int16 idx = getArrIndexOfSegNum(segment);
+ debug(10, "ADS 0x%04x: add 4 remove 8 to state seg %d idx %d", code, segment, idx);
+ if (segment >= 0) {
+ int state = (_adsData->_state[idx] & 8) | 4;
+ _adsData->_state[idx] = state;
+ }
+ return true;
+ }
+
+ case 0xF210: { // RUN_SCRIPT, 1 param
+ int16 segment = scr->readSint16LE();
+ int16 idx = getArrIndexOfSegNum(segment);
+ debug(10, "ADS 0x%04x: add 3 remove 8 to state seg %d idx %d", code, segment, idx);
+ if (segment >= 0) {
+ int state = (_adsData->_state[idx] & 8) | 3;
+ _adsData->_state[idx] = state;
+ }
+ return true;
+ }
+
case 0xffff: // END
+ debug(10, "ADS 0xFFF: end");
return false;
//// unknown / to-be-implemented
- case 0x1010: // unknown, 2 params
- case 0x1020: // unknown, 2 params
- case 0x1030: // unknown, 2 params
- case 0x1040: // unknown, 2 params
- case 0x1050: // unknown, 2 params
- case 0x1060: // unknown, 2 params
- case 0x1070: // unknown, 2 params
- case 0x1080: // if current seq countdown, 1 param
case 0x1420: // AND, 0 params
case 0x1430: // OR, 0 params
- case 0xF200: // RUN_SCRIPT, 1 param
- case 0xF210: // RUN_SCRIPT, 1 param
case 0xFF10:
case 0xFFF0: // END_IF, 0 params
default: {
int nops = numArgs(code);
- warning("ADS: Unimplemented opcode: 0x%04X (skip %d args)", code, nops);
+ warning("ADS 0x%04x: Unimplemented opcode: (skip %d args)", code, nops);
for (int i = 0; i < nops; i++)
scr->readUint16LE();
break;
@@ -1506,7 +1558,7 @@ bool ADSInterpreter::run() {
}
}
- if (rflag == kRunTypeTimeLimited && seq._timeCut > g_engine->getTotalPlayTime()) {
+ if (rflag == kRunTypeTimeLimited && seq._timeCut <= g_engine->getTotalPlayTime()) {
seq._runFlag = kRunTypeFinished;
}
}
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 47ebdc4434f..9b1162a08ab 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -28,6 +28,7 @@
#include "dgds/parser.h"
#include "dgds/scene.h"
+#include "dgds/font.h"
namespace Dgds {
@@ -55,6 +56,7 @@ class TTMEnviro : public ScriptParserData {
public:
TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
ARRAYCLEAR(_scriptPals);
+ _fonts.push_back(FontManager::kDefaultFont); // is this right?
}
Common::Error syncState(Common::Serializer &s);
@@ -66,6 +68,7 @@ public:
Common::Array<GetPutRegion> _getPuts;
int _scriptPals[6];
Common::String _strings[10];
+ Common::Array<FontManager::FontType> _fonts;
};
enum TTMRunType {
Commit: 87666a29ed6ce97710e43424d3eb22e70e5b9304
https://github.com/scummvm/scummvm/commit/87666a29ed6ce97710e43424d3eb22e70e5b9304
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add debug command to dump all frames of bmp
Changed paths:
engines/dgds/console.cpp
engines/dgds/console.h
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index f23a7ab6139..ec7646dca28 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -44,6 +44,7 @@ Console::Console(DgdsEngine *vm) : _vm(vm) {
registerCmd("filesearch", WRAP_METHOD(Console, cmdFileSearch));
registerCmd("filedump", WRAP_METHOD(Console, cmdFileDump));
registerCmd("imagedump", WRAP_METHOD(Console, cmdImageDump));
+ registerCmd("imagedumpall", WRAP_METHOD(Console, cmdImageDumpAll));
}
bool Console::cmdFileInfo(int argc, const char **argv) {
@@ -78,6 +79,7 @@ bool Console::cmdFileSearch(int argc, const char **argv) {
bool Console::cmdFileDump(int argc, const char **argv) {
if (argc < 2) {
debugPrintf("Usage: %s <file> [ignore patches] [unpack] [outputpath] [chunktype]\n", argv[0]);
+ debugPrintf(" eg: %s CLLIVING.ADH 0 1 clliving_unpack.adscript SCR:\n", argv[0]);
return true;
}
@@ -145,44 +147,27 @@ bool Console::cmdFileDump(int argc, const char **argv) {
return true;
}
-bool Console::cmdImageDump(int argc, const char **argv) {
-#ifdef USE_PNG
- if (argc < 3) {
- debugPrintf("Usage: %s <imagefilename> <frameno> [outputpath]\n", argv[0]);
- return true;
- }
-
- const char *fname = argv[1];
- int frameno = atoi(argv[2]);
-
- if (!_vm->getResourceManager()->hasResource(fname)) {
- debugPrintf("Resource %s not found\n", fname);
- return true;
- }
-
+bool Console::dumpImageFrame(const char *fname, int frameno, const char *outpath) {
Image img(_vm->getResourceManager(), _vm->getDecompressor());
-
int maxframe = img.frameCount(fname);
if (frameno > maxframe) {
debugPrintf("Image only has %d frames\n", maxframe);
- return true;
+ return false;
}
GamePalettes pal(_vm->getResourceManager(), _vm->getDecompressor());
- pal.loadPalette("DYNAMIX.PAL");
- pal.setPalette();
img.loadBitmap(fname);
int width = img.width(frameno);
int height = img.height(frameno);
if (!width || !height) {
debugPrintf("Image %s:%d not valid\n", fname, frameno);
- return true;
+ return false;
}
Common::DumpFile outf;
Common::String outfname = Common::String::format("%s-%d.png", fname, frameno);
- if (argc == 4) {
- Common::Path path(argv[3]);
+ if (outpath) {
+ Common::Path path(outpath);
path.joinInPlace(outfname);
outf.open(path);
} else {
@@ -190,7 +175,7 @@ bool Console::cmdImageDump(int argc, const char **argv) {
}
if (!outf.isOpen()) {
debugPrintf("Couldn't open %s\n", outfname.c_str());
- return true;
+ return false;
}
byte palbuf[768];
@@ -198,11 +183,64 @@ bool Console::cmdImageDump(int argc, const char **argv) {
::Image::writePNG(outf, *(img.getSurface(frameno)->surfacePtr()), palbuf);
outf.close();
debugPrintf("wrote %dx%d png to %s\n", width, height, outfname.c_str());
+ return true;
+}
+
+bool Console::cmdImageDumpAll(int argc, const char **argv) {
+#ifdef USE_PNG
+ if (argc < 2) {
+ debugPrintf("Usage: %s <imagefilename> [outputdir]\n", argv[0]);
+ debugPrintf(" eg: %s CLGAME2.BMP /tmp\n", argv[0]);
+ return true;
+ }
+
+ const char *fname = argv[1];
+ if (!_vm->getResourceManager()->hasResource(fname)) {
+ debugPrintf("Resource %s not found\n", fname);
+ return true;
+ }
+
+ Image img(_vm->getResourceManager(), _vm->getDecompressor());
+ int maxframe = img.frameCount(fname);
+ const char *outpath = (argc > 2 ? argv[2] : nullptr);
+
+ for (int i = 0; i < maxframe; i++) {
+ if (!dumpImageFrame(fname, i, outpath))
+ break;
+ }
+ return true;
#else
warning("dumpimage needs png support");
+ return true;
#endif // USE_PNG
+
+}
+
+bool Console::cmdImageDump(int argc, const char **argv) {
+#ifdef USE_PNG
+ if (argc < 3) {
+ debugPrintf("Usage: %s <imagefilename> <frameno> [outputdir]\n", argv[0]);
+ debugPrintf(" eg: %s CLGAME2.BMP 2 /tmp\n", argv[0]);
+ return true;
+ }
+
+ const char *fname = argv[1];
+ int frameno = atoi(argv[2]);
+
+ if (!_vm->getResourceManager()->hasResource(fname)) {
+ debugPrintf("Resource %s not found\n", fname);
+ return true;
+ }
+
+ const char *outpath = (argc > 3 ? argv[3] : nullptr);
+
+ dumpImageFrame(fname, frameno, outpath);
return true;
+#else
+ warning("dumpimage needs png support");
+ return true;
+#endif // USE_PNG
}
} // End of namespace Dgds
diff --git a/engines/dgds/console.h b/engines/dgds/console.h
index f3c75638082..a348beae811 100644
--- a/engines/dgds/console.h
+++ b/engines/dgds/console.h
@@ -38,6 +38,8 @@ private:
bool cmdFileInfo(int argc, const char **argv);
bool cmdFileSearch(int argc, const char **argv);
bool cmdFileDump(int argc, const char **argv);
+ bool dumpImageFrame(const char *fname, int frame, const char *outpath);
+ bool cmdImageDumpAll(int argc, const char **argv);
bool cmdImageDump(int argc, const char **argv);
DgdsEngine *_vm;
};
Commit: cd1aba710a1629e23f052092ba16cdebbfff225a
https://github.com/scummvm/scummvm/commit/cd1aba710a1629e23f052092ba16cdebbfff225a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix ADS while handling and improve debug messages
Changed paths:
engines/dgds/parser.cpp
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 8cc54c65e9d..56febd7ee6f 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -76,7 +76,7 @@ bool DgdsParser::parse(ParserData *data, const Common::String &filename) {
Common::HashMap<uint16, Common::String> DgdsParser::readTags(Common::SeekableReadStream *stream) {
Common::HashMap<uint16, Common::String> tags;
uint16 count = stream->readUint16LE();
- debug(" %u:", count);
+ debug(" %u tags:", count);
for (uint16 i = 0; i < count; i++) {
uint16 idx = stream->readUint16LE();
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index 540fa97609b..cd69f603cbb 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -521,7 +521,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa530:
// CHINA
// DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial simmetry? you can see this in the Dynamix logo star.
+ // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial symmetry?
+ // you can see this in the Dynamix logo star.
// FALL THROUGH
case 0xa500: {
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
@@ -647,7 +648,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
default:
if (count < 15)
- warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)", op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
+ warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)",
+ op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
else
warning("Unimplemented TTM opcode: 0x%04X (sval: %s)", op, sval.c_str());
break;
@@ -661,8 +663,9 @@ bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
if (scr->pos() >= scr->size())
return false;
- debug(10, "TTM: Run env %d seq %d frame %d (scr offset %d)", seq._enviro, seq._seqNum,
- seq._currentFrame, (int)scr->pos());
+ debug(10, "TTM: Run env %d seq %d (%s) frame %d (scr offset %d, %s)", seq._enviro, seq._seqNum,
+ env._tags[seq._seqNum].c_str(), seq._currentFrame, (int)scr->pos(),
+ seq._executed ? "already executed" : "first execution");
uint16 code = 0;
while (code != 0x0ff0 && scr->pos() < scr->size()) {
code = scr->readUint16LE();
@@ -833,6 +836,7 @@ bool ADSInterpreter::load(const Common::String &filename) {
for (const auto &file : _adsData->_scriptNames) {
_adsData->_scriptEnvs.resize(_adsData->_scriptEnvs.size() + 1);
+ debug(" load TTM %s to env %d", file.c_str(), _adsData->_scriptEnvs.size());
TTMEnviro &data = _adsData->_scriptEnvs.back();
data._enviro = _adsData->_scriptEnvs.size();
_ttmInterpreter->load(file, data);
@@ -876,12 +880,12 @@ static const uint16 ADS_SEQ_OPCODES[] = {
0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
};
-bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
+bool ADSInterpreter::updateSeqTimeAndFrame(const TTMEnviro *env, TTMSeq &seq) {
if (seq._timeInterval != 0) {
uint32 now = g_engine->getTotalPlayTime();
if (now < seq._timeNext) {
- debug(10, "env %d seq %d not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
- seq._seqNum, seq._currentFrame, now, seq._timeNext, seq._timeInterval);
+ debug(10, "env %d seq %d (%s) not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
+ seq._seqNum, env->_tags[seq._seqNum].c_str(), seq._currentFrame, now, seq._timeNext, seq._timeInterval);
return false;
}
seq._timeNext = now + seq._timeInterval;
@@ -889,12 +893,12 @@ bool ADSInterpreter::updateSeqTimeAndFrame(TTMSeq &seq) {
seq._executed = false;
if (seq._gotoFrame == -1) {
- debug(10, "env %d seq %d advance to frame %d->%d (start %d last %d)", seq._enviro,
- seq._seqNum, seq._currentFrame, seq._currentFrame + 1, seq._startFrame, seq._lastFrame);
+ debug(10, "env %d seq %d (%s) advance to frame %d->%d (start %d last %d)", seq._enviro, seq._seqNum,
+ env->_tags[seq._seqNum].c_str(), seq._currentFrame, seq._currentFrame + 1, seq._startFrame, seq._lastFrame);
seq._currentFrame++;
} else {
- debug(10, "env %d seq %d goto to frame %d->%d (start %d last %d)", seq._enviro,
- seq._seqNum, seq._currentFrame, seq._gotoFrame, seq._startFrame, seq._lastFrame);
+ debug(10, "env %d seq %d (%s) goto to frame %d->%d (start %d last %d)", seq._enviro, seq._seqNum,
+ env->_tags[seq._seqNum].c_str(), seq._currentFrame, seq._gotoFrame, seq._startFrame, seq._lastFrame);
seq._currentFrame = seq._gotoFrame;
seq._gotoFrame = -1;
}
@@ -984,14 +988,28 @@ bool ADSInterpreter::skipToEndIf() {
bool result = skipSceneLogicBranch();
if (result) {
uint16 op = scr->readUint16LE();
- if (op == 0x1500) {
+ if (op == 0x1500)
result = runUntilBranchOpOrEnd();
- }
// don't rewind - the calls to this should always return ptr+2
}
return result;
}
+bool ADSInterpreter::skipToEndWhile() {
+ Common::SeekableReadStream *scr = _adsData->scr;
+ while (scr->pos() < scr->size()) {
+ uint16 op = scr->readUint16LE();
+ // don't rewind - the calls to this should always return after the last op.
+ if (op == 0x1520)
+ return true;
+ else if (op == 0 || op == 0xffff)
+ return false;
+
+ scr->skip(numArgs(op) * 2);
+ }
+ return false;
+}
+
TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
for (auto & env : _adsData->_scriptEnvs) {
if (env._enviro == enviro)
@@ -1044,69 +1062,76 @@ void ADSInterpreter::findEndOrInitOp() {
}
}
-bool ADSInterpreter::logicOpResult(uint16 code, const TTMSeq *seq) {
+bool ADSInterpreter::logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq) {
+ const char *tag = env->_tags[seq->_seqNum].c_str();
+ int16 envNum = env->_enviro;
+ int16 seqNum = seq->_seqNum;
+ const char *optype = (code < 0x1300 ? "while" : "if");
switch (code) {
- case 0x1010:
+ case 0x1010: // WHILE runtype 5
case 0x1310: // IF runtype 5, 2 params
- debugN(10, "ADS 0x%04x: if runtype 5 env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s runtype 5 env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return seq->_runFlag == kRunType5;
- case 0x1020:
+ case 0x1020: // WHILE not runtype 5
case 0x1320: // IF not runtype 5, 2 params
- debugN(10, "ADS 0x%04x: if not runtype 5 env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s not runtype 5 env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return seq->_runFlag != kRunType5;
- case 0x1030:
+ case 0x1030: // WHILE NOT PLAYED
case 0x1330: // IF_NOT_PLAYED, 2 params
- debugN(10, "ADS 0x%04x: if not played env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s not played env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return !seq->_runPlayed;
- case 0x1040:
+ case 0x1040: // WHILE PLAYED
case 0x1340: // IF_PLAYED, 2 params
- debugN(10, "ADS 0x%04x: if played env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s played env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return seq->_runPlayed;
- case 0x1050:
+ case 0x1050: // WHILE FINISHED
case 0x1350: // IF_FINISHED, 2 params
- debugN(10, "ADS 0x%04x: if finished env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s finished env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return seq->_runFlag == kRunTypeFinished;
- case 0x1060:
+ case 0x1060: // WHILE NOT RUNNING
case 0x1360: // IF_NOT_RUNNING, 2 params
- debugN(10, "ADS 0x%04x: if not running env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s not running env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return seq->_runFlag == kRunTypeStopped;
- case 0x1070:
+ case 0x1070: // WHILE RUNNING
case 0x1370: // IF_RUNNING, 2 params
- debugN(10, "ADS 0x%04x: if running env %d seq %d", code, seq->_enviro, seq->_seqNum);
+ debugN(10, "ADS 0x%04x: %s running env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
case 0x1080:
case 0x1090:
case 0x1380: // IF_???????, 0 params
case 0x1390: // IF_???????, 0 params
- warning("Unimplemented IF operation 0x%x", code);
+ warning("Unimplemented IF/WHILE operation 0x%x", code);
return true;
default:
error("Not an ADS logic op: %04x, how did we get here?", code);
}
}
-bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr) {
+bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr) {
bool testval = true;
uint16 andor = 0x1420; // start with "true" AND..
+ int32 startPos = scr->pos() - 2;
while (scr->pos() < scr->size()) {
uint16 enviro;
uint16 seqnum;
TTMSeq *seq = nullptr;
+ TTMEnviro *env = nullptr;
if (code != 0x1380 && code != 0x1390) {
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
seq = findTTMSeq(enviro, seqnum);
+ env = findTTMEnviro(enviro);
if (!seq) {
warning("ADS if op referenced non-existant env %d seq %d", enviro, seqnum);
return false;
}
} else {
- // not actually enviro I think? for now just read it.
+ // TODO: not actually enviro I think? for now just read it.
enviro = scr->readUint16LE();
}
- bool logicResult = logicOpResult(code, seq);
+ bool logicResult = logicOpResult(code, env, seq);
if (andor == 0x1420) // AND
testval &= logicResult;
@@ -1114,6 +1139,7 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr
testval |= logicResult;
debug(10, " -> %s (overall %s)", logicResult ? "true" : "false", testval ? "true" : "false");
+ bool isWhile = code < 0x1300;
code = scr->readUint16LE();
@@ -1125,10 +1151,23 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr
} else {
// No AND or OR, next op is just what to do.
scr->seek(-2, SEEK_CUR);
- if (testval)
- return runUntilBranchOpOrEnd();
- else
- return skipToEndIf();
+ if (testval) {
+ if (isWhile) {
+ _adsData->_countdown[_adsData->_runningSegmentIdx]++;
+ _adsData->_charWhile[_adsData->_runningSegmentIdx] = startPos;
+ }
+ bool runResult = runUntilBranchOpOrEnd();
+ // WHILE (10x0) series always return false
+ return (!isWhile) && runResult;
+ } else {
+ if (isWhile) {
+ _adsData->_countdown[_adsData->_runningSegmentIdx] = 0;
+ _adsData->_charWhile[_adsData->_runningSegmentIdx] = 0;
+ return skipToEndWhile();
+ } else {
+ return skipToEndIf();
+ }
+ }
}
}
error("didn't return from ADS logic test");
@@ -1183,7 +1222,7 @@ void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr
break;
code = scr->readUint16LE();
} while (code != 0 && scr->pos() < scr->size());
- if (code)
+ if (code && code != 0x3020)
handleOperation(code, scr);
scr->seek(endpos, SEEK_SET);
@@ -1198,13 +1237,13 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug(10, "ADS 0x%04x: init", code);
// "init". 0x0005 can be used for searching for next thing.
break;
- case 0x1010: // unknown, 2 params
- case 0x1020: // unknown, 2 params
- case 0x1030: // unknown, 2 params
- case 0x1040: // unknown, 2 params
- case 0x1050: // unknown, 2 params
- case 0x1060: // unknown, 2 params
- case 0x1070: // unknown, 2 params
+ case 0x1010: // if unknown, 2 params
+ case 0x1020: // if unknown, 2 params
+ case 0x1030: // if unknown, 2 params
+ case 0x1040: // if unknown, 2 params
+ case 0x1050: // if unknown, 2 params
+ case 0x1060: // if unknown, 2 params
+ case 0x1070: // if unknown, 2 params
case 0x1080: // if current seq countdown??, 1 param
case 0x1090: // if ??? ???
case 0x1310: // IF runtype 5, 2 params
@@ -1223,12 +1262,12 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
skipToEndIf();
_adsData->_hitBranchOp = true;
return true;
- case 0x1510: // PLAY_SCENE? 0 params
- debug(10, "ADS 0x%04x: hit branch op true", code);
+ case 0x1510: // PLAY_SCENEENDIF? 0 params
+ debug(10, "ADS 0x%04x: hit branch op endif", code);
_adsData->_hitBranchOp = true;
return true;
- case 0x1520: // PLAY_SCENE_ENDIF?, 0 params
- debug(10, "ADS 0x%04x: hit branch op", code);
+ case 0x1520: // PLAY_SCENE_ENDWHILE?, 0 params
+ debug(10, "ADS 0x%04x: hit branch op endwhile", code);
_adsData->_hitBranchOp = true;
return false;
@@ -1238,12 +1277,15 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seqnum = scr->readUint16LE();
int16 runCount = scr->readSint16LE();
uint16 unk = scr->readUint16LE(); // proportion
- debug(10, "ADS 0x%04x: add scene - env %d seq %d runCount %d prop %d", code, enviro, seqnum, runCount, unk);
TTMSeq *seq = findTTMSeq(enviro, seqnum);
- if (!seq)
+ TTMEnviro *env = findTTMEnviro(enviro);
+ if (!seq || !env)
error("ADS invalid seq requested %d %d", enviro, seqnum);
+ debug(10, "ADS 0x%04x: add scene - env %d seq %d (%s) runCount %d prop %d", code,
+ enviro, seqnum, env->_tags[seqnum].c_str(), runCount, unk);
+
if (code == 0x2000)
seq->_currentFrame = seq->_startFrame;
@@ -1265,8 +1307,10 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug(10, "ADS 0x2010: stop seq env %d seq %d prop %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
+ const TTMEnviro *env = findTTMEnviro(enviro);
+ debug(10, "ADS 0x2010: stop seq env %d seq %d (%s) prop %d", enviro, seqnum,
+ env->_tags[seqnum].c_str(), unk);
if (_currentTTMSeq)
_currentTTMSeq->_runFlag = kRunTypeStopped;
break;
@@ -1275,8 +1319,10 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug(10, "ADS 0x2015: set runflag5 env %d seq %d prop %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
+ const TTMEnviro *env = findTTMEnviro(enviro);
+ debug(10, "ADS 0x2015: set runflag5 env %d seq %d (%s) prop %d", enviro, seqnum,
+ env->_tags[seqnum].c_str(), unk);
if (_currentTTMSeq)
_currentTTMSeq->_runFlag = kRunType5;
break;
@@ -1285,8 +1331,10 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
- debug(10, "ADS 0x2020: reset scene env %d seq %d prop %d", enviro, seqnum, unk);
_currentTTMSeq = findTTMSeq(enviro, seqnum);
+ const TTMEnviro *env = findTTMEnviro(enviro);
+ debug(10, "ADS 0x2020: reset scene env %d seq %d (%s) prop %d", enviro, seqnum,
+ env->_tags[seqnum].c_str(), unk);
if (_currentTTMSeq)
_currentTTMSeq->reset();
break;
@@ -1534,18 +1582,18 @@ bool ADSInterpreter::run() {
seq._selfLoop = true;
}
if (seq._runFlag != kRunType5)
- updateSeqTimeAndFrame(seq);
+ updateSeqTimeAndFrame(env, seq);
} else {
seq._gotoFrame = seq._startFrame;
if (seq._runFlag == kRunTypeMulti && seq._runCount != 0) {
- bool updated = updateSeqTimeAndFrame(seq);
+ bool updated = updateSeqTimeAndFrame(env, seq);
if (updated) {
seq._runCount--;
}
} else if (seq._runFlag == kRunTypeTimeLimited && seq._timeCut != 0) {
- updateSeqTimeAndFrame(seq);
+ updateSeqTimeAndFrame(env, seq);
} else {
- bool updated = updateSeqTimeAndFrame(seq);
+ bool updated = updateSeqTimeAndFrame(env, seq);
if (updated) {
seq._runFlag = kRunTypeFinished;
seq._timeInterval = 0;
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 9b1162a08ab..a3bd4c5e686 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -190,17 +190,18 @@ protected:
bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
bool handleLogicOp(uint16 code, Common::SeekableReadStream *scr);
- bool logicOpResult(uint16 code, const TTMSeq *seq);
+ bool logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq);
int16 randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr);
bool playScene();
bool skipToEndIf();
+ bool skipToEndWhile();
bool skipSceneLogicBranch();
TTMSeq *findTTMSeq(int16 enviro, int16 seq);
TTMEnviro *findTTMEnviro(int16 enviro);
bool runUntilBranchOpOrEnd();
void findUsedSequencesForSegment(int segno);
void findEndOrInitOp();
- bool updateSeqTimeAndFrame(TTMSeq &seq);
+ bool updateSeqTimeAndFrame(const TTMEnviro *env, TTMSeq &seq);
int getArrIndexOfSegNum(uint16 segnum);
DgdsEngine *_vm;
Commit: 2e408a73c34088cf033e4ed744fec8810cb0f256
https://github.com/scummvm/scummvm/commit/2e408a73c34088cf033e4ed744fec8810cb0f256
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix msvc build
Changed paths:
engines/dgds/inventory.cpp
engines/dgds/inventory.h
engines/dgds/scripts.cpp
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 2e55f97c971..b673ab4ea28 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -33,7 +33,7 @@ namespace Dgds {
Inventory::Inventory() : _isOpen(false), _prevPageBtn(nullptr), _nextPageBtn(nullptr),
_invClock(nullptr), _itemZoomBox(nullptr), _exitButton(nullptr), _clockSkipMinBtn(nullptr),
_itemArea(nullptr), _clockSkipHrBtn(nullptr), _dropBtn(nullptr), _highlightItemNo(-1),
- _itemOffset(0), _openedFromSceneNum(-1), _showZoomBox(false), _fullWidth(-1)
+ _itemOffset(0), _openedFromSceneNum(0), _showZoomBox(false), _fullWidth(-1)
{
}
@@ -54,11 +54,12 @@ void Inventory::open() {
void Inventory::close() {
if (!_isOpen)
return;
+ assert(_openedFromSceneNum != 0);
_isOpen = false;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
engine->changeScene(_openedFromSceneNum);
_showZoomBox = false;
- _openedFromSceneNum = -1;
+ _openedFromSceneNum = 0;
}
void Inventory::setRequestData(const REQFileData &data) {
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 225e9b9cd67..54116883296 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -31,7 +31,7 @@ class ManagedSurface;
namespace Dgds {
-class GameItem;
+struct GameItem;
class Inventory {
public:
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index cd69f603cbb..f674ad018fb 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -43,7 +43,7 @@
namespace Dgds {
-static const float MS_PER_FRAME = 16.667;
+static const float MS_PER_FRAME = 16.6667f;
void GetPutRegion::reset() {
_area = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
Commit: bbfd955b0e36a05079f920a4241b74f6d9416d21
https://github.com/scummvm/scummvm/commit/bbfd955b0e36a05079f920a4241b74f6d9416d21
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix dropping wire clips on electrical board
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/image.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 0f7b03baa91..b02b865bb79 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -204,7 +204,6 @@ void DgdsEngine::setMouseCursor(uint num) {
if ((int)num == _currentCursor)
return;
- // TODO: Get mouse cursors from _gdsScene for hotspot info??
const Common::Array<MouseCursor> &cursors = _gdsScene->getCursorList();
if (num >= cursors.size())
@@ -212,6 +211,7 @@ void DgdsEngine::setMouseCursor(uint num) {
uint16 hotX = cursors[num]._hotX;
uint16 hotY = cursors[num]._hotY;
+ _currentCursorHot = Common::Point(hotX, hotY);
/*
// Adjust mouse location so hot pixel is in the same place as before?
@@ -230,6 +230,10 @@ void DgdsEngine::setMouseCursor(uint num) {
_currentCursor = num;
}
+Common::Point DgdsEngine::getLastMouseMinusHot() const {
+ return _lastMouse - _currentCursorHot;
+}
+
void DgdsEngine::setShowClock(bool val) {
_clock.setVisibleScript(val);
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 9601fa290fe..192947f094b 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -110,6 +110,7 @@ private:
Common::RandomSource _random;
Common::Point _lastMouse; // originals start mouse at 0,0.
int _currentCursor;
+ Common::Point _currentCursorHot;
Clock _clock;
@@ -149,6 +150,7 @@ public:
bool justChangedScene2() const { return _justChangedScene2; }
Common::RandomSource &getRandom() { return _random; }
Common::Point getLastMouse() const { return _lastMouse; }
+ Common::Point getLastMouseMinusHot() const;
Clock &getClock() { return _clock; }
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index cfb6084498e..b167ea92fd0 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -640,22 +640,4 @@ Common::SharedPtr<Graphics::ManagedSurface> Image::getSurface(uint frameno) {
return _frames[frameno];
}
- // grayscale palette.
-/*
- for (uint i=0; i<256; i++) {
- palette[i*3+0] = 255-i;
- palette[i*3+1] = 255-i;
- palette[i*3+2] = 255-i;
- }
- */
-/*
- // Amiga grayscale palette.
- for (uint i=0; i<32; i++) {
- palette[i*3+0] = 255-i*8;
- palette[i*3+1] = 255-i*8;
- palette[i*3+2] = 255-i*8;
- }
- g_system->getPaletteManager()->setPalette(palette, 0, 256);
- */
-
} // End of namespace Dgds
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index c195afade79..0982481e4e4 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -119,6 +119,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpShowDlg: return "showdlg";
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
+ case kSceneOpAddFlagToDragItem: return "addFlagToDragItem";
case kSceneOpMoveItemsBetweenScenes: return "moveItemsBetweenScenes";
case kSceneOpOpenInventoryZoom: return "openInventoryZoom";
case kSceneOpShowClock: return "sceneOpShowClock";
@@ -439,7 +440,6 @@ void Scene::setDragItemOp(const Common::Array<uint16> &args) {
Common::Point lastMouse = engine->getLastMouse();
item.rect.x = lastMouse.x;
item.rect.y = lastMouse.y;
- // TODO: Update hot x/y here ?
engine->setMouseCursor(item._iconNum);
}
}
@@ -538,7 +538,10 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
GameItem *item = engine->getScene()->getDragItem();
if (item) {
item->_flags |= 1;
- // TODO: Also update position?
+ // TODO: Use hot x/y or just position?
+ Common::Point lastMouse = engine->getLastMouseMinusHot();
+ item->rect.x = lastMouse.x;
+ item->rect.y = lastMouse.y;
}
break;
}
@@ -1053,23 +1056,20 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
// and items, ignoring enable condition.
GameItem *dragItem = _dragItem;
- _dragItem = nullptr;
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const DragonGlobals *globals = static_cast<DragonGlobals *>(engine->getGameGlobals());
runOps(dragItem->onDragFinishedOps, globals->getGameMinsToAddOnDragFinished());
- engine->setMouseCursor(0);
-
// TODO: Both these loops are very similar.. there should be a cleaner way.
for (const auto &item : engine->getGDSScene()->getGameItems()) {
if (item._inSceneNum == _num && _isInRect(pt, item.rect)) {
- debug("Dragged item %d onto item %d", dragItem->_num, item._num);
+ debug("Dragged item %d onto item %d @ (%d, %d)", dragItem->_num, item._num, pt.x, pt.y);
for (const auto &i : engine->getGDSScene()->getObjInteractions2()) {
if (i._droppedItemNum == dragItem->_num && i._targetItemNum == item._num) {
- debug(" --> exec item %d drag ops", i.opList.size());
+ debug(" --> exec %d drag ops for item %d", i.opList.size(), item._num);
if (!runOps(i.opList, globals->getGameMinsToAddOnObjInteraction()))
return;
break;
@@ -1086,10 +1086,10 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
debug("Item %d dropped on inventory.", dragItem->_num);
dragItem->_inSceneNum = 2;
} else {
- debug("Dragged item %d onto area %d", dragItem->_num, area._num);
+ debug("Dragged item %d onto area %d @ (%d, %d)", dragItem->_num, area._num, pt.x, pt.y);
for (const auto &i : engine->getScene()->getObjInteractions1()) {
if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area._num) {
- debug(" --> exec area %d drag ops", i.opList.size());
+ debug(" --> exec %d drag ops for area %d", i.opList.size(), area._num);
if (!runOps(i.opList, globals->getGameMinsToAddOnObjInteraction()))
return;
break;
@@ -1097,6 +1097,9 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
}
}
}
+
+ engine->setMouseCursor(0);
+ _dragItem = nullptr;
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 1c11ac1a29f..3155ce5f97a 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -127,9 +127,6 @@ struct GameItem : public HotArea {
struct MouseCursor {
uint16 _hotX;
uint16 _hotY;
- uint16 _iconNum;
- // pointer to cursor image
- //Common::SharedPtr<Image> _img;
Common::String dump(const Common::String &indent) const;
};
Commit: 42481c5684631e2621df2d3735cb3dfa7df6b54e
https://github.com/scummvm/scummvm/commit/42481c5684631e2621df2d3735cb3dfa7df6b54e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Mark most detection entries as unstable
Changed paths:
engines/dgds/detection_tables.h
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index 112a974abc5..43522c3da0b 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -49,7 +49,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -64,7 +64,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformAmiga,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -79,7 +79,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformMacintosh,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -94,7 +94,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -109,7 +109,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformMacintosh,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -124,7 +124,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -139,7 +139,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -154,7 +154,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -169,7 +169,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformMacintosh,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
@@ -183,7 +183,7 @@ static const ADGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformDOS,
- ADGF_DEMO,
+ ADGF_DEMO | ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
Commit: 15f8a90b31cbdeecece71d610f54c7d4b8f31311
https://github.com/scummvm/scummvm/commit/15f8a90b31cbdeecece71d610f54c7d4b8f31311
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactor to split into smaller files
Split TTM and ADS logic into their own files, and separate palette management
from image loading.
Also refactor scene types a bit to be more objecty.
Changed paths:
A engines/dgds/ads.cpp
A engines/dgds/ads.h
A engines/dgds/game_palettes.cpp
A engines/dgds/game_palettes.h
A engines/dgds/ttm.cpp
A engines/dgds/ttm.h
engines/dgds/console.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/includes.h
engines/dgds/inventory.cpp
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/module.mk
engines/dgds/parser.cpp
engines/dgds/parser.h
engines/dgds/resource.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.cpp
engines/dgds/scripts.h
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
new file mode 100644
index 00000000000..d9da92d138d
--- /dev/null
+++ b/engines/dgds/ads.cpp
@@ -0,0 +1,981 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dgds/ads.h"
+
+namespace Dgds {
+
+
+Common::Error ADSData::syncState(Common::Serializer &s) {
+ uint16 arrSize = ARRAYSIZE(_state);
+ s.syncAsUint16LE(arrSize);
+ if (arrSize != ARRAYSIZE(_state))
+ error("Expected fixed size state array");
+ for (uint i = 0; i < arrSize; i++)
+ s.syncAsSint16LE(_state[i]);
+
+ uint16 nenvs = _scriptEnvs.size();
+ s.syncAsUint16LE(nenvs);
+ // This should be the same on load as the data comes from the ADS/TTM files.
+ if (nenvs != _scriptEnvs.size())
+ error("Unexpected number of script envs (%d in save vs %d in ADS)", nenvs, _scriptEnvs.size());
+
+ for (auto &env : _scriptEnvs)
+ env.syncState(s);
+
+ uint16 nseqs = _ttmSeqs.size();
+ s.syncAsUint16LE(nseqs);
+ if (nseqs != _ttmSeqs.size())
+ error("Unexpected number of ttm seqeunces (%d in save vs %d in ADS)", nseqs, _ttmSeqs.size());
+
+ for (auto &seq : _ttmSeqs)
+ seq.syncState(s);
+
+ return Common::kNoError;
+}
+
+
+ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _currentTTMSeq(nullptr), _adsData(nullptr) {
+ _ttmInterpreter = new TTMInterpreter(_vm);
+}
+
+ADSInterpreter::~ADSInterpreter() {
+ delete _ttmInterpreter;
+ _ttmInterpreter = nullptr;
+ for (auto &data : _adsTexts)
+ delete data._value.scr;
+}
+
+bool ADSInterpreter::load(const Common::String &filename) {
+ // Don't clear current _adsData, we reset that below.
+ _currentTTMSeq = nullptr;
+
+ // For high detail, replace extension ADS with ADH. Low detail is ADL.
+ Common::String detailfile = filename.substr(0, filename.size() - 1);
+ if (_vm->getDetailLevel() == kDgdsDetailLow)
+ detailfile += "L";
+ else
+ detailfile += "H";
+
+ if (!_vm->getResourceManager()->hasResource(detailfile))
+ detailfile = filename;
+
+ debug("ADSInterpreter: load %s", detailfile.c_str());
+ /* FIXME: quick hack - never reuse data.
+ if (_adsTexts.contains(detailfile)) {
+ _adsData = &(_adsTexts.getVal(detailfile));
+ return true;
+ }*/
+
+ _adsTexts.setVal(detailfile, ADSData());
+ _adsData = &(_adsTexts.getVal(detailfile));
+
+ ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
+ dgds.parse(_adsData, detailfile);
+
+ for (const auto &file : _adsData->_scriptNames) {
+ _adsData->_scriptEnvs.resize(_adsData->_scriptEnvs.size() + 1);
+ debug(" load TTM %s to env %d", file.c_str(), _adsData->_scriptEnvs.size());
+ TTMEnviro &data = _adsData->_scriptEnvs.back();
+ data._enviro = _adsData->_scriptEnvs.size();
+ _ttmInterpreter->load(file, data);
+ _ttmInterpreter->findAndAddSequences(data, _adsData->_ttmSeqs);
+ }
+
+ _adsData->scr->seek(0);
+
+ uint16 opcode = 0;
+ int segcount = 0;
+ findUsedSequencesForSegment(0);
+ _adsData->_segments[0] = 0;
+ opcode = _adsData->scr->readUint16LE();
+ while (_adsData->scr->pos() < _adsData->scr->size()) {
+ if (opcode == 0xffff) {
+ segcount++;
+ _adsData->_segments[segcount] = _adsData->scr->pos();
+ findUsedSequencesForSegment(segcount);
+ } else {
+ _adsData->scr->skip(numArgs(opcode) * 2);
+ }
+ opcode = _adsData->scr->readUint16LE();
+ }
+
+ for (uint i = segcount + 1; i < ARRAYSIZE(_adsData->_segments); i++)
+ _adsData->_segments[i] = -1;
+
+ _adsData->_maxSegments = segcount + 1;
+ _adsData->_filename = filename;
+
+ for (uint i = 0; i < ARRAYSIZE(_adsData->_state); i++)
+ _adsData->_state[i] = 8;
+ for (auto &seq : _adsData->_ttmSeqs)
+ seq.reset();
+
+ return true;
+}
+
+static const uint16 ADS_SEQ_OPCODES[] = {
+ 0x2000, 0x2005, 0x2010, 0x2015, 0x4000, 0x4010, 0x1330,
+ 0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
+};
+
+bool ADSInterpreter::updateSeqTimeAndFrame(const TTMEnviro *env, TTMSeq &seq) {
+ if (seq._timeInterval != 0) {
+ uint32 now = g_engine->getTotalPlayTime();
+ if (now < seq._timeNext) {
+ debug(10, "env %d seq %d (%s) not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
+ seq._seqNum, env->_tags[seq._seqNum].c_str(), seq._currentFrame, now, seq._timeNext, seq._timeInterval);
+ return false;
+ }
+ seq._timeNext = now + seq._timeInterval;
+ }
+
+ seq._executed = false;
+ if (seq._gotoFrame == -1) {
+ debug(10, "env %d seq %d (%s) advance to frame %d->%d (start %d last %d)", seq._enviro, seq._seqNum,
+ env->_tags[seq._seqNum].c_str(), seq._currentFrame, seq._currentFrame + 1, seq._startFrame, seq._lastFrame);
+ seq._currentFrame++;
+ } else {
+ debug(10, "env %d seq %d (%s) goto to frame %d->%d (start %d last %d)", seq._enviro, seq._seqNum,
+ env->_tags[seq._seqNum].c_str(), seq._currentFrame, seq._gotoFrame, seq._startFrame, seq._lastFrame);
+ seq._currentFrame = seq._gotoFrame;
+ seq._gotoFrame = -1;
+ }
+
+ return true;
+}
+
+void ADSInterpreter::findUsedSequencesForSegment(int segno) {
+ _adsData->_usedSeqs[segno].clear();
+ int64 startoff = _adsData->scr->pos();
+ uint16 opcode = 0;
+ // Skip the segment number.
+ _adsData->scr->readUint16LE();
+ while (opcode != 0xffff && _adsData->scr->pos() < _adsData->scr->size()) {
+ opcode = _adsData->scr->readUint16LE();
+ for (uint16 o : ADS_SEQ_OPCODES) {
+ if (opcode == o) {
+ int16 envno = _adsData->scr->readSint16LE();
+ int16 seqno = _adsData->scr->readSint16LE();
+ TTMSeq *seq = findTTMSeq(envno, seqno);
+ if (!seq) {
+ warning("ADS opcode %04x at offset %d references unknown seq %d %d",
+ opcode, (int)_adsData->scr->pos(), envno, seqno);
+ } else {
+ bool already_added = false;
+ for (const TTMSeq *s : _adsData->_usedSeqs[segno]) {
+ if (s == seq) {
+ already_added = true;
+ break;
+ }
+ }
+ if (!already_added)
+ _adsData->_usedSeqs[segno].push_back(seq);
+ }
+ // Rewind as we will go forward again outside this loop.
+ _adsData->scr->seek(-4, SEEK_CUR);
+ break;
+ }
+ }
+ _adsData->scr->skip(numArgs(opcode) * 2);
+ }
+ _adsData->scr->seek(startoff);
+}
+
+
+void ADSInterpreter::unload() {
+ _adsData = nullptr;
+ _currentTTMSeq = nullptr;
+ _adsTexts.clear();
+}
+
+bool ADSInterpreter::playScene() {
+ if (!_currentTTMSeq)
+ return false;
+
+ TTMEnviro *env = findTTMEnviro(_currentTTMSeq->_enviro);
+ if (!env)
+ error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
+
+ _adsData->_gotoTarget = -1;
+ return _ttmInterpreter->run(*env, *_currentTTMSeq);
+}
+
+bool ADSInterpreter::skipSceneLogicBranch() {
+ Common::SeekableReadStream *scr = _adsData->scr;
+ bool result = true;
+ while (scr->pos() < scr->size()) {
+ uint16 op = scr->readUint16LE();
+ if (op == 0x1510 || op == 0x1500) {
+ scr->seek(-2, SEEK_CUR);
+ return true;
+ } else if (op == 0 || op == 0xffff) {
+ // end of segment
+ return false;
+ } else if ((op & 0xff0f) == 0x1300) {
+ // a 0x13x0 logic op
+ result = handleOperation(op, scr);
+ } else {
+ scr->skip(numArgs(op) * 2);
+ }
+ }
+ return result && scr->pos() < scr->size();
+}
+
+bool ADSInterpreter::skipToEndIf() {
+ Common::SeekableReadStream *scr = _adsData->scr;
+ bool result = skipSceneLogicBranch();
+ if (result) {
+ uint16 op = scr->readUint16LE();
+ if (op == 0x1500)
+ result = runUntilBranchOpOrEnd();
+ // don't rewind - the calls to this should always return ptr+2
+ }
+ return result;
+}
+
+bool ADSInterpreter::skipToEndWhile() {
+ Common::SeekableReadStream *scr = _adsData->scr;
+ while (scr->pos() < scr->size()) {
+ uint16 op = scr->readUint16LE();
+ // don't rewind - the calls to this should always return after the last op.
+ if (op == 0x1520)
+ return true;
+ else if (op == 0 || op == 0xffff)
+ return false;
+
+ scr->skip(numArgs(op) * 2);
+ }
+ return false;
+}
+
+TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
+ for (auto & env : _adsData->_scriptEnvs) {
+ if (env._enviro == enviro)
+ return &env;
+ }
+ return nullptr;
+}
+
+TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seqno) {
+ for (auto &seq : _adsData->_ttmSeqs) {
+ if (seq._enviro == enviro && seq._seqNum == seqno)
+ return &seq;
+ }
+ return nullptr;
+}
+
+void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
+ int idx = getArrIndexOfSegNum(seg);
+ if (idx >= 0) {
+ _adsData->_charWhile[idx] = 0;
+ _adsData->_state[idx] = (_adsData->_state[idx] & 8) | val;
+ }
+}
+
+
+void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
+ int idx = getArrIndexOfSegNum(seg);
+ if (idx >= 0) {
+ _adsData->_charWhile[idx] = 0;
+ if (_adsData->_state[idx] != 8)
+ _adsData->_state[idx] = val;
+ }
+}
+
+void ADSInterpreter::findEndOrInitOp() {
+ Common::SeekableReadStream *scr = _adsData->scr;
+ int32 startoff = scr->pos();
+ while (scr->pos() < scr->size()) {
+ uint16 opcode = scr->readUint16LE();
+ // on FFFF return the original offset
+ if (opcode == 0xffff) {
+ scr->seek(startoff);
+ return;
+ }
+ // on 5 (init) return the next offset (don't rewind)
+ if (opcode == 0x0005)
+ return;
+ // everything else just go forward.
+ scr->skip(numArgs(opcode) * 2);
+ }
+}
+
+bool ADSInterpreter::logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq) {
+ const char *tag = env->_tags[seq->_seqNum].c_str();
+ int16 envNum = env->_enviro;
+ int16 seqNum = seq->_seqNum;
+ const char *optype = (code < 0x1300 ? "while" : "if");
+ switch (code) {
+ case 0x1010: // WHILE runtype 5
+ case 0x1310: // IF runtype 5, 2 params
+ debugN(10, "ADS 0x%04x: %s runtype 5 env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return seq->_runFlag == kRunType5;
+ case 0x1020: // WHILE not runtype 5
+ case 0x1320: // IF not runtype 5, 2 params
+ debugN(10, "ADS 0x%04x: %s not runtype 5 env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return seq->_runFlag != kRunType5;
+ case 0x1030: // WHILE NOT PLAYED
+ case 0x1330: // IF_NOT_PLAYED, 2 params
+ debugN(10, "ADS 0x%04x: %s not played env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return !seq->_runPlayed;
+ case 0x1040: // WHILE PLAYED
+ case 0x1340: // IF_PLAYED, 2 params
+ debugN(10, "ADS 0x%04x: %s played env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return seq->_runPlayed;
+ case 0x1050: // WHILE FINISHED
+ case 0x1350: // IF_FINISHED, 2 params
+ debugN(10, "ADS 0x%04x: %s finished env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return seq->_runFlag == kRunTypeFinished;
+ case 0x1060: // WHILE NOT RUNNING
+ case 0x1360: // IF_NOT_RUNNING, 2 params
+ debugN(10, "ADS 0x%04x: %s not running env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return seq->_runFlag == kRunTypeStopped;
+ case 0x1070: // WHILE RUNNING
+ case 0x1370: // IF_RUNNING, 2 params
+ debugN(10, "ADS 0x%04x: %s running env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
+ return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
+ case 0x1080:
+ case 0x1090:
+ case 0x1380: // IF_???????, 0 params
+ case 0x1390: // IF_???????, 0 params
+ warning("Unimplemented IF/WHILE operation 0x%x", code);
+ return true;
+ default:
+ error("Not an ADS logic op: %04x, how did we get here?", code);
+ }
+}
+
+bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr) {
+ bool testval = true;
+ uint16 andor = 0x1420; // start with "true" AND..
+ int32 startPos = scr->pos() - 2;
+ while (scr->pos() < scr->size()) {
+ uint16 enviro;
+ uint16 seqnum;
+ TTMSeq *seq = nullptr;
+ TTMEnviro *env = nullptr;
+
+ if (code != 0x1380 && code != 0x1390) {
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ seq = findTTMSeq(enviro, seqnum);
+ env = findTTMEnviro(enviro);
+ if (!seq) {
+ warning("ADS if op referenced non-existant env %d seq %d", enviro, seqnum);
+ return false;
+ }
+ } else {
+ // TODO: not actually enviro I think? for now just read it.
+ enviro = scr->readUint16LE();
+ }
+
+ bool logicResult = logicOpResult(code, env, seq);
+
+ if (andor == 0x1420) // AND
+ testval &= logicResult;
+ else // OR
+ testval |= logicResult;
+
+ debug(10, " -> %s (overall %s)", logicResult ? "true" : "false", testval ? "true" : "false");
+ bool isWhile = code < 0x1300;
+
+ code = scr->readUint16LE();
+
+ if (code == 0x1420 || code == 0x1430) {
+ andor = code;
+ debug(10, " ADS 0x%04x: %s", code, code == 0x1420 ? "AND" : "OR");
+ code = scr->readUint16LE();
+ // The next op should be another logic op
+ } else {
+ // No AND or OR, next op is just what to do.
+ scr->seek(-2, SEEK_CUR);
+ if (testval) {
+ if (isWhile) {
+ _adsData->_countdown[_adsData->_runningSegmentIdx]++;
+ _adsData->_charWhile[_adsData->_runningSegmentIdx] = startPos;
+ }
+ bool runResult = runUntilBranchOpOrEnd();
+ // WHILE (10x0) series always return false
+ return (!isWhile) && runResult;
+ } else {
+ if (isWhile) {
+ _adsData->_countdown[_adsData->_runningSegmentIdx] = 0;
+ _adsData->_charWhile[_adsData->_runningSegmentIdx] = 0;
+ return skipToEndWhile();
+ } else {
+ return skipToEndIf();
+ }
+ }
+ }
+ }
+ error("didn't return from ADS logic test");
+}
+
+int16 ADSInterpreter::randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr) {
+ // Leaves the pointer at the same place it started
+ int argsize = numArgs(code) * 2;
+ if (argsize == 0)
+ error("Unexpected 0-arg ADS opcode 0x%04x inside random block", code);
+ // skip args before the random proportion
+ if (argsize > 2)
+ scr->seek(argsize - 2, SEEK_CUR);
+ int16 result = scr->readSint16LE();
+ scr->seek(-argsize, SEEK_CUR);
+ return result;
+}
+
+void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr) {
+ int16 max = 0;
+ int64 startpos = scr->pos();
+ // Collect the random proportions
+ code = scr->readUint16LE();
+ while (code != 0 && code != 0x30ff && scr->pos() < scr->size()) {
+ int16 val = randomOpGetProportion(code, scr);
+ // leaves pointer at beginning of next op
+ max += val;
+ scr->skip(numArgs(code) * 2);
+ if (scr->pos() >= scr->size())
+ break;
+ code = scr->readUint16LE();
+ }
+ if (!max)
+ return;
+
+ int64 endpos = scr->pos();
+
+ int16 randval = _vm->getRandom().getRandomNumber(max - 1) + 1; // Random from 1-max.
+ scr->seek(startpos, SEEK_SET);
+
+ // Now find the random bit to jump to
+ code = scr->readUint16LE();
+ do {
+ int16 val = randomOpGetProportion(code, scr);
+ randval -= val;
+ if (randval < 1) {
+ // This is the opcode we want to execute
+ break;
+ }
+ scr->skip(numArgs(code) * 2);
+ if (scr->pos() >= scr->size())
+ break;
+ code = scr->readUint16LE();
+ } while (code != 0 && scr->pos() < scr->size());
+ if (code && code != 0x3020)
+ handleOperation(code, scr);
+
+ scr->seek(endpos, SEEK_SET);
+}
+
+bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
+ uint16 enviro, seqnum;
+
+ switch (code) {
+ case 0x0001:
+ case 0x0005:
+ debug(10, "ADS 0x%04x: init", code);
+ // "init". 0x0005 can be used for searching for next thing.
+ break;
+ case 0x1010: // if unknown, 2 params
+ case 0x1020: // if unknown, 2 params
+ case 0x1030: // if unknown, 2 params
+ case 0x1040: // if unknown, 2 params
+ case 0x1050: // if unknown, 2 params
+ case 0x1060: // if unknown, 2 params
+ case 0x1070: // if unknown, 2 params
+ case 0x1080: // if current seq countdown??, 1 param
+ case 0x1090: // if ??? ???
+ case 0x1310: // IF runtype 5, 2 params
+ case 0x1320: // IF not runtype 5, 2 params
+ case 0x1330: // IF_NOT_PLAYED, 2 params
+ case 0x1340: // IF_PLAYED, 2 params
+ case 0x1350: // IF_FINISHED, 2 params
+ case 0x1360: // IF_NOT_RUNNING, 2 params
+ case 0x1370: // IF_RUNNING, 2 params
+ case 0x1380: // IF_??????, 1 param (HOC+ only)
+ case 0x1390: // IF_??????, 1 param (HOC+ only)
+ return handleLogicOp(code, scr);
+ case 0x1500: // ? IF ?, 0 params
+ //debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
+ debug(10, "ADS 0x%04x: skip to end if", code);
+ skipToEndIf();
+ _adsData->_hitBranchOp = true;
+ return true;
+ case 0x1510: // PLAY_SCENEENDIF? 0 params
+ debug(10, "ADS 0x%04x: hit branch op endif", code);
+ _adsData->_hitBranchOp = true;
+ return true;
+ case 0x1520: // PLAY_SCENE_ENDWHILE?, 0 params
+ debug(10, "ADS 0x%04x: hit branch op endwhile", code);
+ _adsData->_hitBranchOp = true;
+ return false;
+
+ case 0x2000:
+ case 0x2005: { // ADD sequence
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ int16 runCount = scr->readSint16LE();
+ uint16 unk = scr->readUint16LE(); // proportion
+
+ TTMSeq *seq = findTTMSeq(enviro, seqnum);
+ TTMEnviro *env = findTTMEnviro(enviro);
+ if (!seq || !env)
+ error("ADS invalid seq requested %d %d", enviro, seqnum);
+
+ debug(10, "ADS 0x%04x: add scene - env %d seq %d (%s) runCount %d prop %d", code,
+ enviro, seqnum, env->_tags[seqnum].c_str(), runCount, unk);
+
+ if (code == 0x2000)
+ seq->_currentFrame = seq->_startFrame;
+
+ _currentTTMSeq = seq;
+ if (runCount == 0) {
+ seq->_runFlag = kRunType1;
+ } else if (runCount < 0) {
+ // Negative run count sets the cut time
+ seq->_timeCut = g_engine->getTotalPlayTime() + (-runCount * MS_PER_FRAME);
+ seq->_runFlag = kRunTypeTimeLimited;
+ } else {
+ seq->_runFlag = kRunTypeMulti;
+ seq->_runCount = runCount - 1;
+ }
+ seq->_runPlayed++;
+ break;
+ }
+ case 0x2010: { // STOP_SCENE, 3 params (ttmenv, ttmseq, proportion)
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ _currentTTMSeq = findTTMSeq(enviro, seqnum);
+ const TTMEnviro *env = findTTMEnviro(enviro);
+ debug(10, "ADS 0x2010: stop seq env %d seq %d (%s) prop %d", enviro, seqnum,
+ env->_tags[seqnum].c_str(), unk);
+ if (_currentTTMSeq)
+ _currentTTMSeq->_runFlag = kRunTypeStopped;
+ break;
+ }
+ case 0x2015: { // SET RUNFLAG 5, 3 params (ttmenv, ttmseq, proportion)
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ _currentTTMSeq = findTTMSeq(enviro, seqnum);
+ const TTMEnviro *env = findTTMEnviro(enviro);
+ debug(10, "ADS 0x2015: set runflag5 env %d seq %d (%s) prop %d", enviro, seqnum,
+ env->_tags[seqnum].c_str(), unk);
+ if (_currentTTMSeq)
+ _currentTTMSeq->_runFlag = kRunType5;
+ break;
+ }
+ case 0x2020: { // RESET SEQ, 2 params (env, seq, proportion)
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ uint16 unk = scr->readUint16LE();
+ _currentTTMSeq = findTTMSeq(enviro, seqnum);
+ const TTMEnviro *env = findTTMEnviro(enviro);
+ debug(10, "ADS 0x2020: reset scene env %d seq %d (%s) prop %d", enviro, seqnum,
+ env->_tags[seqnum].c_str(), unk);
+ if (_currentTTMSeq)
+ _currentTTMSeq->reset();
+ break;
+ }
+
+ case 0x3020: {// RANDOM_NOOP, 1 param (proportion)
+ uint16 unk = scr->readUint16LE();
+ debug(10, "ADS 0x3020: random noop? prop %d", unk);
+ return true;
+ }
+ case 0x3010: // RANDOM_START, 0 params
+ case 0x30FF: // RANDOM_END, 0 params
+ debug(10, "ADS 0x%04x: random %s", code, code == 0x3010 ? "start" : "end");
+ handleRandomOp(code, scr);
+ break;
+
+ case 0x4000: { // MOVE SEQ TO BACK
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ debug(10, "ADS 0x%04x: mov seq to back env %d seq %d", code, enviro, seqnum);
+ /*uint16 unk = */scr->readUint16LE();
+ // This is O(N) but the N is small and it's not called often.
+ TTMSeq seq;
+ bool success = false;
+ for (uint i = 0; i < _adsData->_ttmSeqs.size(); i++) {
+ if (_adsData->_ttmSeqs[i]._enviro == enviro && _adsData->_ttmSeqs[i]._seqNum == seqnum) {
+ seq = _adsData->_ttmSeqs[i];
+ _adsData->_ttmSeqs.remove_at(i);
+ success = true;
+ break;
+ }
+ }
+
+ if (success)
+ _adsData->_ttmSeqs.push_back(seq);
+ else
+ warning("ADS: 0x4000 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
+
+ break;
+ }
+
+ case 0x4010: { // MOVE SEQ TO FRONT
+ enviro = scr->readUint16LE();
+ seqnum = scr->readUint16LE();
+ debug(10, "ADS 0x%04x: mov seq to front env %d seq %d", code, enviro, seqnum);
+ /*uint16 unk = */scr->readUint16LE();
+ // This is O(N) but the N is small and it's not called often.
+ TTMSeq seq;
+ bool success = false;
+ for (uint i = 0; i < _adsData->_ttmSeqs.size(); i++) {
+ if (_adsData->_ttmSeqs[i]._enviro == enviro && _adsData->_ttmSeqs[i]._seqNum == seqnum) {
+ seq = _adsData->_ttmSeqs[i];
+ _adsData->_ttmSeqs.remove_at(i);
+ success = true;
+ break;
+ }
+ }
+
+ if (success)
+ _adsData->_ttmSeqs.insert_at(0, seq);
+ else
+ warning("ADS: 0x4010 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
+
+ break;
+ }
+
+ case 0xF000:
+ debug(10, "ADS 0x%04x: set state 2, current idx (%d)", code, _adsData->_runningSegmentIdx);
+ if (_adsData->_runningSegmentIdx != -1)
+ _adsData->_state[_adsData->_runningSegmentIdx] = 2;
+ return false;
+
+ case 0xF010: {// FADE_OUT, 1 param
+ int16 segment = scr->readSint16LE();
+ int16 idx = _adsData->_runningSegmentIdx;
+ if (segment >= 0)
+ idx = getArrIndexOfSegNum(segment);
+ debug(10, "ADS 0x%04x: set state 2, segment %d (idx %d)", code, segment, idx);
+ if (idx >= 0)
+ _adsData->_state[idx] = 2;
+ if (idx == _adsData->_runningSegmentIdx)
+ return false;
+ else
+ return true;
+ }
+
+ case 0xF200: { // RUN_SCRIPT, 1 param
+ int16 segment = scr->readSint16LE();
+ int16 idx = getArrIndexOfSegNum(segment);
+ debug(10, "ADS 0x%04x: add 4 remove 8 to state seg %d idx %d", code, segment, idx);
+ if (segment >= 0) {
+ int state = (_adsData->_state[idx] & 8) | 4;
+ _adsData->_state[idx] = state;
+ }
+ return true;
+ }
+
+ case 0xF210: { // RUN_SCRIPT, 1 param
+ int16 segment = scr->readSint16LE();
+ int16 idx = getArrIndexOfSegNum(segment);
+ debug(10, "ADS 0x%04x: add 3 remove 8 to state seg %d idx %d", code, segment, idx);
+ if (segment >= 0) {
+ int state = (_adsData->_state[idx] & 8) | 3;
+ _adsData->_state[idx] = state;
+ }
+ return true;
+ }
+
+ case 0xffff: // END
+ debug(10, "ADS 0xFFF: end");
+ return false;
+
+ //// unknown / to-be-implemented
+ case 0x1420: // AND, 0 params
+ case 0x1430: // OR, 0 params
+ case 0xFF10:
+ case 0xFFF0: // END_IF, 0 params
+ default: {
+ int nops = numArgs(code);
+ warning("ADS 0x%04x: Unimplemented opcode: (skip %d args)", code, nops);
+ for (int i = 0; i < nops; i++)
+ scr->readUint16LE();
+ break;
+ }
+ }
+
+ return true;
+}
+
+int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
+ int idx = getArrIndexOfSegNum(segnum);
+ if (idx < 0)
+ return 0;
+ if (!(_adsData->_state[idx] & 4)) {
+ for (auto *seq : _adsData->_usedSeqs[idx]) {
+ if (!seq)
+ return 0;
+ if (seq->_runFlag != kRunTypeStopped && !seq->_selfLoop)
+ return 1;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+
+int ADSInterpreter::getArrIndexOfSegNum(uint16 segnum) {
+ int32 startoff = _adsData->scr->pos();
+ int result = -1;
+ for (int i = 0; i < _adsData->_maxSegments; i++) {
+ _adsData->scr->seek(_adsData->_segments[i]);
+ int16 seg = _adsData->scr->readSint16LE();
+ if (seg == segnum) {
+ result = i;
+ break;
+ }
+ }
+ _adsData->scr->seek(startoff);
+ return result;
+}
+
+
+bool ADSInterpreter::run() {
+ if (_adsData->_ttmSeqs.empty())
+ return false;
+
+ for (int i = 0; i < _adsData->_maxSegments; i++) {
+ int16 flag = _adsData->_state[i] & 0xfff7;
+ for (auto seq : _adsData->_usedSeqs[i]) {
+ if (flag == 3) {
+ seq->reset();
+ } else {
+ seq->_scriptFlag = flag;
+ }
+ }
+ }
+
+ for (int i = 0; i < _adsData->_maxSegments; i++) {
+ int16 state = _adsData->_state[i];
+ int32 offset = _adsData->_segments[i];
+ _adsData->scr->seek(offset);
+ // skip over the segment num
+ offset += 2;
+ /*int16 segnum =*/ _adsData->scr->readSint16LE();
+ if (state & 8) {
+ state &= 0xfff7;
+ _adsData->_state[i] = state;
+ } else {
+ findEndOrInitOp();
+ offset = _adsData->scr->pos();
+ }
+
+ if (_adsData->_charWhile[i])
+ offset = _adsData->_charWhile[i];
+
+ if (state == 3 || state == 4) {
+ _adsData->_state[i] = 1;
+ state = 1;
+ }
+
+ _adsData->_runningSegmentIdx = i;
+ if (_adsData->scr && state == 1) {
+ _adsData->scr->seek(offset);
+ //debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData->_maxSegments);
+ runUntilBranchOpOrEnd();
+ }
+ }
+
+ bool result = false;
+ for (auto &seq : _adsData->_ttmSeqs) {
+ _currentTTMSeq = &seq;
+ seq._lastFrame = -1;
+ int sflag = seq._scriptFlag;
+ TTMRunType rflag = seq._runFlag;
+ if (sflag == 6 || (rflag != kRunType1 && rflag != kRunTypeTimeLimited && rflag != kRunTypeMulti && rflag != kRunType5)) {
+ if (sflag != 6 && sflag != 5 && rflag == kRunTypeFinished) {
+ seq._runFlag = kRunTypeStopped;
+ }
+ } else {
+ int16 curframe = seq._currentFrame;
+ TTMEnviro *env = findTTMEnviro(seq._enviro);
+ _adsData->_hitTTMOp0110 = false;
+ _adsData->_scriptDelay = -1;
+ bool scriptresult = false;
+ // Next few lines of code in a separate function in the original..
+ if (curframe < env->_totalFrames && curframe > -1 && env->_frameOffsets[curframe] > -1) {
+ env->scr->seek(env->_frameOffsets[curframe]);
+ scriptresult = playScene();
+ }
+
+ if (scriptresult && sflag != 5) {
+ seq._executed = true;
+ seq._lastFrame = seq._currentFrame;
+ result = true;
+ if (_adsData->_scriptDelay != -1 && seq._timeInterval != _adsData->_scriptDelay) {
+ uint32 now = g_engine->getTotalPlayTime();
+ seq._timeNext = now + _adsData->_scriptDelay;
+ seq._timeInterval = _adsData->_scriptDelay;
+ }
+
+ if (!_adsData->_hitTTMOp0110) {
+ if (_adsData->_gotoTarget != -1) {
+ seq._gotoFrame = _adsData->_gotoTarget;
+ if (seq._currentFrame == _adsData->_gotoTarget)
+ seq._selfLoop = true;
+ }
+ if (seq._runFlag != kRunType5)
+ updateSeqTimeAndFrame(env, seq);
+ } else {
+ seq._gotoFrame = seq._startFrame;
+ if (seq._runFlag == kRunTypeMulti && seq._runCount != 0) {
+ bool updated = updateSeqTimeAndFrame(env, seq);
+ if (updated) {
+ seq._runCount--;
+ }
+ } else if (seq._runFlag == kRunTypeTimeLimited && seq._timeCut != 0) {
+ updateSeqTimeAndFrame(env, seq);
+ } else {
+ bool updated = updateSeqTimeAndFrame(env, seq);
+ if (updated) {
+ seq._runFlag = kRunTypeFinished;
+ seq._timeInterval = 0;
+ }
+ }
+ }
+ } else if (sflag != 5) {
+ seq._gotoFrame = seq._startFrame;
+ seq._runFlag = kRunTypeFinished;
+ }
+ }
+
+ if (rflag == kRunTypeTimeLimited && seq._timeCut <= g_engine->getTotalPlayTime()) {
+ seq._runFlag = kRunTypeFinished;
+ }
+ }
+ return result;
+}
+
+bool ADSInterpreter::runUntilBranchOpOrEnd() {
+ Common::SeekableReadStream *scr = _adsData->scr;
+ if (!scr || scr->pos() >= scr->size())
+ return false;
+
+ bool more = true;
+ do {
+ uint16 code = scr->readUint16LE();
+ if (code == 0xffff)
+ return false;
+ more = handleOperation(code, scr);
+ } while (!_adsData->_hitBranchOp && more && scr->pos() < scr->size());
+
+ _adsData->_hitBranchOp = false;
+
+ return more;
+}
+
+void ADSInterpreter::setHitTTMOp0110() {
+ _adsData->_hitTTMOp0110 = true;
+}
+
+void ADSInterpreter::setGotoTarget(int32 target) {
+ _adsData->_gotoTarget = target;
+}
+
+int ADSInterpreter::numArgs(uint16 opcode) const {
+ // TODO: This list is from DRAGON, there may be more entries in newer games.
+ switch (opcode) {
+ case 0x1080:
+ case 0x1380:
+ case 0x1390:
+ case 0x3020:
+ case 0xF010:
+ case 0xF200:
+ case 0xF210:
+ return 1;
+
+ case 0x1010:
+ case 0x1020:
+ case 0x1030:
+ case 0x1040:
+ case 0x1050:
+ case 0x1060:
+ case 0x1070:
+ case 0x1310:
+ case 0x1320:
+ case 0x1330:
+ case 0x1340:
+ case 0x1350:
+ case 0x1360:
+ case 0x1370:
+ return 2;
+
+ case 0x2010:
+ case 0x2015:
+ case 0x2020:
+ case 0x4000:
+ case 0x4010:
+ return 3;
+
+ case 0x2000:
+ case 0x2005:
+ return 4;
+
+ default:
+ return 0;
+ }
+}
+
+Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
+ //TODO: Currently sync all states then set the active one,
+ // do we need to load/save all?
+ uint32 numTexts = _adsTexts.size();
+ s.syncAsUint32LE(numTexts);
+
+ Common::Array<Common::String> scriptNames;
+ Common::String activeScript;
+
+ if (s.isLoading()) {
+ for (uint32 i = 0; i < numTexts; i++) {
+ Common::String txtName;
+ s.syncString(txtName);
+ load(txtName);
+ scriptNames.push_back(txtName);
+ }
+ } else {
+ for (const auto &node : _adsTexts) {
+ Common::String txtName = node._key;
+ s.syncString(txtName);
+ scriptNames.push_back(txtName);
+ if (&node._value == _adsData)
+ activeScript = txtName;
+ }
+ }
+
+ // Text order should be the same
+ for (const Common::String &name : scriptNames) {
+ _adsTexts[name].syncState(s);
+ }
+
+ s.syncString(activeScript);
+ assert(_adsTexts.contains(activeScript));
+ _adsData = &_adsTexts[activeScript];
+
+ return Common::kNoError;
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/ads.h b/engines/dgds/ads.h
new file mode 100644
index 00000000000..6b1993dbec2
--- /dev/null
+++ b/engines/dgds/ads.h
@@ -0,0 +1,111 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_ADS_H
+#define DGDS_ADS_H
+
+#include "dgds/scripts.h"
+#include "dgds/ttm.h"
+
+namespace Dgds {
+
+class ADSData : public ScriptParserData {
+public:
+ ADSData() : _maxSegments(0), _scriptDelay(-1), _hitTTMOp0110(false), _hitBranchOp(false),
+ _gotoTarget(-1), _runningSegmentIdx(0) {
+ for (int i = 0; i < ARRAYSIZE(_state); i++)
+ _state[i] = 8;
+
+ for (int i = 0; i < ARRAYSIZE(_segments); i++)
+ _segments[i] = -1;
+
+ ARRAYCLEAR(_countdown);
+ ARRAYCLEAR(_charWhile);
+ }
+ Common::Array<Common::String> _scriptNames;
+ Common::Array<TTMEnviro> _scriptEnvs;
+ Common::Array<TTMSeq> _ttmSeqs;
+ int _maxSegments;
+ // TODO: replace these with dynamic arrays - fixed arrays inherited from original.
+ int _state[80];
+ int _countdown[80];
+ // note: originals uses char * but we use offsets into script for less pointers. -1 is nullptr
+ int32 _segments[80];
+ int32 _charWhile[80];
+ Common::Array<struct TTMSeq *> _usedSeqs[80];
+ int32 _scriptDelay;
+ int32 _gotoTarget;
+ bool _hitTTMOp0110;
+ bool _hitBranchOp;
+ int16 _runningSegmentIdx;
+
+ Common::Error syncState(Common::Serializer &s);
+};
+
+class ADSInterpreter {
+public:
+ ADSInterpreter(DgdsEngine *vm);
+ ~ADSInterpreter();
+
+ bool load(const Common::String &filename);
+ void unload();
+ bool run();
+ int numArgs(uint16 opcode) const;
+ void segmentOrState(int16 seg, uint16 val);
+ void segmentSetState(int16 seg, uint16 val);
+
+ void setHitTTMOp0110(); // TODO: better name for this global?
+ void setGotoTarget(int32 target);
+ int16 getStateForSceneOp(uint16 segnum);
+ void setScriptDelay(int16 delay) { _adsData->_scriptDelay = delay; }
+
+ Common::Error syncState(Common::Serializer &s);
+
+protected:
+ bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
+ void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
+ bool handleLogicOp(uint16 code, Common::SeekableReadStream *scr);
+ bool logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq);
+ int16 randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr);
+ bool playScene();
+ bool skipToEndIf();
+ bool skipToEndWhile();
+ bool skipSceneLogicBranch();
+ TTMSeq *findTTMSeq(int16 enviro, int16 seq);
+ TTMEnviro *findTTMEnviro(int16 enviro);
+ bool runUntilBranchOpOrEnd();
+ void findUsedSequencesForSegment(int segno);
+ void findEndOrInitOp();
+ bool updateSeqTimeAndFrame(const TTMEnviro *env, TTMSeq &seq);
+ int getArrIndexOfSegNum(uint16 segnum);
+
+ DgdsEngine *_vm;
+ TTMInterpreter *_ttmInterpreter;
+
+ Common::HashMap<Common::String, ADSData> _adsTexts;
+ ADSData *_adsData;
+
+ TTMSeq *_currentTTMSeq;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_ADS_H
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index ec7646dca28..66a76048a47 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -35,6 +35,7 @@
#include "dgds/image.h"
#include "dgds/parser.h"
#include "dgds/resource.h"
+#include "dgds/game_palettes.h"
#include "gui/debugger.h"
namespace Dgds {
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index b02b865bb79..7d878a40a9b 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -46,6 +46,7 @@
#include "engines/util.h"
#include "dgds/console.h"
+#include "dgds/ads.h"
#include "dgds/decompress.h"
#include "dgds/scene.h"
#include "dgds/detection_tables.h"
@@ -61,6 +62,7 @@
#include "dgds/resource.h"
#include "dgds/scripts.h"
#include "dgds/sound.h"
+#include "dgds/game_palettes.h"
// for frame contents debugging
//#define DUMP_FRAME_DATA 1
@@ -209,9 +211,7 @@ void DgdsEngine::setMouseCursor(uint num) {
if (num >= cursors.size())
error("Not enough cursor info, need %d have %d", num, cursors.size());
- uint16 hotX = cursors[num]._hotX;
- uint16 hotY = cursors[num]._hotY;
- _currentCursorHot = Common::Point(hotX, hotY);
+ _currentCursorHot = cursors[num].getHot();
/*
// Adjust mouse location so hot pixel is in the same place as before?
@@ -224,7 +224,7 @@ void DgdsEngine::setMouseCursor(uint num) {
g_system->warpMouse(newMouseX, newMouseY);
*/
- CursorMan.replaceCursor(*(_icons->getSurface(num)->surfacePtr()), hotX, hotY, 0, 0);
+ CursorMan.replaceCursor(*(_icons->getSurface(num)->surfacePtr()), _currentCursorHot.x, _currentCursorHot.y, 0, 0);
CursorMan.showMouse(true);
_currentCursor = num;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 192947f094b..b8d6c150c04 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -41,6 +41,7 @@
#include "dgds/clock.h"
#include "dgds/menu.h"
+
namespace Dgds {
class Console;
@@ -59,6 +60,8 @@ struct DgdsADS;
class ADSInterpreter;
class Globals;
+const float MS_PER_FRAME = 16.6667f;
+
enum DgdsGameId {
GID_DRAGON,
GID_CHINA,
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 260f89f8e07..67b830f6bdc 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -33,6 +33,7 @@
#include "dgds/includes.h"
#include "dgds/request.h"
#include "dgds/scripts.h"
+#include "dgds/scene.h"
#include "dgds/font.h"
namespace Dgds {
diff --git a/engines/dgds/game_palettes.cpp b/engines/dgds/game_palettes.cpp
new file mode 100644
index 00000000000..911e2a647fd
--- /dev/null
+++ b/engines/dgds/game_palettes.cpp
@@ -0,0 +1,139 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/paletteman.h"
+
+#include "dgds/game_palettes.h"
+#include "dgds/includes.h"
+#include "dgds/resource.h"
+
+namespace Dgds {
+
+DgdsPal::DgdsPal() : Palette(256) {
+}
+
+GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor) : _curPalNum(0),
+_resourceMan(resourceMan), _decompressor(decompressor) {
+}
+
+int GamePalettes::loadPalette(const Common::String &filename) {
+ Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
+ if (!fileStream) {
+ // Happens in the Amiga version of Dragon
+ warning("Couldn't load palette resource %s", filename.c_str());
+ return 0;
+ }
+
+ _palettes.resize(_palettes.size() + 1);
+
+ DgdsPal &pal = _palettes.back();
+
+ DgdsChunkReader chunk(fileStream);
+ while (chunk.readNextHeader(EX_PAL, filename)) {
+ chunk.readContent(_decompressor);
+ Common::SeekableReadStream *chunkStream = chunk.getContent();
+ if (chunk.isSection(ID_VGA)) {
+ for (uint k = 0; k < 256; k++) {
+ byte r = chunkStream->readByte() << 2;
+ byte g = chunkStream->readByte() << 2;
+ byte b = chunkStream->readByte() << 2;
+ pal.set(k, r, g, b);
+ }
+ }
+ }
+ pal.setName(filename);
+
+ delete fileStream;
+ selectPalNum(_palettes.size() - 1);
+
+ return _palettes.size() - 1;
+}
+
+void GamePalettes::selectPalNum(int num) {
+ _curPalNum = num;
+ setPalette();
+}
+
+void GamePalettes::setPalette() {
+ if (_curPalNum >= _palettes.size())
+ error("request to set pal %d but only have %d pals", _curPalNum, _palettes.size());
+
+ _curPal = _palettes[_curPalNum];
+ g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
+}
+
+void GamePalettes::clearPalette() {
+ _curPal = DgdsPal();
+ g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
+}
+
+void GamePalettes::setFade(int col, int ncols, int targetcol, int fade) {
+ if (_curPalNum >= _palettes.size())
+ error("GamePalettes::setFade: invalid curPalNum %d, only have %d pals", _curPalNum, _palettes.size());
+
+ if (col + ncols > 256)
+ error("GamePalettes::setFade: request to fade past the end of the palette");
+
+ const DgdsPal &pal = _palettes[_curPalNum];
+
+ byte r2, b2, g2;
+ pal.get(targetcol, r2, b2, g2);
+
+ for (int c = col; c < col + ncols; c++) {
+ byte r, g, b;
+ pal.get(c, r, g, b);
+
+ _curPal.set(c,
+ r2 * fade / 255 + r * (255 - fade) / 255,
+ g2 * fade / 255 + g * (255 - fade) / 255,
+ b2 * fade / 255 + b * (255 - fade) / 255);
+ }
+ g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
+}
+
+Common::Error GamePalettes::syncState(Common::Serializer &s) {
+ s.syncAsUint16LE(_curPalNum);
+ uint npals = _palettes.size();
+ s.syncAsUint16LE(npals);
+
+ if (s.isLoading()) {
+ for (uint i = 0; i < npals; i++) {
+ Common::String name;
+ s.syncString(name);
+ loadPalette(name);
+ }
+ if (_curPalNum >= _palettes.size())
+ error("Current palette number %d greater than available palettes %d",
+ _curPalNum, _palettes.size());
+
+ setPalette();
+ } else {
+ for (uint i = 0; i < npals; i++) {
+ Common::String name = _palettes[i].getName();
+ s.syncString(name);
+ }
+ }
+
+ return Common::kNoError;
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/game_palettes.h b/engines/dgds/game_palettes.h
new file mode 100644
index 00000000000..d4158cf048b
--- /dev/null
+++ b/engines/dgds/game_palettes.h
@@ -0,0 +1,70 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_GAME_PALETTES_H
+#define DGDS_GAME_PALETTES_H
+
+#include "common/error.h"
+#include "common/str.h"
+#include "common/serializer.h"
+#include "graphics/palette.h"
+
+namespace Dgds {
+
+class Decompressor;
+class ResourceManager;
+
+class DgdsPal : public Graphics::Palette {
+public:
+ DgdsPal();
+ virtual ~DgdsPal() {}
+ const Common::String &getName() { return _name; }
+ void setName(const Common::String &name) { _name = name; }
+private:
+ Common::String _name;
+};
+
+class GamePalettes {
+public:
+ GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor);
+ int loadPalette(const Common::String &filename);
+ void selectPalNum(int num);
+ void setPalette();
+ void clearPalette();
+
+ // Fade the colors in the current palette toward black. Start at col, and fade ncols of the palette.
+ // Add coloff to the result to move toward white.
+ void setFade(int col, int ncols, int coloff, int fade);
+
+ Common::Error syncState(Common::Serializer &s);
+
+private:
+ ResourceManager *_resourceMan;
+ Decompressor *_decompressor;
+
+ DgdsPal _curPal;
+ uint _curPalNum;
+ Common::Array<DgdsPal> _palettes;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_GAME_PALETTES_H
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index b167ea92fd0..edcc84ff8f8 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -28,8 +28,6 @@
#include "common/system.h"
#include "common/platform.h"
#include "graphics/managed_surface.h"
-#include "graphics/palette.h"
-#include "graphics/paletteman.h"
#include "graphics/surface.h"
#include "dgds/dgds.h"
#include "dgds/font.h"
@@ -40,114 +38,6 @@
namespace Dgds {
-DgdsPal::DgdsPal() : Palette(256) {
-}
-
-GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor) : _curPalNum(0),
-_resourceMan(resourceMan), _decompressor(decompressor) {
-}
-
-int GamePalettes::loadPalette(const Common::String &filename) {
- Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
- if (!fileStream) {
- // Happens in the Amiga version of Dragon
- warning("Couldn't load palette resource %s", filename.c_str());
- return 0;
- }
-
- _palettes.resize(_palettes.size() + 1);
-
- DgdsPal &pal = _palettes.back();
-
- DgdsChunkReader chunk(fileStream);
- while (chunk.readNextHeader(EX_PAL, filename)) {
- chunk.readContent(_decompressor);
- Common::SeekableReadStream *chunkStream = chunk.getContent();
- if (chunk.isSection(ID_VGA)) {
- for (uint k = 0; k < 256; k++) {
- byte r = chunkStream->readByte() << 2;
- byte g = chunkStream->readByte() << 2;
- byte b = chunkStream->readByte() << 2;
- pal.set(k, r, g, b);
- }
- }
- }
- pal.setName(filename);
-
- delete fileStream;
- selectPalNum(_palettes.size() - 1);
-
- return _palettes.size() - 1;
-}
-
-void GamePalettes::selectPalNum(int num) {
- _curPalNum = num;
- setPalette();
-}
-
-void GamePalettes::setPalette() {
- if (_curPalNum >= _palettes.size())
- error("request to set pal %d but only have %d pals", _curPalNum, _palettes.size());
-
- _curPal = _palettes[_curPalNum];
- g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
-}
-
-void GamePalettes::clearPalette() {
- _curPal = DgdsPal();
- g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
-}
-
-void GamePalettes::setFade(int col, int ncols, int targetcol, int fade) {
- if (_curPalNum >= _palettes.size())
- error("GamePalettes::setFade: invalid curPalNum %d, only have %d pals", _curPalNum, _palettes.size());
-
- if (col + ncols > 256)
- error("GamePalettes::setFade: request to fade past the end of the palette");
-
- const DgdsPal &pal = _palettes[_curPalNum];
-
- byte r2, b2, g2;
- pal.get(targetcol, r2, b2, g2);
-
- for (int c = col; c < col + ncols; c++) {
- byte r, g, b;
- pal.get(c, r, g, b);
-
- _curPal.set(c,
- r2 * fade / 255 + r * (255 - fade) / 255,
- g2 * fade / 255 + g * (255 - fade) / 255,
- b2 * fade / 255 + b * (255 - fade) / 255);
- }
- g_system->getPaletteManager()->setPalette(_curPal.data(), 0, 256);
-}
-
-Common::Error GamePalettes::syncState(Common::Serializer &s) {
- s.syncAsUint16LE(_curPalNum);
- uint npals = _palettes.size();
- s.syncAsUint16LE(npals);
-
- if (s.isLoading()) {
- for (uint i = 0; i < npals; i++) {
- Common::String name;
- s.syncString(name);
- loadPalette(name);
- }
- if (_curPalNum >= _palettes.size())
- error("Current palette number %d greater than available palettes %d",
- _curPalNum, _palettes.size());
-
- setPalette();
- } else {
- for (uint i = 0; i < npals; i++) {
- Common::String name = _palettes[i].getName();
- s.syncString(name);
- }
- }
-
- return Common::kNoError;
-}
-
Image::Image(ResourceManager *resourceMan, Decompressor *decompressor) : _resourceMan(resourceMan), _decompressor(decompressor) {
}
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 92c3f17dec7..b7a0c4f9ac1 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -41,39 +41,6 @@ class Decompressor;
class DgdsChunkReader;
class ResourceManager;
-class DgdsPal : public Graphics::Palette {
-public:
- DgdsPal();
- virtual ~DgdsPal() {}
- const Common::String &getName() { return _name; }
- void setName(const Common::String &name) { _name = name; }
-private:
- Common::String _name;
-};
-
-class GamePalettes {
-public:
- GamePalettes(ResourceManager *resourceMan, Decompressor *decompressor);
- int loadPalette(const Common::String &filename);
- void selectPalNum(int num);
- void setPalette();
- void clearPalette();
-
- // Fade the colors in the current palette toward black. Start at col, and fade ncols of the palette.
- // Add coloff to the result to move toward white.
- void setFade(int col, int ncols, int coloff, int fade);
-
- Common::Error syncState(Common::Serializer &s);
-
-private:
- ResourceManager *_resourceMan;
- Decompressor *_decompressor;
-
- DgdsPal _curPal;
- uint _curPalNum;
- Common::Array<DgdsPal> _palettes;
-};
-
class Image {
public:
Image(ResourceManager *resourceMan, Decompressor *decompressor);
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
index d4f0ea72760..27185991c28 100644
--- a/engines/dgds/includes.h
+++ b/engines/dgds/includes.h
@@ -86,8 +86,6 @@ namespace Dgds {
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200
-#define FILENAME_LENGTH 12
-
} // End of namespace Dgds
#endif // DGDS_INCLUDES_H
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index b673ab4ea28..9c9c987a721 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -189,18 +189,18 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
// the Napent in Dragon is weirdly offset in y because its rect has a large height?
Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
if (icon) {
- item.rect.width = MIN((int)icon->w, item.rect.width);
- item.rect.height = MIN((int)icon->h, item.rect.height);
+ item._rect.width = MIN((int)icon->w, item._rect.width);
+ item._rect.height = MIN((int)icon->h, item._rect.height);
}
// calculate draw offset for the image
- int drawX = imgAreaX + x + (xstep - item.rect.width) / 2;
- int drawY = imgAreaY + y + (ystep - item.rect.height) / 2;
+ int drawX = imgAreaX + x + (xstep - item._rect.width) / 2;
+ int drawY = imgAreaY + y + (ystep - item._rect.height) / 2;
icons->drawBitmap(item._iconNum, drawX, drawY, drawMask, surf);
- item.rect.x = drawX;
- item.rect.y = drawY;
+ item._rect.x = drawX;
+ item._rect.y = drawY;
x += xstep;
if (x >= _itemArea->_width) {
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 5ac19f74645..a89ac7bed05 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -279,6 +279,7 @@ void Menu::handleMenu(Common::Point &mouse) {
break;
case kMenuIntroSkip:
hideMenu();
+ static_cast<DgdsEngine *>(g_engine)->setShowClock(true);
static_cast<DgdsEngine *>(g_engine)->changeScene(5);
break;
case kMenuQuitYes:
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 2c8f0d40b33..0bbd4b8f949 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -63,7 +63,7 @@ enum MenuId {
kMenuQuit = 16,
// 17: I'm frustrated - keep trying / win arcade
kMenuSkipPlayIntro = 18,
- // 19: save game before arcade
+ kMenuBetterSaveGame = 19, // save game before arcade
// 20: replay arcade
};
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 6ac27bc0751..8d92c482150 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/dgds
MODULE_OBJS := \
+ ads.o \
clock.o \
console.o \
decompress.o \
@@ -8,6 +9,7 @@ MODULE_OBJS := \
dgds_rect.o \
dialog.o \
font.o \
+ game_palettes.o \
globals.o \
image.o \
inventory.o \
@@ -18,6 +20,7 @@ MODULE_OBJS := \
request.o \
resource.o \
scripts.o \
+ ttm.o \
scene.o \
sound.o
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index 56febd7ee6f..dea7059d229 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -29,6 +29,8 @@
#include "dgds/resource.h"
#include "dgds/parser.h"
#include "dgds/scripts.h"
+#include "dgds/ttm.h"
+#include "dgds/ads.h"
namespace Dgds {
diff --git a/engines/dgds/parser.h b/engines/dgds/parser.h
index af3299d5297..99ca4ad2fa6 100644
--- a/engines/dgds/parser.h
+++ b/engines/dgds/parser.h
@@ -23,6 +23,11 @@
#ifndef DGDS_PARSER_H
#define DGDS_PARSER_H
+#include "common/types.h"
+#include "common/hashmap.h"
+#include "common/str.h"
+#include "common/stream.h"
+
namespace Dgds {
class DgdsChunkReader;
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index e8435dd3142..d7e8d3797ab 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -33,6 +33,8 @@
namespace Dgds {
+static const int FILENAME_LENGTH = 12;
+
ResourceManager::ResourceManager() {
const char *indexFiles[] = {
"volume.vga", // early Dragon versions
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 0982481e4e4..5d1eee58c39 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -36,7 +36,7 @@
#include "dgds/resource.h"
#include "dgds/request.h"
#include "dgds/scene.h"
-#include "dgds/scripts.h"
+#include "dgds/ads.h"
#include "dgds/menu.h"
#include "dgds/font.h"
#include "dgds/globals.h"
@@ -45,7 +45,7 @@
namespace Dgds {
-template<class S> Common::String _dumpStructList(const Common::String &indent, const Common::String &name, const Common::Array<S> &list) {
+template<class S> static Common::String _dumpStructList(const Common::String &indent, const Common::String &name, const Common::Array<S> &list) {
if (list.empty())
return "";
@@ -59,6 +59,7 @@ template<class S> Common::String _dumpStructList(const Common::String &indent, c
}
+
Common::String _sceneConditionStr(SceneCondition cflag) {
Common::String ret;
@@ -95,7 +96,7 @@ Common::String SceneConditions::dump(const Common::String &indent) const {
Common::String HotArea::dump(const Common::String &indent) const {
Common::String str = Common::String::format("%sHotArea<%s num %d cursor %d",
- indent.c_str(), rect.dump("").c_str(), _num, _cursorNum);
+ indent.c_str(), _rect.dump("").c_str(), _num, _cursorNum);
str += _dumpStructList(indent, "enableConditions", enableConditions);
str += _dumpStructList(indent, "onRClickOps", onRClickOps);
str += _dumpStructList(indent, "onLDownOps", onLDownOps);
@@ -172,7 +173,7 @@ Common::String GameItem::dump(const Common::String &indent) const {
Common::String MouseCursor::dump(const Common::String &indent) const {
- return Common::String::format("%sMouseCursor<%d %d>", indent.c_str(), _hotX, _hotY);
+ return Common::String::format("%sMouseCursor<%d %d>", indent.c_str(), _hot.x, _hot.y);
}
@@ -215,21 +216,22 @@ bool Scene::isVersionUnder(const char *version) const {
bool Scene::readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const {
- list.resize(s->readUint16LE());
- for (SceneConditions &dst : list) {
- dst._num = s->readUint16LE();
- dst._flags = static_cast<SceneCondition>(s->readUint16LE());
- dst._val = s->readUint16LE();
+ uint16 num = s->readUint16LE();
+ for (uint16 i = 0; i < num; i++) {
+ uint16 num = s->readUint16LE();
+ SceneCondition cond = static_cast<SceneCondition>(s->readUint16LE());
+ uint16 val = s->readUint16LE();
+ list.push_back(SceneConditions(num, cond, val));
}
return !s->err();
}
bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
- dst.rect.x = s->readUint16LE();
- dst.rect.y = s->readUint16LE();
- dst.rect.width = s->readUint16LE();
- dst.rect.height = s->readUint16LE();
+ dst._rect.x = s->readUint16LE();
+ dst._rect.y = s->readUint16LE();
+ dst._rect.width = s->readUint16LE();
+ dst._rect.height = s->readUint16LE();
dst._num = s->readUint16LE();
dst._cursorNum = s->readUint16LE();
readConditionList(s, dst.enableConditions);
@@ -271,27 +273,28 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
bool Scene::readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const {
- list.resize(s->readUint16LE());
- for (MouseCursor &dst : list) {
- dst._hotX = s->readUint16LE();
- dst._hotY = s->readUint16LE();
+ uint16 num = s->readUint16LE();
+ for (uint16 i = 0; i < num; i++) {
+ list.push_back(MouseCursor(s->readUint16LE(), s->readUint16LE()));
}
return !s->err();
}
bool Scene::readObjInteractionList(Common::SeekableReadStream *s, Common::Array<ObjectInteraction> &list) const {
- list.resize(s->readUint16LE());
- for (ObjectInteraction &dst : list) {
+ uint16 num = s->readUint16LE();
+ for (uint16 i = 0; i < num; i++) {
+ uint16 dropped, target;
if (!isVersionOver(" 1.205")) {
- dst._targetItemNum = s->readUint16LE();
- dst._droppedItemNum = s->readUint16LE();
- dst._targetItemNum += s->readUint16LE();
+ target = s->readUint16LE();
+ dropped = s->readUint16LE();
+ target += s->readUint16LE();
} else {
- dst._droppedItemNum = s->readUint16LE();
- dst._targetItemNum = s->readUint16LE();
+ dropped = s->readUint16LE();
+ target = s->readUint16LE();
}
- readOpList(s, dst.opList);
+ list.push_back(ObjectInteraction(dropped, target));
+ readOpList(s, list.back().opList);
}
return !s->err();
}
@@ -376,12 +379,11 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const {
- list.resize(s->readUint16LE());
- for (SceneTrigger &dst : list) {
- dst._num = s->readUint16LE();
- dst._enabled = false;
- readConditionList(s, dst.conditionList);
- readOpList(s, dst.sceneOpList);
+ uint16 num = s->readUint16LE();
+ for (uint16 i = 0; i < num; i++) {
+ list.push_back(SceneTrigger(s->readUint16LE()));
+ readConditionList(s, list.back().conditionList);
+ readOpList(s, list.back().sceneOpList);
}
return !s->err();
@@ -438,8 +440,8 @@ void Scene::setDragItemOp(const Common::Array<uint16> &args) {
item._inSceneNum = engine->getScene()->getNum(); // else do some redraw??
Common::Point lastMouse = engine->getLastMouse();
- item.rect.x = lastMouse.x;
- item.rect.y = lastMouse.y;
+ item._rect.x = lastMouse.x;
+ item._rect.y = lastMouse.y;
engine->setMouseCursor(item._iconNum);
}
}
@@ -540,8 +542,8 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
item->_flags |= 1;
// TODO: Use hot x/y or just position?
Common::Point lastMouse = engine->getLastMouseMinusHot();
- item->rect.x = lastMouse.x;
- item->rect.y = lastMouse.y;
+ item->_rect.x = lastMouse.x;
+ item->_rect.y = lastMouse.y;
}
break;
}
@@ -585,6 +587,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
case kSceneOpOpenPlaySkipIntroMenu:
static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuSkipPlayIntro);
break;
+ case kSceneOpOpenBetterSaveGameMenu:
+ static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuBetterSaveGame);
+ break;
default:
warning("TODO: Implement scene op %d", op._opCode);
break;
@@ -593,22 +598,22 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
return true;
}
-bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds) {
+bool Scene::checkConditions(const Common::Array<SceneConditions> &conds) const {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
uint cnum = 0;
while (cnum < conds.size()) {
- const struct SceneConditions &c = conds[cnum];
- int16 refval = c._val;
+ const SceneConditions &c = conds[cnum];
+ int16 refval = c.getVal();
int16 checkval = -1;
- SceneCondition cflag = c._flags;
+ SceneCondition cflag = c.getCond();
// Hit an "or" here means the last result was true.
if (cflag & kSceneCondOr)
return true;
if (cflag & kSceneCondSceneState) {
refval = 1;
- checkval = engine->adsInterpreter()->getStateForSceneOp(c._num);
+ checkval = engine->adsInterpreter()->getStateForSceneOp(c.getNum());
SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
refval = 0;
@@ -616,7 +621,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
} else if (cflag & kSceneCondNeedItemQuality || cflag & kSceneCondNeedItemSceneNum) {
const Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
for (const auto &item : items) {
- if (item._num == c._num) {
+ if (item._num == c.getNum()) {
if (cflag & kSceneCondNeedItemSceneNum)
checkval = item._inSceneNum;
else // cflag & kSceneCondNeedItemQuality
@@ -625,7 +630,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
}
}
} else {
- checkval = engine->getGDSScene()->getGlobal(c._num);
+ checkval = engine->getGDSScene()->getGlobal(c.getNum());
if (!(cflag & kSceneCondAbsVal))
refval = engine->getGDSScene()->getGlobal((uint16)refval);
}
@@ -645,7 +650,7 @@ bool Scene::checkConditions(const Common::Array<struct SceneConditions> &conds)
if (!result) {
// Skip just past the next or, or to the end.
- while (cnum < conds.size() && !(conds[cnum]._flags & kSceneCondOr))
+ while (cnum < conds.size() && !(conds[cnum].getCond() & kSceneCondOr))
cnum++;
if (cnum >= conds.size())
return false;
@@ -759,7 +764,7 @@ Common::String SDSScene::dump(const Common::String &indent) const {
void SDSScene::enableTrigger(uint16 num) {
for (auto &trigger : _triggers) {
- if (trigger._num == num)
+ if (trigger.getNum() == num)
trigger._enabled = true;
}
}
@@ -768,7 +773,7 @@ void SDSScene::checkTriggers() {
// scene can change on these triggers. if that happens we stop.
int startSceneNum = _num;
- for (struct SceneTrigger &trigger : _triggers) {
+ for (SceneTrigger &trigger : _triggers) {
if (!trigger._enabled)
continue;
@@ -835,7 +840,7 @@ bool SDSScene::checkDialogActive() {
if ((!finished && !no_options) || dlg.hasFlag(kDlgFlagHi20) || dlg.hasFlag(kDlgFlagHi40)) {
if (!finished && dlg._action.size() > 1 && !dlg.hasFlag(kDlgFlagHiFinished)) {
- struct DialogAction *action = dlg.pickAction(false, clearDlgFlag);
+ DialogAction *action = dlg.pickAction(false, clearDlgFlag);
if (dlg._state->_selectedAction != action) {
dlg._state->_selectedAction = action;
dlg.clearFlag(kDlgFlagHi10);
@@ -845,7 +850,7 @@ bool SDSScene::checkDialogActive() {
} else {
// this dialog is finished - call the ops and maybe show the next one
_dlgWithFlagLo8IsClosing = dlg.hasFlag(kDlgFlagLo8);
- struct DialogAction *action = dlg.pickAction(true, clearDlgFlag);
+ DialogAction *action = dlg.pickAction(true, clearDlgFlag);
if (action || dlg._action.empty()) {
dlg.setFlag(kDlgFlagHiFinished);
if (action) {
@@ -999,8 +1004,8 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
if (!area)
return;
- debug(9, "Mouse LDown on area %d (%d,%d,%d,%d) cursor %d", area->_num, area->rect.x, area->rect.y,
- area->rect.width, area->rect.height, area->_cursorNum);
+ debug(9, "Mouse LDown on area %d (%d,%d,%d,%d) cursor %d", area->_num, area->_rect.x, area->_rect.y,
+ area->_rect.width, area->_rect.height, area->_cursorNum);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int16 addmins = static_cast<DragonGlobals *>(engine->getGameGlobals())->getGameMinsToAddOnStartDrag();
@@ -1028,8 +1033,8 @@ void SDSScene::mouseLUp(const Common::Point &pt) {
if (!area)
return;
- debug(9, "Mouse LUp on area %d (%d,%d,%d,%d) cursor %d", area->_num, area->rect.x, area->rect.y,
- area->rect.width, area->rect.height, area->_cursorNum);
+ debug(9, "Mouse LUp on area %d (%d,%d,%d,%d) cursor %d", area->_num, area->_rect.x, area->_rect.y,
+ area->_rect.width, area->_rect.height, area->_cursorNum);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
engine->setMouseCursor(area->_cursorNum);
@@ -1065,10 +1070,10 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
// TODO: Both these loops are very similar.. there should be a cleaner way.
for (const auto &item : engine->getGDSScene()->getGameItems()) {
- if (item._inSceneNum == _num && _isInRect(pt, item.rect)) {
+ if (item._inSceneNum == _num && _isInRect(pt, item._rect)) {
debug("Dragged item %d onto item %d @ (%d, %d)", dragItem->_num, item._num, pt.x, pt.y);
for (const auto &i : engine->getGDSScene()->getObjInteractions2()) {
- if (i._droppedItemNum == dragItem->_num && i._targetItemNum == item._num) {
+ if (i.matches(dragItem->_num, item._num)) {
debug(" --> exec %d drag ops for item %d", i.opList.size(), item._num);
if (!runOps(i.opList, globals->getGameMinsToAddOnObjInteraction()))
return;
@@ -1079,7 +1084,7 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
}
for (const auto &area : _hotAreaList) {
- if (!_isInRect(pt, area.rect))
+ if (!_isInRect(pt, area._rect))
continue;
if (area._num == 0) {
@@ -1088,7 +1093,7 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
} else {
debug("Dragged item %d onto area %d @ (%d, %d)", dragItem->_num, area._num, pt.x, pt.y);
for (const auto &i : engine->getScene()->getObjInteractions1()) {
- if (i._droppedItemNum == dragItem->_num && i._targetItemNum == area._num) {
+ if (i.matches(dragItem->_num, area._num)) {
debug(" --> exec %d drag ops for area %d", i.opList.size(), area._num);
if (!runOps(i.opList, globals->getGameMinsToAddOnObjInteraction()))
return;
@@ -1147,13 +1152,13 @@ HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
for (auto &item : engine->getGDSScene()->getGameItems()) {
if (item._inSceneNum == _num && checkConditions(item.enableConditions)
- && _isInRect(pt, item.rect)) {
+ && _isInRect(pt, item._rect)) {
return &item;
}
}
for (auto &area : _hotAreaList) {
- if (checkConditions(area.enableConditions) && _isInRect(pt, area.rect)) {
+ if (checkConditions(area.enableConditions) && _isInRect(pt, area._rect)) {
return &area;
}
}
@@ -1174,10 +1179,10 @@ void SDSScene::addInvButtonToHotAreaList() {
HotArea area;
area._num = 0;
area._cursorNum = 0;
- area.rect.width = icons->width(2);
- area.rect.height = icons->height(2);
- area.rect.x = SCREEN_WIDTH - area.rect.width;
- area.rect.y = SCREEN_HEIGHT - area.rect.height;
+ area._rect.width = icons->width(2);
+ area._rect.height = icons->height(2);
+ area._rect.x = SCREEN_WIDTH - area._rect.width;
+ area._rect.y = SCREEN_HEIGHT - area._rect.height;
_hotAreaList.insert_at(0, area);
}
@@ -1251,11 +1256,10 @@ bool GDSScene::load(const Common::String &filename, ResourceManager *resourceMan
}
bool GDSScene::readPerSceneGlobals(Common::SeekableReadStream *s) {
- _perSceneGlobals.resize(s->readUint16LE());
- for (PerSceneGlobal &dst : _perSceneGlobals) {
- dst._num = s->readUint16LE();
- dst._sceneNo = s->readUint16LE();
- dst._val = s->readSint16LE();
+ uint16 numGlobals = s->readUint16LE();
+ for (uint16 i = 0; i < numGlobals; i++) {
+ _perSceneGlobals.push_back(PerSceneGlobal(s->readUint16LE(), s->readUint16LE()));
+ _perSceneGlobals.back()._val = s->readSint16LE();
}
return !s->err();
}
@@ -1344,7 +1348,7 @@ int16 GDSScene::getGlobal(uint16 num) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int curSceneNum = engine->getScene()->getNum();
for (const auto &global : _perSceneGlobals) {
- if (global._num == num && (global._sceneNo == 0 || global._sceneNo == curSceneNum))
+ if (global.matches(num, curSceneNum))
return global._val;
}
Globals *gameGlobals = engine->getGameGlobals();
@@ -1355,7 +1359,7 @@ int16 GDSScene::setGlobal(uint16 num, int16 val) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int curSceneNum = engine->getScene()->getNum();
for (auto &global : _perSceneGlobals) {
- if (global._num == num && (global._sceneNo == 0 || global._sceneNo == curSceneNum)) {
+ if (global.matches(num, curSceneNum)) {
global._val = val;
return val;
}
@@ -1383,18 +1387,18 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
// but then the napent icon is offset??
Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
if (icon) {
- item.rect.width = MIN((int)icon->w, item.rect.width);
- item.rect.height = MIN((int)icon->h, item.rect.height);
+ item._rect.width = MIN((int)icon->w, item._rect.width);
+ item._rect.height = MIN((int)icon->h, item._rect.height);
}
- if (xoff + item.rect.width > maxx)
+ if (xoff + item._rect.width > maxx)
xoff = 20;
- int yoff = SCREEN_HEIGHT - (item.rect.height + 2);
- item.rect.x = xoff;
- item.rect.y = yoff;
+ int yoff = SCREEN_HEIGHT - (item._rect.height + 2);
+ item._rect.x = xoff;
+ item._rect.y = yoff;
icons->drawBitmap(item._iconNum, xoff, yoff, screenWin, surf);
- xoff += (item.rect.width + 6);
+ xoff += (item._rect.width + 6);
} else {
- icons->drawBitmap(item._iconNum, item.rect.x, item.rect.y, screenWin, surf);
+ icons->drawBitmap(item._iconNum, item._rect.x, item._rect.y, screenWin, surf);
}
}
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 3155ce5f97a..1126288f58c 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -48,22 +48,30 @@ enum SceneCondition {
kSceneCondSceneState = 0x80
};
-struct SceneConditions {
+class SceneConditions {
+public:
+ SceneConditions(uint16 num, SceneCondition cond, uint16 val) : _num(num), _flags(cond), _val(val) {}
+ Common::String dump(const Common::String &indent) const;
+
+ uint16 getNum() const { return _num; }
+ SceneCondition getCond() const { return _flags; }
+ uint16 getVal() const { return _val; }
+
+private:
uint16 _num;
SceneCondition _flags; /* eg, see usage in FUN_1f1a_2106 */
uint16 _val;
-
- Common::String dump(const Common::String &indent) const;
};
-struct HotArea {
- DgdsRect rect;
+class HotArea {
+public:
+ DgdsRect _rect;
uint16 _num; //
uint16 _cursorNum;
- Common::Array<struct SceneConditions> enableConditions;
- Common::Array<struct SceneOp> onRClickOps;
- Common::Array<struct SceneOp> onLDownOps;
- Common::Array<struct SceneOp> onLClickOps;
+ Common::Array<SceneConditions> enableConditions;
+ Common::Array<SceneOp> onRClickOps;
+ Common::Array<SceneOp> onLDownOps;
+ Common::Array<SceneOp> onLClickOps;
virtual ~HotArea() {}
@@ -101,22 +109,26 @@ enum SceneOpCode {
kSceneOp105 = 105, // args: none. Draw some number at 141, 56
kSceneOp106 = 106, // args: none. Draw some number at 42, 250
kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. DRAGON: Show menu 50, the "Play Introduction" / "Skip Introduction" menu.
- kSceneOp108 = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
+ kSceneOpOpenBetterSaveGameMenu = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
};
-struct SceneOp {
- Common::Array<struct SceneConditions> _conditionList;
+class SceneOp {
+public:
+ Common::Array<SceneConditions> _conditionList;
Common::Array<uint16> _args;
SceneOpCode _opCode;
Common::String dump(const Common::String &indent) const;
};
-struct GameItem : public HotArea {
- Common::Array<struct SceneOp> onDragFinishedOps;
- Common::Array<struct SceneOp> opList5;
+class GameItem : public HotArea {
+public:
+ Common::Array<SceneOp> onDragFinishedOps;
+ Common::Array<SceneOp> opList5;
uint16 _altCursor;
uint16 _iconNum;
+
+ // mutable values
uint16 _inSceneNum;
uint16 _flags;
uint16 _quality;
@@ -124,40 +136,67 @@ struct GameItem : public HotArea {
Common::String dump(const Common::String &indent) const override;
};
-struct MouseCursor {
- uint16 _hotX;
- uint16 _hotY;
+class MouseCursor {
+public:
+ MouseCursor(uint16 hotX, uint16 hotY) : _hot(hotX, hotY) {}
Common::String dump(const Common::String &indent) const;
+
+ const Common::Point getHot() const { return _hot; }
+
+private:
+ Common::Point _hot;
};
// Interactions between two objects when one is dropped on the other
-struct ObjectInteraction {
+class ObjectInteraction {
+public:
+ ObjectInteraction(uint16 dropped, uint16 target) : _droppedItemNum(dropped), _targetItemNum(target) {}
+
+ Common::Array<SceneOp> opList;
+
+ bool matches(uint16 droppedItemNum, uint16 targetItemNum) const {
+ return _droppedItemNum == droppedItemNum && _targetItemNum == targetItemNum;
+ }
+
+ Common::String dump(const Common::String &indent) const;
+
+private:
uint16 _droppedItemNum;
uint16 _targetItemNum;
- Common::Array<struct SceneOp> opList;
- Common::String dump(const Common::String &indent) const;
};
-struct SceneTrigger {
- uint16 _num;
+class SceneTrigger {
+public:
+ SceneTrigger(uint16 num) : _num(num), _enabled(false) {}
+ Common::String dump(const Common::String &indent) const;
+
+ Common::Array<SceneConditions> conditionList;
+ Common::Array<SceneOp> sceneOpList;
bool _enabled;
- Common::Array<struct SceneConditions> conditionList;
- Common::Array<struct SceneOp> sceneOpList;
+ uint16 getNum() const { return _num; }
- Common::String dump(const Common::String &indent) const;
+private:
+ uint16 _num;
};
/* A global value that only applies on a per-SDS-scene,
but stays with the GDS data as it sticks around during
the game */
-struct PerSceneGlobal {
- uint16 _num;
- uint16 _sceneNo;
- int16 _val;
+class PerSceneGlobal {
+public:
+ PerSceneGlobal(uint16 num, uint16 scene) : _num(num), _sceneNo(scene) {}
Common::String dump(const Common::String &indent) const;
+ bool matches(uint16 num, uint16 scene) const { return num == _num && (_sceneNo == 0 || _sceneNo == scene); }
+
+ int16 _val;
+
+private:
+ // Immutable, read from the data file
+ uint16 _num;
+ uint16 _sceneNo;
};
@@ -198,16 +237,12 @@ protected:
bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const;
- bool checkConditions(const Common::Array<struct SceneConditions> &cond);
+ bool checkConditions(const Common::Array<SceneConditions> &cond) const;
virtual void enableTrigger(uint16 num) {}
virtual void showDialog(uint16 num) {}
virtual void globalOps(const Common::Array<uint16> &args) {}
virtual void segmentStateOps(const Common::Array<uint16> &args);
- void segmentStateOp9(uint16 arg);
- void segmentStateOp10(uint16 arg);
- void segmentStateOp11(uint16 arg);
- void segmentStateOp12(uint16 arg);
void setItemAttrOp(const Common::Array<uint16> &args);
void setDragItemOp(const Common::Array<uint16> &args);
@@ -215,8 +250,8 @@ protected:
uint32 _magic;
Common::String _version;
- Common::Array<struct SceneOp> _preTickOps;
- Common::Array<struct SceneOp> _postTickOps;
+ Common::Array<SceneOp> _preTickOps;
+ Common::Array<SceneOp> _postTickOps;
};
@@ -239,27 +274,26 @@ public:
int16 getGlobal(uint16 num);
int16 setGlobal(uint16 num, int16 val);
- const Common::Array<struct MouseCursor> &getCursorList() const { return _cursorList; }
+ const Common::Array<MouseCursor> &getCursorList() const { return _cursorList; }
void drawItems(Graphics::ManagedSurface &surf);
- Common::Array<struct GameItem> &getGameItems() { return _gameItems; }
+ Common::Array<GameItem> &getGameItems() { return _gameItems; }
int countItemsInScene2() const;
- const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
- const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+ const Common::Array<ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
+ const Common::Array<ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
Common::Error syncState(Common::Serializer &s) override;
private:
- //byte _unk[32];
Common::String _iconFile;
- Common::Array<struct GameItem> _gameItems;
- Common::Array<struct SceneOp> _startGameOps;
- Common::Array<struct SceneOp> _quitGameOps;
- Common::Array<struct SceneOp> _onChangeSceneOps;
- Common::Array<struct MouseCursor> _cursorList;
- Common::Array<struct PerSceneGlobal> _perSceneGlobals;
- Common::Array<struct ObjectInteraction> _objInteractions1;
- Common::Array<struct ObjectInteraction> _objInteractions2;
+ Common::Array<GameItem> _gameItems;
+ Common::Array<SceneOp> _startGameOps;
+ Common::Array<SceneOp> _quitGameOps;
+ Common::Array<SceneOp> _onChangeSceneOps;
+ Common::Array<MouseCursor> _cursorList;
+ Common::Array<PerSceneGlobal> _perSceneGlobals;
+ Common::Array<ObjectInteraction> _objInteractions1;
+ Common::Array<ObjectInteraction> _objInteractions2;
};
class SDSScene : public Scene {
@@ -293,14 +327,14 @@ public:
void addInvButtonToHotAreaList();
void removeInvButtonFromHotAreaList();
- const Common::Array<struct HotArea> &getHotAreas() const { return _hotAreaList; }
+ const Common::Array<HotArea> &getHotAreas() const { return _hotAreaList; }
const GameItem *getDragItem() const { return _dragItem; }
GameItem *getDragItem() { return _dragItem; }
void setDragItem(GameItem *item) { _dragItem = item; }
- const Common::Array<struct ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
- const Common::Array<struct ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+ const Common::Array<ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
+ const Common::Array<ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
bool hasVisibleDialog();
@@ -317,20 +351,22 @@ private:
Dialog *getVisibleDialog();
int _num;
- Common::Array<struct SceneOp> _enterSceneOps;
- Common::Array<struct SceneOp> _leaveSceneOps;
+ Common::Array<SceneOp> _enterSceneOps;
+ Common::Array<SceneOp> _leaveSceneOps;
//uint _field5_0x12;
uint _field6_0x14;
Common::String _adsFile;
//uint _field8_0x23;
- Common::Array<struct HotArea> _hotAreaList;
- Common::Array<struct ObjectInteraction> _objInteractions1;
- Common::Array<struct ObjectInteraction> _objInteractions2;
+ Common::Array<HotArea> _hotAreaList;
+ Common::Array<ObjectInteraction> _objInteractions1;
+ Common::Array<ObjectInteraction> _objInteractions2;
//uint _field12_0x2b;
- Common::Array<class Dialog> _dialogs;
- Common::Array<struct SceneTrigger> _triggers;
//uint _field15_0x33;
+ // From here on is mutable stuff that might need saving
+ Common::Array<Dialog> _dialogs;
+ Common::Array<SceneTrigger> _triggers;
+
GameItem *_dragItem;
bool _shouldClearDlg;
bool _ignoreMouseUp;
diff --git a/engines/dgds/scripts.cpp b/engines/dgds/scripts.cpp
index f674ad018fb..883871a9af8 100644
--- a/engines/dgds/scripts.cpp
+++ b/engines/dgds/scripts.cpp
@@ -20,1706 +20,8 @@
*
*/
-#include "common/debug.h"
-#include "common/rect.h"
-#include "common/textconsole.h"
-#include "common/random.h"
-#include "common/str.h"
-#include "common/stream.h"
-#include "common/system.h"
-#include "common/platform.h"
-#include "graphics/managed_surface.h"
-#include "graphics/palette.h"
-#include "graphics/surface.h"
-#include "dgds/dgds.h"
-#include "dgds/scene.h"
-#include "dgds/font.h"
-#include "dgds/image.h"
-#include "dgds/includes.h"
-#include "dgds/scripts.h"
-#include "dgds/sound.h"
-#include "dgds/resource.h"
-#include "dgds/parser.h"
namespace Dgds {
-static const float MS_PER_FRAME = 16.6667f;
-
-void GetPutRegion::reset() {
- _area = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
- _surf.reset();
-}
-
-Common::Error TTMEnviro::syncState(Common::Serializer &s) {
- DgdsEngine *engine = dynamic_cast<DgdsEngine *>(g_engine);
- for (auto &shape : _scriptShapes) {
- bool hasShape = shape.get() != nullptr;
- s.syncAsByte(hasShape);
- if (hasShape) {
- Common::String name;
- if (s.isLoading()) {
- s.syncString(name);
- shape.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
- shape->loadBitmap(name);
- } else {
- name = shape->getFilename();
- s.syncString(name);
- }
- }
- }
-
- uint16 ngetput = _getPuts.size();
- s.syncAsUint16LE(ngetput);
- _getPuts.resize(ngetput);
- for (uint i = 0; i < ngetput; i++) {
- s.syncAsUint16LE(_getPuts[i]._area.left);
- s.syncAsUint16LE(_getPuts[i]._area.top);
- s.syncAsUint16LE(_getPuts[i]._area.right);
- s.syncAsUint16LE(_getPuts[i]._area.bottom);
- if (s.isLoading()) {
- _getPuts[i]._surf.reset(new Graphics::ManagedSurface());
- } else {
- // TODO: Save the getput buffer contents here?
- }
- }
- for (uint i = 0; i < ARRAYSIZE(_scriptPals); i++)
- s.syncAsSint32LE(_scriptPals[i]);
- for (uint i = 0; i < ARRAYSIZE(_strings); i++)
- s.syncString(_strings[i]);
-
- // TODO: Save the font list.
-
- return Common::kNoError;
-}
-
-Common::Error TTMSeq::syncState(Common::Serializer &s) {
- s.syncAsSint16LE(_gotoFrame);
- s.syncAsSint16LE(_currentFrame);
- s.syncAsSint16LE(_lastFrame);
- s.syncAsByte(_selfLoop);
- s.syncAsByte(_executed);
- s.syncAsUint32LE(_timeNext);
- s.syncAsUint32LE(_timeCut);
-
- s.syncAsUint16LE(_drawWin.left);
- s.syncAsUint16LE(_drawWin.top);
- s.syncAsUint16LE(_drawWin.right);
- s.syncAsUint16LE(_drawWin.bottom);
-
- s.syncAsSint16LE(_currentFontId);
- s.syncAsSint16LE(_currentPalId);
- s.syncAsSint16LE(_currentSongId);
- s.syncAsSint16LE(_currentBmpId);
- s.syncAsSint16LE(_currentGetPutId);
- s.syncAsSint16LE(_brushNum);
- s.syncAsByte(_drawColFG);
- s.syncAsByte(_drawColBG);
- s.syncAsSint16LE(_runPlayed);
- s.syncAsSint16LE(_runCount);
- s.syncAsSint16LE(_timeInterval);
- s.syncAsUint32LE(_runFlag);
- s.syncAsSint16LE(_scriptFlag);
-
- return Common::kNoError;
-}
-
-Common::Error ADSData::syncState(Common::Serializer &s) {
- uint16 arrSize = ARRAYSIZE(_state);
- s.syncAsUint16LE(arrSize);
- if (arrSize != ARRAYSIZE(_state))
- error("Expected fixed size state array");
- for (uint i = 0; i < arrSize; i++)
- s.syncAsSint16LE(_state[i]);
-
- uint16 nenvs = _scriptEnvs.size();
- s.syncAsUint16LE(nenvs);
- // This should be the same on load as the data comes from the ADS/TTM files.
- if (nenvs != _scriptEnvs.size())
- error("Unexpected number of script envs (%d in save vs %d in ADS)", nenvs, _scriptEnvs.size());
-
- for (auto &env : _scriptEnvs)
- env.syncState(s);
-
- uint16 nseqs = _ttmSeqs.size();
- s.syncAsUint16LE(nseqs);
- if (nseqs != _ttmSeqs.size())
- error("Unexpected number of ttm seqeunces (%d in save vs %d in ADS)", nseqs, _ttmSeqs.size());
-
- for (auto &seq : _ttmSeqs)
- seq.syncState(s);
-
- return Common::kNoError;
-}
-
-
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
-
-bool TTMInterpreter::load(const Common::String &filename, TTMEnviro &scriptData) {
- TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- bool parseResult = dgds.parse(&scriptData, filename);
-
- scriptData.scr->seek(0);
-
- return parseResult;
-}
-
-void TTMInterpreter::unload() {
-}
-
-static const char *ttmOpName(uint16 op) {
- switch (op) {
- case 0x0000: return "FINISH";
- case 0x0020: return "SAVE(free?) BACKGROUND";
- case 0x0070: return "FREE PALETTE";
- case 0x0080: return "FREE SHAPE / DRAW BACKGROUND??";
- case 0x0090: return "FREE FONT";
- case 0x00B0: return "NULLOP";
- case 0x0110: return "PURGE";
- case 0x0ff0: return "FINISH FRAME / DRAW";
- case 0x1020: return "SET DELAY";
- case 0x1030: return "SET BRUSH";
- case 0x1050: return "SELECT BMP";
- case 0x1060: return "SELECT PAL";
- case 0x1070: return "SELECT FONT";
- case 0x1090: return "SELECT SONG";
- case 0x10a0: return "SET SCENE";
- case 0x1100: // fall through
- case 0x1110: return "SET SCENE";
- case 0x1120: return "SET GETPUT NUM";
- case 0x1200: return "GOTO";
- case 0x1300: return "PLAY SFX";
- case 0x2000: return "SET DRAW COLORS";
- case 0x2010: return "SET FRAME";
- case 0x2020: return "SET RANDOM DELAY";
- case 0x4000: return "SET CLIP WINDOW";
- case 0x4110: return "FADE OUT";
- case 0x4120: return "FADE IN";
- case 0x4200: return "STORE AREA";
- case 0x4210: return "SAVE GETPUT REGION";
- case 0xa000: return "DRAW PIXEL";
- case 0xa010: return "SAVE REGION 10?????";
- case 0xa020: return "SAVE REGION 20?????";
- case 0xa030: return "SAVE REGION 30?????";
- case 0xa040: return "SAVE REGION 40?????";
- case 0xa050: return "SAVE REGION";
- case 0xa060: return "SAVE REGION FLIPPED??";
- case 0xa070: return "SAVE REGION 70?????";
- case 0xa080: return "SAVE REGION 80?????";
- case 0xa090: return "SAVE REGION 90?????";
- case 0xa0a0: return "DRAW LINE";
- case 0xa100: return "DRAW FILLED RECT";
- case 0xa110: return "DRAW EMPTY RECT";
- case 0xa200: return "DRAW STRING 0";
- case 0xa210: return "DRAW STRING 1";
- case 0xa220: return "DRAW STRING 2";
- case 0xa230: return "DRAW STRING 3";
- case 0xa240: return "DRAW STRING 4";
- case 0xa250: return "DRAW STRING 5";
- case 0xa260: return "DRAW STRING 6";
- case 0xa270: return "DRAW STRING 7";
- case 0xa280: return "DRAW STRING 8";
- case 0xa290: return "DRAW STRING 9";
- case 0xa500: return "DRAW BMP";
- case 0xa520: return "DRAW SPRITE FLIP";
- case 0xa530: return "DRAW BMP4";
- case 0xa600: return "DRAW GETPUT";
- case 0xf010: return "LOAD SCR";
- case 0xf020: return "LOAD BMP";
- case 0xf040: return "LOAD FONT";
- case 0xf050: return "LOAD PAL";
- case 0xf060: return "LOAD SONG";
- case 0xf100: return "SET STRING 0";
- case 0xf110: return "SET STRING 1";
- case 0xf120: return "SET STRING 2";
- case 0xf130: return "SET STRING 3";
- case 0xf140: return "SET STRING 4";
- case 0xf150: return "SET STRING 5";
- case 0xf160: return "SET STRING 6";
- case 0xf170: return "SET STRING 7";
- case 0xf180: return "SET STRING 8";
- case 0xf190: return "SET STRING 9";
- case 0x0220: return "STOP CURRENT MUSIC";
-
- case 0x00C0: return "FREE BACKGROUND";
- case 0x0230: return "reset current music?";
- case 0x1310: return "STOP SFX";
- case 0xa300: return "DRAW some string";
- case 0xa400: return "DRAW FILLED CIRCLE";
- case 0xa420: return "DRAW EMPTY CIRCLE";
- case 0xa510: return "DRAW SPRITE1";
- case 0xb000: return "? (0 args)";
- case 0xb010: return "? (3 args: 30, 2, 19)";
- case 0xb600: return "DRAW SCREEN";
- case 0xc020: return "LOAD_SAMPLE";
- case 0xc030: return "SELECT_SAMPLE";
- case 0xc040: return "DESELECT_SAMPLE";
- case 0xc050: return "PLAY_SAMPLE";
- case 0xc060: return "STOP_SAMPLE";
-
- default: return "UNKNOWN!!";
- }
-}
-
-void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
- switch (op) {
- case 0x0000: // FINISH: void
- break;
- case 0x0020: // SAVE (free?) BACKGROUND
- if (seq._executed) // this is a one-shot op
- break;
- //
- // This appears in the credits, intro sequence, and the
- // "meanwhile" event with the factory in DRAGON. Seems it
- // should reload the background image to clear any previous 0020
- // event, and then save the current FG over it.
- // Credits - (no scr loaded) Store large image on black bg after loading and before txt scroll
- // Intro - (no scr loaded) After each screen change, draw and save the new comic frame as bg
- // on "aaaaah" scene, called after only drawing the AAAH and calling store area
- // Meanwhile - (scr loaded) Save the foreground people onto the background before walk animation
- //
- _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _vm->getBackgroundBuffer().blitFrom(_vm->_compositionBuffer);
- break;
- case 0x0070: // FREE PALETTE
- if (seq._executed) // this is a one-shot op
- break;
- warning("TODO: Implement me: op 0x0070 free palette (current pal)");
- seq._currentPalId = 0;
- break;
- case 0x0080: // FREE SHAPE
- env._scriptShapes[seq._currentBmpId].reset();
- break;
- case 0x0090: // FREE FONT
- if (seq._executed) // this is a one-shot op
- break;
- if (seq._currentFontId >= (int16)env._fonts.size()) {
- warning("Request to free font not loaded %d", seq._currentFontId);
- break;
- }
- env._fonts.remove_at(seq._currentFontId);
- seq._currentFontId = 0;
- break;
- case 0x00B0:
- // Does nothing?
- break;
- case 0x00C0: // (one-shot) FREE GETPUT (free getput item pointed to by _currentGetPutId)
- if (seq._executed) // this is a one-shot op
- break;
- env._getPuts[seq._currentGetPutId].reset();
- break;
- case 0x0110: // PURGE void
- _vm->adsInterpreter()->setHitTTMOp0110();
- break;
- case 0x0220: // STOP CURRENT MUSIC
- if (seq._executed) // this is a one-shot op
- break;
- _vm->_soundPlayer->stopMusic();
- break;
- case 0x0ff0: // REFRESH: void
- break;
- case 0x1020: // SET DELAY: i:int [0..n]
- // TODO: Probably should do this accounting (as well as timeCut and dialogs)
- // in game frames, not millis.
- _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * MS_PER_FRAME));
- break;
- case 0x1030: // SET BRUSH: id:int [-1:n]
- seq._brushNum = ivals[0];
- break;
- case 0x1050: // SELECT BMP: id:int [0:n]
- seq._currentBmpId = ivals[0];
- break;
- case 0x1060: // SELECT PAL: id:int [0]
- seq._currentPalId = ivals[0];
- if (seq._executed) // this is a mostly on-shot op.
- break;
- _vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
- break;
- case 0x1070: // SELECT FONT i:int
- seq._currentFontId = ivals[0];
- break;
- case 0x1090: // SELECT SONG: id:int [0]
- seq._currentSongId = ivals[0];
- break;
- case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
- // In the original this sets a global that seems to be never used?
- break;
- case 0x1100: // SET_SCENE: i:int [1..n]
- case 0x1110: // SET_SCENE: i:int [1..n]
- // DESCRIPTION IN TTM TAGS. num only used as GOTO target.
- break;
- case 0x1120: // SET GETPUT NUM
- seq._currentGetPutId = ivals[0];
- break;
- case 0x1200: // GOTO
- _vm->adsInterpreter()->setGotoTarget(findGOTOTarget(env, seq, ivals[0]));
- break;
- case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
- if (seq._executed) // this is a one-shot op.
- break;
- _vm->_soundPlayer->playSFX(ivals[0]);
- break;
- case 0x1310: // STOP SFX i:int eg [107]
- if (seq._executed) // this is a one-shot op.
- break;
- warning("TODO: Implement TTM 0x1310 stop SFX %d", ivals[0]);
- // Implement this:
- //_vm->_soundPlayer->stopSfxById(ivals[0])
- break;
- case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
- seq._drawColFG = static_cast<byte>(ivals[0]);
- seq._drawColBG = static_cast<byte>(ivals[1]);
- break;
- case 0x2020: { // SET RANDOM SLEEP: min,max: int (eg, 60,300)
- if (seq._executed) // this is a one-shot op.
- break;
- uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
- // TODO: do same time fix as for 0x1020
- _vm->adsInterpreter()->setScriptDelay((int)(sleep * MS_PER_FRAME));
- break;
- }
- case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
- // NOTE: params are xmax/ymax, NOT w/h
- seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
- break;
- case 0x4110: // FADE OUT: colorno,ncolors,targetcol,speed:byte
- if (seq._executed) // this is a one-shot op.
- break;
- if (ivals[3] == 0) {
- _vm->getGamePals()->clearPalette();
- } else {
- // The original tight-loops here with 640 steps and i/10 as the fade level..
- // bring that down a bit to use less cpu.
- // Speed 4 should complete fade in 2 seconds (eg, Dynamix logo fade)
-
- // TODO: this is a pretty bad way to do it - should pump messages in this loop?
- for (int i = 0; i < 320; i += ivals[3]) {
- int fade = MIN(i / 5, 63);
- _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- g_system->updateScreen();
- g_system->delayMillis(5);
- }
- }
- // Clear all the buffers
- _vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _vm->_compositionBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- // reset to previous palette.
- _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], 0);
- break;
- case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
- if (seq._executed) // this is a one-shot op.
- break;
-
- if (ivals[3] == 0) {
- _vm->getGamePals()->setPalette();
- } else {
- for (int i = 320; i > 0; i -= ivals[3]) {
- int fade = MAX(0, MIN(i / 5, 63));
- _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
- if (i == 320) {
- // update screen first to make the initial fade-in work
- g_system->copyRectToScreen(_vm->_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- }
- g_system->updateScreen();
- g_system->delayMillis(5);
- }
- }
- break;
- }
- case 0x4200: { // STORE AREA: x,y,w,h:int [0..n] ; makes this area of foreground persist in the next frames.
- if (seq._executed) // this is a one-shot op
- break;
- const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getStoredAreaBuffer().blitFrom(_vm->_compositionBuffer, rect, rect);
- break;
- }
- case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
- if (seq._executed) // this is a one-shot op.
- break;
- if (seq._currentGetPutId >= (int)env._getPuts.size()) {
- env._getPuts.resize(seq._currentGetPutId + 1);
- }
- const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- env._getPuts[seq._currentGetPutId]._area = rect;
-
- // Getput reads an area from the front buffer.
- Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_compositionBuffer.format);
- surf->blitFrom(_vm->_compositionBuffer, rect, Common::Point(0, 0));
- env._getPuts[seq._currentGetPutId]._surf.reset(surf);
- break;
- }
- case 0xa000: // DRAW PIXEL x,y:int
- _vm->_compositionBuffer.setPixel(ivals[0], ivals[1], seq._drawColFG);
- break;
- case 0xa050: {// SAVE REGION x,y,w,h:int
- // This is used in DRAGON intro sequence to draw the AAAAH
- // it works like a bitblit, but it doesn't write if there's something already at the destination?
- // TODO: This is part of a whole set of operations - 0xa0n4.
- // They do various flips etc.
- warning("TODO: Fix implementation of SAVE REGION (0xa050) (%d, %d, %d, %d)",
- ivals[0], ivals[1], ivals[2], ivals[3]);
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- //_vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
- //_vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
- //_vm->_compositionBuffer.transBlitFrom(_vm->_compositionBuffer);
- //_vm->_compositionBuffer.blitFrom(_vm->_compositionBuffer, r, r);
- break;
- }
- case 0xa060: { // RESTORE REGION
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getStoredAreaBuffer().fillRect(r, 0);
- break;
- }
- case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->_compositionBuffer.drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
- break;
- case 0xa100: { // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->_compositionBuffer.fillRect(r, seq._drawColFG);
- break;
- }
- case 0xa110: { // DRAW EMPTY RECT x1,y1,x2,y2:int
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->_compositionBuffer.drawLine(r.left, r.top, r.right, r.top, seq._drawColFG);
- _vm->_compositionBuffer.drawLine(r.left, r.bottom, r.right, r.bottom, seq._drawColFG);
- _vm->_compositionBuffer.drawLine(r.left, r.top, r.left, r.bottom, seq._drawColFG);
- _vm->_compositionBuffer.drawLine(r.right, r.top, r.right, r.bottom, seq._drawColFG);
- break;
- }
- case 0xa200: // 0xa2n0 DRAW STRING n: x,y,w,h:int - draw the nth string from the string table
- case 0xa210:
- case 0xa220:
- case 0xa230:
- case 0xa240:
- case 0xa250:
- case 0xa260:
- case 0xa270:
- case 0xa280:
- case 0xa290: {
- int16 fontno = seq._currentFontId;
- if (fontno >= (int16)env._fonts.size()) {
- warning("Trying to draw font no %d but only loaded %d", seq._currentFontId, env._fonts.size());
- fontno = 0;
- }
- uint strnum = (op & 0x70) >> 4;
- const Common::String &str = env._strings[strnum];
- const FontManager *mgr = _vm->getFontMan();
- const Font *font = mgr->getFont(env._fonts[fontno]);
- // Note: ignore the y-height argument (ivals[3]) for now. If width is 0, draw as much as we can.
- int width = ivals[2];
- if (width == 0)
- width = SCREEN_WIDTH - ivals[0];
- font->drawString(&(_vm->_compositionBuffer), str, ivals[0], ivals[1], width, seq._drawColFG);
- break;
- }
- case 0xa510:
- // DRAW SPRITE x,y:int .. how different from 0xa500??
- // FALL THROUGH
- case 0xa520:
- // DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
- // FALL THROUGH
- case 0xa530:
- // CHINA
- // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial symmetry?
- // you can see this in the Dynamix logo star.
- // FALL THROUGH
- case 0xa500: {
- // DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // This is kind of file system intensive, will likely have to change to store all the BMPs.
- int frameno;
- if (count == 4) {
- frameno = ivals[2];
- // TODO: Check if the bmp id is changed here in CHINA or if a temp val is used.
- seq._currentBmpId = ivals[3];
- } else {
- frameno = seq._brushNum;
- }
-
- // DRAW BMP: x,y:int [-n,+n] (RISE)
- Common::SharedPtr<Image> img = env._scriptShapes[seq._currentBmpId];
- if (img)
- img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->_compositionBuffer, op == 0xa520);
- else
- warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
- break;
- }
- case 0xa600: { // DRAW GETPUT
- if (seq._executed) // this is a one-shot op.
- break;
- int16 i = ivals[0];
- if (i >= (int16)env._getPuts.size() || !env._getPuts[i]._surf.get()) {
- warning("Trying to put getput region %d we never got", i);
- break;
- }
- const Common::Rect &r = env._getPuts[i]._area;
- // Getput should overwrite the contents
- _vm->_compositionBuffer.blitFrom(*(env._getPuts[i]._surf.get()),
- Common::Point(r.left, r.top));
- break;
- }
- case 0xf010: { // LOAD SCR: filename:str
- if (seq._executed) // this is a one-shot op
- break;
- Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
- tmp.drawScreen(sval, _vm->getBackgroundBuffer());
- _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
- _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- _vm->setBackgroundFile(sval);
- break;
- }
- case 0xf020: // LOAD BMP: filename:str
- if (seq._executed) // this is a one-shot op
- break;
- env._scriptShapes[seq._currentBmpId].reset(new Image(_vm->getResourceManager(), _vm->getDecompressor()));
- env._scriptShapes[seq._currentBmpId]->loadBitmap(sval);
- break;
- case 0xf040: { // LOAD FONT: filename:str
- if (seq._executed) // this is a one-shot op
- break;
- const FontManager *mgr = _vm->getFontMan();
- env._fonts.push_back(mgr->fontTypeByName(sval));
- seq._currentFontId = env._fonts.size() - 1;
- break;
- }
- case 0xf050: { // LOAD PAL: filename:str
- if (seq._executed) // this is a one-shot op
- break;
- int newPalNum = _vm->getGamePals()->loadPalette(sval);
- env._scriptPals[seq._currentPalId] = newPalNum;
- break;
- }
- case 0xf060: // LOAD SONG: filename:str
- if (seq._executed) // this is a one-shot op
- break;
- if (_vm->_platform == Common::kPlatformAmiga) {
- // TODO: remove hard-coded stuff..
- _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
- } else if (_vm->_platform == Common::kPlatformMacintosh) {
- _vm->_soundPlayer->loadMacMusic(sval.c_str());
- _vm->_soundPlayer->playMusic(seq._currentSongId);
- } else {
- _vm->_soundPlayer->loadMusic(sval.c_str());
- _vm->_soundPlayer->playMusic(seq._currentSongId);
- }
- break;
- case 0xf100: // 0xf1n0 - SET STRING n: s:str - set the nth string in the table
- case 0xf110:
- case 0xf120:
- case 0xf130:
- case 0xf140:
- case 0xf150:
- case 0xf160:
- case 0xf170:
- case 0xf180:
- case 0xf190: {
- uint strnum = (op & 0xf0) >> 4;
- env._strings[strnum] = sval;
- break;
- }
-
- // Unimplemented / unknown
- case 0x0010: // (one-shot) ??
- case 0x0230: // (one-shot) reset current music? (0 args) - found in HoC intro. Sets params about current music.
- case 0x0400: // (one-shot) set palette??
- case 0x1040: // Sets some global? i:int
- case 0x10B0: // null op?
- case 0x2010: // SET FRAME?? x,y
- case 0xa010: // SAVE REGION ????
- case 0xa020: // SAVE REGION ????
- case 0xa030: // SAVE REGION ????
- case 0xa040: // SAVE REGION ????
- case 0xa070: // SAVE REGION ????
- case 0xa080: // SAVE REGION ????
- case 0xa090: // SAVE REGION ????
- case 0xa300: // DRAW some string? x,y,?,?:int
- case 0xa400: // DRAW FILLED CIRCLE
- case 0xa420: // DRAW EMPTY CIRCLE
-
- // From here on are not implemented in DRAGON
- case 0xb000: // ? (0 args) - found in HoC intro
- case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
- case 0xb600: // DRAW SCREEN
- case 0xc020: // LOAD_SAMPLE
- case 0xc030: // SELECT_SAMPLE
- case 0xc040: // DESELECT_SAMPLE
- case 0xc050: // PLAY_SAMPLE
- case 0xc060: // STOP_SAMPLE
-
- default:
- if (count < 15)
- warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)",
- op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
- else
- warning("Unimplemented TTM opcode: 0x%04X (sval: %s)", op, sval.c_str());
- break;
- }
-}
-
-bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
- Common::SeekableReadStream *scr = env.scr;
- if (!scr)
- return false;
- if (scr->pos() >= scr->size())
- return false;
-
- debug(10, "TTM: Run env %d seq %d (%s) frame %d (scr offset %d, %s)", seq._enviro, seq._seqNum,
- env._tags[seq._seqNum].c_str(), seq._currentFrame, (int)scr->pos(),
- seq._executed ? "already executed" : "first execution");
- uint16 code = 0;
- while (code != 0x0ff0 && scr->pos() < scr->size()) {
- code = scr->readUint16LE();
- uint16 op = code & 0xFFF0;
- byte count = code & 0x000F;
- int16 ivals[8];
- Common::String sval;
-
- if (count > 8 && count != 0x0f)
- error("Invalid TTM opcode %04x requires %d locals", code, count);
-
- debugN(10, "\tOP: 0x%4.4x %2u ", op, count);
- if (count == 0x0F) {
- byte ch[2];
-
- do {
- ch[0] = scr->readByte();
- ch[1] = scr->readByte();
- if (ch[0])
- sval += ch[0];
- if (ch[1])
- sval += ch[1];
- } while (ch[0] != 0 && ch[1] != 0);
-
- debugN(10, "\"%s\"", sval.c_str());
- } else {
- for (byte i = 0; i < count; i++) {
- ivals[i] = scr->readSint16LE();
- if (i > 0)
- debugN(10, ", ");
- debugN(10, "%d", ivals[i]);
- }
- }
- debug(10, " (%s)", ttmOpName(op));
-
- handleOperation(env, seq, op, count, ivals, sval);
- }
-
- return true;
-}
-
-int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 targetFrame) {
- int64 startpos = env.scr->pos();
- int32 retval = -1;
- for (int32 i = 0; i < (int)env._frameOffsets.size(); i++) {
- if (env._frameOffsets[i] < 0)
- continue;
- env.scr->seek(env._frameOffsets[i]);
- uint16 op = env.scr->readUint16LE();
- if (op == 0x1101 || op == 0x1111) {
- uint16 frameno = env.scr->readUint16LE();
- if (frameno == targetFrame) {
- retval = i;
- break;
- }
- }
- }
- env.scr->seek(startpos);
- return retval;
-}
-
-void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &seqArray) {
- int16 envno = env._enviro;
- env.scr->seek(0);
- uint16 op = 0;
- for (uint frame = 0; frame < env._totalFrames; frame++) {
- env._frameOffsets[frame] = env.scr->pos();
- //debug("findAndAddSequences: frame %d at offset %d", frame, (int)env.scr->pos());
- op = env.scr->readUint16LE();
- while (op != 0x0ff0 && env.scr->pos() < env.scr->size()) {
- //debug("findAndAddSequences: check ttm op %04x", op);
- if (op == 0xaf1f || op == 0xaf2f)
- warning("TODO: Fix findAndAddSequences for opcode %x which has variable length arg", op);
- switch (op & 0xf) {
- case 0:
- break;
- case 1:
- if (op == 0x1111) {
- TTMSeq newseq;
- newseq._enviro = envno;
- newseq._seqNum = env.scr->readUint16LE();
- newseq._startFrame = frame;
- newseq._currentFrame = frame;
- newseq._lastFrame = -1;
- //debug("findAndAddSequences: found env %d seq %d at %d", newseq._enviro, newseq._seqNum, (int)env.scr->pos());
- seqArray.push_back(newseq);
- } else {
- env.scr->skip(2);
- }
- break;
- case 0xf: {
- byte ch[2];
- do {
- ch[0] = env.scr->readByte();
- ch[1] = env.scr->readByte();
- } while (ch[0] != 0 && ch[1] != 0);
- break;
- }
- default:
- env.scr->skip((op & 0xf) * 2);
- break;
- }
- op = env.scr->readUint16LE();
- }
- }
- env.scr->seek(0);
-}
-
-void TTMSeq::reset() {
- _currentFontId = 0;
- _currentPalId = 0;
- _currentPalId = 0;
- _currentBmpId = 0;
- _currentGetPutId = 0;
- _currentFrame = _startFrame;
- _gotoFrame = -1;
- _drawColBG = 0xf;
- _drawColFG = 0xf;
- _brushNum = 0;
- _timeInterval = 0;
- _timeNext = 0;
- _runCount = 0;
- _runPlayed = 0;
- _executed = false;
- _runFlag = kRunTypeStopped;
- _scriptFlag = 0;
- _selfLoop = false;
- _drawWin = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
-}
-
-ADSInterpreter::ADSInterpreter(DgdsEngine *vm) : _vm(vm), _currentTTMSeq(nullptr), _adsData(nullptr) {
- _ttmInterpreter = new TTMInterpreter(_vm);
-}
-
-ADSInterpreter::~ADSInterpreter() {
- delete _ttmInterpreter;
- _ttmInterpreter = nullptr;
- for (auto &data : _adsTexts)
- delete data._value.scr;
-}
-
-bool ADSInterpreter::load(const Common::String &filename) {
- // Don't clear current _adsData, we reset that below.
- _currentTTMSeq = nullptr;
-
- // For high detail, replace extension ADS with ADH. Low detail is ADL.
- Common::String detailfile = filename.substr(0, filename.size() - 1);
- if (_vm->getDetailLevel() == kDgdsDetailLow)
- detailfile += "L";
- else
- detailfile += "H";
-
- if (!_vm->getResourceManager()->hasResource(detailfile))
- detailfile = filename;
-
- debug("ADSInterpreter: load %s", detailfile.c_str());
- /* FIXME: quick hack - never reuse data.
- if (_adsTexts.contains(detailfile)) {
- _adsData = &(_adsTexts.getVal(detailfile));
- return true;
- }*/
-
- _adsTexts.setVal(detailfile, ADSData());
- _adsData = &(_adsTexts.getVal(detailfile));
-
- ADSParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
- dgds.parse(_adsData, detailfile);
-
- for (const auto &file : _adsData->_scriptNames) {
- _adsData->_scriptEnvs.resize(_adsData->_scriptEnvs.size() + 1);
- debug(" load TTM %s to env %d", file.c_str(), _adsData->_scriptEnvs.size());
- TTMEnviro &data = _adsData->_scriptEnvs.back();
- data._enviro = _adsData->_scriptEnvs.size();
- _ttmInterpreter->load(file, data);
- _ttmInterpreter->findAndAddSequences(data, _adsData->_ttmSeqs);
- }
-
- _adsData->scr->seek(0);
-
- uint16 opcode = 0;
- int segcount = 0;
- findUsedSequencesForSegment(0);
- _adsData->_segments[0] = 0;
- opcode = _adsData->scr->readUint16LE();
- while (_adsData->scr->pos() < _adsData->scr->size()) {
- if (opcode == 0xffff) {
- segcount++;
- _adsData->_segments[segcount] = _adsData->scr->pos();
- findUsedSequencesForSegment(segcount);
- } else {
- _adsData->scr->skip(numArgs(opcode) * 2);
- }
- opcode = _adsData->scr->readUint16LE();
- }
-
- for (uint i = segcount + 1; i < ARRAYSIZE(_adsData->_segments); i++)
- _adsData->_segments[i] = -1;
-
- _adsData->_maxSegments = segcount + 1;
- _adsData->filename = filename;
-
- for (uint i = 0; i < ARRAYSIZE(_adsData->_state); i++)
- _adsData->_state[i] = 8;
- for (auto &seq : _adsData->_ttmSeqs)
- seq.reset();
-
- return true;
-}
-
-static const uint16 ADS_SEQ_OPCODES[] = {
- 0x2000, 0x2005, 0x2010, 0x2015, 0x4000, 0x4010, 0x1330,
- 0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
-};
-
-bool ADSInterpreter::updateSeqTimeAndFrame(const TTMEnviro *env, TTMSeq &seq) {
- if (seq._timeInterval != 0) {
- uint32 now = g_engine->getTotalPlayTime();
- if (now < seq._timeNext) {
- debug(10, "env %d seq %d (%s) not advancing from frame %d (now %d timeNext %d interval %d)", seq._enviro,
- seq._seqNum, env->_tags[seq._seqNum].c_str(), seq._currentFrame, now, seq._timeNext, seq._timeInterval);
- return false;
- }
- seq._timeNext = now + seq._timeInterval;
- }
-
- seq._executed = false;
- if (seq._gotoFrame == -1) {
- debug(10, "env %d seq %d (%s) advance to frame %d->%d (start %d last %d)", seq._enviro, seq._seqNum,
- env->_tags[seq._seqNum].c_str(), seq._currentFrame, seq._currentFrame + 1, seq._startFrame, seq._lastFrame);
- seq._currentFrame++;
- } else {
- debug(10, "env %d seq %d (%s) goto to frame %d->%d (start %d last %d)", seq._enviro, seq._seqNum,
- env->_tags[seq._seqNum].c_str(), seq._currentFrame, seq._gotoFrame, seq._startFrame, seq._lastFrame);
- seq._currentFrame = seq._gotoFrame;
- seq._gotoFrame = -1;
- }
-
- return true;
-}
-
-void ADSInterpreter::findUsedSequencesForSegment(int segno) {
- _adsData->_usedSeqs[segno].clear();
- int64 startoff = _adsData->scr->pos();
- uint16 opcode = 0;
- // Skip the segment number.
- _adsData->scr->readUint16LE();
- while (opcode != 0xffff && _adsData->scr->pos() < _adsData->scr->size()) {
- opcode = _adsData->scr->readUint16LE();
- for (uint16 o : ADS_SEQ_OPCODES) {
- if (opcode == o) {
- int16 envno = _adsData->scr->readSint16LE();
- int16 seqno = _adsData->scr->readSint16LE();
- TTMSeq *seq = findTTMSeq(envno, seqno);
- if (!seq) {
- warning("ADS opcode %04x at offset %d references unknown seq %d %d",
- opcode, (int)_adsData->scr->pos(), envno, seqno);
- } else {
- bool already_added = false;
- for (const TTMSeq *s : _adsData->_usedSeqs[segno]) {
- if (s == seq) {
- already_added = true;
- break;
- }
- }
- if (!already_added)
- _adsData->_usedSeqs[segno].push_back(seq);
- }
- // Rewind as we will go forward again outside this loop.
- _adsData->scr->seek(-4, SEEK_CUR);
- break;
- }
- }
- _adsData->scr->skip(numArgs(opcode) * 2);
- }
- _adsData->scr->seek(startoff);
-}
-
-
-void ADSInterpreter::unload() {
- _adsData = nullptr;
- _currentTTMSeq = nullptr;
- _adsTexts.clear();
-}
-
-bool ADSInterpreter::playScene() {
- if (!_currentTTMSeq)
- return false;
-
- TTMEnviro *env = findTTMEnviro(_currentTTMSeq->_enviro);
- if (!env)
- error("Couldn't find environment num %d", _currentTTMSeq->_enviro);
-
- _adsData->_gotoTarget = -1;
- return _ttmInterpreter->run(*env, *_currentTTMSeq);
-}
-
-bool ADSInterpreter::skipSceneLogicBranch() {
- Common::SeekableReadStream *scr = _adsData->scr;
- bool result = true;
- while (scr->pos() < scr->size()) {
- uint16 op = scr->readUint16LE();
- if (op == 0x1510 || op == 0x1500) {
- scr->seek(-2, SEEK_CUR);
- return true;
- } else if (op == 0 || op == 0xffff) {
- // end of segment
- return false;
- } else if ((op & 0xff0f) == 0x1300) {
- // a 0x13x0 logic op
- result = handleOperation(op, scr);
- } else {
- scr->skip(numArgs(op) * 2);
- }
- }
- return result && scr->pos() < scr->size();
-}
-
-bool ADSInterpreter::skipToEndIf() {
- Common::SeekableReadStream *scr = _adsData->scr;
- bool result = skipSceneLogicBranch();
- if (result) {
- uint16 op = scr->readUint16LE();
- if (op == 0x1500)
- result = runUntilBranchOpOrEnd();
- // don't rewind - the calls to this should always return ptr+2
- }
- return result;
-}
-
-bool ADSInterpreter::skipToEndWhile() {
- Common::SeekableReadStream *scr = _adsData->scr;
- while (scr->pos() < scr->size()) {
- uint16 op = scr->readUint16LE();
- // don't rewind - the calls to this should always return after the last op.
- if (op == 0x1520)
- return true;
- else if (op == 0 || op == 0xffff)
- return false;
-
- scr->skip(numArgs(op) * 2);
- }
- return false;
-}
-
-TTMEnviro *ADSInterpreter::findTTMEnviro(int16 enviro) {
- for (auto & env : _adsData->_scriptEnvs) {
- if (env._enviro == enviro)
- return &env;
- }
- return nullptr;
-}
-
-TTMSeq *ADSInterpreter::findTTMSeq(int16 enviro, int16 seqno) {
- for (auto &seq : _adsData->_ttmSeqs) {
- if (seq._enviro == enviro && seq._seqNum == seqno)
- return &seq;
- }
- return nullptr;
-}
-
-void ADSInterpreter::segmentOrState(int16 seg, uint16 val) {
- int idx = getArrIndexOfSegNum(seg);
- if (idx >= 0) {
- _adsData->_charWhile[idx] = 0;
- _adsData->_state[idx] = (_adsData->_state[idx] & 8) | val;
- }
-}
-
-
-void ADSInterpreter::segmentSetState(int16 seg, uint16 val) {
- int idx = getArrIndexOfSegNum(seg);
- if (idx >= 0) {
- _adsData->_charWhile[idx] = 0;
- if (_adsData->_state[idx] != 8)
- _adsData->_state[idx] = val;
- }
-}
-
-void ADSInterpreter::findEndOrInitOp() {
- Common::SeekableReadStream *scr = _adsData->scr;
- int32 startoff = scr->pos();
- while (scr->pos() < scr->size()) {
- uint16 opcode = scr->readUint16LE();
- // on FFFF return the original offset
- if (opcode == 0xffff) {
- scr->seek(startoff);
- return;
- }
- // on 5 (init) return the next offset (don't rewind)
- if (opcode == 0x0005)
- return;
- // everything else just go forward.
- scr->skip(numArgs(opcode) * 2);
- }
-}
-
-bool ADSInterpreter::logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq) {
- const char *tag = env->_tags[seq->_seqNum].c_str();
- int16 envNum = env->_enviro;
- int16 seqNum = seq->_seqNum;
- const char *optype = (code < 0x1300 ? "while" : "if");
- switch (code) {
- case 0x1010: // WHILE runtype 5
- case 0x1310: // IF runtype 5, 2 params
- debugN(10, "ADS 0x%04x: %s runtype 5 env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return seq->_runFlag == kRunType5;
- case 0x1020: // WHILE not runtype 5
- case 0x1320: // IF not runtype 5, 2 params
- debugN(10, "ADS 0x%04x: %s not runtype 5 env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return seq->_runFlag != kRunType5;
- case 0x1030: // WHILE NOT PLAYED
- case 0x1330: // IF_NOT_PLAYED, 2 params
- debugN(10, "ADS 0x%04x: %s not played env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return !seq->_runPlayed;
- case 0x1040: // WHILE PLAYED
- case 0x1340: // IF_PLAYED, 2 params
- debugN(10, "ADS 0x%04x: %s played env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return seq->_runPlayed;
- case 0x1050: // WHILE FINISHED
- case 0x1350: // IF_FINISHED, 2 params
- debugN(10, "ADS 0x%04x: %s finished env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return seq->_runFlag == kRunTypeFinished;
- case 0x1060: // WHILE NOT RUNNING
- case 0x1360: // IF_NOT_RUNNING, 2 params
- debugN(10, "ADS 0x%04x: %s not running env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return seq->_runFlag == kRunTypeStopped;
- case 0x1070: // WHILE RUNNING
- case 0x1370: // IF_RUNNING, 2 params
- debugN(10, "ADS 0x%04x: %s running env %d seq %d (%s)", code, optype, envNum, seqNum, tag);
- return seq->_runFlag == kRunType1 || seq->_runFlag == kRunTypeMulti || seq->_runFlag == kRunTypeTimeLimited;
- case 0x1080:
- case 0x1090:
- case 0x1380: // IF_???????, 0 params
- case 0x1390: // IF_???????, 0 params
- warning("Unimplemented IF/WHILE operation 0x%x", code);
- return true;
- default:
- error("Not an ADS logic op: %04x, how did we get here?", code);
- }
-}
-
-bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr) {
- bool testval = true;
- uint16 andor = 0x1420; // start with "true" AND..
- int32 startPos = scr->pos() - 2;
- while (scr->pos() < scr->size()) {
- uint16 enviro;
- uint16 seqnum;
- TTMSeq *seq = nullptr;
- TTMEnviro *env = nullptr;
-
- if (code != 0x1380 && code != 0x1390) {
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- seq = findTTMSeq(enviro, seqnum);
- env = findTTMEnviro(enviro);
- if (!seq) {
- warning("ADS if op referenced non-existant env %d seq %d", enviro, seqnum);
- return false;
- }
- } else {
- // TODO: not actually enviro I think? for now just read it.
- enviro = scr->readUint16LE();
- }
-
- bool logicResult = logicOpResult(code, env, seq);
-
- if (andor == 0x1420) // AND
- testval &= logicResult;
- else // OR
- testval |= logicResult;
-
- debug(10, " -> %s (overall %s)", logicResult ? "true" : "false", testval ? "true" : "false");
- bool isWhile = code < 0x1300;
-
- code = scr->readUint16LE();
-
- if (code == 0x1420 || code == 0x1430) {
- andor = code;
- debug(10, " ADS 0x%04x: %s", code, code == 0x1420 ? "AND" : "OR");
- code = scr->readUint16LE();
- // The next op should be another logic op
- } else {
- // No AND or OR, next op is just what to do.
- scr->seek(-2, SEEK_CUR);
- if (testval) {
- if (isWhile) {
- _adsData->_countdown[_adsData->_runningSegmentIdx]++;
- _adsData->_charWhile[_adsData->_runningSegmentIdx] = startPos;
- }
- bool runResult = runUntilBranchOpOrEnd();
- // WHILE (10x0) series always return false
- return (!isWhile) && runResult;
- } else {
- if (isWhile) {
- _adsData->_countdown[_adsData->_runningSegmentIdx] = 0;
- _adsData->_charWhile[_adsData->_runningSegmentIdx] = 0;
- return skipToEndWhile();
- } else {
- return skipToEndIf();
- }
- }
- }
- }
- error("didn't return from ADS logic test");
-}
-
-int16 ADSInterpreter::randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr) {
- // Leaves the pointer at the same place it started
- int argsize = numArgs(code) * 2;
- if (argsize == 0)
- error("Unexpected 0-arg ADS opcode 0x%04x inside random block", code);
- // skip args before the random proportion
- if (argsize > 2)
- scr->seek(argsize - 2, SEEK_CUR);
- int16 result = scr->readSint16LE();
- scr->seek(-argsize, SEEK_CUR);
- return result;
-}
-
-void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr) {
- int16 max = 0;
- int64 startpos = scr->pos();
- // Collect the random proportions
- code = scr->readUint16LE();
- while (code != 0 && code != 0x30ff && scr->pos() < scr->size()) {
- int16 val = randomOpGetProportion(code, scr);
- // leaves pointer at beginning of next op
- max += val;
- scr->skip(numArgs(code) * 2);
- if (scr->pos() >= scr->size())
- break;
- code = scr->readUint16LE();
- }
- if (!max)
- return;
-
- int64 endpos = scr->pos();
-
- int16 randval = _vm->getRandom().getRandomNumber(max - 1) + 1; // Random from 1-max.
- scr->seek(startpos, SEEK_SET);
-
- // Now find the random bit to jump to
- code = scr->readUint16LE();
- do {
- int16 val = randomOpGetProportion(code, scr);
- randval -= val;
- if (randval < 1) {
- // This is the opcode we want to execute
- break;
- }
- scr->skip(numArgs(code) * 2);
- if (scr->pos() >= scr->size())
- break;
- code = scr->readUint16LE();
- } while (code != 0 && scr->pos() < scr->size());
- if (code && code != 0x3020)
- handleOperation(code, scr);
-
- scr->seek(endpos, SEEK_SET);
-}
-
-bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *scr) {
- uint16 enviro, seqnum;
-
- switch (code) {
- case 0x0001:
- case 0x0005:
- debug(10, "ADS 0x%04x: init", code);
- // "init". 0x0005 can be used for searching for next thing.
- break;
- case 0x1010: // if unknown, 2 params
- case 0x1020: // if unknown, 2 params
- case 0x1030: // if unknown, 2 params
- case 0x1040: // if unknown, 2 params
- case 0x1050: // if unknown, 2 params
- case 0x1060: // if unknown, 2 params
- case 0x1070: // if unknown, 2 params
- case 0x1080: // if current seq countdown??, 1 param
- case 0x1090: // if ??? ???
- case 0x1310: // IF runtype 5, 2 params
- case 0x1320: // IF not runtype 5, 2 params
- case 0x1330: // IF_NOT_PLAYED, 2 params
- case 0x1340: // IF_PLAYED, 2 params
- case 0x1350: // IF_FINISHED, 2 params
- case 0x1360: // IF_NOT_RUNNING, 2 params
- case 0x1370: // IF_RUNNING, 2 params
- case 0x1380: // IF_??????, 1 param (HOC+ only)
- case 0x1390: // IF_??????, 1 param (HOC+ only)
- return handleLogicOp(code, scr);
- case 0x1500: // ? IF ?, 0 params
- //debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
- debug(10, "ADS 0x%04x: skip to end if", code);
- skipToEndIf();
- _adsData->_hitBranchOp = true;
- return true;
- case 0x1510: // PLAY_SCENEENDIF? 0 params
- debug(10, "ADS 0x%04x: hit branch op endif", code);
- _adsData->_hitBranchOp = true;
- return true;
- case 0x1520: // PLAY_SCENE_ENDWHILE?, 0 params
- debug(10, "ADS 0x%04x: hit branch op endwhile", code);
- _adsData->_hitBranchOp = true;
- return false;
-
- case 0x2000:
- case 0x2005: { // ADD sequence
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- int16 runCount = scr->readSint16LE();
- uint16 unk = scr->readUint16LE(); // proportion
-
- TTMSeq *seq = findTTMSeq(enviro, seqnum);
- TTMEnviro *env = findTTMEnviro(enviro);
- if (!seq || !env)
- error("ADS invalid seq requested %d %d", enviro, seqnum);
-
- debug(10, "ADS 0x%04x: add scene - env %d seq %d (%s) runCount %d prop %d", code,
- enviro, seqnum, env->_tags[seqnum].c_str(), runCount, unk);
-
- if (code == 0x2000)
- seq->_currentFrame = seq->_startFrame;
-
- _currentTTMSeq = seq;
- if (runCount == 0) {
- seq->_runFlag = kRunType1;
- } else if (runCount < 0) {
- // Negative run count sets the cut time
- seq->_timeCut = g_engine->getTotalPlayTime() + (-runCount * MS_PER_FRAME);
- seq->_runFlag = kRunTypeTimeLimited;
- } else {
- seq->_runFlag = kRunTypeMulti;
- seq->_runCount = runCount - 1;
- }
- seq->_runPlayed++;
- break;
- }
- case 0x2010: { // STOP_SCENE, 3 params (ttmenv, ttmseq, proportion)
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- uint16 unk = scr->readUint16LE();
- _currentTTMSeq = findTTMSeq(enviro, seqnum);
- const TTMEnviro *env = findTTMEnviro(enviro);
- debug(10, "ADS 0x2010: stop seq env %d seq %d (%s) prop %d", enviro, seqnum,
- env->_tags[seqnum].c_str(), unk);
- if (_currentTTMSeq)
- _currentTTMSeq->_runFlag = kRunTypeStopped;
- break;
- }
- case 0x2015: { // SET RUNFLAG 5, 3 params (ttmenv, ttmseq, proportion)
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- uint16 unk = scr->readUint16LE();
- _currentTTMSeq = findTTMSeq(enviro, seqnum);
- const TTMEnviro *env = findTTMEnviro(enviro);
- debug(10, "ADS 0x2015: set runflag5 env %d seq %d (%s) prop %d", enviro, seqnum,
- env->_tags[seqnum].c_str(), unk);
- if (_currentTTMSeq)
- _currentTTMSeq->_runFlag = kRunType5;
- break;
- }
- case 0x2020: { // RESET SEQ, 2 params (env, seq, proportion)
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- uint16 unk = scr->readUint16LE();
- _currentTTMSeq = findTTMSeq(enviro, seqnum);
- const TTMEnviro *env = findTTMEnviro(enviro);
- debug(10, "ADS 0x2020: reset scene env %d seq %d (%s) prop %d", enviro, seqnum,
- env->_tags[seqnum].c_str(), unk);
- if (_currentTTMSeq)
- _currentTTMSeq->reset();
- break;
- }
-
- case 0x3020: {// RANDOM_NOOP, 1 param (proportion)
- uint16 unk = scr->readUint16LE();
- debug(10, "ADS 0x3020: random noop? prop %d", unk);
- return true;
- }
- case 0x3010: // RANDOM_START, 0 params
- case 0x30FF: // RANDOM_END, 0 params
- debug(10, "ADS 0x%04x: random %s", code, code == 0x3010 ? "start" : "end");
- handleRandomOp(code, scr);
- break;
-
- case 0x4000: { // MOVE SEQ TO BACK
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug(10, "ADS 0x%04x: mov seq to back env %d seq %d", code, enviro, seqnum);
- /*uint16 unk = */scr->readUint16LE();
- // This is O(N) but the N is small and it's not called often.
- TTMSeq seq;
- bool success = false;
- for (uint i = 0; i < _adsData->_ttmSeqs.size(); i++) {
- if (_adsData->_ttmSeqs[i]._enviro == enviro && _adsData->_ttmSeqs[i]._seqNum == seqnum) {
- seq = _adsData->_ttmSeqs[i];
- _adsData->_ttmSeqs.remove_at(i);
- success = true;
- break;
- }
- }
-
- if (success)
- _adsData->_ttmSeqs.push_back(seq);
- else
- warning("ADS: 0x4000 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
-
- break;
- }
-
- case 0x4010: { // MOVE SEQ TO FRONT
- enviro = scr->readUint16LE();
- seqnum = scr->readUint16LE();
- debug(10, "ADS 0x%04x: mov seq to front env %d seq %d", code, enviro, seqnum);
- /*uint16 unk = */scr->readUint16LE();
- // This is O(N) but the N is small and it's not called often.
- TTMSeq seq;
- bool success = false;
- for (uint i = 0; i < _adsData->_ttmSeqs.size(); i++) {
- if (_adsData->_ttmSeqs[i]._enviro == enviro && _adsData->_ttmSeqs[i]._seqNum == seqnum) {
- seq = _adsData->_ttmSeqs[i];
- _adsData->_ttmSeqs.remove_at(i);
- success = true;
- break;
- }
- }
-
- if (success)
- _adsData->_ttmSeqs.insert_at(0, seq);
- else
- warning("ADS: 0x4010 Request to move env %d seq %d which doesn't exist", enviro, seqnum);
-
- break;
- }
-
- case 0xF000:
- debug(10, "ADS 0x%04x: set state 2, current idx (%d)", code, _adsData->_runningSegmentIdx);
- if (_adsData->_runningSegmentIdx != -1)
- _adsData->_state[_adsData->_runningSegmentIdx] = 2;
- return false;
-
- case 0xF010: {// FADE_OUT, 1 param
- int16 segment = scr->readSint16LE();
- int16 idx = _adsData->_runningSegmentIdx;
- if (segment >= 0)
- idx = getArrIndexOfSegNum(segment);
- debug(10, "ADS 0x%04x: set state 2, segment %d (idx %d)", code, segment, idx);
- if (idx >= 0)
- _adsData->_state[idx] = 2;
- if (idx == _adsData->_runningSegmentIdx)
- return false;
- else
- return true;
- }
-
- case 0xF200: { // RUN_SCRIPT, 1 param
- int16 segment = scr->readSint16LE();
- int16 idx = getArrIndexOfSegNum(segment);
- debug(10, "ADS 0x%04x: add 4 remove 8 to state seg %d idx %d", code, segment, idx);
- if (segment >= 0) {
- int state = (_adsData->_state[idx] & 8) | 4;
- _adsData->_state[idx] = state;
- }
- return true;
- }
-
- case 0xF210: { // RUN_SCRIPT, 1 param
- int16 segment = scr->readSint16LE();
- int16 idx = getArrIndexOfSegNum(segment);
- debug(10, "ADS 0x%04x: add 3 remove 8 to state seg %d idx %d", code, segment, idx);
- if (segment >= 0) {
- int state = (_adsData->_state[idx] & 8) | 3;
- _adsData->_state[idx] = state;
- }
- return true;
- }
-
- case 0xffff: // END
- debug(10, "ADS 0xFFF: end");
- return false;
-
- //// unknown / to-be-implemented
- case 0x1420: // AND, 0 params
- case 0x1430: // OR, 0 params
- case 0xFF10:
- case 0xFFF0: // END_IF, 0 params
- default: {
- int nops = numArgs(code);
- warning("ADS 0x%04x: Unimplemented opcode: (skip %d args)", code, nops);
- for (int i = 0; i < nops; i++)
- scr->readUint16LE();
- break;
- }
- }
-
- return true;
-}
-
-int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
- int idx = getArrIndexOfSegNum(segnum);
- if (idx < 0)
- return 0;
- if (!(_adsData->_state[idx] & 4)) {
- for (auto *seq : _adsData->_usedSeqs[idx]) {
- if (!seq)
- return 0;
- if (seq->_runFlag != kRunTypeStopped && !seq->_selfLoop)
- return 1;
- }
- return 0;
- }
- return 1;
-}
-
-
-int ADSInterpreter::getArrIndexOfSegNum(uint16 segnum) {
- int32 startoff = _adsData->scr->pos();
- int result = -1;
- for (int i = 0; i < _adsData->_maxSegments; i++) {
- _adsData->scr->seek(_adsData->_segments[i]);
- int16 seg = _adsData->scr->readSint16LE();
- if (seg == segnum) {
- result = i;
- break;
- }
- }
- _adsData->scr->seek(startoff);
- return result;
-}
-
-
-bool ADSInterpreter::run() {
- if (_adsData->_ttmSeqs.empty())
- return false;
-
- for (int i = 0; i < _adsData->_maxSegments; i++) {
- int16 flag = _adsData->_state[i] & 0xfff7;
- for (auto seq : _adsData->_usedSeqs[i]) {
- if (flag == 3) {
- seq->reset();
- } else {
- seq->_scriptFlag = flag;
- }
- }
- }
-
- for (int i = 0; i < _adsData->_maxSegments; i++) {
- int16 state = _adsData->_state[i];
- int32 offset = _adsData->_segments[i];
- _adsData->scr->seek(offset);
- // skip over the segment num
- offset += 2;
- /*int16 segnum =*/ _adsData->scr->readSint16LE();
- if (state & 8) {
- state &= 0xfff7;
- _adsData->_state[i] = state;
- } else {
- findEndOrInitOp();
- offset = _adsData->scr->pos();
- }
-
- if (_adsData->_charWhile[i])
- offset = _adsData->_charWhile[i];
-
- if (state == 3 || state == 4) {
- _adsData->_state[i] = 1;
- state = 1;
- }
-
- _adsData->_runningSegmentIdx = i;
- if (_adsData->scr && state == 1) {
- _adsData->scr->seek(offset);
- //debug("ADS: Run segment %d idx %d/%d", segnum, i, _adsData->_maxSegments);
- runUntilBranchOpOrEnd();
- }
- }
-
- bool result = false;
- for (auto &seq : _adsData->_ttmSeqs) {
- _currentTTMSeq = &seq;
- seq._lastFrame = -1;
- int sflag = seq._scriptFlag;
- TTMRunType rflag = seq._runFlag;
- if (sflag == 6 || (rflag != kRunType1 && rflag != kRunTypeTimeLimited && rflag != kRunTypeMulti && rflag != kRunType5)) {
- if (sflag != 6 && sflag != 5 && rflag == kRunTypeFinished) {
- seq._runFlag = kRunTypeStopped;
- }
- } else {
- int16 curframe = seq._currentFrame;
- TTMEnviro *env = findTTMEnviro(seq._enviro);
- _adsData->_hitTTMOp0110 = false;
- _adsData->_scriptDelay = -1;
- bool scriptresult = false;
- // Next few lines of code in a separate function in the original..
- if (curframe < env->_totalFrames && curframe > -1 && env->_frameOffsets[curframe] > -1) {
- env->scr->seek(env->_frameOffsets[curframe]);
- scriptresult = playScene();
- }
-
- if (scriptresult && sflag != 5) {
- seq._executed = true;
- seq._lastFrame = seq._currentFrame;
- result = true;
- if (_adsData->_scriptDelay != -1 && seq._timeInterval != _adsData->_scriptDelay) {
- uint32 now = g_engine->getTotalPlayTime();
- seq._timeNext = now + _adsData->_scriptDelay;
- seq._timeInterval = _adsData->_scriptDelay;
- }
-
- if (!_adsData->_hitTTMOp0110) {
- if (_adsData->_gotoTarget != -1) {
- seq._gotoFrame = _adsData->_gotoTarget;
- if (seq._currentFrame == _adsData->_gotoTarget)
- seq._selfLoop = true;
- }
- if (seq._runFlag != kRunType5)
- updateSeqTimeAndFrame(env, seq);
- } else {
- seq._gotoFrame = seq._startFrame;
- if (seq._runFlag == kRunTypeMulti && seq._runCount != 0) {
- bool updated = updateSeqTimeAndFrame(env, seq);
- if (updated) {
- seq._runCount--;
- }
- } else if (seq._runFlag == kRunTypeTimeLimited && seq._timeCut != 0) {
- updateSeqTimeAndFrame(env, seq);
- } else {
- bool updated = updateSeqTimeAndFrame(env, seq);
- if (updated) {
- seq._runFlag = kRunTypeFinished;
- seq._timeInterval = 0;
- }
- }
- }
- } else if (sflag != 5) {
- seq._gotoFrame = seq._startFrame;
- seq._runFlag = kRunTypeFinished;
- }
- }
-
- if (rflag == kRunTypeTimeLimited && seq._timeCut <= g_engine->getTotalPlayTime()) {
- seq._runFlag = kRunTypeFinished;
- }
- }
- return result;
-}
-
-bool ADSInterpreter::runUntilBranchOpOrEnd() {
- Common::SeekableReadStream *scr = _adsData->scr;
- if (!scr || scr->pos() >= scr->size())
- return false;
-
- bool more = true;
- do {
- uint16 code = scr->readUint16LE();
- if (code == 0xffff)
- return false;
- more = handleOperation(code, scr);
- } while (!_adsData->_hitBranchOp && more && scr->pos() < scr->size());
-
- _adsData->_hitBranchOp = false;
-
- return more;
-}
-
-void ADSInterpreter::setHitTTMOp0110() {
- _adsData->_hitTTMOp0110 = true;
-}
-
-void ADSInterpreter::setGotoTarget(int32 target) {
- _adsData->_gotoTarget = target;
-}
-
-int ADSInterpreter::numArgs(uint16 opcode) const {
- // TODO: This list is from DRAGON, there may be more entries in newer games.
- switch (opcode) {
- case 0x1080:
- case 0x1380:
- case 0x1390:
- case 0x3020:
- case 0xF010:
- case 0xF200:
- case 0xF210:
- return 1;
-
- case 0x1010:
- case 0x1020:
- case 0x1030:
- case 0x1040:
- case 0x1050:
- case 0x1060:
- case 0x1070:
- case 0x1310:
- case 0x1320:
- case 0x1330:
- case 0x1340:
- case 0x1350:
- case 0x1360:
- case 0x1370:
- return 2;
-
- case 0x2010:
- case 0x2015:
- case 0x2020:
- case 0x4000:
- case 0x4010:
- return 3;
-
- case 0x2000:
- case 0x2005:
- return 4;
-
- default:
- return 0;
- }
-}
-
-Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
- //TODO: Currently sync all states then set the active one,
- // do we need to load/save all?
- uint32 numTexts = _adsTexts.size();
- s.syncAsUint32LE(numTexts);
-
- Common::Array<Common::String> scriptNames;
- Common::String activeScript;
-
- if (s.isLoading()) {
- for (uint32 i = 0; i < numTexts; i++) {
- Common::String txtName;
- s.syncString(txtName);
- load(txtName);
- scriptNames.push_back(txtName);
- }
- } else {
- for (const auto &node : _adsTexts) {
- Common::String txtName = node._key;
- s.syncString(txtName);
- scriptNames.push_back(txtName);
- if (&node._value == _adsData)
- activeScript = txtName;
- }
- }
-
- // Text order should be the same
- for (const Common::String &name : scriptNames) {
- _adsTexts[name].syncState(s);
- }
-
- s.syncString(activeScript);
- assert(_adsTexts.contains(activeScript));
- _adsData = &_adsTexts[activeScript];
-
- return Common::kNoError;
-}
-
} // End of namespace Dgds
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index a3bd4c5e686..73f885fe527 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -23,195 +23,19 @@
#ifndef DGDS_SCRIPTS_H
#define DGDS_SCRIPTS_H
-#include "common/rect.h"
-#include "graphics/managed_surface.h"
-
#include "dgds/parser.h"
-#include "dgds/scene.h"
-#include "dgds/font.h"
namespace Dgds {
-class DgdsEngine;
-class DgdsChunkReader;
-class Image;
-
class ScriptParserData : public ParserData {
public:
ScriptParserData() : scr(nullptr) {}
- Common::String filename;
+ Common::String _filename;
Common::SeekableReadStream *scr;
Common::HashMap<uint16, Common::String> _tags;
};
-class GetPutRegion {
-public:
- Common::Rect _area;
- Common::SharedPtr<Graphics::ManagedSurface> _surf;
-
- void reset();
-};
-
-class TTMEnviro : public ScriptParserData {
-public:
- TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
- ARRAYCLEAR(_scriptPals);
- _fonts.push_back(FontManager::kDefaultFont); // is this right?
- }
-
- Common::Error syncState(Common::Serializer &s);
-
- uint16 _enviro;
- uint16 _totalFrames;
- Common::Array<int> _frameOffsets;
- Common::SharedPtr<Image> _scriptShapes[6];
- Common::Array<GetPutRegion> _getPuts;
- int _scriptPals[6];
- Common::String _strings[10];
- Common::Array<FontManager::FontType> _fonts;
-};
-
-enum TTMRunType {
- kRunTypeStopped = 0,
- kRunType1 = 1,
- kRunTypeMulti = 2,
- kRunTypeTimeLimited = 3,
- kRunTypeFinished = 4,
- kRunType5 = 5,
-};
-
-
-// Note: this object needs to be safely copy-able - ADS opcodes 0x4000 and 0x4010 require it.
-struct TTMSeq {
- TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _lastFrame(0), _timeCut(0) {
- // Other members are initialized in the reset function.
- reset();
- }
-
- void reset();
- Common::Error syncState(Common::Serializer &s);
-
- int16 _enviro;
- int16 _seqNum;
- int16 _startFrame; // first frame in this sequence
- int16 _gotoFrame; // frame to GOTO (or -1 if not currently set)
- int16 _currentFrame; // currently executing frame
- int16 _lastFrame; // previous frame processed (-1 if none)
- bool _selfLoop; // does the script frame loop back on itself
- bool _executed; // has the current frame already been run
- uint32 _timeNext; // time the next frame should be run
- uint32 _timeCut; // time to finish execution
- Common::Rect _drawWin;
- // these current ids are called "slot"s in the original
- int16 _currentFontId; // aka slot 0
- int16 _currentPalId; // aka slot 1
- int16 _currentSongId; // aka slot 3
- int16 _currentBmpId; // aka slot 4
- int16 _currentGetPutId; // aka slot 5
- int16 _brushNum;
- byte _drawColFG;
- byte _drawColBG;
- int16 _runPlayed; // number of times the sequence has been started from ADS
- int16 _runCount; // number of times to play the sequence before stopping
- int16 _timeInterval; // interval between frames
- TTMRunType _runFlag;
- int16 _scriptFlag;
-};
-
-class ADSData : public ScriptParserData {
-public:
- ADSData() : _maxSegments(0), _scriptDelay(-1), _hitTTMOp0110(false), _hitBranchOp(false),
- _gotoTarget(-1), _runningSegmentIdx(0) {
- for (int i = 0; i < ARRAYSIZE(_state); i++)
- _state[i] = 8;
-
- for (int i = 0; i < ARRAYSIZE(_segments); i++)
- _segments[i] = -1;
-
- ARRAYCLEAR(_countdown);
- ARRAYCLEAR(_charWhile);
- }
- Common::Array<Common::String> _scriptNames;
- Common::Array<TTMEnviro> _scriptEnvs;
- Common::Array<TTMSeq> _ttmSeqs;
- int _maxSegments;
- // TODO: replace these with dynamic arrays - fixed arrays inherited from original.
- int _state[80];
- int _countdown[80];
- // note: originals uses char * but we use offsets into script for less pointers. -1 is nullptr
- int32 _segments[80];
- int32 _charWhile[80];
- Common::Array<struct TTMSeq *> _usedSeqs[80];
- int32 _scriptDelay;
- int32 _gotoTarget;
- bool _hitTTMOp0110;
- bool _hitBranchOp;
- int16 _runningSegmentIdx;
-
- Common::Error syncState(Common::Serializer &s);
-};
-
-class TTMInterpreter {
-public:
- TTMInterpreter(DgdsEngine *vm);
-
- bool load(const Common::String &filename, TTMEnviro &env);
- void unload();
- bool run(TTMEnviro &env, struct TTMSeq &seq);
- void findAndAddSequences(TTMEnviro &scriptData, Common::Array<TTMSeq> &seqArray);
-
-protected:
- void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
- int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);
-
- DgdsEngine *_vm;
-};
-class ADSInterpreter {
-public:
- ADSInterpreter(DgdsEngine *vm);
- ~ADSInterpreter();
-
- bool load(const Common::String &filename);
- void unload();
- bool run();
- int numArgs(uint16 opcode) const;
- void segmentOrState(int16 seg, uint16 val);
- void segmentSetState(int16 seg, uint16 val);
-
- void setHitTTMOp0110(); // TODO: better name for this global?
- void setGotoTarget(int32 target);
- int16 getStateForSceneOp(uint16 segnum);
- void setScriptDelay(int16 delay) { _adsData->_scriptDelay = delay; }
-
- Common::Error syncState(Common::Serializer &s);
-
-protected:
- bool handleOperation(uint16 code, Common::SeekableReadStream *scr);
- void handleRandomOp(uint16 code, Common::SeekableReadStream *scr);
- bool handleLogicOp(uint16 code, Common::SeekableReadStream *scr);
- bool logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq);
- int16 randomOpGetProportion(uint16 code, Common::SeekableReadStream *scr);
- bool playScene();
- bool skipToEndIf();
- bool skipToEndWhile();
- bool skipSceneLogicBranch();
- TTMSeq *findTTMSeq(int16 enviro, int16 seq);
- TTMEnviro *findTTMEnviro(int16 enviro);
- bool runUntilBranchOpOrEnd();
- void findUsedSequencesForSegment(int segno);
- void findEndOrInitOp();
- bool updateSeqTimeAndFrame(const TTMEnviro *env, TTMSeq &seq);
- int getArrIndexOfSegNum(uint16 segnum);
-
- DgdsEngine *_vm;
- TTMInterpreter *_ttmInterpreter;
-
- Common::HashMap<Common::String, ADSData> _adsTexts;
- ADSData *_adsData;
-
- TTMSeq *_currentTTMSeq;
-};
} // End of namespace Dgds
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
new file mode 100644
index 00000000000..52da1b08781
--- /dev/null
+++ b/engines/dgds/ttm.cpp
@@ -0,0 +1,762 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/rect.h"
+#include "common/serializer.h"
+
+#include "graphics/managed_surface.h"
+
+#include "dgds/ttm.h"
+#include "dgds/ads.h"
+#include "dgds/dgds.h"
+#include "dgds/game_palettes.h"
+#include "dgds/includes.h"
+#include "dgds/image.h"
+#include "dgds/sound.h"
+#include "dgds/font.h"
+
+
+namespace Dgds {
+
+void GetPutRegion::reset() {
+ _area = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
+ _surf.reset();
+}
+
+Common::Error TTMEnviro::syncState(Common::Serializer &s) {
+ DgdsEngine *engine = dynamic_cast<DgdsEngine *>(g_engine);
+ for (auto &shape : _scriptShapes) {
+ bool hasShape = shape.get() != nullptr;
+ s.syncAsByte(hasShape);
+ if (hasShape) {
+ Common::String name;
+ if (s.isLoading()) {
+ s.syncString(name);
+ shape.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+ shape->loadBitmap(name);
+ } else {
+ name = shape->getFilename();
+ s.syncString(name);
+ }
+ }
+ }
+
+ uint16 ngetput = _getPuts.size();
+ s.syncAsUint16LE(ngetput);
+ _getPuts.resize(ngetput);
+ for (uint i = 0; i < ngetput; i++) {
+ s.syncAsUint16LE(_getPuts[i]._area.left);
+ s.syncAsUint16LE(_getPuts[i]._area.top);
+ s.syncAsUint16LE(_getPuts[i]._area.right);
+ s.syncAsUint16LE(_getPuts[i]._area.bottom);
+ if (s.isLoading()) {
+ _getPuts[i]._surf.reset(new Graphics::ManagedSurface());
+ } else {
+ // TODO: Save the getput buffer contents here?
+ }
+ }
+ for (uint i = 0; i < ARRAYSIZE(_scriptPals); i++)
+ s.syncAsSint32LE(_scriptPals[i]);
+ for (uint i = 0; i < ARRAYSIZE(_strings); i++)
+ s.syncString(_strings[i]);
+
+ // TODO: Save the font list.
+
+ return Common::kNoError;
+}
+
+Common::Error TTMSeq::syncState(Common::Serializer &s) {
+ s.syncAsSint16LE(_gotoFrame);
+ s.syncAsSint16LE(_currentFrame);
+ s.syncAsSint16LE(_lastFrame);
+ s.syncAsByte(_selfLoop);
+ s.syncAsByte(_executed);
+ s.syncAsUint32LE(_timeNext);
+ s.syncAsUint32LE(_timeCut);
+
+ s.syncAsUint16LE(_drawWin.left);
+ s.syncAsUint16LE(_drawWin.top);
+ s.syncAsUint16LE(_drawWin.right);
+ s.syncAsUint16LE(_drawWin.bottom);
+
+ s.syncAsSint16LE(_currentFontId);
+ s.syncAsSint16LE(_currentPalId);
+ s.syncAsSint16LE(_currentSongId);
+ s.syncAsSint16LE(_currentBmpId);
+ s.syncAsSint16LE(_currentGetPutId);
+ s.syncAsSint16LE(_brushNum);
+ s.syncAsByte(_drawColFG);
+ s.syncAsByte(_drawColBG);
+ s.syncAsSint16LE(_runPlayed);
+ s.syncAsSint16LE(_runCount);
+ s.syncAsSint16LE(_timeInterval);
+ s.syncAsUint32LE(_runFlag);
+ s.syncAsSint16LE(_scriptFlag);
+
+ return Common::kNoError;
+}
+
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
+
+bool TTMInterpreter::load(const Common::String &filename, TTMEnviro &scriptData) {
+ TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
+ bool parseResult = dgds.parse(&scriptData, filename);
+
+ scriptData.scr->seek(0);
+
+ return parseResult;
+}
+
+void TTMInterpreter::unload() {
+}
+
+static const char *ttmOpName(uint16 op) {
+ switch (op) {
+ case 0x0000: return "FINISH";
+ case 0x0020: return "SAVE(free?) BACKGROUND";
+ case 0x0070: return "FREE PALETTE";
+ case 0x0080: return "FREE SHAPE / DRAW BACKGROUND??";
+ case 0x0090: return "FREE FONT";
+ case 0x00B0: return "NULLOP";
+ case 0x0110: return "PURGE";
+ case 0x0ff0: return "FINISH FRAME / DRAW";
+ case 0x1020: return "SET DELAY";
+ case 0x1030: return "SET BRUSH";
+ case 0x1050: return "SELECT BMP";
+ case 0x1060: return "SELECT PAL";
+ case 0x1070: return "SELECT FONT";
+ case 0x1090: return "SELECT SONG";
+ case 0x10a0: return "SET SCENE";
+ case 0x1100: // fall through
+ case 0x1110: return "SET SCENE";
+ case 0x1120: return "SET GETPUT NUM";
+ case 0x1200: return "GOTO";
+ case 0x1300: return "PLAY SFX";
+ case 0x2000: return "SET DRAW COLORS";
+ case 0x2010: return "SET FRAME";
+ case 0x2020: return "SET RANDOM DELAY";
+ case 0x4000: return "SET CLIP WINDOW";
+ case 0x4110: return "FADE OUT";
+ case 0x4120: return "FADE IN";
+ case 0x4200: return "STORE AREA";
+ case 0x4210: return "SAVE GETPUT REGION";
+ case 0xa000: return "DRAW PIXEL";
+ case 0xa010: return "SAVE REGION 10?????";
+ case 0xa020: return "SAVE REGION 20?????";
+ case 0xa030: return "SAVE REGION 30?????";
+ case 0xa040: return "SAVE REGION 40?????";
+ case 0xa050: return "SAVE REGION";
+ case 0xa060: return "SAVE REGION FLIPPED??";
+ case 0xa070: return "SAVE REGION 70?????";
+ case 0xa080: return "SAVE REGION 80?????";
+ case 0xa090: return "SAVE REGION 90?????";
+ case 0xa0a0: return "DRAW LINE";
+ case 0xa100: return "DRAW FILLED RECT";
+ case 0xa110: return "DRAW EMPTY RECT";
+ case 0xa200: return "DRAW STRING 0";
+ case 0xa210: return "DRAW STRING 1";
+ case 0xa220: return "DRAW STRING 2";
+ case 0xa230: return "DRAW STRING 3";
+ case 0xa240: return "DRAW STRING 4";
+ case 0xa250: return "DRAW STRING 5";
+ case 0xa260: return "DRAW STRING 6";
+ case 0xa270: return "DRAW STRING 7";
+ case 0xa280: return "DRAW STRING 8";
+ case 0xa290: return "DRAW STRING 9";
+ case 0xa500: return "DRAW BMP";
+ case 0xa520: return "DRAW SPRITE FLIP";
+ case 0xa530: return "DRAW BMP4";
+ case 0xa600: return "DRAW GETPUT";
+ case 0xf010: return "LOAD SCR";
+ case 0xf020: return "LOAD BMP";
+ case 0xf040: return "LOAD FONT";
+ case 0xf050: return "LOAD PAL";
+ case 0xf060: return "LOAD SONG";
+ case 0xf100: return "SET STRING 0";
+ case 0xf110: return "SET STRING 1";
+ case 0xf120: return "SET STRING 2";
+ case 0xf130: return "SET STRING 3";
+ case 0xf140: return "SET STRING 4";
+ case 0xf150: return "SET STRING 5";
+ case 0xf160: return "SET STRING 6";
+ case 0xf170: return "SET STRING 7";
+ case 0xf180: return "SET STRING 8";
+ case 0xf190: return "SET STRING 9";
+ case 0x0220: return "STOP CURRENT MUSIC";
+
+ case 0x00C0: return "FREE BACKGROUND";
+ case 0x0230: return "reset current music?";
+ case 0x1310: return "STOP SFX";
+ case 0xa300: return "DRAW some string";
+ case 0xa400: return "DRAW FILLED CIRCLE";
+ case 0xa420: return "DRAW EMPTY CIRCLE";
+ case 0xa510: return "DRAW SPRITE1";
+ case 0xb000: return "? (0 args)";
+ case 0xb010: return "? (3 args: 30, 2, 19)";
+ case 0xb600: return "DRAW SCREEN";
+ case 0xc020: return "LOAD_SAMPLE";
+ case 0xc030: return "SELECT_SAMPLE";
+ case 0xc040: return "DESELECT_SAMPLE";
+ case 0xc050: return "PLAY_SAMPLE";
+ case 0xc060: return "STOP_SAMPLE";
+
+ default: return "UNKNOWN!!";
+ }
+}
+
+void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
+ switch (op) {
+ case 0x0000: // FINISH: void
+ break;
+ case 0x0020: // SAVE (free?) BACKGROUND
+ if (seq._executed) // this is a one-shot op
+ break;
+ //
+ // This appears in the credits, intro sequence, and the
+ // "meanwhile" event with the factory in DRAGON. Seems it
+ // should reload the background image to clear any previous 0020
+ // event, and then save the current FG over it.
+ // Credits - (no scr loaded) Store large image on black bg after loading and before txt scroll
+ // Intro - (no scr loaded) After each screen change, draw and save the new comic frame as bg
+ // on "aaaaah" scene, called after only drawing the AAAH and calling store area
+ // Meanwhile - (scr loaded) Save the foreground people onto the background before walk animation
+ //
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getBackgroundBuffer().blitFrom(_vm->_compositionBuffer);
+ break;
+ case 0x0070: // FREE PALETTE
+ if (seq._executed) // this is a one-shot op
+ break;
+ warning("TODO: Implement me: op 0x0070 free palette (current pal)");
+ seq._currentPalId = 0;
+ break;
+ case 0x0080: // FREE SHAPE
+ env._scriptShapes[seq._currentBmpId].reset();
+ break;
+ case 0x0090: // FREE FONT
+ if (seq._executed) // this is a one-shot op
+ break;
+ if (seq._currentFontId >= (int16)env._fonts.size()) {
+ warning("Request to free font not loaded %d", seq._currentFontId);
+ break;
+ }
+ env._fonts.remove_at(seq._currentFontId);
+ seq._currentFontId = 0;
+ break;
+ case 0x00B0:
+ // Does nothing?
+ break;
+ case 0x00C0: // (one-shot) FREE GETPUT (free getput item pointed to by _currentGetPutId)
+ if (seq._executed) // this is a one-shot op
+ break;
+ env._getPuts[seq._currentGetPutId].reset();
+ break;
+ case 0x0110: // PURGE void
+ _vm->adsInterpreter()->setHitTTMOp0110();
+ break;
+ case 0x0220: // STOP CURRENT MUSIC
+ if (seq._executed) // this is a one-shot op
+ break;
+ _vm->_soundPlayer->stopMusic();
+ break;
+ case 0x0ff0: // REFRESH: void
+ break;
+ case 0x1020: // SET DELAY: i:int [0..n]
+ // TODO: Probably should do this accounting (as well as timeCut and dialogs)
+ // in game frames, not millis.
+ _vm->adsInterpreter()->setScriptDelay((int)(ivals[0] * MS_PER_FRAME));
+ break;
+ case 0x1030: // SET BRUSH: id:int [-1:n]
+ seq._brushNum = ivals[0];
+ break;
+ case 0x1050: // SELECT BMP: id:int [0:n]
+ seq._currentBmpId = ivals[0];
+ break;
+ case 0x1060: // SELECT PAL: id:int [0]
+ seq._currentPalId = ivals[0];
+ if (seq._executed) // this is a mostly on-shot op.
+ break;
+ _vm->getGamePals()->selectPalNum(env._scriptPals[ivals[0]]);
+ break;
+ case 0x1070: // SELECT FONT i:int
+ seq._currentFontId = ivals[0];
+ break;
+ case 0x1090: // SELECT SONG: id:int [0]
+ seq._currentSongId = ivals[0];
+ break;
+ case 0x10a0: // SET SCENE?: i:int [0..n], often 0, called on scene change?
+ // In the original this sets a global that seems to be never used?
+ break;
+ case 0x1100: // SET_SCENE: i:int [1..n]
+ case 0x1110: // SET_SCENE: i:int [1..n]
+ // DESCRIPTION IN TTM TAGS. num only used as GOTO target.
+ break;
+ case 0x1120: // SET GETPUT NUM
+ seq._currentGetPutId = ivals[0];
+ break;
+ case 0x1200: // GOTO
+ _vm->adsInterpreter()->setGotoTarget(findGOTOTarget(env, seq, ivals[0]));
+ break;
+ case 0x1300: // PLAY SFX i:int - eg [72], found in Dragon + HoC intro
+ if (seq._executed) // this is a one-shot op.
+ break;
+ _vm->_soundPlayer->playSFX(ivals[0]);
+ break;
+ case 0x1310: // STOP SFX i:int eg [107]
+ if (seq._executed) // this is a one-shot op.
+ break;
+ warning("TODO: Implement TTM 0x1310 stop SFX %d", ivals[0]);
+ // Implement this:
+ //_vm->_soundPlayer->stopSfxById(ivals[0])
+ break;
+ case 0x2000: // SET (DRAW) COLORS: fgcol,bgcol:int [0..255]
+ seq._drawColFG = static_cast<byte>(ivals[0]);
+ seq._drawColBG = static_cast<byte>(ivals[1]);
+ break;
+ case 0x2020: { // SET RANDOM SLEEP: min,max: int (eg, 60,300)
+ if (seq._executed) // this is a one-shot op.
+ break;
+ uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
+ // TODO: do same time fix as for 0x1020
+ _vm->adsInterpreter()->setScriptDelay((int)(sleep * MS_PER_FRAME));
+ break;
+ }
+ case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
+ // NOTE: params are xmax/ymax, NOT w/h
+ seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
+ break;
+ case 0x4110: // FADE OUT: colorno,ncolors,targetcol,speed:byte
+ if (seq._executed) // this is a one-shot op.
+ break;
+ if (ivals[3] == 0) {
+ _vm->getGamePals()->clearPalette();
+ } else {
+ // The original tight-loops here with 640 steps and i/10 as the fade level..
+ // bring that down a bit to use less cpu.
+ // Speed 4 should complete fade in 2 seconds (eg, Dynamix logo fade)
+
+ // TODO: this is a pretty bad way to do it - should pump messages in this loop?
+ for (int i = 0; i < 320; i += ivals[3]) {
+ int fade = MIN(i / 5, 63);
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
+ g_system->updateScreen();
+ g_system->delayMillis(5);
+ }
+ }
+ // Clear all the buffers
+ _vm->getBackgroundBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->_compositionBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ // reset to previous palette.
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], 0);
+ break;
+ case 0x4120: { // FADE IN: colorno,ncolors,targetcol,speed:byte
+ if (seq._executed) // this is a one-shot op.
+ break;
+
+ if (ivals[3] == 0) {
+ _vm->getGamePals()->setPalette();
+ } else {
+ for (int i = 320; i > 0; i -= ivals[3]) {
+ int fade = MAX(0, MIN(i / 5, 63));
+ _vm->getGamePals()->setFade(ivals[0], ivals[1], ivals[2], fade * 4);
+ if (i == 320) {
+ // update screen first to make the initial fade-in work
+ g_system->copyRectToScreen(_vm->_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ }
+ g_system->updateScreen();
+ g_system->delayMillis(5);
+ }
+ }
+ break;
+ }
+ case 0x4200: { // STORE AREA: x,y,w,h:int [0..n] ; makes this area of foreground persist in the next frames.
+ if (seq._executed) // this is a one-shot op
+ break;
+ const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->getStoredAreaBuffer().blitFrom(_vm->_compositionBuffer, rect, rect);
+ break;
+ }
+ case 0x4210: { // SAVE GETPUT REGION (getput area) x,y,w,h:int
+ if (seq._executed) // this is a one-shot op.
+ break;
+ if (seq._currentGetPutId >= (int)env._getPuts.size()) {
+ env._getPuts.resize(seq._currentGetPutId + 1);
+ }
+ const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ env._getPuts[seq._currentGetPutId]._area = rect;
+
+ // Getput reads an area from the front buffer.
+ Graphics::ManagedSurface *surf = new Graphics::ManagedSurface(rect.width(), rect.height(), _vm->_compositionBuffer.format);
+ surf->blitFrom(_vm->_compositionBuffer, rect, Common::Point(0, 0));
+ env._getPuts[seq._currentGetPutId]._surf.reset(surf);
+ break;
+ }
+ case 0xa000: // DRAW PIXEL x,y:int
+ _vm->_compositionBuffer.setPixel(ivals[0], ivals[1], seq._drawColFG);
+ break;
+ case 0xa050: {// SAVE REGION x,y,w,h:int
+ // This is used in DRAGON intro sequence to draw the AAAAH
+ // it works like a bitblit, but it doesn't write if there's something already at the destination?
+ // TODO: This is part of a whole set of operations - 0xa0n4.
+ // They do various flips etc.
+ warning("TODO: Fix implementation of SAVE REGION (0xa050) (%d, %d, %d, %d)",
+ ivals[0], ivals[1], ivals[2], ivals[3]);
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ //_vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
+ //_vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
+ //_vm->_compositionBuffer.transBlitFrom(_vm->_compositionBuffer);
+ //_vm->_compositionBuffer.blitFrom(_vm->_compositionBuffer, r, r);
+ break;
+ }
+ case 0xa060: { // RESTORE REGION
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->getStoredAreaBuffer().fillRect(r, 0);
+ break;
+ }
+ case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
+ _vm->_compositionBuffer.drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
+ break;
+ case 0xa100: { // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->_compositionBuffer.fillRect(r, seq._drawColFG);
+ break;
+ }
+ case 0xa110: { // DRAW EMPTY RECT x1,y1,x2,y2:int
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ _vm->_compositionBuffer.drawLine(r.left, r.top, r.right, r.top, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.left, r.bottom, r.right, r.bottom, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.left, r.top, r.left, r.bottom, seq._drawColFG);
+ _vm->_compositionBuffer.drawLine(r.right, r.top, r.right, r.bottom, seq._drawColFG);
+ break;
+ }
+ case 0xa200: // 0xa2n0 DRAW STRING n: x,y,w,h:int - draw the nth string from the string table
+ case 0xa210:
+ case 0xa220:
+ case 0xa230:
+ case 0xa240:
+ case 0xa250:
+ case 0xa260:
+ case 0xa270:
+ case 0xa280:
+ case 0xa290: {
+ int16 fontno = seq._currentFontId;
+ if (fontno >= (int16)env._fonts.size()) {
+ warning("Trying to draw font no %d but only loaded %d", seq._currentFontId, env._fonts.size());
+ fontno = 0;
+ }
+ uint strnum = (op & 0x70) >> 4;
+ const Common::String &str = env._strings[strnum];
+ const FontManager *mgr = _vm->getFontMan();
+ const Font *font = mgr->getFont(env._fonts[fontno]);
+ // Note: ignore the y-height argument (ivals[3]) for now. If width is 0, draw as much as we can.
+ int width = ivals[2];
+ if (width == 0)
+ width = SCREEN_WIDTH - ivals[0];
+ font->drawString(&(_vm->_compositionBuffer), str, ivals[0], ivals[1], width, seq._drawColFG);
+ break;
+ }
+ case 0xa510:
+ // DRAW SPRITE x,y:int .. how different from 0xa500??
+ // FALL THROUGH
+ case 0xa520:
+ // DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
+ // FALL THROUGH
+ case 0xa530:
+ // CHINA
+ // DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // arguments similar to DRAW BMP but it draws the same BMP multiple times with radial symmetry?
+ // you can see this in the Dynamix logo star.
+ // FALL THROUGH
+ case 0xa500: {
+ // DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
+ // This is kind of file system intensive, will likely have to change to store all the BMPs.
+ int frameno;
+ if (count == 4) {
+ frameno = ivals[2];
+ // TODO: Check if the bmp id is changed here in CHINA or if a temp val is used.
+ seq._currentBmpId = ivals[3];
+ } else {
+ frameno = seq._brushNum;
+ }
+
+ // DRAW BMP: x,y:int [-n,+n] (RISE)
+ Common::SharedPtr<Image> img = env._scriptShapes[seq._currentBmpId];
+ if (img)
+ img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->_compositionBuffer, op == 0xa520);
+ else
+ warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
+ break;
+ }
+ case 0xa600: { // DRAW GETPUT
+ if (seq._executed) // this is a one-shot op.
+ break;
+ int16 i = ivals[0];
+ if (i >= (int16)env._getPuts.size() || !env._getPuts[i]._surf.get()) {
+ warning("Trying to put getput region %d we never got", i);
+ break;
+ }
+ const Common::Rect &r = env._getPuts[i]._area;
+ // Getput should overwrite the contents
+ _vm->_compositionBuffer.blitFrom(*(env._getPuts[i]._surf.get()),
+ Common::Point(r.left, r.top));
+ break;
+ }
+ case 0xf010: { // LOAD SCR: filename:str
+ if (seq._executed) // this is a one-shot op
+ break;
+ Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
+ tmp.drawScreen(sval, _vm->getBackgroundBuffer());
+ _vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
+ _vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ _vm->setBackgroundFile(sval);
+ break;
+ }
+ case 0xf020: // LOAD BMP: filename:str
+ if (seq._executed) // this is a one-shot op
+ break;
+ env._scriptShapes[seq._currentBmpId].reset(new Image(_vm->getResourceManager(), _vm->getDecompressor()));
+ env._scriptShapes[seq._currentBmpId]->loadBitmap(sval);
+ break;
+ case 0xf040: { // LOAD FONT: filename:str
+ if (seq._executed) // this is a one-shot op
+ break;
+ const FontManager *mgr = _vm->getFontMan();
+ env._fonts.push_back(mgr->fontTypeByName(sval));
+ seq._currentFontId = env._fonts.size() - 1;
+ break;
+ }
+ case 0xf050: { // LOAD PAL: filename:str
+ if (seq._executed) // this is a one-shot op
+ break;
+ int newPalNum = _vm->getGamePals()->loadPalette(sval);
+ env._scriptPals[seq._currentPalId] = newPalNum;
+ break;
+ }
+ case 0xf060: // LOAD SONG: filename:str
+ if (seq._executed) // this is a one-shot op
+ break;
+ if (_vm->_platform == Common::kPlatformAmiga) {
+ // TODO: remove hard-coded stuff..
+ _vm->_soundPlayer->playAmigaSfx("DYNAMIX.INS", 0, 255);
+ } else if (_vm->_platform == Common::kPlatformMacintosh) {
+ _vm->_soundPlayer->loadMacMusic(sval.c_str());
+ _vm->_soundPlayer->playMusic(seq._currentSongId);
+ } else {
+ _vm->_soundPlayer->loadMusic(sval.c_str());
+ _vm->_soundPlayer->playMusic(seq._currentSongId);
+ }
+ break;
+ case 0xf100: // 0xf1n0 - SET STRING n: s:str - set the nth string in the table
+ case 0xf110:
+ case 0xf120:
+ case 0xf130:
+ case 0xf140:
+ case 0xf150:
+ case 0xf160:
+ case 0xf170:
+ case 0xf180:
+ case 0xf190: {
+ uint strnum = (op & 0xf0) >> 4;
+ env._strings[strnum] = sval;
+ break;
+ }
+
+ // Unimplemented / unknown
+ case 0x0010: // (one-shot) ??
+ case 0x0230: // (one-shot) reset current music? (0 args) - found in HoC intro. Sets params about current music.
+ case 0x0400: // (one-shot) set palette??
+ case 0x1040: // Sets some global? i:int
+ case 0x10B0: // null op?
+ case 0x2010: // SET FRAME?? x,y
+ case 0xa010: // SAVE REGION ????
+ case 0xa020: // SAVE REGION ????
+ case 0xa030: // SAVE REGION ????
+ case 0xa040: // SAVE REGION ????
+ case 0xa070: // SAVE REGION ????
+ case 0xa080: // SAVE REGION ????
+ case 0xa090: // SAVE REGION ????
+ case 0xa300: // DRAW some string? x,y,?,?:int
+ case 0xa400: // DRAW FILLED CIRCLE
+ case 0xa420: // DRAW EMPTY CIRCLE
+
+ // From here on are not implemented in DRAGON
+ case 0xb000: // ? (0 args) - found in HoC intro
+ case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
+ case 0xb600: // DRAW SCREEN
+ case 0xc020: // LOAD_SAMPLE
+ case 0xc030: // SELECT_SAMPLE
+ case 0xc040: // DESELECT_SAMPLE
+ case 0xc050: // PLAY_SAMPLE
+ case 0xc060: // STOP_SAMPLE
+
+ default:
+ if (count < 15)
+ warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)",
+ op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
+ else
+ warning("Unimplemented TTM opcode: 0x%04X (sval: %s)", op, sval.c_str());
+ break;
+ }
+}
+
+bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
+ Common::SeekableReadStream *scr = env.scr;
+ if (!scr)
+ return false;
+ if (scr->pos() >= scr->size())
+ return false;
+
+ debug(10, "TTM: Run env %d seq %d (%s) frame %d (scr offset %d, %s)", seq._enviro, seq._seqNum,
+ env._tags[seq._seqNum].c_str(), seq._currentFrame, (int)scr->pos(),
+ seq._executed ? "already executed" : "first execution");
+ uint16 code = 0;
+ while (code != 0x0ff0 && scr->pos() < scr->size()) {
+ code = scr->readUint16LE();
+ uint16 op = code & 0xFFF0;
+ byte count = code & 0x000F;
+ int16 ivals[8];
+ Common::String sval;
+
+ if (count > 8 && count != 0x0f)
+ error("Invalid TTM opcode %04x requires %d locals", code, count);
+
+ debugN(10, "\tOP: 0x%4.4x %2u ", op, count);
+ if (count == 0x0F) {
+ byte ch[2];
+
+ do {
+ ch[0] = scr->readByte();
+ ch[1] = scr->readByte();
+ if (ch[0])
+ sval += ch[0];
+ if (ch[1])
+ sval += ch[1];
+ } while (ch[0] != 0 && ch[1] != 0);
+
+ debugN(10, "\"%s\"", sval.c_str());
+ } else {
+ for (byte i = 0; i < count; i++) {
+ ivals[i] = scr->readSint16LE();
+ if (i > 0)
+ debugN(10, ", ");
+ debugN(10, "%d", ivals[i]);
+ }
+ }
+ debug(10, " (%s)", ttmOpName(op));
+
+ handleOperation(env, seq, op, count, ivals, sval);
+ }
+
+ return true;
+}
+
+int32 TTMInterpreter::findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 targetFrame) {
+ int64 startpos = env.scr->pos();
+ int32 retval = -1;
+ for (int32 i = 0; i < (int)env._frameOffsets.size(); i++) {
+ if (env._frameOffsets[i] < 0)
+ continue;
+ env.scr->seek(env._frameOffsets[i]);
+ uint16 op = env.scr->readUint16LE();
+ if (op == 0x1101 || op == 0x1111) {
+ uint16 frameno = env.scr->readUint16LE();
+ if (frameno == targetFrame) {
+ retval = i;
+ break;
+ }
+ }
+ }
+ env.scr->seek(startpos);
+ return retval;
+}
+
+void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &seqArray) {
+ int16 envno = env._enviro;
+ env.scr->seek(0);
+ uint16 op = 0;
+ for (uint frame = 0; frame < env._totalFrames; frame++) {
+ env._frameOffsets[frame] = env.scr->pos();
+ //debug("findAndAddSequences: frame %d at offset %d", frame, (int)env.scr->pos());
+ op = env.scr->readUint16LE();
+ while (op != 0x0ff0 && env.scr->pos() < env.scr->size()) {
+ //debug("findAndAddSequences: check ttm op %04x", op);
+ if (op == 0xaf1f || op == 0xaf2f)
+ warning("TODO: Fix findAndAddSequences for opcode %x which has variable length arg", op);
+ switch (op & 0xf) {
+ case 0:
+ break;
+ case 1:
+ if (op == 0x1111) {
+ TTMSeq newseq;
+ newseq._enviro = envno;
+ newseq._seqNum = env.scr->readUint16LE();
+ newseq._startFrame = frame;
+ newseq._currentFrame = frame;
+ newseq._lastFrame = -1;
+ //debug("findAndAddSequences: found env %d seq %d at %d", newseq._enviro, newseq._seqNum, (int)env.scr->pos());
+ seqArray.push_back(newseq);
+ } else {
+ env.scr->skip(2);
+ }
+ break;
+ case 0xf: {
+ byte ch[2];
+ do {
+ ch[0] = env.scr->readByte();
+ ch[1] = env.scr->readByte();
+ } while (ch[0] != 0 && ch[1] != 0);
+ break;
+ }
+ default:
+ env.scr->skip((op & 0xf) * 2);
+ break;
+ }
+ op = env.scr->readUint16LE();
+ }
+ }
+ env.scr->seek(0);
+}
+
+void TTMSeq::reset() {
+ _currentFontId = 0;
+ _currentPalId = 0;
+ _currentPalId = 0;
+ _currentBmpId = 0;
+ _currentGetPutId = 0;
+ _currentFrame = _startFrame;
+ _gotoFrame = -1;
+ _drawColBG = 0xf;
+ _drawColFG = 0xf;
+ _brushNum = 0;
+ _timeInterval = 0;
+ _timeNext = 0;
+ _runCount = 0;
+ _runPlayed = 0;
+ _executed = false;
+ _runFlag = kRunTypeStopped;
+ _scriptFlag = 0;
+ _selfLoop = false;
+ _drawWin = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
+}
+
+
+} // end namespace Dgds
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
new file mode 100644
index 00000000000..705449d9d19
--- /dev/null
+++ b/engines/dgds/ttm.h
@@ -0,0 +1,122 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_TTM_H
+#define DGDS_TTM_H
+
+#include "dgds/scripts.h"
+#include "dgds/font.h"
+
+namespace Dgds {
+
+class GetPutRegion {
+public:
+ Common::Rect _area;
+ Common::SharedPtr<Graphics::ManagedSurface> _surf;
+
+ void reset();
+};
+
+class TTMEnviro : public ScriptParserData {
+public:
+ TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
+ ARRAYCLEAR(_scriptPals);
+ _fonts.push_back(FontManager::kDefaultFont); // is this right?
+ }
+
+ Common::Error syncState(Common::Serializer &s);
+
+ uint16 _enviro;
+ uint16 _totalFrames;
+ Common::Array<int> _frameOffsets;
+ Common::SharedPtr<Image> _scriptShapes[6];
+ Common::Array<GetPutRegion> _getPuts;
+ int _scriptPals[6];
+ Common::String _strings[10];
+ Common::Array<FontManager::FontType> _fonts;
+};
+
+enum TTMRunType {
+ kRunTypeStopped = 0,
+ kRunType1 = 1,
+ kRunTypeMulti = 2,
+ kRunTypeTimeLimited = 3,
+ kRunTypeFinished = 4,
+ kRunType5 = 5,
+};
+
+
+// Note: this object needs to be safely copy-able - ADS opcodes 0x4000 and 0x4010 require it.
+struct TTMSeq {
+ TTMSeq() : _enviro(0), _seqNum(0), _startFrame(0), _lastFrame(0), _timeCut(0) {
+ // Other members are initialized in the reset function.
+ reset();
+ }
+
+ void reset();
+ Common::Error syncState(Common::Serializer &s);
+
+ int16 _enviro;
+ int16 _seqNum;
+ int16 _startFrame; // first frame in this sequence
+ int16 _gotoFrame; // frame to GOTO (or -1 if not currently set)
+ int16 _currentFrame; // currently executing frame
+ int16 _lastFrame; // previous frame processed (-1 if none)
+ bool _selfLoop; // does the script frame loop back on itself
+ bool _executed; // has the current frame already been run
+ uint32 _timeNext; // time the next frame should be run
+ uint32 _timeCut; // time to finish execution
+ Common::Rect _drawWin;
+ // these current ids are called "slot"s in the original
+ int16 _currentFontId; // aka slot 0
+ int16 _currentPalId; // aka slot 1
+ int16 _currentSongId; // aka slot 3
+ int16 _currentBmpId; // aka slot 4
+ int16 _currentGetPutId; // aka slot 5
+ int16 _brushNum;
+ byte _drawColFG;
+ byte _drawColBG;
+ int16 _runPlayed; // number of times the sequence has been started from ADS
+ int16 _runCount; // number of times to play the sequence before stopping
+ int16 _timeInterval; // interval between frames
+ TTMRunType _runFlag;
+ int16 _scriptFlag;
+};
+
+class TTMInterpreter {
+public:
+ TTMInterpreter(DgdsEngine *vm);
+
+ bool load(const Common::String &filename, TTMEnviro &env);
+ void unload();
+ bool run(TTMEnviro &env, struct TTMSeq &seq);
+ void findAndAddSequences(TTMEnviro &scriptData, Common::Array<TTMSeq> &seqArray);
+
+protected:
+ void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
+ int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);
+
+ DgdsEngine *_vm;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_TTM_H
Commit: 11c3480ffe56cb4fa3e9f9c90498515787366135
https://github.com/scummvm/scummvm/commit/11c3480ffe56cb4fa3e9f9c90498515787366135
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix a few small game interaction bugs
Changed paths:
engines/dgds/ads.cpp
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dgds_rect.h
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/inventory.cpp
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index d9da92d138d..1dbd3ef7690 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -755,7 +755,7 @@ int ADSInterpreter::getArrIndexOfSegNum(uint16 segnum) {
bool ADSInterpreter::run() {
- if (_adsData->_ttmSeqs.empty())
+ if (!_adsData || _adsData->_ttmSeqs.empty())
return false;
for (int i = 0; i < _adsData->_maxSegments; i++) {
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7d878a40a9b..8bea4f222a8 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -79,7 +79,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone) {
+ _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone), _isLoading(true) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -181,6 +181,7 @@ bool DgdsEngine::changeScene(int sceneNum) {
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
_scene->addInvButtonToHotAreaList();
+ _clock.setVisibleScript(true);
if (_scene->getMagic() != _gdsScene->getMagic())
error("Scene %s magic does (0x%08x) not match GDS magic (0x%08x)", sceneFile.c_str(), _scene->getMagic(), _gdsScene->getMagic());
@@ -336,6 +337,7 @@ void DgdsEngine::loadGameFiles() {
}
Common::Error DgdsEngine::run() {
+ _isLoading = true;
init();
loadGameFiles();
@@ -349,6 +351,8 @@ Common::Error DgdsEngine::run() {
Common::EventManager *eventMan = g_system->getEventManager();
Common::Event ev;
+ _isLoading = false;
+
while (!shouldQuit()) {
Common::EventType mouseEvent = Common::EVENT_INVALID;
while (eventMan->pollEvent(ev)) {
@@ -536,7 +540,7 @@ bool DgdsEngine::canLoadGameStateCurrently(Common::U32String *msg /*= nullptr*/)
bool DgdsEngine::canSaveGameStateCurrently(Common::U32String *msg /*= nullptr*/) {
return _gdsScene && _scene && _scene->getNum() != 2
&& !_scene->hasVisibleDialog() && !_menu->menuShown()
- && _scene->getDragItem() == nullptr;
+ && _scene->getDragItem() == nullptr && !_isLoading;
}
@@ -545,13 +549,14 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
// Version history:
//
// 1: First version
+ // 2: Added GameItem.flags
//
assert(_scene && _gdsScene);
_menu->hideMenu();
- if (!s.syncVersion(1))
+ if (!s.syncVersion(2))
error("Save game version too new: %d", s.getVersion());
Common::Error result;
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index b8d6c150c04..480170606b1 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -119,6 +119,8 @@ private:
MenuId _menuToTrigger;
+ bool _isLoading;
+
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
virtual ~DgdsEngine();
diff --git a/engines/dgds/dgds_rect.h b/engines/dgds/dgds_rect.h
index 6ad53b0f6bd..2980d5d645d 100644
--- a/engines/dgds/dgds_rect.h
+++ b/engines/dgds/dgds_rect.h
@@ -39,7 +39,7 @@ public:
int height;
Common::Rect toCommonRect() const { return Common::Rect(x, y, x + width, y + height); }
-
+ bool contains(const Common::Point &pt) const { return pt.x >= x && pt.x < (x + width) && pt.y >= y && pt.y < (y + height); }
Common::String dump(const Common::String &indent) const;
};
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 785443eeba1..1b75d2de118 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -21,6 +21,7 @@
#include "dgds/globals.h"
#include "dgds/dgds.h"
+#include "dgds/scene.h"
namespace Dgds {
@@ -111,12 +112,34 @@ private:
DragonDataTable &_table;
};
+// TODO: Move this to Scene??
+class GameIsInteractiveGlobal : public Global {
+public:
+ GameIsInteractiveGlobal(uint16 num, int16 *ptr) : Global(num), _ptr(ptr), _isSetOff(false) {}
+
+ int16 get() override {
+ SDSScene *scene = static_cast<DgdsEngine *>(g_engine)->getScene();
+ bool nonInteractive = _isSetOff || scene->getDragItem() || scene->hasVisibleDialog();
+ *_ptr = !nonInteractive;
+ return *_ptr;
+ }
+
+ int16 set(int16 val) override {
+ _isSetOff = (val == 0);
+ return get();
+ }
+
+private:
+ int16 *_ptr;
+ bool _isSetOff;
+};
+
////////////////////////////////
DragonGlobals::DragonGlobals(Clock &_clock) : Globals(),
_lastOpcode1SceneChageNum(0), _sceneOp12SceneNum(0), _currentSelectedItem(0),
_gameMinsToAddOnLClick(0), _gameMinsToAddOnStartDrag(0), _gameMinsToAddOnRClick(0), _gameMinsToAddOnDragFinished(0),
-_gameMinsToAddOnObjInteraction(0), _gameGlobal0x57(0), _sceneOpcode15FromScene(0),
+_gameMinsToAddOnObjInteraction(0), _gameIsInteractiveGlobal(0), _sceneOpcode15FromScene(0),
_sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
_opcode106EndMinutes(0) {
_globals.push_back(_clock.getGameMinsAddedGlobal(1));
@@ -133,7 +156,7 @@ _opcode106EndMinutes(0) {
_globals.push_back(new RWI16Global(0x5A, &_gameMinsToAddOnRClick));
_globals.push_back(new RWI16Global(0x59, &_gameMinsToAddOnDragFinished));
_globals.push_back(new RWI16Global(0x58, &_gameMinsToAddOnObjInteraction));
- _globals.push_back(new RWI16Global(0x57, &_gameGlobal0x57)); // TODO: Function to get/set 1f1a:4ec1
+ _globals.push_back(new GameIsInteractiveGlobal(0x57, &_gameIsInteractiveGlobal));
_globals.push_back(_clock.getDays2Global(0x56));
_globals.push_back(new RWI16Global(0x55, &_sceneOpcode15FromScene));
_globals.push_back(new RWI16Global(0x54, &_sceneOpcode15ToScene));
@@ -156,7 +179,7 @@ Common::Error DragonGlobals::syncState(Common::Serializer &s) {
s.syncAsSint16LE(_gameMinsToAddOnRClick);
s.syncAsSint16LE(_gameMinsToAddOnDragFinished);
s.syncAsSint16LE(_gameMinsToAddOnObjInteraction);
- s.syncAsSint16LE(_gameGlobal0x57);
+ s.syncAsSint16LE(_gameIsInteractiveGlobal);
s.syncAsSint16LE(_sceneOpcode15FromScene);
s.syncAsSint16LE(_sceneOpcode15ToScene);
s.syncAsSint16LE(_sceneOpcode100Var);
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 866b0f30878..61052f0f43e 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -118,7 +118,7 @@ private:
int16 _gameMinsToAddOnRClick;
int16 _gameMinsToAddOnDragFinished;
int16 _gameMinsToAddOnObjInteraction;
- int16 _gameGlobal0x57;
+ int16 _gameIsInteractiveGlobal;
int16 _sceneOpcode15FromScene;
int16 _sceneOpcode15ToScene;
int16 _sceneOpcode100Var;
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index edcc84ff8f8..17cc56a1508 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -381,7 +381,7 @@ static void _doVqtDecode2(struct VQTDecodeState *state, const uint16 x, const ui
return;
}
- byte tmpbuf [262];
+ byte tmpbuf[262];
byte *ptmpbuf = tmpbuf;
for (; bval != 0; bval--) {
*ptmpbuf = _getVqtBits(state, 8);
@@ -524,7 +524,7 @@ int16 Image::height(uint frameno) const {
return _frames[frameno]->h;
}
-Common::SharedPtr<Graphics::ManagedSurface> Image::getSurface(uint frameno) {
+Common::SharedPtr<Graphics::ManagedSurface> Image::getSurface(uint frameno) const {
if (frameno >= _frames.size())
error("Invalid frameno %d", frameno);
return _frames[frameno];
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index b7a0c4f9ac1..9b7bdbaa52f 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -52,9 +52,9 @@ public:
int frameCount(const Common::String &filename);
void drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &dst, bool flip = false) const;
- Common::SharedPtr<Graphics::ManagedSurface> getSurface(uint frameno);
+ Common::SharedPtr<Graphics::ManagedSurface> getSurface(uint frameno) const;
- const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &getFrames() { return _frames; }
+ const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &getFrames() const { return _frames; }
int16 width(uint frameno) const;
int16 height(uint frameno) const;
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 9c9c987a721..de251ebf73f 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -60,6 +60,7 @@ void Inventory::close() {
engine->changeScene(_openedFromSceneNum);
_showZoomBox = false;
_openedFromSceneNum = 0;
+ _highlightItemNo = -1;
}
void Inventory::setRequestData(const REQFileData &data) {
@@ -81,7 +82,7 @@ void Inventory::setRequestData(const REQFileData &data) {
_dropBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(16));
_itemArea = dynamic_cast<ImageGadget *>(req.findGadgetByNumWithFlags3Not0x40(8));
- _fullWidth = req._width;
+ _fullWidth = req._rect.width;
if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton || !_itemArea)
error("Didn't get all expected inventory gadgets");
@@ -94,8 +95,8 @@ void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
static const char *title = "INVENTORY";
int titleWidth = font->getStringWidth(title);
- int y1 = r._y + 7;
- int x1 = r._x + 112;
+ int y1 = r._rect.y + 7;
+ int x1 = r._rect.x + 112;
font->drawString(&surf, title, x1 + 4, y1 + 2, titleWidth, 0);
int x2 = x1 + titleWidth + 6;
@@ -111,10 +112,10 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount) {
if (_showZoomBox) {
_itemZoomBox->_flags3 &= ~0x40;
- boxreq._width = _fullWidth;
+ boxreq._rect.width = _fullWidth;
} else {
_itemZoomBox->_flags3 |= 0x40;
- boxreq._width = _itemBox->_width + _itemBox->_x * 2;
+ boxreq._rect.width = _itemBox->_width + _itemBox->_x * 2;
}
//
@@ -161,7 +162,6 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
const int imgAreaY = _itemArea->_parentY + _itemArea->_y;
Common::Rect itemRect(Common::Point(imgAreaX, imgAreaY), _itemArea->_width, _itemArea->_height);
- //surf.fillRect(itemRect, (byte)imgArea->_col1);
if (!icons)
return;
@@ -219,8 +219,7 @@ void Inventory::mouseMoved(const Common::Point &pt) {
if (dragItem) {
engine->setMouseCursor(dragItem->_iconNum);
const RequestData &req = _reqData._requests[0];
- const Common::Rect bgsize(Common::Point(req._x, req._y), req._width, req._height);
- if (!bgsize.contains(pt)) {
+ if (!req._rect.contains(pt)) {
// dragged an item outside the inventory
dragItem->_inSceneNum = _openedFromSceneNum;
close();
@@ -260,6 +259,12 @@ GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
void Inventory::mouseLDown(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ RequestData &boxreq = _reqData._requests[0];
+
+ // Ignore this, and close on mouseup.
+ if (!boxreq._rect.contains(pt))
+ return;
+
if (engine->getScene()->hasVisibleDialog() || !_itemBox->containsPoint(pt)) {
return engine->getScene()->mouseLDown(pt);
} else {
@@ -277,13 +282,14 @@ void Inventory::mouseLDown(const Common::Point &pt) {
void Inventory::mouseLUp(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
GameItem *dragItem = engine->getScene()->getDragItem();
- engine->setMouseCursor(0);
if (dragItem) {
engine->getScene()->onDragFinish(pt);
return;
}
+ engine->setMouseCursor(0);
+
int itemsPerPage = (_itemArea->_width / _itemArea->_xStep) * (_itemArea->_height / _itemArea->_yStep);
if (_exitButton->containsPoint(pt)) {
close();
@@ -303,16 +309,13 @@ void Inventory::mouseLUp(const Common::Point &pt) {
engine->getClock().addGameTime(1);
} else if (_clockSkipHrBtn && _clockSkipHrBtn->containsPoint(pt)) {
engine->getClock().addGameTime(60);
- } else if (_dropBtn && _dropBtn->containsPoint(pt)) {
- if (_highlightItemNo >= 0) {
- Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
- for (auto &item: items) {
- if (item._num == _highlightItemNo) {
- item._inSceneNum = _openedFromSceneNum;
- break;
- }
+ } else if (_dropBtn && _dropBtn->containsPoint(pt) && _highlightItemNo >= 0) {
+ Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ for (auto &item: items) {
+ if (item._num == _highlightItemNo) {
+ item._inSceneNum = _openedFromSceneNum;
+ break;
}
- _highlightItemNo = -1;
}
}
}
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index a89ac7bed05..841ce02991e 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -85,6 +85,9 @@ enum MenuButtonIds {
kMenuQuitYes = 134,
kMenuQuitNo = 133,
+ kMenuMaybeBetterSaveYes = 137,
+ kMenuMaybeBetterSaveNo = 138,
+
kMenuIntroSkip = 143,
kMenuIntroPlay = 144,
@@ -199,6 +202,7 @@ void Menu::handleMenu(Common::Point &mouse) {
case kMenuCalibratePlayHoC:
case kMenuFilesPlay:
case kMenuMouseCalibrationPlay:
+ case kMenuMaybeBetterSaveNo:
_curMenu = kMenuNone;
CursorMan.showMouse(false);
break;
@@ -236,8 +240,8 @@ void Menu::handleMenu(Common::Point &mouse) {
drawMenu(kMenuMain);
break;
case kMenuOptionsJoystickOnOff:
- case kMenuOptionsMouseOnOff:
- case kMenuOptionsSoundsOnOff:
+ //case kMenuOptionsMouseOnOff: // same id as kMenuMaybeBetterSaveNo
+ //case kMenuOptionsSoundsOnOff: // same id as kMenuMaybeBetterSaveYes
case kMenuOptionsMusicOnOff:
// TODO
debug("Clicked option with ID %d", clickedMenuItem);
@@ -265,6 +269,7 @@ void Menu::handleMenu(Common::Point &mouse) {
case kMenuSavePrevious:
case kMenuSaveNext:
case kMenuSaveSave:
+ case kMenuMaybeBetterSaveYes:
if (g_engine->saveGameDialog())
hideMenu();
else
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 192af33f9b1..ba28829614d 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -119,8 +119,8 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
gptr->_col1 = vals[9];
gptr->_col2 = vals[10];
gptr->_col3 = vals[11];
- gptr->_parentX = data._x;
- gptr->_parentY = data._y;
+ gptr->_parentX = data._rect.x;
+ gptr->_parentY = data._rect.y;
}
uint16 type1 = str->readUint16LE();
@@ -218,10 +218,10 @@ bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int
error("Request::parseGADChunk: Implement handling of num other than -1");
data._fileNum = chunkNum;
- data._x = str->readUint16LE();
- data._y = str->readUint16LE();
- data._width = str->readUint16LE();
- data._height = str->readUint16LE();
+ data._rect.x = str->readUint16LE();
+ data._rect.y = str->readUint16LE();
+ data._rect.width = str->readUint16LE();
+ data._rect.height = str->readUint16LE();
data._col1 = str->readUint16LE();
data._col2 = str->readUint16LE();
data._flags = str->readUint16LE();
@@ -517,8 +517,8 @@ void ImageGadget::draw(Graphics::ManagedSurface *dst) const {
}
Common::String RequestData::dump() const {
- Common::String ret = Common::String::format("RequestData<file %d pos (%d,%d) size (%d, %d) c1 %d c2 %d flg %d\n",
- _fileNum, _x, _y, _width, _height, _col1, _col2, _flags);
+ Common::String ret = Common::String::format("RequestData<file %d %s c1 %d c2 %d flg %d\n",
+ _fileNum, _rect.dump("").c_str(), _col1, _col2, _flags);
for (const auto &t : _textItemList)
ret += Common::String::format(" TextItem<'%s' pos (%d,%d) %d %d>\n", t._txt.c_str(),
t._x, t._y, t._vals[0], t._vals[1]);
@@ -557,7 +557,7 @@ void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
drawBackgroundNoSliders(dst, "");
for (const auto &fillArea : _fillAreaList) {
- Common::Rect r(Common::Point(_x + fillArea._x, _y + fillArea._y), fillArea._width, fillArea._height);
+ Common::Rect r(Common::Point(_rect.x + fillArea._x, _rect.y + fillArea._y), fillArea._width, fillArea._height);
dst->fillRect(r, fillArea._col1);
}
@@ -638,50 +638,54 @@ void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, in
}
void RequestData::drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, int16 sliderHeight, const Common::String &header) const {
+ int16 x = _rect.x;
+ int16 y = _rect.y;
+ int16 width = _rect.width;
+ int16 height = _rect.height;
uint16 sliderBgHeight = sliderHeight + 18;
- fillBackground(dst, _x, _y, _width, sliderBgHeight, 0);
- fillBackground(dst, _x + 8, _y + sliderBgHeight, _width - 16, _height - sliderBgHeight, 8 - sliderBgHeight);
- fillBackground(dst, _x + 9, _y + 8, _width - 18, sliderHeight + 2, 8);
- fillBackground(dst, _x + 17, _y + 8 + sliderHeight + 2, _width - 34, _height - sliderBgHeight, 32 - sliderBgHeight);
+ fillBackground(dst, x, y, width, sliderBgHeight, 0);
+ fillBackground(dst, x + 8, y + sliderBgHeight, width - 16, height - sliderBgHeight, 8 - sliderBgHeight);
+ fillBackground(dst, x + 9, y + 8, width - 18, sliderHeight + 2, 8);
+ fillBackground(dst, x + 17, y + 8 + sliderHeight + 2, width - 34, height - sliderBgHeight, 32 - sliderBgHeight);
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
assert(uiCorners->loadedFrameCount() >= 11);
const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &corners = uiCorners->getFrames();
- for (int xoff = _x + corners[0]->w; xoff < (_x + _width) - corners[3]->w; xoff += corners[2]->w) {
- dst->transBlitFrom(*corners[2], Common::Point(xoff, _y));
+ for (int xoff = x + corners[0]->w; xoff < (x + width) - corners[3]->w; xoff += corners[2]->w) {
+ dst->transBlitFrom(*corners[2], Common::Point(xoff, y));
}
- for (int xoff = _x + 8 + corners[6]->w; xoff < (_x + 8 + _width - 16) - corners[8]->w; xoff += corners[7]->w) {
- dst->transBlitFrom(*corners[7], Common::Point(xoff, (_y + _height) - corners[7]->h));
+ for (int xoff = x + 8 + corners[6]->w; xoff < (x + 8 + width - 16) - corners[8]->w; xoff += corners[7]->w) {
+ dst->transBlitFrom(*corners[7], Common::Point(xoff, (y + height) - corners[7]->h));
}
- for (int yoff = _y + corners[3]->h; yoff < (_y + sliderBgHeight) - corners[10]->h; yoff += corners[5]->h) {
- dst->transBlitFrom(*corners[5], Common::Point((_x + _width) - corners[5]->w, yoff));
+ for (int yoff = y + corners[3]->h; yoff < (y + sliderBgHeight) - corners[10]->h; yoff += corners[5]->h) {
+ dst->transBlitFrom(*corners[5], Common::Point((x + width) - corners[5]->w, yoff));
}
- for (int yoff = _y + corners[1]->h; yoff < (_y + sliderBgHeight) - corners[9]->h; yoff += corners[4]->h) {
- dst->transBlitFrom(*corners[4], Common::Point(_x, yoff));
+ for (int yoff = y + corners[1]->h; yoff < (y + sliderBgHeight) - corners[9]->h; yoff += corners[4]->h) {
+ dst->transBlitFrom(*corners[4], Common::Point(x, yoff));
}
- for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[6]->h; yoff += corners[4]->h) {
- dst->transBlitFrom(*corners[4], Common::Point(_x + 8, yoff));
+ for (int yoff = y + sliderBgHeight; yoff < (y + height) - corners[6]->h; yoff += corners[4]->h) {
+ dst->transBlitFrom(*corners[4], Common::Point(x + 8, yoff));
}
- for (int yoff = _y + sliderBgHeight; yoff < (_y + _height) - corners[8]->h; yoff += corners[5]->h) {
- dst->transBlitFrom(*corners[5], Common::Point((_x + 8 + _width - 16) - corners[5]->w, yoff));
+ for (int yoff = y + sliderBgHeight; yoff < (y + height) - corners[8]->h; yoff += corners[5]->h) {
+ dst->transBlitFrom(*corners[5], Common::Point((x + 8 + width - 16) - corners[5]->w, yoff));
}
- dst->transBlitFrom(*corners[1], Common::Point(_x, _y));
- dst->transBlitFrom(*corners[3], Common::Point((_x + _width) - corners[3]->w, _y));
- dst->transBlitFrom(*corners[6], Common::Point(_x + 8, (_y + _height) - corners[6]->h));
- dst->transBlitFrom(*corners[8], Common::Point((_x + _width - 8) - corners[8]->w, (_y + _height) - corners[8]->h));
- dst->transBlitFrom(*corners[9], Common::Point(_x, (_y + sliderBgHeight) - corners[9]->h));
- dst->transBlitFrom(*corners[10], Common::Point((_x + _width) - corners[10]->w, (_y + sliderBgHeight) - corners[10]->h));
-
- drawHeader(dst, _x, _y, _width, 9, header);
+ dst->transBlitFrom(*corners[1], Common::Point(x, y));
+ dst->transBlitFrom(*corners[3], Common::Point((x + width) - corners[3]->w, y));
+ dst->transBlitFrom(*corners[6], Common::Point(x + 8, (y + height) - corners[6]->h));
+ dst->transBlitFrom(*corners[8], Common::Point((x + width - 8) - corners[8]->w, (y + height) - corners[8]->h));
+ dst->transBlitFrom(*corners[9], Common::Point(x, (y + sliderBgHeight) - corners[9]->h));
+ dst->transBlitFrom(*corners[10], Common::Point((x + width) - corners[10]->w, (y + sliderBgHeight) - corners[10]->h));
+
+ drawHeader(dst, x, y, width, 9, header);
}
void RequestData::drawBackgroundNoSliders(Graphics::ManagedSurface *dst, const Common::String &header) const {
- fillBackground(dst, _x, _y, _width, _height, 0);
- drawCorners(dst, 11, _x, _y, _width, _height);
- drawHeader(dst, _x, _y, _width, 4, header);
+ fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
+ drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
+ drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, header);
}
/*static*/
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 023840c6f6d..4e99371ff64 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -27,6 +27,7 @@
#include "common/array.h"
#include "dgds/parser.h"
+#include "dgds/dgds_rect.h"
namespace Dgds {
@@ -145,10 +146,7 @@ public:
class RequestData {
public:
uint16 _fileNum;
- uint16 _x;
- uint16 _y;
- uint16 _width;
- uint16 _height;
+ DgdsRect _rect;
uint16 _col1;
uint16 _col2;
uint16 _flags;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 5d1eee58c39..8cb72d26d00 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -1431,9 +1431,12 @@ Common::Error GDSScene::syncState(Common::Serializer &s) {
error("Item count in save doesn't match count in game (%d vs %d)",
nitems, _gameItems.size());
}
- for (auto &item : _gameItems) {
+ for (GameItem &item : _gameItems) {
s.syncAsUint16LE(item._inSceneNum);
+ if (s.getVersion() > 1)
+ s.syncAsUint16LE(item._flags);
s.syncAsUint16LE(item._quality);
+ //debug("loaded item: %d %d %d %d", item._num, item._inSceneNum, item._flags, item._quality);
}
uint16 nglobals = _perSceneGlobals.size();
@@ -1442,7 +1445,7 @@ Common::Error GDSScene::syncState(Common::Serializer &s) {
error("Scene global count in save doesn't match count in game (%d vs %d)",
nglobals, _perSceneGlobals.size());
}
- for (auto &glob : _perSceneGlobals) {
+ for (PerSceneGlobal &glob : _perSceneGlobals) {
s.syncAsUint16LE(glob._val);
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 1126288f58c..6818f422419 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -95,8 +95,8 @@ enum SceneOpCode {
kSceneOpAddFlagToDragItem = 13, // args: none.
kSceneOpOpenInventoryZoom = 14, // args: none.
kSceneOpMoveItemsBetweenScenes = 15, // args: none.
- kSceneOpShowClock = 16, // args: none. set some clock-related globals
- kSceneOpHideClock = 17, // args: none. set some clock-related values.
+ kSceneOpShowClock = 16, // args: none. set clock script-visible.
+ kSceneOpHideClock = 17, // args: none. set clock script-hidden.
kSceneOpShowMouse = 18, // args: none.
kSceneOpHideMouse = 19, // args: none.
@@ -105,7 +105,7 @@ enum SceneOpCode {
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOpOpenGameOverMenu = 102, // args: none.
kSceneOp103 = 103, // args: none. Something about "boy am I tired"?
- kSceneOp104 = 104, // args: none.
+ kSceneOp104 = 104, // args: none. Called in arcade post-tick.
kSceneOp105 = 105, // args: none. Draw some number at 141, 56
kSceneOp106 = 106, // args: none. Draw some number at 42, 250
kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. DRAGON: Show menu 50, the "Play Introduction" / "Skip Introduction" menu.
Commit: e9815f141304a5cdabb2ec3a61614794d7f24302
https://github.com/scummvm/scummvm/commit/e9815f141304a5cdabb2ec3a61614794d7f24302
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix more small engine bugs
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/ttm.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 8bea4f222a8..72de7a4ccce 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -164,8 +164,9 @@ bool DgdsEngine::changeScene(int sceneNum) {
_scene->runLeaveSceneOps();
- // store the last scene num
- _gameGlobals->setGlobal(0x61, _scene->getNum());
+ // store the last scene num if it's not 2
+ if (_scene->getNum() != 2)
+ _gameGlobals->setGlobal(0x61, _scene->getNum());
_scene->unload();
_backgroundFile.clear();
@@ -241,7 +242,7 @@ void DgdsEngine::setShowClock(bool val) {
void DgdsEngine::checkDrawInventoryButton() {
if (_gdsScene->getCursorList().size() < 2 || _icons->loadedFrameCount() < 2 ||
- _scene->getHotAreas().size() < 1 || _scene->getHotAreas()[0]._num != 0)
+ _scene->getHotAreas().size() < 1 || _scene->getHotAreas().front()._num != 0)
return;
int x = SCREEN_WIDTH - _icons->width(2) - 5;
@@ -419,7 +420,7 @@ Common::Error DgdsEngine::run() {
_compositionBuffer.blitFrom(_backgroundBuffer);
- if (_inventory->isOpen()) {
+ if (_inventory->isOpen() && _scene->getNum() == 2) {
int invCount = _gdsScene->countItemsInScene2();
_inventory->draw(_compositionBuffer, invCount);
}
@@ -428,7 +429,7 @@ Common::Error DgdsEngine::run() {
_scene->drawActiveDialogBgs(&_compositionBuffer);
- if (!_inventory->isOpen() || _inventory->isZoomVisible())
+ if (_scene->getNum() != 2 || _inventory->isZoomVisible())
_adsInterp->run();
if (mouseEvent != Common::EVENT_INVALID) {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8cb72d26d00..8a4566e0360 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -45,7 +45,7 @@
namespace Dgds {
-template<class S> static Common::String _dumpStructList(const Common::String &indent, const Common::String &name, const Common::Array<S> &list) {
+template<class C> static Common::String _dumpStructList(const Common::String &indent, const Common::String &name, const C &list) {
if (list.empty())
return "";
@@ -59,7 +59,6 @@ template<class S> static Common::String _dumpStructList(const Common::String &in
}
-
Common::String _sceneConditionStr(SceneCondition cflag) {
Common::String ret;
@@ -118,6 +117,8 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpSetDragItem: return "setDragItem";
case kSceneOpOpenInventory: return "openInventory";
case kSceneOpShowDlg: return "showdlg";
+ case kSceneOpShowInvButton: return "showInvButton";
+ case kSceneOpHideInvButton: return "hideInvButton";
case kSceneOpEnableTrigger: return "enabletrigger";
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
case kSceneOpAddFlagToDragItem: return "addFlagToDragItem";
@@ -127,10 +128,15 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpHideClock: return "sceneOpHideClock";
case kSceneOpShowMouse: return "sceneOpShowMouse";
case kSceneOpHideMouse: return "sceneOpHideMouse";
+ case kSceneOpPasscode: return "passcode";
case kSceneOpMeanwhile: return "meanwhile";
+ case kSceneOpOpenGameOverMenu: return "openGameOverMenu";
+ case kSceneOpTiredDialog: return "openTiredDialog";
+ case kSceneOpArcadeTick: return "sceneOpArcadeTick";
+ case kSceneOp105: return "sceneOp105";
+ case kSceneOp106: return "sceneOp106";
case kSceneOpOpenPlaySkipIntroMenu: return "openPlaySkipIntroMovie";
- case kSceneOpShowInvButton: return "showInvButton";
- case kSceneOpHideInvButton: return "hideInvButton";
+ case kSceneOpOpenBetterSaveGameMenu: return "openBetterSaveGameMenu";
default:
return Common::String::format("sceneOp%d", (int)code);
}
@@ -242,10 +248,12 @@ bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
}
-bool Scene::readHotAreaList(Common::SeekableReadStream *s, Common::Array<HotArea> &list) const {
- list.resize(s->readUint16LE());
- for (HotArea &dst : list) {
+bool Scene::readHotAreaList(Common::SeekableReadStream *s, Common::List<HotArea> &list) const {
+ uint16 num = s->readUint16LE();
+ for (uint16 i = 0; i < num; i++) {
+ HotArea dst;
readHotArea(s, dst);
+ list.push_back(dst);
}
return !s->err();
}
@@ -573,7 +581,8 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
CursorMan.showMouse(false);
break;
case kSceneOpMeanwhile:
- warning("TODO: Implement meanwhile screen");
+ // TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway..
+ static_cast<DgdsEngine *>(g_engine)->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case kSceneOpShowInvButton:
static_cast<DgdsEngine *>(g_engine)->getScene()->addInvButtonToHotAreaList();
@@ -584,6 +593,16 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
case kSceneOpOpenGameOverMenu:
static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuGameOver);
break;
+ case kSceneOpTiredDialog:
+ engine->getInventory()->close();
+ engine->getScene()->addAndShowTiredDialog();
+ break;
+ case kSceneOpArcadeTick:
+ error("TODO: Implement sceneOpArcadeTick");
+ case kSceneOp105:
+ error("TODO: Implement sceneOp105");
+ case kSceneOp106:
+ error("TODO: Implement sceneOp106");
case kSceneOpOpenPlaySkipIntroMenu:
static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuSkipPlayIntro);
break;
@@ -789,6 +808,33 @@ void SDSScene::checkTriggers() {
}
}
+static const uint16 TIRED_DLG_ID = 7777;
+
+void SDSScene::addAndShowTiredDialog() {
+ bool haveTiredDlg = false;
+ for (auto &d : _dialogs) {
+ if (d._num == TIRED_DLG_ID) {
+ haveTiredDlg = true;
+ break;
+ }
+ }
+ if (!haveTiredDlg) {
+ Dialog dlg;
+ dlg._num = TIRED_DLG_ID;
+ dlg._rect = DgdsRect(4, 18, 208, 91);
+ dlg._bgColor = 15;
+ dlg._fontColor = 0;
+ dlg._selectionBgCol = 15;
+ dlg._selectonFontCol = 0;
+ dlg._flags = static_cast<DialogFlags>(kDlgFlagLo8 | kDlgFlagLeftJust | kDlgFlagFlatBg);
+ dlg._frameType = kDlgFrameThought;
+ dlg._time = 420;
+ dlg._str = "Boy, am I tired. Better get some sleep in about an hour.";
+ _dialogs.push_back(dlg);
+ }
+ showDialog(TIRED_DLG_ID);
+}
+
void SDSScene::showDialog(uint16 num) {
for (auto &dialog : _dialogs) {
if (dialog._num == num) {
@@ -1173,7 +1219,7 @@ void SDSScene::addInvButtonToHotAreaList() {
if (cursors.empty() || !icons || icons->loadedFrameCount() <= 2 || _num == 2)
return;
- if (_hotAreaList.size() && _hotAreaList[0]._num == 0)
+ if (_hotAreaList.size() && _hotAreaList.front()._num == 0)
return;
HotArea area;
@@ -1184,12 +1230,12 @@ void SDSScene::addInvButtonToHotAreaList() {
area._rect.x = SCREEN_WIDTH - area._rect.width;
area._rect.y = SCREEN_HEIGHT - area._rect.height;
- _hotAreaList.insert_at(0, area);
+ _hotAreaList.push_front(area);
}
void SDSScene::removeInvButtonFromHotAreaList() {
- if (_hotAreaList.size() && _hotAreaList[0]._num == 0)
- _hotAreaList.remove_at(0);
+ if (_hotAreaList.size() && _hotAreaList.front()._num == 0)
+ _hotAreaList.pop_front();
}
Common::Error SDSScene::syncState(Common::Serializer &s) {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 6818f422419..103cf14516f 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -101,13 +101,13 @@ enum SceneOpCode {
kSceneOpHideMouse = 19, // args: none.
// From here on might be game-specific?
- kSceneOp100 = 100, // args: none.
+ kSceneOpPasscode = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOpOpenGameOverMenu = 102, // args: none.
- kSceneOp103 = 103, // args: none. Something about "boy am I tired"?
- kSceneOp104 = 104, // args: none. Called in arcade post-tick.
+ kSceneOpTiredDialog = 103, // args: none. Something about "boy am I tired"?
+ kSceneOpArcadeTick = 104, // args: none. Called in arcade post-tick.
kSceneOp105 = 105, // args: none. Draw some number at 141, 56
- kSceneOp106 = 106, // args: none. Draw some number at 42, 250
+ kSceneOp106 = 106, // args: none. Draw some number at 250, 42
kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. DRAGON: Show menu 50, the "Play Introduction" / "Skip Introduction" menu.
kSceneOpOpenBetterSaveGameMenu = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
};
@@ -228,7 +228,7 @@ public:
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
bool readHotArea(Common::SeekableReadStream *s, HotArea &dst) const;
- bool readHotAreaList(Common::SeekableReadStream *s, Common::Array<HotArea> &list) const;
+ bool readHotAreaList(Common::SeekableReadStream *s, Common::List<HotArea> &list) const;
bool readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const;
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readObjInteractionList(Common::SeekableReadStream *s, Common::Array<ObjectInteraction> &list) const;
@@ -327,7 +327,7 @@ public:
void addInvButtonToHotAreaList();
void removeInvButtonFromHotAreaList();
- const Common::Array<HotArea> &getHotAreas() const { return _hotAreaList; }
+ const Common::List<HotArea> &getHotAreas() const { return _hotAreaList; }
const GameItem *getDragItem() const { return _dragItem; }
GameItem *getDragItem() { return _dragItem; }
@@ -341,6 +341,7 @@ public:
Common::Error syncState(Common::Serializer &s) override;
void onDragFinish(const Common::Point &pt);
+ void addAndShowTiredDialog();
protected:
HotArea *findAreaUnderMouse(const Common::Point &pt);
@@ -357,7 +358,7 @@ private:
uint _field6_0x14;
Common::String _adsFile;
//uint _field8_0x23;
- Common::Array<HotArea> _hotAreaList;
+ Common::List<HotArea> _hotAreaList;
Common::Array<ObjectInteraction> _objInteractions1;
Common::Array<ObjectInteraction> _objInteractions2;
//uint _field12_0x2b;
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 52da1b08781..4a70f8987e7 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -441,7 +441,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
}
case 0xa110: { // DRAW EMPTY RECT x1,y1,x2,y2:int
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2] - 1, ivals[3] - 1);
_vm->_compositionBuffer.drawLine(r.left, r.top, r.right, r.top, seq._drawColFG);
_vm->_compositionBuffer.drawLine(r.left, r.bottom, r.right, r.bottom, seq._drawColFG);
_vm->_compositionBuffer.drawLine(r.left, r.top, r.left, r.bottom, seq._drawColFG);
Commit: 25f1fa5604030466246e43f3f046d2966ee42f03
https://github.com/scummvm/scummvm/commit/25f1fa5604030466246e43f3f046d2966ee42f03
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix some msvc errors
Changed paths:
engines/dgds/ads.h
engines/dgds/dialog.h
engines/dgds/inventory.cpp
engines/dgds/inventory.h
diff --git a/engines/dgds/ads.h b/engines/dgds/ads.h
index 6b1993dbec2..538e704c158 100644
--- a/engines/dgds/ads.h
+++ b/engines/dgds/ads.h
@@ -50,7 +50,7 @@ public:
// note: originals uses char * but we use offsets into script for less pointers. -1 is nullptr
int32 _segments[80];
int32 _charWhile[80];
- Common::Array<struct TTMSeq *> _usedSeqs[80];
+ Common::Array<TTMSeq *> _usedSeqs[80];
int32 _scriptDelay;
int32 _gotoTarget;
bool _hitTTMOp0110;
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index d9bc117e587..64f727cc7a5 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -36,6 +36,7 @@ class ManagedSurface;
namespace Dgds {
class Font;
+class SceneOp;
enum DialogFlags {
kDlgFlagNone = 0,
@@ -74,7 +75,7 @@ struct DialogAction {
uint16 strStart; /// The start of the clickable text for this action
uint16 strEnd; /// End of clickable text for this action
byte unk[8]; /* Not initialized in loader */
- Common::Array<struct SceneOp> sceneOpList; /// ops to run when this is selected
+ Common::Array<SceneOp> sceneOpList; /// ops to run when this is selected
uint val; /* First entry initialized to 1 in loader */
Common::String dump(const Common::String &indent) const;
@@ -111,7 +112,7 @@ public:
DialogFrameType _frameType;
uint16 _time;
uint16 _nextDialogNum;
- Common::Array<struct DialogAction> _action;
+ Common::Array<DialogAction> _action;
Common::String _str;
uint16 _field18_0x28;
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index de251ebf73f..7787ec29666 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -169,7 +169,7 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
// TODO: does this need to be adjusted ever?
const Common::Rect drawMask(0, 0, 320, 200);
int offset = _itemOffset;
- Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
for (auto & item: items) {
if (item._inSceneNum != 2) // || !(item._flags & 4))
continue;
@@ -234,7 +234,7 @@ GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
if (!_itemArea)
return nullptr;
- Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
if (_itemArea->containsPoint(pt)) {
const int imgAreaX = _itemArea->_parentX + _itemArea->_x;
const int imgAreaY = _itemArea->_parentY + _itemArea->_y;
@@ -295,7 +295,7 @@ void Inventory::mouseLUp(const Common::Point &pt) {
close();
} else if (_nextPageBtn->containsPoint(pt) && !(_nextPageBtn->_flags3 & 0x40)) {
int numInvItems = 0;
- Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
for (auto &item: items) {
if (item._inSceneNum == 2) // && item._flags & 4)
numInvItems++;
@@ -310,7 +310,7 @@ void Inventory::mouseLUp(const Common::Point &pt) {
} else if (_clockSkipHrBtn && _clockSkipHrBtn->containsPoint(pt)) {
engine->getClock().addGameTime(60);
} else if (_dropBtn && _dropBtn->containsPoint(pt) && _highlightItemNo >= 0) {
- Common::Array<struct GameItem> &items = engine->getGDSScene()->getGameItems();
+ Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
for (auto &item: items) {
if (item._num == _highlightItemNo) {
item._inSceneNum = _openedFromSceneNum;
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 54116883296..225e9b9cd67 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -31,7 +31,7 @@ class ManagedSurface;
namespace Dgds {
-struct GameItem;
+class GameItem;
class Inventory {
public:
Commit: c3b0b32df52dbe7034c7a9c4bae5f9dc7b7de9cb
https://github.com/scummvm/scummvm/commit/c3b0b32df52dbe7034c7a9c4bae5f9dc7b7de9cb
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement RST (reset state) loading
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/menu.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/scripts.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 72de7a4ccce..963c415a820 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -79,7 +79,7 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone), _isLoading(true) {
+ _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone), _isLoading(true), _rstFileName(nullptr) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -251,12 +251,28 @@ void DgdsEngine::checkDrawInventoryButton() {
_icons->drawBitmap(2, x, y, drawWin, _compositionBuffer);
}
-void DgdsEngine::init() {
- initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
+void DgdsEngine::init(bool restarting) {
+ if (!restarting) {
+ // Init things with no state only once
+ initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ _console = new Console(this);
+ _resource = new ResourceManager();
+ _decompressor = new Decompressor();
+
+ setDebugger(_console);
+ } else {
+ // Reset the stateful objects
+ delete _gamePals;
+ delete _soundPlayer;
+ delete _scene;
+ delete _gdsScene;
+ delete _fontManager;
+ delete _menu;
+ delete _adsInterp;
+ delete _inventory;
+ }
- _console = new Console(this);
- _resource = new ResourceManager();
- _decompressor = new Decompressor();
_gamePals = new GamePalettes(_resource, _decompressor);
_soundPlayer = new Sound(_mixer, _resource, _decompressor);
_scene = new SDSScene();
@@ -266,8 +282,6 @@ void DgdsEngine::init() {
_adsInterp = new ADSInterpreter(this);
_inventory = new Inventory();
- setDebugger(_console);
-
_backgroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_storedAreaBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
_compositionBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
@@ -282,34 +296,40 @@ void DgdsEngine::loadGameFiles() {
_fontManager->loadFonts(getGameId(), _resource, _decompressor);
- if (getGameId() == GID_DRAGON) {
+ switch (getGameId()) {
+ case GID_DRAGON:
_soundPlayer->loadSFX("SOUNDS.SNG");
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("DRAGON.PAL");
_gdsScene->load("DRAGON.GDS", _resource, _decompressor);
+ _rstFileName = "DRAGON.RST";
debug("%s", _gdsScene->dump("").c_str());
loadCorners("DCORNERS.BMP");
reqParser.parse(&invRequestData, "DINV.REQ");
reqParser.parse(&vcrRequestData, "DVCR.REQ");
- } else if (getGameId() == GID_CHINA) {
+ break;
+ case GID_CHINA:
// TODO: Create a better type for this..
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("HOC.PAL");
_gdsScene->load("HOC.GDS", _resource, _decompressor);
+ _rstFileName = "HOC.RST";
//debug("%s", _gdsScene->dump("").c_str());
loadCorners("HCORNERS.BMP");
reqParser.parse(&invRequestData, "HINV.REQ");
reqParser.parse(&vcrRequestData, "HVCR.REQ");
- } else if (getGameId() == GID_BEAMISH) {
+ break;
+ case GID_BEAMISH:
// TODO: Create a better type for this..
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("WILLY.PAL");
// TODO: This doesn't parse correctly yet.
//_gdsScene->load("WILLY.GDS", _resource, _decompressor);
+ _rstFileName = "WILLY.RST";
loadCorners("WCORNERS.BMP");
reqParser.parse(&invRequestData, "WINV.REQ");
@@ -317,15 +337,20 @@ void DgdsEngine::loadGameFiles() {
//_scene->load("S34.SDS", _resource, _decompressor);
_adsInterp->load("TITLE.ADS");
- } else if (getGameId() == GID_SQ5DEMO) {
+ break;
+ case GID_SQ5DEMO:
// TODO: Create a better type for this..
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("NORMAL.PAL");
_adsInterp->load("CESDEMO.ADS");
+ break;
+ default:
+ error("Unsupported game type in loadGameFiles");
}
_gdsScene->runStartGameOps();
loadIcons();
+ _gdsScene->initIconSizes();
setMouseCursor(0);
_inventory->setRequestData(invRequestData);
@@ -337,9 +362,16 @@ void DgdsEngine::loadGameFiles() {
debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
}
+void DgdsEngine::loadRestartFile() {
+ if (!_rstFileName)
+ error("Trying to restart game but no rst file name set!");
+
+ _gdsScene->loadRestart(_rstFileName, _resource, _decompressor);
+}
+
Common::Error DgdsEngine::run() {
_isLoading = true;
- init();
+ init(false);
loadGameFiles();
// changeScene(55); // to test DRAGON intro sequence (after credits)
@@ -528,6 +560,14 @@ Common::Error DgdsEngine::run() {
return Common::kNoError;
}
+void DgdsEngine::restartGame() {
+ _isLoading = true;
+ init(true);
+ loadGameFiles();
+ loadRestartFile();
+ _gameGlobals->setGlobal(0x57, 1);
+}
+
Common::SeekableReadStream *DgdsEngine::getResource(const Common::String &name, bool ignorePatches) {
return _resource->getResource(name, ignorePatches);
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 480170606b1..2324e296c89 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -120,6 +120,7 @@ private:
MenuId _menuToTrigger;
bool _isLoading;
+ const char *_rstFileName;
public:
DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -127,6 +128,8 @@ public:
virtual Common::Error run() override;
+ void restartGame();
+
DgdsGameId getGameId() { return _gameId; }
Graphics::ManagedSurface &getBackgroundBuffer() { return _backgroundBuffer; }
@@ -189,8 +192,9 @@ private:
void loadIcons();
void checkDrawInventoryButton();
- void init();
+ void init(bool restarting);
void loadGameFiles();
+ void loadRestartFile();
};
} // End of namespace Dgds
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 67b830f6bdc..113a47369a8 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -58,8 +58,7 @@ Dialog *Dialog::_lastDialogSelectionChangedFor = nullptr;
Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _selectionBgCol(0), _selectonFontCol(0),
- _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0),
- _field18_0x28(0)
+ _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0)
{}
@@ -626,9 +625,9 @@ void Dialog::fixupStringAndActions() {
Common::String Dialog::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
- "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d unk18 %d",
+ "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d",
indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _selectionBgCol, _selectonFontCol, _fontSize,
- _flags, _frameType, _time, _nextDialogNum, _field18_0x28);
+ _flags, _frameType, _time, _nextDialogNum);
str += indent + "state=" + (_state ? _state->dump("") : "null");
str += "\n";
str += _dumpStructList(indent, "actions", _action);
@@ -675,7 +674,7 @@ Common::Error DialogState::syncState(Common::Serializer &s) {
Common::String DialogAction::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sDialogueAction<%d span: %d-%d", indent.c_str(), val, strStart, strEnd);
+ Common::String str = Common::String::format("%sDialogueAction<span: %d-%d", indent.c_str(), strStart, strEnd);
str += _dumpStructList(indent, "opList", sceneOpList);
if (!sceneOpList.empty()) {
str += "\n";
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 64f727cc7a5..e6246d801c1 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -74,9 +74,8 @@ struct DialogAction {
// The game initializes str offsets to pointers, but let's be a bit nicer.
uint16 strStart; /// The start of the clickable text for this action
uint16 strEnd; /// End of clickable text for this action
- byte unk[8]; /* Not initialized in loader */
+ //byte unk[8]; /* Not initialized in loader */
Common::Array<SceneOp> sceneOpList; /// ops to run when this is selected
- uint val; /* First entry initialized to 1 in loader */
Common::String dump(const Common::String &indent) const;
};
@@ -114,7 +113,6 @@ public:
uint16 _nextDialogNum;
Common::Array<DialogAction> _action;
Common::String _str;
- uint16 _field18_0x28;
Common::SharedPtr<DialogState> _state;
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 1b75d2de118..135ef48ed05 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -65,6 +65,7 @@ public:
DetailLevelROGlobal(uint16 num) : Global(num) {}
int16 get() override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
int16 set(int16 val) override { return static_cast<DgdsEngine *>(g_engine)->getDetailLevel(); }
+ void setRaw(int16 val) override { }
};
////////////////////////////////
@@ -108,6 +109,7 @@ public:
DragonDataTableGlobal(uint16 num, DragonDataTable &table) : Global(num), _table(table) {}
int16 get() override { return _table.getValueFromTable(); }
int16 set(int16 val) override { return _table.getValueFromTable(); }
+ void setRaw(int16 val) override { }
private:
DragonDataTable &_table;
};
@@ -129,6 +131,8 @@ public:
return get();
}
+ void setRaw(int16 val) override { }
+
private:
int16 *_ptr;
bool _isSetOff;
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 61052f0f43e..8f31c36b634 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -49,15 +49,21 @@ public:
virtual int16 get() = 0;
virtual int16 set(int16 val) = 0;
virtual uint16 getNum() const { return _num; }
+ virtual void setRaw(int16 val) = 0; /// only for use in loading state.
};
+/*
+ This is a bit of a misnomer - the global is readonly during play,
+ but it can be set by load/save or restart operations
+*/
template<typename T> class ReadOnlyGlobal : public Global {
public:
- ReadOnlyGlobal(uint16 num, const T *val) : Global(num), _val(val) {}
+ ReadOnlyGlobal(uint16 num, T *val) : Global(num), _val(val) {}
int16 get() override { return *_val; }
int16 set(int16 val) override { return *_val; }
+ void setRaw(int16 val) override { *_val = val; }
private:
- const T *_val;
+ T *_val;
};
template<typename T> class ReadWriteGlobal : public Global {
@@ -65,6 +71,7 @@ public:
ReadWriteGlobal(uint16 num, T *val) : Global(num), _val(val) {}
int16 get() override { return *_val; }
int16 set(int16 val) override { *_val = val; return *_val; }
+ void setRaw(int16 val) override { *_val = val; }
private:
T *_val;
};
@@ -78,7 +85,9 @@ public:
int16 getGlobal(uint16 num);
int16 setGlobal(uint16 num, int16 val);
- virtual Common::Error syncState(Common::Serializer &s) { return Common::kNoError; };
+ virtual Common::Error syncState(Common::Serializer &s) { return Common::kNoError; }
+ Common::Array<Global *> &getAllGlobals() { return _globals; }
+
protected:
Common::Array<Global *> _globals;
};
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 841ce02991e..5cd0bb7c214 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -184,6 +184,7 @@ int16 Menu::getClickedMenuItem(Common::Point mouseClick) {
void Menu::handleMenu(Common::Point &mouse) {
const int16 clickedMenuItem = getClickedMenuItem(mouse);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
// Click animation
// TODO: Handle on/off buttons
@@ -291,8 +292,7 @@ void Menu::handleMenu(Common::Point &mouse) {
g_engine->quitGame();
break;
case kMenuRestartYes:
- // TODO
- debug("Clicked Restart - Yes %d", clickedMenuItem);
+ engine->restartGame();
break;
case kMenuGameOverQuit:
drawMenu(kMenuQuit);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8a4566e0360..3a353a22a22 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -224,10 +224,10 @@ bool Scene::isVersionUnder(const char *version) const {
bool Scene::readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const {
uint16 num = s->readUint16LE();
for (uint16 i = 0; i < num; i++) {
- uint16 num = s->readUint16LE();
+ uint16 cnum = s->readUint16LE();
SceneCondition cond = static_cast<SceneCondition>(s->readUint16LE());
uint16 val = s->readUint16LE();
- list.push_back(SceneConditions(num, cond, val));
+ list.push_back(SceneConditions(cnum, cond, val));
}
return !s->err();
}
@@ -401,8 +401,10 @@ bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTr
bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const {
list.resize(s->readUint16LE());
- if (!list.empty())
- list[0].val = 1;
+ // The original initializes a field in the first entry to 1 here, but it seems
+ // only used for memory management so we don't need it?
+ // if (!list.empty())
+ // list[0].val = 1;
for (DialogAction &dst : list) {
dst.strStart = s->readUint16LE();
@@ -580,9 +582,13 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
case kSceneOpHideMouse:
CursorMan.showMouse(false);
break;
+ case kSceneOpPasscode:
+ static_cast<DgdsEngine *>(g_engine)->getScene()->sceneOpUpdatePasscodeGlobal();
+ break;
case kSceneOpMeanwhile:
- // TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway..
- static_cast<DgdsEngine *>(g_engine)->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ // TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway.
+ // Probably need to do something here to avoid flashing..
+ //static_cast<DgdsEngine *>(g_engine)->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case kSceneOpShowInvButton:
static_cast<DgdsEngine *>(g_engine)->getScene()->addInvButtonToHotAreaList();
@@ -781,10 +787,12 @@ Common::String SDSScene::dump(const Common::String &indent) const {
}
-void SDSScene::enableTrigger(uint16 num) {
+void SDSScene::enableTrigger(uint16 num, bool enable /* = true */) {
for (auto &trigger : _triggers) {
- if (trigger.getNum() == num)
- trigger._enabled = true;
+ if (trigger.getNum() == num) {
+ trigger._enabled = enable;
+ break;
+ }
}
}
@@ -835,6 +843,71 @@ void SDSScene::addAndShowTiredDialog() {
showDialog(TIRED_DLG_ID);
}
+/*
+static const uint16 DRAGON_PASSCODE[] = {
+ 1, 4, 3, 4, 0, 3, 4, 1, 3, 0, 1, 4, 3, 2, 0,
+ 4, 4, 2, 3, 4, 0, 0, 4, 3, 2, 1, 1, 2, 4, 0,
+ 4, 1, 3, 2, 0, 2, 1, 4, 3, 4, 1, 3, 2, 0, 1
+};
+
+static uint16 g_passcodeBtnVal = 0;
+static uint16 passcodeBlockNum = 0;
+static uint16 passcodeVal4 = 0;
+static uint16 passcodeVal1 = 0;
+static uint16 passcodeVal2 = 0;
+static uint16 passcodeVal3 = 0;
+*/
+
+void SDSScene::sceneOpUpdatePasscodeGlobal() {
+ warning("TODO: Finish implementing sceneOpUpdatePasscodeGlobal");
+/*
+ if (g_passcodeBtnVal > 33)
+ return;
+
+ if (g_passcodeBtnVal >= 30) {
+ if (DRAGON_PASSCODE[passcodeVal4 + passcodeBlockNum * 15] == g_passcodeBtnVal - 30) {
+ passcodeVal4++;
+ if (passcodeVal4 < passcodeVal3) {
+ g_passcodeBtnVal = 0;
+ } else if (passcodeVal3 < 15) {
+ g_passcodeBtnVal = 5;
+ } else {
+ g_passcodeBtnVal = 6;
+ }
+ } else {
+ g_passcodeBtnVal = 7;
+ passcodeVal2 = 0;
+ passcodeVal1 = 5;
+ }
+ } else {
+ if (g_passcodeBtnVal > 4)
+ return;
+
+ if (g_passcodeBtnVal < 4) {
+ passcodeBlockNum = g_passcodeBtnVal - 1;
+ passcodeVal2 = 0;
+ passcodeVal1 = 5;
+ passcodeVal4 = 0;
+ passcodeVal3 = 15;
+ } else if (passcodeVal1 > passcodeVal2) {
+ passcodeVal2++;
+ g_passcodeBtnVal = DRAGON_PASSCODE[passcodeVal2 + passcodeBlockNum * 15] + 20;
+ } else if (passcodeVal1 > 14) {
+ passcodeVal2 = 0;
+ passcodeVal4 = 0;
+ passcodeVal3 = passcodeVal1;
+ g_passcodeBtnVal = 8;
+ } else {
+ passcodeVal2 = 0;
+ passcodeVal3 = passcodeVal1;
+ passcodeVal1 += 5;
+ passcodeVal4 = 0;
+ g_passcodeBtnVal = 8;
+ }
+ }
+*/
+}
+
void SDSScene::showDialog(uint16 num) {
for (auto &dialog : _dialogs) {
if (dialog._num == num) {
@@ -900,7 +973,7 @@ bool SDSScene::checkDialogActive() {
if (action || dlg._action.empty()) {
dlg.setFlag(kDlgFlagHiFinished);
if (action) {
- debug("Dialog closing: run action %d op list (%d ops)", action->val, action->sceneOpList.size());
+ debug("Dialog closing: run action (%d ops)", action->sceneOpList.size());
if (!runOps(action->sceneOpList)) {
_dlgWithFlagLo8IsClosing = false;
return true;
@@ -1296,11 +1369,116 @@ bool GDSScene::load(const Common::String &filename, ResourceManager *resourceMan
}
}
+ initIconSizes();
+
delete sceneFile;
return result;
}
+bool GDSScene::loadRestart(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
+ Common::SeekableReadStream *file = resourceManager->getResource(filename);
+ if (!file)
+ error("Restart data %s not found", filename.c_str());
+
+ uint32 magic = file->readUint32LE();
+ if (magic != _magic)
+ error("Restart file magic doesn't match (%04X vs %04X)", magic, _magic);
+
+ uint16 num = file->readUint16LE();
+ // Find matching game item and load its values
+ while (num) {
+ bool found = false;
+ for (GameItem &item : _gameItems) {
+ if (item._num == num) {
+ item._rect.x = file->readUint16LE();
+ item._rect.y = file->readUint16LE();
+ item._rect.width = file->readUint16LE();
+ item._rect.height = file->readUint16LE();
+ item._inSceneNum = file->readUint16LE();
+ item._flags = file->readUint16LE();
+ item._quality = file->readUint16LE();
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ error("Reset file references unknown item %d", num);
+ num = file->readUint16LE();
+ }
+ initIconSizes();
+
+ num = file->readUint16LE();
+ while (num) {
+ uint16 scene = file->readUint16LE();
+ int16 val = file->readSint16LE();
+ bool found = false;
+ for (PerSceneGlobal &glob : _perSceneGlobals) {
+ if (glob.matches(num, scene)) {
+ glob._val = val;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ error("Reset file references unknown global %d", num);
+ num = file->readUint16LE();
+ }
+
+ /*uint32 unk = */ file->readUint32LE();
+
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ Common::Array<Global *> &globs = engine->getGameGlobals()->getAllGlobals();
+
+ if (globs.size() > 50)
+ error("Too many globals to load from RST file");
+
+ int g = 0;
+ for (Global *glob : globs) {
+ int16 val = file->readUint16LE();
+ glob->setRaw(val);
+ g++;
+ }
+
+ // Always 50 int16s worth of globals in the file, skip any unused.
+ if (g < 50)
+ file->skip(2 * (50 - g));
+
+ uint16 triggers[100];
+ for (int i = 0; i < ARRAYSIZE(triggers); i++) {
+ triggers[i] = file->readUint16LE();
+ }
+
+ engine->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ // TODO: FIXME: What should this scene num be? For now hacked to work with Dragon.
+ engine->changeScene(3);
+ SDSScene *scene = engine->getScene();
+ int t = 0;
+ num = triggers[t++];
+ while (num) {
+ uint16 val = triggers[t++];
+ scene->enableTrigger(num, (bool)val);
+ num = triggers[t++];
+ }
+
+ return true;
+}
+
+void GDSScene::initIconSizes() {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::SharedPtr<Image> icons = engine->getIcons();
+ uint16 nicons = icons ? icons->getFrames().size() : 0;
+ for (GameItem &item : _gameItems) {
+ if (item._iconNum < nicons) {
+ item._rect.width = icons->getFrames()[item._iconNum]->w;
+ item._rect.height = icons->getFrames()[item._iconNum]->w;
+ } else {
+ item._rect.width = 32;
+ item._rect.height = 32;
+ }
+ }
+}
+
bool GDSScene::readPerSceneGlobals(Common::SeekableReadStream *s) {
uint16 numGlobals = s->readUint16LE();
for (uint16 i = 0; i < numGlobals; i++) {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 103cf14516f..75ceeaf796c 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -224,6 +224,7 @@ public:
bool runOps(const Common::Array<SceneOp> &ops, int16 addMinutes = 0);
virtual Common::Error syncState(Common::Serializer &s) = 0;
+ virtual void enableTrigger(uint16 numm, bool enable = true) {}
protected:
bool readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const;
@@ -239,7 +240,6 @@ protected:
bool checkConditions(const Common::Array<SceneConditions> &cond) const;
- virtual void enableTrigger(uint16 num) {}
virtual void showDialog(uint16 num) {}
virtual void globalOps(const Common::Array<uint16> &args) {}
virtual void segmentStateOps(const Common::Array<uint16> &args);
@@ -260,6 +260,7 @@ public:
GDSScene();
bool load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
+ bool loadRestart(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
bool parse(Common::SeekableReadStream *s) override;
bool parseInf(Common::SeekableReadStream *s);
const Common::String &getIconFile() const { return _iconFile; }
@@ -283,6 +284,7 @@ public:
const Common::Array<ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
Common::Error syncState(Common::Serializer &s) override;
+ void initIconSizes();
private:
Common::String _iconFile;
@@ -341,13 +343,16 @@ public:
Common::Error syncState(Common::Serializer &s) override;
void onDragFinish(const Common::Point &pt);
+ void enableTrigger(uint16 num, bool enable = true) override;
+
+ // dragon-specific scene ops
void addAndShowTiredDialog();
+ void sceneOpUpdatePasscodeGlobal();
protected:
HotArea *findAreaUnderMouse(const Common::Point &pt);
private:
- void enableTrigger(uint16 num) override;
void showDialog(uint16 num) override;
Dialog *getVisibleDialog();
diff --git a/engines/dgds/scripts.h b/engines/dgds/scripts.h
index 73f885fe527..a798c889801 100644
--- a/engines/dgds/scripts.h
+++ b/engines/dgds/scripts.h
@@ -36,7 +36,6 @@ public:
};
-
} // End of namespace Dgds
#endif // DGDS_SCRIPTS_H
Commit: 3abd356fea0b60ced7748c90746869a87a03ce97
https://github.com/scummvm/scummvm/commit/3abd356fea0b60ced7748c90746869a87a03ce97
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Enforce clip window on drawline
Changed paths:
engines/dgds/ttm.cpp
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 4a70f8987e7..ed8e670a79f 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -23,6 +23,7 @@
#include "common/serializer.h"
#include "graphics/managed_surface.h"
+#include "graphics/primitives.h"
#include "dgds/ttm.h"
#include "dgds/ads.h"
@@ -222,6 +223,20 @@ static const char *ttmOpName(uint16 op) {
}
}
+struct ClipSurface {
+ Graphics::Surface *_surf;
+ Common::Rect _clipWin;
+};
+
+static void plotClippedPoint(int x, int y, int color, void *data) {
+ ClipSurface *cs = (ClipSurface *)data;
+ if (cs->_clipWin.contains(x, y)) {
+ byte *ptr = (byte *)cs->_surf->getBasePtr(x, y);
+ *ptr = (byte)color;
+ }
+}
+
+
void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
switch (op) {
case 0x0000: // FINISH: void
@@ -432,9 +447,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->getStoredAreaBuffer().fillRect(r, 0);
break;
}
- case 0xa0a0: // DRAW LINE x1,y1,x2,y2:int
- _vm->_compositionBuffer.drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG);
+ case 0xa0a0: { // DRAW LINE x1,y1,x2,y2:int
+ ClipSurface clipSurf;
+ clipSurf._clipWin = seq._drawWin;
+ clipSurf._surf = _vm->_compositionBuffer.surfacePtr();
+ Graphics::drawLine(ivals[0], ivals[1], ivals[2], ivals[3], seq._drawColFG, plotClippedPoint, &clipSurf);
break;
+ }
case 0xa100: { // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
_vm->_compositionBuffer.fillRect(r, seq._drawColFG);
Commit: 50522d65673890033f00887a1ccd1a9f5be56b4a
https://github.com/scummvm/scummvm/commit/50522d65673890033f00887a1ccd1a9f5be56b4a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix rendering on game load
Changed paths:
engines/dgds/ads.cpp
engines/dgds/dgds.cpp
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index 1dbd3ef7690..b863bf04287 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -320,9 +320,9 @@ void ADSInterpreter::findEndOrInitOp() {
}
bool ADSInterpreter::logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq) {
- const char *tag = env->_tags[seq->_seqNum].c_str();
- int16 envNum = env->_enviro;
- int16 seqNum = seq->_seqNum;
+ const char *tag = seq ? env->_tags[seq->_seqNum].c_str() : "";
+ int16 envNum = env ? env->_enviro : 0;
+ int16 seqNum = seq ? seq->_seqNum : 0;
const char *optype = (code < 0x1300 ? "while" : "if");
switch (code) {
case 0x1010: // WHILE runtype 5
@@ -967,8 +967,14 @@ Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
}
// Text order should be the same
+ if (s.getVersion() < 3) {
+ for (const Common::String &name : scriptNames) {
+ _adsTexts[name].syncState(s);
+ }
+ }
+
for (const Common::String &name : scriptNames) {
- _adsTexts[name].syncState(s);
+ load(name);
}
s.syncString(activeScript);
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 963c415a820..193bd4a5582 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -597,7 +597,7 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
_menu->hideMenu();
- if (!s.syncVersion(2))
+ if (!s.syncVersion(3))
error("Save game version too new: %d", s.getVersion());
Common::Error result;
@@ -654,6 +654,8 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
_storedAreaBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
}
+ _scene->runEnterSceneOps();
+
return Common::kNoError;
}
Commit: 009e430bde4b19b57062b200b11e39a026c97cae
https://github.com/scummvm/scummvm/commit/009e430bde4b19b57062b200b11e39a026c97cae
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add passcode opcode for Dragon.
Changed paths:
engines/dgds/scene.cpp
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 3a353a22a22..21e17118cfb 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -843,69 +843,69 @@ void SDSScene::addAndShowTiredDialog() {
showDialog(TIRED_DLG_ID);
}
-/*
+
static const uint16 DRAGON_PASSCODE[] = {
1, 4, 3, 4, 0, 3, 4, 1, 3, 0, 1, 4, 3, 2, 0,
4, 4, 2, 3, 4, 0, 0, 4, 3, 2, 1, 1, 2, 4, 0,
4, 1, 3, 2, 0, 2, 1, 4, 3, 4, 1, 3, 2, 0, 1
};
-static uint16 g_passcodeBtnVal = 0;
static uint16 passcodeBlockNum = 0;
-static uint16 passcodeVal4 = 0;
static uint16 passcodeVal1 = 0;
static uint16 passcodeVal2 = 0;
static uint16 passcodeVal3 = 0;
-*/
+static uint16 passcodeVal4 = 0;
void SDSScene::sceneOpUpdatePasscodeGlobal() {
- warning("TODO: Finish implementing sceneOpUpdatePasscodeGlobal");
-/*
- if (g_passcodeBtnVal > 33)
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ int16 globalval = engine->getGDSScene()->getGlobal(0x20);
+
+ if (globalval > 33)
return;
- if (g_passcodeBtnVal >= 30) {
- if (DRAGON_PASSCODE[passcodeVal4 + passcodeBlockNum * 15] == g_passcodeBtnVal - 30) {
+ if (globalval >= 30) {
+ if (DRAGON_PASSCODE[passcodeVal4 + passcodeBlockNum * 15] == globalval - 30) {
passcodeVal4++;
if (passcodeVal4 < passcodeVal3) {
- g_passcodeBtnVal = 0;
+ globalval = 0;
} else if (passcodeVal3 < 15) {
- g_passcodeBtnVal = 5;
+ globalval = 5;
} else {
- g_passcodeBtnVal = 6;
+ globalval = 6;
}
} else {
- g_passcodeBtnVal = 7;
- passcodeVal2 = 0;
passcodeVal1 = 5;
+ passcodeVal2 = 0;
+ globalval = 7;
}
} else {
- if (g_passcodeBtnVal > 4)
+ if (globalval > 4)
return;
- if (g_passcodeBtnVal < 4) {
- passcodeBlockNum = g_passcodeBtnVal - 1;
- passcodeVal2 = 0;
+ if (globalval < 4) {
+ passcodeBlockNum = globalval - 1;
passcodeVal1 = 5;
- passcodeVal4 = 0;
+ passcodeVal2 = 0;
passcodeVal3 = 15;
+ passcodeVal4 = 0;
} else if (passcodeVal1 > passcodeVal2) {
passcodeVal2++;
- g_passcodeBtnVal = DRAGON_PASSCODE[passcodeVal2 + passcodeBlockNum * 15] + 20;
+ globalval = DRAGON_PASSCODE[passcodeVal2 + passcodeBlockNum * 15] + 20;
} else if (passcodeVal1 > 14) {
passcodeVal2 = 0;
- passcodeVal4 = 0;
passcodeVal3 = passcodeVal1;
- g_passcodeBtnVal = 8;
+ passcodeVal4 = 0;
+ globalval = 8;
} else {
+ passcodeVal1 += 5;
passcodeVal2 = 0;
passcodeVal3 = passcodeVal1;
- passcodeVal1 += 5;
passcodeVal4 = 0;
- g_passcodeBtnVal = 8;
+ globalval = 8;
}
}
-*/
+
+ engine->getGDSScene()->setGlobal(0x20, globalval);
}
void SDSScene::showDialog(uint16 num) {
@@ -1112,8 +1112,8 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
}
void SDSScene::mouseLDown(const Common::Point &pt) {
- Dialog *dlg = getVisibleDialog();
- if (dlg) {
+ if (hasVisibleDialog()) {
+ debug(9, "Mouse LDown on at %d,%d clearing visible dialog", pt.x, pt.y);
_shouldClearDlg = true;
_ignoreMouseUp = true;
return;
@@ -1139,6 +1139,7 @@ void SDSScene::mouseLDown(const Common::Point &pt) {
void SDSScene::mouseLUp(const Common::Point &pt) {
if (_ignoreMouseUp) {
+ debug(9, "Ignoring mouseup at %d,%d as it was used to clear a dialog", pt.x, pt.y);
_ignoreMouseUp = false;
return;
}
@@ -1176,6 +1177,7 @@ static bool _isInRect(const Common::Point &pt, const DgdsRect rect) {
void SDSScene::onDragFinish(const Common::Point &pt) {
assert(_dragItem);
+ debug(9, "Drag finished at %d, %d", pt.x , pt.y);
// Unlike a click operation, this runs the drop event for *all* areas
// and items, ignoring enable condition.
@@ -1471,7 +1473,7 @@ void GDSScene::initIconSizes() {
for (GameItem &item : _gameItems) {
if (item._iconNum < nicons) {
item._rect.width = icons->getFrames()[item._iconNum]->w;
- item._rect.height = icons->getFrames()[item._iconNum]->w;
+ item._rect.height = icons->getFrames()[item._iconNum]->h;
} else {
item._rect.width = 32;
item._rect.height = 32;
@@ -1609,11 +1611,11 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
// Dropped item.
// Update the rect for the icon - Note: original doesn't do this,
// but then the napent icon is offset??
- Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
+ /*Common::SharedPtr<Graphics::ManagedSurface> icon = icons->getSurface(item._iconNum);
if (icon) {
item._rect.width = MIN((int)icon->w, item._rect.width);
item._rect.height = MIN((int)icon->h, item._rect.height);
- }
+ }*/
if (xoff + item._rect.width > maxx)
xoff = 20;
int yoff = SCREEN_HEIGHT - (item._rect.height + 2);
Commit: 9a0ebf8f0a101786b87e90e961f122a15d3eec0f
https://github.com/scummvm/scummvm/commit/9a0ebf8f0a101786b87e90e961f122a15d3eec0f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix use of scene num global
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/globals.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 193bd4a5582..cfa754a5e6e 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -156,6 +156,10 @@ bool DgdsEngine::changeScene(int sceneNum) {
return false;
}
+ // TODO: For non-dragon games this will need tweaking.
+ DragonGlobals *globals = static_cast<DragonGlobals *>(_gameGlobals);
+ globals->setLastSceneNum(sceneNum);
+
// Save the current foreground if we are going to the inventory, clear it otherwise.
if (sceneNum == 2)
_backgroundBuffer.blitFrom(_compositionBuffer);
@@ -164,7 +168,7 @@ bool DgdsEngine::changeScene(int sceneNum) {
_scene->runLeaveSceneOps();
- // store the last scene num if it's not 2
+ // store the last non-inventory scene num
if (_scene->getNum() != 2)
_gameGlobals->setGlobal(0x61, _scene->getNum());
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 8f31c36b634..962c5ec371f 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -118,6 +118,8 @@ public:
int16 getGameMinsToAddOnDragFinished() const { return _gameMinsToAddOnDragFinished; }
int16 getGameMinsToAddOnObjInteraction() const { return _gameMinsToAddOnObjInteraction; }
+ void setLastSceneNum(int16 num) { _lastOpcode1SceneChageNum = num; }
+
private:
int16 _lastOpcode1SceneChageNum;
int16 _sceneOp12SceneNum;
Commit: 7fec7d48485ad43d445f8ef7ea4124627e040b6b
https://github.com/scummvm/scummvm/commit/7fec7d48485ad43d445f8ef7ea4124627e040b6b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement various wipe-copy operations
Changed paths:
engines/dgds/ttm.cpp
engines/dgds/ttm.h
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index ed8e670a79f..cee84c2f6bf 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -160,15 +160,15 @@ static const char *ttmOpName(uint16 op) {
case 0x4200: return "STORE AREA";
case 0x4210: return "SAVE GETPUT REGION";
case 0xa000: return "DRAW PIXEL";
- case 0xa010: return "SAVE REGION 10?????";
- case 0xa020: return "SAVE REGION 20?????";
- case 0xa030: return "SAVE REGION 30?????";
- case 0xa040: return "SAVE REGION 40?????";
- case 0xa050: return "SAVE REGION";
- case 0xa060: return "SAVE REGION FLIPPED??";
- case 0xa070: return "SAVE REGION 70?????";
- case 0xa080: return "SAVE REGION 80?????";
- case 0xa090: return "SAVE REGION 90?????";
+ case 0xa010: return "WIPE 10?";
+ case 0xa020: return "WIPE 20?";
+ case 0xa030: return "WIPE OUT-TO-IN";
+ case 0xa040: return "WIPE INTERLACED";
+ case 0xa050: return "WIPE LEFT-TO-RIGHT";
+ case 0xa060: return "WIPE RIGHT-TO-LEFT";
+ case 0xa070: return "WIPE TOP-TO-BOTTOM";
+ case 0xa080: return "WIPE BOTTOM-TO-TOP";
+ case 0xa090: return "WIPE IN-TO-OUT";
case 0xa0a0: return "DRAW LINE";
case 0xa100: return "DRAW FILLED RECT";
case 0xa110: return "DRAW EMPTY RECT";
@@ -236,6 +236,131 @@ static void plotClippedPoint(int x, int y, int color, void *data) {
}
}
+static void _copyRectToScreen(const Graphics::ManagedSurface &src, const Common::Rect &r) {
+ if (r.isEmpty())
+ return;
+ Graphics::Surface *surf = g_system->lockScreen();
+ surf->copyRectToSurface(src.rawSurface(), r.left, r.top, r);
+ g_system->unlockScreen();
+}
+
+
+void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, const Common::Rect &r) {
+ //
+ // In the original games, these operations copy certain parts of the buffer on to
+ // the screen, and rely on the system's speed to make it happen faster than a regular
+ // game frame.
+ //
+ // This gives a "wipe" effect. In ScummVM we try to emulate the same final effect with
+ // some fudge-factors to update the screen roughly every 10 rows copied. This gives
+ // a reasonably nice result.
+ //
+ // Example uses:
+ // Left-to-right wipe: the "AAAHHHHH" in Dragon intro
+ // outside-to-inside or in-to-out: Blood cell video from Karyn in Dragon (scene 94)
+ //
+ switch(code) {
+ case 0xa010:
+ // TODO: How is this different to a020?
+ _copyRectToScreen(_vm->_compositionBuffer, r);
+ g_system->updateScreen();
+ break;
+
+ case 0xa020:
+ _copyRectToScreen(_vm->_compositionBuffer, r);
+ g_system->updateScreen();
+ break;
+
+ case 0xa040: // Interlaced effect
+ for (int i = 1; i < 11; i++) {
+ int yoffset = 0;
+ while (r.top + i + yoffset <= r.bottom) {
+ if (r.width()) {
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(r.left, r.top + i + yoffset), r.width(), 1));
+ }
+ yoffset += 10;
+ }
+ if (i % 3 == 0)
+ g_system->updateScreen();
+ }
+ break;
+
+ case 0xa050: // Copy from left-to-right
+ case 0xa060: // Copy from right-to-left
+ for (int i = 3; i <= r.width() - 3; i++) {
+ int x;
+ if (code == 0xa060) {
+ x = r.right - i;
+ } else { // a050
+ x = i - 3;
+ }
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(r.left + x, r.top), 3, r.height()));
+ if (i % 10 == 0)
+ g_system->updateScreen();
+ }
+ break;
+
+ case 0xa070: // Copy from top to bottom
+ case 0xa080: // Copy from bottom to top
+ for (int i = 3; i <= r.height() - 3; i++) {
+ int y;
+ if (code == 0xa080) {
+ y = r.bottom - i;
+ } else { // a070
+ y = i - 3;
+ }
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(r.left, r.top + y), r.width(), 3));
+ if (i % 10 == 0)
+ g_system->updateScreen();
+ }
+ break;
+
+ case 0xa030: // Copy from outside to middle
+ case 0xa090: // Copy from middle to outside
+ {
+ uint halfwidth = r.width() / 2;
+ uint halfheight = r.height() / 2;
+ uint maxside = MAX(halfheight, halfwidth);
+
+ long widthScale = 1000 * halfwidth / maxside;
+ long heightScale = 1000 * halfheight / maxside;
+ uint i = (code == 0xa030) ? maxside : 1;
+
+ do {
+ if (code == 0xa030) {
+ if (i < 1)
+ return;
+ i--;
+ } else {
+ if (i > maxside)
+ return;
+ i++;
+ }
+ uint xoff = widthScale * i / 1000;
+ uint yoff = heightScale * i / 1000;
+ uint16 xinside = (r.left + halfwidth) - xoff;
+ uint16 yinside = (r.top + halfheight) - yoff;
+ uint16 width = xoff * 2;
+ uint16 height = yoff * 2;
+ if (code == 0xa030) {
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(r.left, r.top), xinside - r.left, r.bottom - r.top));
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(xinside + width, r.top), (r.right - xinside) - xoff * 2, r.bottom - r.top));
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(xinside, r.top), width, yinside - r.top));
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(xinside, yinside + height), width, r.bottom - yinside - yoff * 2));
+ } else {
+ _copyRectToScreen(_vm->_compositionBuffer, Common::Rect(Common::Point(xinside, yinside), width, height));
+ }
+ if (i % 10 == 0)
+ g_system->updateScreen();
+ } while( true );
+
+ break;
+ }
+ default:
+ error("unsupported opcode for doSaveRegion 0x%04x", code);
+ }
+}
+
void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
switch (op) {
@@ -428,25 +553,17 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa000: // DRAW PIXEL x,y:int
_vm->_compositionBuffer.setPixel(ivals[0], ivals[1], seq._drawColFG);
break;
- case 0xa050: {// SAVE REGION x,y,w,h:int
- // This is used in DRAGON intro sequence to draw the AAAAH
- // it works like a bitblit, but it doesn't write if there's something already at the destination?
- // TODO: This is part of a whole set of operations - 0xa0n4.
- // They do various flips etc.
- warning("TODO: Fix implementation of SAVE REGION (0xa050) (%d, %d, %d, %d)",
- ivals[0], ivals[1], ivals[2], ivals[3]);
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- //_vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
- //_vm->_compositionBuffer.transBlitFrom(_vm->getStoredAreaBuffer());
- //_vm->_compositionBuffer.transBlitFrom(_vm->_compositionBuffer);
- //_vm->_compositionBuffer.blitFrom(_vm->_compositionBuffer, r, r);
+ case 0xa010:
+ case 0xa020:
+ case 0xa030:
+ case 0xa040:
+ case 0xa050:
+ case 0xa060:
+ case 0xa070:
+ case 0xa080:
+ case 0xa090:
+ doWipeOp(op, env, seq, Common::Rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]));
break;
- }
- case 0xa060: { // RESTORE REGION
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
- _vm->getStoredAreaBuffer().fillRect(r, 0);
- break;
- }
case 0xa0a0: { // DRAW LINE x1,y1,x2,y2:int
ClipSurface clipSurf;
clipSurf._clipWin = seq._drawWin;
@@ -606,13 +723,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x1040: // Sets some global? i:int
case 0x10B0: // null op?
case 0x2010: // SET FRAME?? x,y
- case 0xa010: // SAVE REGION ????
- case 0xa020: // SAVE REGION ????
- case 0xa030: // SAVE REGION ????
- case 0xa040: // SAVE REGION ????
- case 0xa070: // SAVE REGION ????
- case 0xa080: // SAVE REGION ????
- case 0xa090: // SAVE REGION ????
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa420: // DRAW EMPTY CIRCLE
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index 705449d9d19..9ce917c02b2 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -113,6 +113,7 @@ public:
protected:
void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);
+ void doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, const Common::Rect &r);
DgdsEngine *_vm;
};
Commit: 80becfc075455502a34ee013621840d3e6e9b24d
https://github.com/scummvm/scummvm/commit/80becfc075455502a34ee013621840d3e6e9b24d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add 'coming soon' non-interactive demo detection
Changed paths:
engines/dgds/detection.cpp
engines/dgds/detection_tables.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/font.cpp
diff --git a/engines/dgds/detection.cpp b/engines/dgds/detection.cpp
index 1719e7ce9fe..7fe0e72de35 100644
--- a/engines/dgds/detection.cpp
+++ b/engines/dgds/detection.cpp
@@ -29,6 +29,7 @@ static const PlainGameDescriptor dgdsGames[] = {
{"china", "Heart of China"},
{"beamish", "The Adventures of Willy Beamish"},
{"sq5", "Space Quest V CES Demo"},
+ {"comingsoon", "Coming Soon from Sierra Demo"},
{0, 0}
};
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index 43522c3da0b..ecd8e55303a 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -53,6 +53,21 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
+ // Rise of the Dragon (PC) 16 Color, 1.2MB disks
+ {
+ "rise",
+ "EGA",
+ {
+ {"volume.ega", 0, "20508ad920355c00e14043f728163f80", 6163},
+ {"volume.001", 0, "34fdc6addd1992d72d4f947af7905c75", 845289},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
// Rise of the Dragon (Amiga)
{
"rise",
@@ -187,6 +202,20 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
+ // "Coming Soon" non-interactive demo
+ {
+ "comingsoon",
+ 0,
+ {
+ {"demo.ads", 0, "bc709c5defe472f1ddc03db8cf6c83df", 94},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO | ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
AD_TABLE_END_MARKER
};
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index cfa754a5e6e..4b98147c252 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -92,6 +92,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_gameId = GID_BEAMISH;
else if (!strcmp(gameDesc->gameId, "sq5"))
_gameId = GID_SQ5DEMO;
+ else if (!strcmp(gameDesc->gameId, "comingsoon"))
+ _gameId = GID_COMINGSOON;
else
error("Unknown game ID");
@@ -186,7 +188,8 @@ bool DgdsEngine::changeScene(int sceneNum) {
_scene->load(sceneFile, _resource, _decompressor);
// These are done inside the load function in the original.. cleaner here..
_scene->addInvButtonToHotAreaList();
- _clock.setVisibleScript(true);
+ if (_gameId == GID_DRAGON)
+ _clock.setVisibleScript(true);
if (_scene->getMagic() != _gdsScene->getMagic())
error("Scene %s magic does (0x%08x) not match GDS magic (0x%08x)", sceneFile.c_str(), _scene->getMagic(), _gdsScene->getMagic());
@@ -348,6 +351,12 @@ void DgdsEngine::loadGameFiles() {
_gamePals->loadPalette("NORMAL.PAL");
_adsInterp->load("CESDEMO.ADS");
break;
+ case GID_COMINGSOON:
+ // TODO: Create a better type for this..
+ _gameGlobals = new DragonGlobals(_clock);
+ _gamePals->loadPalette("DYNAMIX.PAL");
+ _adsInterp->load("DEMO.ADS");
+ break;
default:
error("Unsupported game type in loadGameFiles");
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 2324e296c89..eff6e4fc1b0 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -67,6 +67,7 @@ enum DgdsGameId {
GID_CHINA,
GID_BEAMISH,
GID_SQ5DEMO,
+ GID_COMINGSOON,
};
enum DgdsDetailLevel {
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index 26526f57c88..d5364c3e804 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -229,7 +229,7 @@ FontManager::FontType FontManager::fontTypeByName(const Common::String &filename
void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompressor *decomp) {
- if (gameId == GID_SQ5DEMO) {
+ if (gameId == GID_SQ5DEMO || gameId == GID_COMINGSOON) {
tryLoadFont("EXIT.FNT", resMgr, decomp);
//tryLoadFont("SSM1_12.FNT", resMgr, decomp);
//tryLoadFont("SSM1_15.FNT", resMgr, decomp);
Commit: 04f97efdcd0fd8caefebbd7dfb7f353f486e4871
https://github.com/scummvm/scummvm/commit/04f97efdcd0fd8caefebbd7dfb7f353f486e4871
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Avoid crashing on Dragon EGA
Changed paths:
engines/dgds/font.cpp
engines/dgds/resource.cpp
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index d5364c3e804..ed373cefacc 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -33,8 +33,10 @@ namespace Dgds {
Font *Font::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
Common::SeekableReadStream *fontFile = resourceManager->getResource(filename);
- if (!fontFile)
- error("Font file %s not found", filename.c_str());
+ if (!fontFile) {
+ warning("Font file %s not found", filename.c_str());
+ return nullptr;
+ }
DgdsChunkReader chunk(fontFile);
@@ -208,7 +210,7 @@ void FontManager::tryLoadFont(const char *fname, ResourceManager *resMgr, Decomp
if (font)
_fonts.setVal(ftype, font);
else
- error("Failed to load font %s", fname);
+ warning("Failed to load font %s", fname);
}
FontManager::FontType FontManager::fontTypeByName(const Common::String &filename) const {
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index d7e8d3797ab..fbcf4de6fc8 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -37,7 +37,8 @@ static const int FILENAME_LENGTH = 12;
ResourceManager::ResourceManager() {
const char *indexFiles[] = {
- "volume.vga", // early Dragon versions
+ "volume.vga", // Dragon VGA versions
+ "volume.ega", // Dragon EGA versions
"volume.rmf", // Beamish / HoC
"volume.map" // Beamish CD
};
Commit: 7582100484f7c87e2b92e924496635709a10c475
https://github.com/scummvm/scummvm/commit/7582100484f7c87e2b92e924496635709a10c475
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix inventory right-click zoom
Changed paths:
engines/dgds/inventory.cpp
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 7787ec29666..b12cddebe9a 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -325,6 +325,7 @@ void Inventory::mouseRUp(const Common::Point &pt) {
if (_itemBox->containsPoint(pt)) {
GameItem *underMouse = itemUnderMouse(pt);
if (underMouse) {
+ setShowZoomBox(true);
engine->getScene()->runOps(underMouse->onRClickOps);
}
} else {
Commit: 57e272d9b6d08ea077d0ed6bafdf5475a981ac79
https://github.com/scummvm/scummvm/commit/57e272d9b6d08ea077d0ed6bafdf5475a981ac79
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Clean up sound and music a bit
Allow midi sounds and music to play at the same time.
Still some bug with sfx not finishing correctly, but better than before.
Changed paths:
engines/dgds/music.cpp
engines/dgds/music.h
engines/dgds/sound.cpp
engines/dgds/sound.h
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
index cc18bf41c71..9816df7829c 100644
--- a/engines/dgds/music.cpp
+++ b/engines/dgds/music.cpp
@@ -21,6 +21,7 @@
*/
#include "common/debug.h"
+#include "common/config-manager.h"
#include "audio/midiparser.h"
#include "dgds/sound.h"
@@ -34,36 +35,32 @@ namespace Dgds {
class MidiParser_DGDS : public MidiParser {
protected:
byte *_init;
- byte *_last;
+ const byte *_last;
byte _numParts;
const byte *_trackPtr[0xFF];
uint16 _trackSz[0xFF];
protected:
- void parseNextEvent(EventInfo &info);
+ void parseNextEvent(EventInfo &info) override;
public:
MidiParser_DGDS();
~MidiParser_DGDS();
- void sendInitCommands();
+ void sendInitCommands() {};
- bool loadMusic(byte *data, uint32 size);
+ bool loadMusic(byte *data, uint32 size) override;
- bool validateNextRead(uint i, uint16 *_curPos);
- byte midiGetNextChannel(uint16 *_curPos, uint32 *_time, long ticker);
+ bool validateNextRead(uint i, const uint16 *trackPos) const;
+ byte midiGetNextChannel(const uint16 *trackPos, const uint32 *trackTimer, long ticker) const;
void mixChannels();
};
-MidiParser_DGDS::MidiParser_DGDS() : _init(0), _last(0) {
- _numParts = 0;
+MidiParser_DGDS::MidiParser_DGDS() : _init(nullptr), _last(nullptr), _numParts(0) {
memset(_trackSz, 0, sizeof(_trackSz));
}
-void MidiParser_DGDS::sendInitCommands() {
-}
-
MidiParser_DGDS::~MidiParser_DGDS() {
free(_init);
}
@@ -161,12 +158,12 @@ void MidiParser_DGDS::parseNextEvent(EventInfo &info) {
}
}
-byte MidiParser_DGDS::midiGetNextChannel(uint16 *trackPos, uint32 *trackTimer, long ticker) {
+byte MidiParser_DGDS::midiGetNextChannel(const uint16 *trackPos, const uint32 *trackTimer, long ticker) const {
byte curr = 0xFF;
uint32 closest = ticker + 1000000, next = 0;
for (byte i = 0; i < _numParts; i++) {
- if (trackTimer[i] == 0xFFFFFFFF) // channel ended
+ if (trackTimer[i] == 0xFFFFFFFF) // channel ended
continue;
if (trackPos[i] >= _trackSz[i])
continue;
@@ -183,7 +180,7 @@ byte MidiParser_DGDS::midiGetNextChannel(uint16 *trackPos, uint32 *trackTimer, l
return curr;
}
-inline bool MidiParser_DGDS::validateNextRead(uint i, uint16 *trackPos) {
+bool MidiParser_DGDS::validateNextRead(uint i, const uint16 *trackPos) const {
if (_trackSz[i] <= trackPos[i]) {
warning("Unexpected end. Music may sound wrong due to game resource corruption");
return false;
@@ -192,7 +189,7 @@ inline bool MidiParser_DGDS::validateNextRead(uint i, uint16 *trackPos) {
}
}
-static const byte commandLengths[] = { 2, 2, 2, 2, 1, 1, 2, 0 };
+static const byte CMD_LENGTHS[] = { 2, 2, 2, 2, 1, 1, 2, 0 };
void MidiParser_DGDS::mixChannels() {
int totalSize = 0;
@@ -267,7 +264,7 @@ void MidiParser_DGDS::mixChannels() {
if (midiCommand != globalPrev)
*output++ = midiCommand;
*output++ = midiParam;
- if (commandLengths[(midiCommand >> 4) - 8] == 2) {
+ if (CMD_LENGTHS[(midiCommand >> 4) - 8] == 2) {
if (!validateNextRead(channel, trackPos))
goto end;
*output++ = _trackPtr[channel][trackPos[channel]++];
@@ -285,10 +282,12 @@ end:
bool MidiParser_DGDS::loadMusic(byte *data, uint32 size) {
unloadMusic();
- if (!data) return false;
+ if (!data)
+ return false;
_numParts = loadSndTrack(TRACK_MT32, _trackPtr, _trackSz, data, size);
- if (_numParts == 0) return false;
+ if (_numParts == 0)
+ return false;
for (byte part = 0; part < _numParts; part++) {
const byte *ptr = _trackPtr[part];
@@ -315,13 +314,12 @@ bool MidiParser_DGDS::loadMusic(byte *data, uint32 size) {
// copy the data to our own buffer. Take warning....
resetTracking();
setTrack(0);
+
return true;
}
-MidiParser_DGDS *createParser_DGDS() { return new MidiParser_DGDS; }
-
-DgdsMidiPlayer::DgdsMidiPlayer() {
+DgdsMidiPlayer::DgdsMidiPlayer(bool isSfx) : _isSfx(isSfx), Audio::MidiPlayer() {
MidiPlayer::createDriver();
int ret = _driver->open();
@@ -332,7 +330,14 @@ DgdsMidiPlayer::DgdsMidiPlayer() {
_driver->sendGMReset();
_driver->setTimerCallback(this, &timerCallback);
}
- debug("MidiPlayer()");
+}
+
+void DgdsMidiPlayer::syncVolumeForChannel() {
+ int volume = ConfMan.getInt(_isSfx ? "sfx_volume": "music_volume");
+ if (ConfMan.getBool("mute")) {
+ volume = -1;
+ }
+ setVolume(volume);
}
void DgdsMidiPlayer::play(byte *data, uint32 size) {
@@ -341,19 +346,21 @@ void DgdsMidiPlayer::play(byte *data, uint32 size) {
stop();
if (!data) return;
- MidiParser_DGDS *parser = createParser_DGDS();
+ MidiParser_DGDS *parser = new MidiParser_DGDS();
if (parser->loadMusic(data, size)) {
parser->setMidiDriver(this);
parser->sendInitCommands();
- parser->setTimerRate(_driver->getBaseTempo());/*
+ parser->setTimerRate(_driver->getBaseTempo());
+ /*
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
- parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);*/
+ parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
+ */
_parser = parser;
- syncVolume();
+ syncVolumeForChannel();
_isLooping = false;
_isPlaying = true;
- debug("Playing music track");
+ debug("Playing music track sz %d", size);
} else {
debug("Cannot play music track");
delete parser;
@@ -361,6 +368,9 @@ void DgdsMidiPlayer::play(byte *data, uint32 size) {
}
void DgdsMidiPlayer::stop() {
+ _driver->stopAllNotes();
+ _isPlaying = false;
+ _isLooping = false;
Audio::MidiPlayer::stop();
debug("Stopping track");
}
diff --git a/engines/dgds/music.h b/engines/dgds/music.h
index 6fae6225e55..467837b9e55 100644
--- a/engines/dgds/music.h
+++ b/engines/dgds/music.h
@@ -29,10 +29,15 @@ namespace Dgds {
class DgdsMidiPlayer : public Audio::MidiPlayer {
public:
- DgdsMidiPlayer();
+ DgdsMidiPlayer(bool isSfx);
void play(byte *data, uint32 size);
void stop();
+
+private:
+ /** like MidiPlyer::syncVolume, syncs sfx/music volume depending on isSfx */
+ void syncVolumeForChannel();
+ bool _isSfx;
};
} // End of namespace Dgds
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 314efea751b..23fd3b6adf9 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -39,9 +39,104 @@
namespace Dgds {
+static void _readHeader(const byte* &pos, uint32 &sci_header) {
+ sci_header = 0;
+ if (READ_LE_UINT16(pos) == 0x0084)
+ sci_header = 2;
+
+ pos += sci_header;
+ if (pos[0] == 0xF0) {
+ debug("SysEx transfer = %d bytes", pos[1]);
+ pos += 2;
+ pos += 6;
+ }
+}
+
+static void _readPartHeader(const byte* &pos, uint16 &off, uint16 &siz) {
+ pos += 2;
+ off = READ_LE_UINT16(pos);
+ pos += 2;
+ siz = READ_LE_UINT16(pos);
+ pos += 2;
+}
+
+static void _skipPartHeader(const byte* &pos) {
+ pos += 6;
+}
+
+static uint32 _availableSndTracks(const byte *data, uint32 size) {
+ const byte *pos = data;
+
+ uint32 sci_header;
+ _readHeader(pos, sci_header);
+
+ uint32 tracks = 0;
+ while (pos[0] != 0xFF) {
+ byte drv = *pos++;
+
+ //debug("(%d)", drv);
+
+ while (pos[0] != 0xFF) {
+ uint16 off, siz;
+ _readPartHeader(pos, off, siz);
+ off += sci_header;
+
+ //debug("%06d:%d ", off, siz);
+
+ //debug("Header bytes");
+ //debug("[%06X] ", data[off]);
+ //debug("[%02X] ", data[off+0]);
+ //debug("[%02X] ", data[off+1]);
+
+ bool digital_pcm = false;
+ if (READ_LE_UINT16(&data[off]) == 0x00FE) {
+ digital_pcm = true;
+ }
+
+ switch (drv) {
+ case 0: if (digital_pcm) {
+ //debug("- Soundblaster");
+ tracks |= DIGITAL_PCM;
+ } else {
+ //debug("- Adlib");
+ tracks |= TRACK_ADLIB;
+ }
+ break;
+ case 7:
+ //debug("- General MIDI");
+ tracks |= TRACK_GM;
+ break;
+ case 9:
+ //debug("- CMS");
+ break;
+ case 12:
+ //debug("- MT-32");
+ tracks |= TRACK_MT32;
+ break;
+ case 18:
+ //debug("- PC Speaker");
+ break;
+ case 19:
+ //debug("- Tandy 1000");
+ break;
+ default:
+ //debug("- Unknown %d", drv);
+ warning("Unknown music type %d", drv);
+ break;
+ }
+ }
+
+ pos++;
+ }
+ pos++;
+ return tracks;
+}
+
+
Sound::Sound(Audio::Mixer *mixer, ResourceManager *resource, Decompressor *decompressor) :
_mixer(mixer), _resource(resource), _decompressor(decompressor) {
- _midiPlayer = new DgdsMidiPlayer();
+ _midiMusicPlayer = new DgdsMidiPlayer(false);
+ _midiSoundPlayer = new DgdsMidiPlayer(true);
}
Sound::~Sound() {
@@ -50,7 +145,8 @@ Sound::~Sound() {
for (auto *data: _sfxData)
delete [] data;
- delete _midiPlayer;
+ delete _midiMusicPlayer;
+ delete _midiSoundPlayer;
}
void Sound::playAmigaSfx(const Common::String &filename, byte channel, byte volume) {
@@ -81,6 +177,7 @@ void Sound::playAmigaSfx(const Common::String &filename, byte channel, byte volu
void Sound::stopAllSfx() {
for (uint i = 0; i < ARRAYSIZE(_channels); i++)
stopSfx(i);
+ _midiSoundPlayer->stop();
}
void Sound::stopSfx(byte channel) {
@@ -137,17 +234,14 @@ bool Sound::playPCM(const byte *data, uint32 size) {
return true;
}
-static void readStrings(Common::SeekableReadStream *stream) {
+static void _readStrings(Common::SeekableReadStream *stream) {
uint16 count = stream->readUint16LE();
- debug(" %u:", count);
+ debug(" %u strs:", count);
for (uint16 k = 0; k < count; k++) {
- byte ch;
uint16 idx = stream->readUint16LE();
+ Common::String str = stream->readString();
- Common::String str;
- while ((ch = stream->readByte()))
- str += ch;
debug(" %2u: %2u, \"%s\"", k, idx, str.c_str());
}
}
@@ -186,7 +280,7 @@ void Sound::loadMacMusic(const Common::String &filename) {
debug(" %2u: %u", k, idx);
}
} else if (chunk.isSection(ID_TAG) || chunk.isSection(ID_FNM)) {
- readStrings(stream);
+ _readStrings(stream);
} else if (chunk.isSection(ID_DAT)) {
// TODO: Should we record the indexes?
/*uint16 idx = */ stream->readUint16LE();
@@ -253,18 +347,18 @@ void Sound::loadPCSound(const Common::String &filename, Common::Array<uint32> &s
}
void Sound::playSFX(uint num) {
- playPCSound(num, _sfxSizes, _sfxData);
+ playPCSound(num, _sfxSizes, _sfxData, _midiSoundPlayer);
}
void Sound::playMusic(uint num) {
- playPCSound(num, _musicSizes, _musicData);
+ playPCSound(num, _musicSizes, _musicData, _midiMusicPlayer);
}
-void Sound::playPCSound(uint num, const Common::Array<uint32> &sizeArray, const Common::Array<byte *> &dataArray) {
+void Sound::playPCSound(uint num, const Common::Array<uint32> &sizeArray, const Common::Array<byte *> &dataArray, DgdsMidiPlayer *midiPlayer) {
if (num < dataArray.size()) {
- uint32 tracks = availableSndTracks(dataArray[num], sizeArray[num]);
+ uint32 tracks = _availableSndTracks(dataArray[num], sizeArray[num]);
if (tracks & TRACK_MT32)
- _midiPlayer->play(dataArray[num], sizeArray[num]);
+ midiPlayer->play(dataArray[num], sizeArray[num]);
else if (tracks & DIGITAL_PCM)
playPCM(dataArray[num], sizeArray[num]);
} else {
@@ -273,7 +367,7 @@ void Sound::playPCSound(uint num, const Common::Array<uint32> &sizeArray, const
}
void Sound::stopMusic() {
- _midiPlayer->stop();
+ _midiMusicPlayer->stop();
_mixer->stopAll();
}
@@ -290,101 +384,6 @@ void Sound::unloadMusic() {
_soundData = nullptr;
}
-static inline
-void readHeader(const byte* &pos, uint32 &sci_header) {
- sci_header = 0;
- if (READ_LE_UINT16(pos) == 0x0084) sci_header = 2;
-
- pos += sci_header;
- if (pos[0] == 0xF0) {
- debug("SysEx transfer = %d bytes", pos[1]);
- pos += 2;
- pos += 6;
- }
-}
-
-static inline
-void readPartHeader(const byte* &pos, uint16 &off, uint16 &siz) {
- pos += 2;
- off = READ_LE_UINT16(pos);
- pos += 2;
- siz = READ_LE_UINT16(pos);
- pos += 2;
-}
-
-static inline
-void skipPartHeader(const byte* &pos) {
- pos += 6;
-}
-
-uint32 availableSndTracks(const byte *data, uint32 size) {
- const byte *pos = data;
-
- uint32 sci_header;
- readHeader(pos, sci_header);
-
- uint32 tracks = 0;
- while (pos[0] != 0xFF) {
- byte drv = *pos++;
-
- //debug("(%d)", drv);
-
- while (pos[0] != 0xFF) {
- uint16 off, siz;
- readPartHeader(pos, off, siz);
- off += sci_header;
-
- //debug("%06d:%d ", off, siz);
-
- //debug("Header bytes");
- //debug("[%06X] ", data[off]);
- //debug("[%02X] ", data[off+0]);
- //debug("[%02X] ", data[off+1]);
-
- bool digital_pcm = false;
- if (READ_LE_UINT16(&data[off]) == 0x00FE) {
- digital_pcm = true;
- }
-
- switch (drv) {
- case 0: if (digital_pcm) {
- //debug("- Soundblaster");
- tracks |= DIGITAL_PCM;
- } else {
- //debug("- Adlib");
- tracks |= TRACK_ADLIB;
- }
- break;
- case 7:
- //debug("- General MIDI");
- tracks |= TRACK_GM;
- break;
- case 9:
- //debug("- CMS");
- break;
- case 12:
- //debug("- MT-32");
- tracks |= TRACK_MT32;
- break;
- case 18:
- //debug("- PC Speaker");
- break;
- case 19:
- //debug("- Tandy 1000");
- break;
- default:
- //debug("- Unknown %d", drv);
- warning("Unknown music type %d", drv);
- break;
- }
- }
-
- pos++;
- }
- pos++;
- return tracks;
-}
-
byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const byte *data, uint32 size) {
byte matchDrv;
switch (track) {
@@ -398,7 +397,7 @@ byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const b
const byte *pos = data;
uint32 sci_header;
- readHeader(pos, sci_header);
+ _readHeader(pos, sci_header);
while (pos[0] != 0xFF) {
byte drv = *pos++;
@@ -407,14 +406,14 @@ byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const b
const byte *ptr;
part = 0;
- for (ptr = pos; *ptr != 0xFF; skipPartHeader(ptr))
+ for (ptr = pos; *ptr != 0xFF; _skipPartHeader(ptr))
part++;
if (matchDrv == drv) {
part = 0;
while (pos[0] != 0xFF) {
uint16 off, siz;
- readPartHeader(pos, off, siz);
+ _readPartHeader(pos, off, siz);
off += sci_header;
trackPtr[part] = data + off;
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 58dc89abfb6..230e6235cd9 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -62,7 +62,7 @@ public:
private:
void loadPCSound(const Common::String &filename, Common::Array<uint32> &sizeArray, Common::Array<byte *> &dataArray);
- void playPCSound(uint num, const Common::Array<uint32> &sizeArray, const Common::Array<byte *> &dataArray);
+ void playPCSound(uint num, const Common::Array<uint32> &sizeArray, const Common::Array<byte *> &dataArray, DgdsMidiPlayer *midiPlayer);
struct Channel _channels[2];
Common::SeekableReadStream *_soundData = nullptr;
@@ -74,7 +74,8 @@ private:
Common::Array<byte *> _sfxData;
Audio::Mixer *_mixer;
- DgdsMidiPlayer *_midiPlayer;
+ DgdsMidiPlayer *_midiMusicPlayer;
+ DgdsMidiPlayer *_midiSoundPlayer;
ResourceManager *_resource;
Decompressor *_decompressor;
};
@@ -86,7 +87,6 @@ enum {
TRACK_MT32 = 1 << 3
};
-uint32 availableSndTracks(const byte *data, uint32 size);
byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const byte *data, uint32 size);
} // End of namespace Dgds
Commit: 822aa3db8e940217b25b44dd8096002f955ffe34
https://github.com/scummvm/scummvm/commit/822aa3db8e940217b25b44dd8096002f955ffe34
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Reset palette list on game load
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/game_palettes.cpp
engines/dgds/game_palettes.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 4b98147c252..3abeba8a849 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -177,6 +177,7 @@ bool DgdsEngine::changeScene(int sceneNum) {
_scene->unload();
_backgroundFile.clear();
_soundPlayer->unloadMusic();
+ _soundPlayer->stopAllSfx();
_gdsScene->runChangeSceneOps();
@@ -604,13 +605,15 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
//
// 1: First version
// 2: Added GameItem.flags
+ // 3: Stopped saving ADS/TTM state
+ // 4: Stopped saving palette state
//
assert(_scene && _gdsScene);
_menu->hideMenu();
- if (!s.syncVersion(3))
+ if (!s.syncVersion(4))
error("Save game version too new: %d", s.getVersion());
Common::Error result;
@@ -646,8 +649,12 @@ Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
result = _inventory->syncState(s);
if (result.getCode() != Common::kNoError) return result;
- result = _gamePals->syncState(s);
- if (result.getCode() != Common::kNoError) return result;
+ if (s.getVersion() < 4) {
+ result = _gamePals->syncState(s);
+ if (result.getCode() != Common::kNoError) return result;
+ } else if (s.isLoading()) {
+ _gamePals->reset();
+ }
result = _adsInterp->syncState(s);
if (result.getCode() != Common::kNoError) return result;
diff --git a/engines/dgds/game_palettes.cpp b/engines/dgds/game_palettes.cpp
index 911e2a647fd..355bd1d6f01 100644
--- a/engines/dgds/game_palettes.cpp
+++ b/engines/dgds/game_palettes.cpp
@@ -35,6 +35,11 @@ GamePalettes::GamePalettes(ResourceManager *resourceMan, Decompressor *decompres
_resourceMan(resourceMan), _decompressor(decompressor) {
}
+void GamePalettes::reset() {
+ _palettes.resize(1);
+ selectPalNum(0);
+}
+
int GamePalettes::loadPalette(const Common::String &filename) {
Common::SeekableReadStream *fileStream = _resourceMan->getResource(filename);
if (!fileStream) {
@@ -116,6 +121,8 @@ Common::Error GamePalettes::syncState(Common::Serializer &s) {
s.syncAsUint16LE(npals);
if (s.isLoading()) {
+ if (npals > 100)
+ error("Too many palettes to load, save is probably corrupt");
for (uint i = 0; i < npals; i++) {
Common::String name;
s.syncString(name);
diff --git a/engines/dgds/game_palettes.h b/engines/dgds/game_palettes.h
index d4158cf048b..8df30f898c9 100644
--- a/engines/dgds/game_palettes.h
+++ b/engines/dgds/game_palettes.h
@@ -50,6 +50,9 @@ public:
void setPalette();
void clearPalette();
+ // Reset the list to the post-game-load state (1 palette loaded)
+ void reset();
+
// Fade the colors in the current palette toward black. Start at col, and fade ncols of the palette.
// Add coloff to the result to move toward white.
void setFade(int col, int ncols, int coloff, int fade);
Commit: fc14318df310a0b0e7b44f94cfe690d4f720f895
https://github.com/scummvm/scummvm/commit/fc14318df310a0b0e7b44f94cfe690d4f720f895
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix game events happening at wrong times
Changed paths:
engines/dgds/globals.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 135ef48ed05..e211a5a9af4 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -121,7 +121,7 @@ public:
int16 get() override {
SDSScene *scene = static_cast<DgdsEngine *>(g_engine)->getScene();
- bool nonInteractive = _isSetOff || scene->getDragItem() || scene->hasVisibleDialog();
+ bool nonInteractive = _isSetOff || scene->getDragItem() || scene->hasVisibleOrOpeningDialog();
*_ptr = !nonInteractive;
return *_ptr;
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 21e17118cfb..f2c18db07ff 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -1268,6 +1268,15 @@ bool SDSScene::hasVisibleDialog() {
return getVisibleDialog() != nullptr;
}
+bool SDSScene::hasVisibleOrOpeningDialog() const {
+ for (const auto &dlg : _dialogs) {
+ if (dlg.hasFlag(kDlgFlagVisible) || dlg.hasFlag(kDlgFlagOpening)) {
+ return true;
+ }
+ }
+ return false;
+}
+
HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 75ceeaf796c..e389acbe84b 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -339,6 +339,7 @@ public:
const Common::Array<ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
bool hasVisibleDialog();
+ bool hasVisibleOrOpeningDialog() const;
Common::Error syncState(Common::Serializer &s) override;
Commit: b1a67aa263903e5023a51a471c638ec86c5a6801
https://github.com/scummvm/scummvm/commit/b1a67aa263903e5023a51a471c638ec86c5a6801
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Refactor globals as some are common between games
Changed paths:
engines/dgds/globals.cpp
engines/dgds/globals.h
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index e211a5a9af4..c9eff39768f 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -31,7 +31,54 @@ typedef ReadWriteGlobal<int16> RWI16Global;
////////////////////////////////
-Globals::Globals() {
+// TODO: Move this to Scene??
+class GameIsInteractiveGlobal : public Global {
+public:
+ GameIsInteractiveGlobal(uint16 num, int16 *ptr) : Global(num), _ptr(ptr), _isSetOff(false) {}
+
+ int16 get() override {
+ SDSScene *scene = static_cast<DgdsEngine *>(g_engine)->getScene();
+ bool nonInteractive = _isSetOff || scene->getDragItem() || scene->hasVisibleOrOpeningDialog();
+ *_ptr = !nonInteractive;
+ return *_ptr;
+ }
+
+ int16 set(int16 val) override {
+ _isSetOff = (val == 0);
+ return get();
+ }
+
+ void setRaw(int16 val) override { }
+
+private:
+ int16 *_ptr;
+ bool _isSetOff;
+};
+
+
+Globals::Globals(Clock &clock) :
+_lastOpcode1SceneChageNum(0), _sceneOp12SceneNum(0), _currentSelectedItem(0),
+_gameMinsToAddOnLClick(0), _gameMinsToAddOnStartDrag(0), _gameMinsToAddOnRClick(0), _gameMinsToAddOnDragFinished(0),
+_gameMinsToAddOnObjInteraction(0), _gameIsInteractiveGlobal(0), _sceneOpcode15FromScene(0),
+_sceneOpcode15ToScene(0) {
+ _globals.push_back(clock.getGameMinsAddedGlobal(1));
+ _globals.push_back(clock.getGameTicksUpGlobal(0x64));
+ _globals.push_back(clock.getGameTicksDownGlobal(0x63));
+ _globals.push_back(new ROI16Global(0x62, &_lastOpcode1SceneChageNum));
+ _globals.push_back(new RWI16Global(0x61, &_sceneOp12SceneNum));
+ _globals.push_back(new RWI16Global(0x60, &_currentSelectedItem));
+ _globals.push_back(clock.getDaysGlobal(0x5F));
+ _globals.push_back(clock.getHoursGlobal(0x5E));
+ _globals.push_back(clock.getMinsGlobal(0x5D));
+ _globals.push_back(new RWI16Global(0x5C, &_gameMinsToAddOnLClick));
+ _globals.push_back(new RWI16Global(0x5B, &_gameMinsToAddOnStartDrag));
+ _globals.push_back(new RWI16Global(0x5A, &_gameMinsToAddOnRClick));
+ _globals.push_back(new RWI16Global(0x59, &_gameMinsToAddOnDragFinished));
+ _globals.push_back(new RWI16Global(0x58, &_gameMinsToAddOnObjInteraction));
+ _globals.push_back(new GameIsInteractiveGlobal(0x57, &_gameIsInteractiveGlobal));
+ _globals.push_back(clock.getDays2Global(0x56));
+ _globals.push_back(new RWI16Global(0x55, &_sceneOpcode15FromScene));
+ _globals.push_back(new RWI16Global(0x54, &_sceneOpcode15ToScene));
}
Globals::~Globals() {
@@ -58,6 +105,21 @@ int16 Globals::setGlobal(uint16 num, int16 val) {
return 0;
}
+Common::Error Globals::syncState(Common::Serializer &s) {
+ s.syncAsSint16LE(_lastOpcode1SceneChageNum);
+ s.syncAsSint16LE(_sceneOp12SceneNum);
+ s.syncAsSint16LE(_currentSelectedItem);
+ s.syncAsSint16LE(_gameMinsToAddOnLClick);
+ s.syncAsSint16LE(_gameMinsToAddOnStartDrag);
+ s.syncAsSint16LE(_gameMinsToAddOnRClick);
+ s.syncAsSint16LE(_gameMinsToAddOnDragFinished);
+ s.syncAsSint16LE(_gameMinsToAddOnObjInteraction);
+ s.syncAsSint16LE(_gameIsInteractiveGlobal);
+ s.syncAsSint16LE(_sceneOpcode15FromScene);
+ s.syncAsSint16LE(_sceneOpcode15ToScene);
+ return Common::kNoError;
+}
+
////////////////////////////////
class DetailLevelROGlobal : public Global {
@@ -114,56 +176,11 @@ private:
DragonDataTable &_table;
};
-// TODO: Move this to Scene??
-class GameIsInteractiveGlobal : public Global {
-public:
- GameIsInteractiveGlobal(uint16 num, int16 *ptr) : Global(num), _ptr(ptr), _isSetOff(false) {}
-
- int16 get() override {
- SDSScene *scene = static_cast<DgdsEngine *>(g_engine)->getScene();
- bool nonInteractive = _isSetOff || scene->getDragItem() || scene->hasVisibleOrOpeningDialog();
- *_ptr = !nonInteractive;
- return *_ptr;
- }
-
- int16 set(int16 val) override {
- _isSetOff = (val == 0);
- return get();
- }
-
- void setRaw(int16 val) override { }
-
-private:
- int16 *_ptr;
- bool _isSetOff;
-};
////////////////////////////////
-DragonGlobals::DragonGlobals(Clock &_clock) : Globals(),
-_lastOpcode1SceneChageNum(0), _sceneOp12SceneNum(0), _currentSelectedItem(0),
-_gameMinsToAddOnLClick(0), _gameMinsToAddOnStartDrag(0), _gameMinsToAddOnRClick(0), _gameMinsToAddOnDragFinished(0),
-_gameMinsToAddOnObjInteraction(0), _gameIsInteractiveGlobal(0), _sceneOpcode15FromScene(0),
-_sceneOpcode15ToScene(0), _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0),
-_opcode106EndMinutes(0) {
- _globals.push_back(_clock.getGameMinsAddedGlobal(1));
- _globals.push_back(_clock.getGameTicksUpGlobal(0x64));
- _globals.push_back(_clock.getGameTicksDownGlobal(0x63));
- _globals.push_back(new ROI16Global(0x62, &_lastOpcode1SceneChageNum));
- _globals.push_back(new RWI16Global(0x61, &_sceneOp12SceneNum));
- _globals.push_back(new RWI16Global(0x60, &_currentSelectedItem));
- _globals.push_back(_clock.getDaysGlobal(0x5F));
- _globals.push_back(_clock.getHoursGlobal(0x5E));
- _globals.push_back(_clock.getMinsGlobal(0x5D));
- _globals.push_back(new RWI16Global(0x5C, &_gameMinsToAddOnLClick));
- _globals.push_back(new RWI16Global(0x5B, &_gameMinsToAddOnStartDrag));
- _globals.push_back(new RWI16Global(0x5A, &_gameMinsToAddOnRClick));
- _globals.push_back(new RWI16Global(0x59, &_gameMinsToAddOnDragFinished));
- _globals.push_back(new RWI16Global(0x58, &_gameMinsToAddOnObjInteraction));
- _globals.push_back(new GameIsInteractiveGlobal(0x57, &_gameIsInteractiveGlobal));
- _globals.push_back(_clock.getDays2Global(0x56));
- _globals.push_back(new RWI16Global(0x55, &_sceneOpcode15FromScene));
- _globals.push_back(new RWI16Global(0x54, &_sceneOpcode15ToScene));
+DragonGlobals::DragonGlobals(Clock &clock) : Globals(clock),
+ _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0), _opcode106EndMinutes(0) {
_globals.push_back(new RWI16Global(0x20, &_sceneOpcode100Var));
_globals.push_back(new RWI16Global(0x21, &_arcadeModeFlag_3cdc));
_globals.push_back(new RWI16Global(0x22, &_opcode106EndMinutes));
@@ -175,17 +192,7 @@ _opcode106EndMinutes(0) {
}
Common::Error DragonGlobals::syncState(Common::Serializer &s) {
- s.syncAsSint16LE(_lastOpcode1SceneChageNum);
- s.syncAsSint16LE(_sceneOp12SceneNum);
- s.syncAsSint16LE(_currentSelectedItem);
- s.syncAsSint16LE(_gameMinsToAddOnLClick);
- s.syncAsSint16LE(_gameMinsToAddOnStartDrag);
- s.syncAsSint16LE(_gameMinsToAddOnRClick);
- s.syncAsSint16LE(_gameMinsToAddOnDragFinished);
- s.syncAsSint16LE(_gameMinsToAddOnObjInteraction);
- s.syncAsSint16LE(_gameIsInteractiveGlobal);
- s.syncAsSint16LE(_sceneOpcode15FromScene);
- s.syncAsSint16LE(_sceneOpcode15ToScene);
+ Globals::syncState(s);
s.syncAsSint16LE(_sceneOpcode100Var);
s.syncAsSint16LE(_arcadeModeFlag_3cdc);
s.syncAsSint16LE(_opcode106EndMinutes);
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 962c5ec371f..4a05c418212 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -79,16 +79,38 @@ private:
class Globals {
public:
- Globals();
+ Globals(Clock &clock);
virtual ~Globals();
int16 getGlobal(uint16 num);
int16 setGlobal(uint16 num, int16 val);
- virtual Common::Error syncState(Common::Serializer &s) { return Common::kNoError; }
+ virtual Common::Error syncState(Common::Serializer &s); // note: children should call parent first
Common::Array<Global *> &getAllGlobals() { return _globals; }
+ int16 getGameMinsToAddOnLClick() const { return _gameMinsToAddOnLClick; }
+ int16 getGameMinsToAddOnStartDrag() const { return _gameMinsToAddOnStartDrag; }
+ int16 getGameMinsToAddOnRClick() const { return _gameMinsToAddOnRClick; }
+ int16 getGameMinsToAddOnDragFinished() const { return _gameMinsToAddOnDragFinished; }
+ int16 getGameMinsToAddOnObjInteraction() const { return _gameMinsToAddOnObjInteraction; }
+
+ void setLastSceneNum(int16 num) { _lastOpcode1SceneChageNum = num; }
+
protected:
+
+ // these ones seem to be common between games
+ int16 _lastOpcode1SceneChageNum;
+ int16 _sceneOp12SceneNum;
+ int16 _currentSelectedItem;
+ int16 _gameMinsToAddOnLClick;
+ int16 _gameMinsToAddOnStartDrag;
+ int16 _gameMinsToAddOnRClick;
+ int16 _gameMinsToAddOnDragFinished;
+ int16 _gameMinsToAddOnObjInteraction;
+ int16 _gameIsInteractiveGlobal; // used to decide if the game can start a "meanwhile" sequence
+ int16 _sceneOpcode15FromScene;
+ int16 _sceneOpcode15ToScene;
+
Common::Array<Global *> _globals;
};
@@ -112,32 +134,12 @@ class DragonGlobals : public Globals {
public:
DragonGlobals(Clock &clock);
- int16 getGameMinsToAddOnLClick() const { return _gameMinsToAddOnLClick; }
- int16 getGameMinsToAddOnStartDrag() const { return _gameMinsToAddOnStartDrag; }
- int16 getGameMinsToAddOnRClick() const { return _gameMinsToAddOnRClick; }
- int16 getGameMinsToAddOnDragFinished() const { return _gameMinsToAddOnDragFinished; }
- int16 getGameMinsToAddOnObjInteraction() const { return _gameMinsToAddOnObjInteraction; }
-
- void setLastSceneNum(int16 num) { _lastOpcode1SceneChageNum = num; }
-
private:
- int16 _lastOpcode1SceneChageNum;
- int16 _sceneOp12SceneNum;
- int16 _currentSelectedItem;
- int16 _gameMinsToAddOnLClick;
- int16 _gameMinsToAddOnStartDrag;
- int16 _gameMinsToAddOnRClick;
- int16 _gameMinsToAddOnDragFinished;
- int16 _gameMinsToAddOnObjInteraction;
- int16 _gameIsInteractiveGlobal;
- int16 _sceneOpcode15FromScene;
- int16 _sceneOpcode15ToScene;
+ // Dragon-specific globals
int16 _sceneOpcode100Var;
int16 _arcadeModeFlag_3cdc;
int16 _opcode106EndMinutes;
DragonDataTable _table;
- // Clock _clock; // kept in the engine
- // uint16 _detailSliderSetting; // kept in the engine
Common::Error syncState(Common::Serializer &s) override;
};
Commit: 7d0631ee87bfc5ad2ad09789de86fbcc1c2ac396
https://github.com/scummvm/scummvm/commit/7d0631ee87bfc5ad2ad09789de86fbcc1c2ac396
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add slidget gadget support
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/request.cpp
engines/dgds/request.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 3abeba8a849..c12efd9c1b1 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -79,7 +79,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr),
_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
- _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone), _isLoading(true), _rstFileName(nullptr) {
+ _random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone), _isLoading(true),
+ _rstFileName(nullptr), _difficulty(1) {
syncSoundSettings();
_platform = gameDesc->platform;
@@ -449,12 +450,22 @@ Common::Error DgdsEngine::run() {
}
if (_menu->menuShown()) {
- if (mouseEvent == Common::EVENT_LBUTTONUP) {
- _menu->handleMenu(_lastMouse);
- mouseEvent = Common::EVENT_INVALID;
+ switch (mouseEvent) {
+ case Common::EVENT_LBUTTONUP:
+ _menu->onMouseLUp(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _menu->onMouseLDown(_lastMouse);
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _menu->onMouseMove(_lastMouse);
+ break;
+ default:
+ break;
}
g_system->updateScreen();
g_system->delayMillis(10);
+ _clock.update(false);
continue;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index eff6e4fc1b0..31552cbedf7 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -107,6 +107,7 @@ private:
// Settings which we should integrate with ScummVM settings UI
DgdsDetailLevel _detailLevel;
int _textSpeed;
+ int _difficulty;
bool _justChangedScene1;
bool _justChangedScene2;
@@ -151,8 +152,13 @@ public:
Inventory *getInventory() { return _inventory; }
void setMouseCursor(uint num);
- DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
int getTextSpeed() const { return _textSpeed; }
+ void setTextSpeed(int16 speed) { _textSpeed = speed; }
+ int16 getDifficulty() const { return _difficulty; }
+ void setDetailLevel(DgdsDetailLevel level) { _detailLevel = level; }
+ DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
+ void setDifficulty(int16 difficulty) { _difficulty = difficulty; }
+
void setShowClock(bool val);
ADSInterpreter *adsInterpreter() { return _adsInterp; }
bool justChangedScene1() const { return _justChangedScene1; }
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 5cd0bb7c214..2deb1549b81 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -36,7 +36,7 @@
namespace Dgds {
-
+// TODO: These are the IDs for Dragon, this code needs updates for China/Beamish/etc
enum MenuButtonIds {
kMenuMainPlay = 120,
kMenuMainControls = 20,
@@ -48,6 +48,10 @@ enum MenuButtonIds {
kMenuControlsVCR = 127,
kMenuControlsPlay = 128,
+ kMenuSliderControlsDifficulty = 123,
+ kMenuSliderControlsTextSpeed = 125,
+ kMenuSliderControlsDetailLevel = 131,
+
kMenuOptionsJoystickOnOff = 139,
kMenuOptionsMouseOnOff = 138,
kMenuOptionsSoundsOnOff = 137,
@@ -99,7 +103,7 @@ enum MenuButtonIds {
kMenuGameOverRestore = 170,
};
-Menu::Menu() : _curMenu(kMenuNone) {
+Menu::Menu() : _curMenu(kMenuNone), _dragGadget(nullptr) {
_screenBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
}
@@ -113,7 +117,33 @@ void Menu::setScreenBuffer() {
g_system->unlockScreen();
}
+void Menu::configureGadget(MenuId menu, Gadget* gadget) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ // a bit of a hack - set up the gadget with the correct value before we draw it.
+ if (menu == kMenuControls) {
+ SliderGadget *slider = dynamic_cast<SliderGadget *>(gadget);
+ switch (gadget->_gadgetNo) {
+ case kMenuSliderControlsDifficulty:
+ slider->setSteps(3, false);
+ slider->setValue(engine->getDifficulty()); // TODO: set a difficulty value
+ break;
+ case kMenuSliderControlsTextSpeed:
+ slider->setSteps(10, false);
+ slider->setValue(9 - engine->getTextSpeed());
+ break;
+ case kMenuSliderControlsDetailLevel:
+ slider->setSteps(2, true);
+ slider->setValue(engine->getDetailLevel());
+ break;
+ default:
+ break;
+ // do nothing.
+ }
+ }
+}
+
void Menu::drawMenu(MenuId menu) {
+ bool firstDraw = (_curMenu != menu);
_curMenu = menu;
Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
@@ -129,8 +159,11 @@ void Menu::drawMenu(MenuId menu) {
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
- if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider)
+ if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider) {
+ if (firstDraw)
+ configureGadget(menu, gadget);
gadget->draw(&managed);
+ }
}
drawMenuText(managed);
@@ -165,34 +198,74 @@ void Menu::drawMenuText(Graphics::ManagedSurface &dst) {
}
}
-int16 Menu::getClickedMenuItem(Common::Point mouseClick) {
+Gadget *Menu::getClickedMenuItem(const Common::Point &mouseClick) {
if (_curMenu == kMenuNone)
- return -1;
+ return nullptr;
Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
if (gadget->_gadgetType == kGadgetButton || gadget->_gadgetType == kGadgetSlider) {
- if (gadget->containsPoint(mouseClick))
- return (int16)gadget->_gadgetNo;
+ if (gadget->containsPoint(mouseClick)) {
+ return gadget;
+ }
}
}
- return -1;
+ return nullptr;
+}
+
+void Menu::onMouseLDown(const Common::Point &mouse) {
+ SliderGadget *slider = dynamic_cast<SliderGadget *>(getClickedMenuItem(mouse));
+ if (slider) {
+ _dragGadget = slider;
+ _dragStartPt = mouse;
+ }
+}
+
+void Menu::onMouseMove(const Common::Point &mouse) {
+ if (!_dragGadget)
+ return;
+ _dragGadget->onDrag(mouse);
+ drawMenu(_curMenu);
}
-void Menu::handleMenu(Common::Point &mouse) {
- const int16 clickedMenuItem = getClickedMenuItem(mouse);
+void Menu::onMouseLUp(const Common::Point &mouse) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (_dragGadget && mouse != _dragStartPt) {
+ int16 setting = _dragGadget->onDragFinish(mouse);
+ switch (_dragGadget->_gadgetNo) {
+ case kMenuSliderControlsDifficulty:
+ engine->setDifficulty(setting);
+ break;
+ case kMenuSliderControlsTextSpeed:
+ engine->setTextSpeed(9 - setting);
+ break;
+ case kMenuSliderControlsDetailLevel:
+ engine->setDetailLevel(static_cast<DgdsDetailLevel>(setting));
+ break;
+ }
+ drawMenu(_curMenu);
+ _dragGadget = nullptr;
+ _dragStartPt = Common::Point();
+ return;
+ }
+ _dragGadget = nullptr;
+
+ Gadget *gadget = getClickedMenuItem(mouse);
+ if (!gadget)
+ return;
+
+ int16 clickedMenuItem = gadget->_gadgetNo;
// Click animation
// TODO: Handle on/off buttons
- if (clickedMenuItem >= 0) {
- toggleGadget(clickedMenuItem, false);
+ if (dynamic_cast<ButtonGadget *>(gadget)) {
+ gadget->toggle(false);
drawMenu(_curMenu);
g_system->delayMillis(500);
- toggleGadget(clickedMenuItem, true);
+ gadget->toggle(true);
}
switch (clickedMenuItem) {
@@ -300,6 +373,25 @@ void Menu::handleMenu(Common::Point &mouse) {
case kMenuGameOverRestart:
drawMenu(kMenuRestart);
break;
+ case kMenuSliderControlsDifficulty: {
+ int16 setting = dynamic_cast<SliderGadget *>(gadget)->onClick(mouse);
+ engine->setDifficulty(setting);
+ // redraw for update.
+ drawMenu(_curMenu);
+ break;
+ }
+ case kMenuSliderControlsTextSpeed: {
+ int16 setting = dynamic_cast<SliderGadget *>(gadget)->onClick(mouse);
+ engine->setTextSpeed(9 - setting);
+ drawMenu(_curMenu);
+ break;
+ }
+ case kMenuSliderControlsDetailLevel: {
+ int16 setting = dynamic_cast<SliderGadget *>(gadget)->onClick(mouse);
+ engine->setDetailLevel(static_cast<DgdsDetailLevel>(setting));
+ drawMenu(_curMenu);
+ break;
+ }
default:
debug("Clicked ID %d", clickedMenuItem);
break;
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 0bbd4b8f949..73dcab82d9f 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -78,7 +78,9 @@ public:
void setScreenBuffer();
void drawMenu(MenuId menu = kMenuMain);
- void handleMenu(Common::Point &mouse);
+ void onMouseLUp(const Common::Point &mouse);
+ void onMouseLDown(const Common::Point &mouse);
+ void onMouseMove(const Common::Point &mouse);
bool menuShown() const { return _curMenu != kMenuNone; }
void hideMenu() { _curMenu = kMenuNone; }
@@ -87,10 +89,14 @@ public:
}
private:
- int16 getClickedMenuItem(Common::Point mouseClick);
+ Gadget *getClickedMenuItem(const Common::Point &mouseClick);
void drawMenuText(Graphics::ManagedSurface &dst);
void toggleGadget(int16 gadgetId, bool enable);
+ void configureGadget(MenuId menu, Gadget *gadget);
REQFileData _reqData;
+
+ SliderGadget *_dragGadget;
+ Common::Point _dragStartPt;
};
} // End of namespace Dgds
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index ba28829614d..4ae87a348df 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -155,8 +155,6 @@ bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int
gptr->_field21_0x2a = val >> 0xf;
}
- // TODO: In each of these cases, work out the true offsets to these fields.
- // and if they are shared between gadget types.
switch (gadgetType) {
case kGadgetText: {
uint16 i1 = str->readUint16LE();
@@ -303,12 +301,13 @@ Common::String Gadget::dump() const {
void Gadget::draw(Graphics::ManagedSurface *dst) const {}
+Common::Point Gadget::topLeft() const {
+ return Common::Point(_x + _parentX, _y + _parentY);
+}
+
bool Gadget::containsPoint(const Common::Point &pt) {
- int16 x = _x + _parentX;
- int16 y = _y + _parentY;
- int16 right = x + _width;
- int16 bottom = (y + _height) - 1;
- Common::Rect gadgetRect(x, y, right, bottom);
+ Common::Point tl = topLeft();
+ Common::Rect gadgetRect(tl, _width, _height - 1);
return gadgetRect.contains(pt);
}
@@ -440,14 +439,16 @@ static const char *_sliderLabelsForGadget(uint16 num) {
}
}
+static const int SLIDER_HANDLE_FRAME = 28;
+
void SliderGadget::draw(Graphics::ManagedSurface *dst) const {
const Font *font = RequestData::getMenuFont();
int16 x = _x + _parentX;
int16 y = _y + _parentY;
+
int16 x2 = x + _width;
int16 y2 = (y + _height) - 1;
-
int16 titley = (y - font->getFontHeight()) + 1;
const char *title = _sliderTitleForGadget(_gadgetNo);
const char *labels = _sliderLabelsForGadget(_gadgetNo);
@@ -470,6 +471,79 @@ void SliderGadget::draw(Graphics::ManagedSurface *dst) const {
dst->fillRect(fillrect, SliderColors[5]);
fillrect.grow(-1);
dst->fillRect(fillrect, SliderColors[6]);
+
+ // Draw the slider control in the right spot
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
+ uiCorners->drawBitmap(SLIDER_HANDLE_FRAME, x + _handleX, y, Common::Rect(0, 0, 320, 200), *dst);
+}
+
+SliderGadget::SliderGadget() : _lock(false), _steps(0), _gadget2_i1(0),
+ _gadget2_i2(0), _gadget2_i3(0), _gadget2_i4(0) {
+}
+
+int16 SliderGadget::getHandleWidth() const {
+ const Common::SharedPtr<Image> uiCorners = static_cast<DgdsEngine *>(g_engine)->getUICorners();
+ int16 handleWidth = uiCorners->width(SLIDER_HANDLE_FRAME);
+ return handleWidth - 2;
+}
+
+int16 SliderGadget::getUsableWidth() const {
+ return _width + 4 - getHandleWidth();
+}
+
+void SliderGadget::onDrag(const Common::Point &mousePt) {
+ const Common::Point topLeftPt = topLeft();
+ const Common::Point relMouse = mousePt - topLeftPt;
+ // match middle of handle to mouse point
+ int16 handleWidth = getHandleWidth();
+ _handleX = CLIP(relMouse.x - handleWidth / 2, 0, (int)getUsableWidth());
+}
+
+int16 SliderGadget::onDragFinish(const Common::Point &mousePt) {
+ onDrag(mousePt);
+ int16 newVal = getValue();
+ if (_lock)
+ setValue(newVal);
+ return newVal;
+}
+
+int16 SliderGadget::getValue() {
+ int16 stepSize = getUsableWidth() / (_steps - 1);
+ // Find the closest step point to the left end of the handle
+ int16 closestStep = (_handleX + stepSize / 2) / stepSize;
+ return CLIP(closestStep, (int16)0, _steps);
+}
+
+void SliderGadget::setValue(int16 val) {
+ // if val is steps-1, slider x should be at..
+ int16 usableWidth = getUsableWidth();
+ if (val == _steps - 1)
+ _handleX = usableWidth;
+ else
+ _handleX = (usableWidth * val) / (_steps - 1);
+}
+
+int16 SliderGadget::onClick(const Common::Point &mousePt) {
+ const Common::Point topLeftPt = topLeft();
+ const Common::Point relMouse = mousePt - topLeftPt;
+
+ // A click should move the slider to the next step in the direction of the click.
+ int16 handleMiddle = _handleX + getHandleWidth() / 2;
+ // round up step size to ensure we move far enough..
+
+ int16 val = getValue();
+ int16 newVal = val;
+ if (relMouse.x > handleMiddle)
+ newVal++;
+ else
+ newVal--;
+
+ debug("clicked on slider %d, move val from %d -> %d", _gadgetNo, val, newVal);
+
+ newVal = CLIP((int)newVal, 0, _steps - 1);
+ setValue(newVal);
+ return newVal;
}
Common::String ImageGadget::dump() const {
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 4e99371ff64..34c91c4a7ca 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -102,6 +102,8 @@ public:
virtual void toggle(bool enable) {}
bool containsPoint(const Common::Point &pt);
+
+ Common::Point topLeft() const;
};
// Button gadget has no additional fields, but some behavior differences.
@@ -124,6 +126,8 @@ public:
// extended gadget type 2 is 74 (0x4a) bytes
class SliderGadget : public Gadget {
public:
+ SliderGadget();
+
uint16 _gadget2_i1;
uint16 _gadget2_i2;
uint16 _gadget2_i3;
@@ -131,6 +135,37 @@ public:
Common::String dump() const override;
void draw(Graphics::ManagedSurface *dst) const override;
+
+ /// Set number of steps the slider has
+ /// If lock is true, jumps the final position to match the step.
+ void setSteps(int16 steps, bool lock) {
+ _steps = steps;
+ _lock = lock;
+ }
+
+ void setValue(int16 val);
+ // Return the closest step value to the current handle position.
+ int16 getValue();
+
+ ///
+ /// Work out where the mouse click was and what the new setting should be
+ /// from 0 to steps-1.
+ ///
+ int16 onClick(const Common::Point &mousePt);
+
+ // Returns true if the mouse is over the handle and a drag operation should start
+ bool onMouseDown(const Common::Point &mousePt);
+ void onDrag(const Common::Point &mousePt);
+ // returns the new value
+ int16 onDragFinish(const Common::Point &mousePt);
+
+private:
+ bool _lock;
+ int16 _steps;
+ int16 _handleX;
+
+ int16 getHandleWidth() const;
+ int16 getUsableWidth() const;
};
// extended gadget type 8 is 68 (0x44) bytes
Commit: 30363ff4920e6d860223ed97dfcafbbc3f918c43
https://github.com/scummvm/scummvm/commit/30363ff4920e6d860223ed97dfcafbbc3f918c43
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Skip arcade sequences automatically
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/scene.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index c12efd9c1b1..5d65eade8d1 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -605,10 +605,12 @@ bool DgdsEngine::canLoadGameStateCurrently(Common::U32String *msg /*= nullptr*/)
bool DgdsEngine::canSaveGameStateCurrently(Common::U32String *msg /*= nullptr*/) {
return _gdsScene && _scene && _scene->getNum() != 2
- && !_scene->hasVisibleDialog() && !_menu->menuShown()
&& _scene->getDragItem() == nullptr && !_isLoading;
}
+bool DgdsEngine::canSaveAutosaveCurrently() {
+ return canSaveGameStateCurrently() && !_scene->hasVisibleDialog() && !_menu->menuShown();
+}
Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
//
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 31552cbedf7..55d18c93cb1 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -171,6 +171,7 @@ public:
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+ bool canSaveAutosaveCurrently() override;
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override {
Common::Serializer s(nullptr, stream);
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index c9eff39768f..e2489b563fe 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -180,9 +180,9 @@ private:
////////////////////////////////
DragonGlobals::DragonGlobals(Clock &clock) : Globals(clock),
- _sceneOpcode100Var(0), _arcadeModeFlag_3cdc(0), _opcode106EndMinutes(0) {
+ _sceneOpcode100Var(0), _arcadeModeState(0), _opcode106EndMinutes(0) {
_globals.push_back(new RWI16Global(0x20, &_sceneOpcode100Var));
- _globals.push_back(new RWI16Global(0x21, &_arcadeModeFlag_3cdc));
+ _globals.push_back(new RWI16Global(0x21, &_arcadeModeState));
_globals.push_back(new RWI16Global(0x22, &_opcode106EndMinutes));
_globals.push_back(new RWI16Global(0x23, &_table._row));
_globals.push_back(new RWI16Global(0x24, &_table._col));
@@ -194,7 +194,7 @@ DragonGlobals::DragonGlobals(Clock &clock) : Globals(clock),
Common::Error DragonGlobals::syncState(Common::Serializer &s) {
Globals::syncState(s);
s.syncAsSint16LE(_sceneOpcode100Var);
- s.syncAsSint16LE(_arcadeModeFlag_3cdc);
+ s.syncAsSint16LE(_arcadeModeState);
s.syncAsSint16LE(_opcode106EndMinutes);
s.syncAsSint16LE(_table._row);
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 4a05c418212..39d8738c643 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -137,7 +137,7 @@ public:
private:
// Dragon-specific globals
int16 _sceneOpcode100Var;
- int16 _arcadeModeFlag_3cdc;
+ int16 _arcadeModeState;
int16 _opcode106EndMinutes;
DragonDataTable _table;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index f2c18db07ff..b405bd6d811 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -26,8 +26,9 @@
#include "common/rect.h"
#include "common/system.h"
#include "common/util.h"
-#include "graphics/cursorman.h"
+#include "common/translation.h"
+#include "graphics/cursorman.h"
#include "graphics/surface.h"
#include "graphics/primitives.h"
@@ -112,7 +113,7 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpChangeScene: return "changeScene";
case kSceneOpNoop: return "noop";
case kSceneOpGlobal: return "global";
- case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
+ case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
case kSceneOpSetItemAttr: return "setItemAttr";
case kSceneOpSetDragItem: return "setDragItem";
case kSceneOpOpenInventory: return "openInventory";
@@ -120,10 +121,10 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpShowInvButton: return "showInvButton";
case kSceneOpHideInvButton: return "hideInvButton";
case kSceneOpEnableTrigger: return "enabletrigger";
- case kSceneOpChangeSceneToStored: return "changeSceneToStored";
- case kSceneOpAddFlagToDragItem: return "addFlagToDragItem";
+ case kSceneOpChangeSceneToStored: return "changeSceneToStored";
+ case kSceneOpAddFlagToDragItem: return "addFlagToDragItem";
case kSceneOpMoveItemsBetweenScenes: return "moveItemsBetweenScenes";
- case kSceneOpOpenInventoryZoom: return "openInventoryZoom";
+ case kSceneOpOpenInventoryZoom: return "openInventoryZoom";
case kSceneOpShowClock: return "sceneOpShowClock";
case kSceneOpHideClock: return "sceneOpHideClock";
case kSceneOpShowMouse: return "sceneOpShowMouse";
@@ -604,7 +605,12 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
engine->getScene()->addAndShowTiredDialog();
break;
case kSceneOpArcadeTick:
- error("TODO: Implement sceneOpArcadeTick");
+ // TODO: Implement this properly! for now jsut
+ // set the global arcade state variable to the "skip" value.
+ warning("Setting arcade global to 8 (skip)");
+ g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
+ engine->getGameGlobals()->setGlobal(0x21, 6);
+ break;
case kSceneOp105:
error("TODO: Implement sceneOp105");
case kSceneOp106:
@@ -1657,8 +1663,8 @@ Common::Error GDSScene::syncState(Common::Serializer &s) {
assert(!_perSceneGlobals.empty());
// TODO: Maybe it would be nicer to save the item/global numbers
- // with the values in case the order changed in some other version of the game data? This assumes they will be
- // the same order.
+ // with the values in case the order changed in some other version of
+ // the game data? This assumes they will be the same order.
uint16 nitems = _gameItems.size();
s.syncAsUint16LE(nitems);
Commit: fec21fa8f34481fb3c84f4700aaf97757aad6def
https://github.com/scummvm/scummvm/commit/fec21fa8f34481fb3c84f4700aaf97757aad6def
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Small cleanups to run non-interactive demos
Changed paths:
engines/dgds/ads.cpp
engines/dgds/detection_tables.h
engines/dgds/dgds.cpp
engines/dgds/globals.cpp
engines/dgds/globals.h
engines/dgds/scene.cpp
engines/dgds/ttm.cpp
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index b863bf04287..69489559a4d 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -79,12 +79,8 @@ bool ADSInterpreter::load(const Common::String &filename) {
detailfile = filename;
debug("ADSInterpreter: load %s", detailfile.c_str());
- /* FIXME: quick hack - never reuse data.
- if (_adsTexts.contains(detailfile)) {
- _adsData = &(_adsTexts.getVal(detailfile));
- return true;
- }*/
+ // Reset the state
_adsTexts.setVal(detailfile, ADSData());
_adsData = &(_adsTexts.getVal(detailfile));
@@ -384,7 +380,7 @@ bool ADSInterpreter::handleLogicOp(uint16 code, Common::SeekableReadStream *scr)
return false;
}
} else {
- // TODO: not actually enviro I think? for now just read it.
+ // TODO: this value is not actually enviro? for now just read it.
enviro = scr->readUint16LE();
}
@@ -446,6 +442,7 @@ int16 ADSInterpreter::randomOpGetProportion(uint16 code, Common::SeekableReadStr
void ADSInterpreter::handleRandomOp(uint16 code, Common::SeekableReadStream *scr) {
int16 max = 0;
int64 startpos = scr->pos();
+
// Collect the random proportions
code = scr->readUint16LE();
while (code != 0 && code != 0x30ff && scr->pos() < scr->size()) {
@@ -494,36 +491,35 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
debug(10, "ADS 0x%04x: init", code);
// "init". 0x0005 can be used for searching for next thing.
break;
- case 0x1010: // if unknown, 2 params
- case 0x1020: // if unknown, 2 params
- case 0x1030: // if unknown, 2 params
- case 0x1040: // if unknown, 2 params
- case 0x1050: // if unknown, 2 params
- case 0x1060: // if unknown, 2 params
- case 0x1070: // if unknown, 2 params
- case 0x1080: // if current seq countdown??, 1 param
- case 0x1090: // if ??? ???
+ case 0x1010: // WHILE runtype, 2 params
+ case 0x1020: // WHILE not runtype, 2 params
+ case 0x1030: // WHILE not played, 2 params
+ case 0x1040: // WHILE played, 2 params
+ case 0x1050: // WHILE finished, 2 params
+ case 0x1060: // WHILE not running, 2 params
+ case 0x1070: // WHILE running, 2 params
+ case 0x1080: // WHILE ??, 1 param (HOC+ only)
+ case 0x1090: // WHILE ??, 1 param (HOC+ only)
case 0x1310: // IF runtype 5, 2 params
case 0x1320: // IF not runtype 5, 2 params
- case 0x1330: // IF_NOT_PLAYED, 2 params
- case 0x1340: // IF_PLAYED, 2 params
- case 0x1350: // IF_FINISHED, 2 params
- case 0x1360: // IF_NOT_RUNNING, 2 params
- case 0x1370: // IF_RUNNING, 2 params
- case 0x1380: // IF_??????, 1 param (HOC+ only)
- case 0x1390: // IF_??????, 1 param (HOC+ only)
+ case 0x1330: // IF NOT_PLAYED, 2 params
+ case 0x1340: // IF PLAYED, 2 params
+ case 0x1350: // IF FINISHED, 2 params
+ case 0x1360: // IF NOT_RUNNING, 2 params
+ case 0x1370: // IF RUNNING, 2 params
+ case 0x1380: // IF ??????, 1 param (HOC+ only)
+ case 0x1390: // IF ??????, 1 param (HOC+ only)
return handleLogicOp(code, scr);
- case 0x1500: // ? IF ?, 0 params
- //debug("ADS: Unimplemented ADS branch logic opcode 0x1500");
+ case 0x1500: // Skip to end-if, 0 params
debug(10, "ADS 0x%04x: skip to end if", code);
skipToEndIf();
_adsData->_hitBranchOp = true;
return true;
- case 0x1510: // PLAY_SCENEENDIF? 0 params
+ case 0x1510: // END IF 0 params
debug(10, "ADS 0x%04x: hit branch op endif", code);
_adsData->_hitBranchOp = true;
return true;
- case 0x1520: // PLAY_SCENE_ENDWHILE?, 0 params
+ case 0x1520: // END WHILE 0 params
debug(10, "ADS 0x%04x: hit branch op endwhile", code);
_adsData->_hitBranchOp = true;
return false;
@@ -560,7 +556,7 @@ bool ADSInterpreter::handleOperation(uint16 code, Common::SeekableReadStream *sc
seq->_runPlayed++;
break;
}
- case 0x2010: { // STOP_SCENE, 3 params (ttmenv, ttmseq, proportion)
+ case 0x2010: { // STOP SCENE, 3 params (ttmenv, ttmseq, proportion)
enviro = scr->readUint16LE();
seqnum = scr->readUint16LE();
uint16 unk = scr->readUint16LE();
@@ -900,6 +896,7 @@ int ADSInterpreter::numArgs(uint16 opcode) const {
// TODO: This list is from DRAGON, there may be more entries in newer games.
switch (opcode) {
case 0x1080:
+ case 0x1090:
case 0x1380:
case 0x1390:
case 0x3020:
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index ecd8e55303a..78103d86557 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -23,7 +23,7 @@
namespace Dgds {
static const ADGameDescription gameDescriptions[] = {
- // Rise of the Dragon (PC) : GOG
+ // Rise of the Dragon (PC) GOG
{
"rise",
0,
@@ -143,7 +143,7 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
- // Heart of China (PC) : GOG
+ // Heart of China (PC) GOG
{
"china",
0,
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 5d65eade8d1..8a0252b41a2 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -352,12 +352,14 @@ void DgdsEngine::loadGameFiles() {
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("NORMAL.PAL");
_adsInterp->load("CESDEMO.ADS");
+ _adsInterp->segmentOrState(1, 3);
break;
case GID_COMINGSOON:
// TODO: Create a better type for this..
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("DYNAMIX.PAL");
_adsInterp->load("DEMO.ADS");
+ _adsInterp->segmentOrState(1, 3);
break;
default:
error("Unsupported game type in loadGameFiles");
@@ -469,111 +471,105 @@ Common::Error DgdsEngine::run() {
continue;
}
- if (getGameId() == GID_DRAGON || getGameId() == GID_CHINA) {
- _scene->checkForClearedDialogs();
+ _scene->checkForClearedDialogs();
- _gdsScene->runPreTickOps();
- _scene->runPreTickOps();
+ _gdsScene->runPreTickOps();
+ _scene->runPreTickOps();
- _compositionBuffer.blitFrom(_backgroundBuffer);
+ _compositionBuffer.blitFrom(_backgroundBuffer);
- if (_inventory->isOpen() && _scene->getNum() == 2) {
- int invCount = _gdsScene->countItemsInScene2();
- _inventory->draw(_compositionBuffer, invCount);
- }
+ if (_inventory->isOpen() && _scene->getNum() == 2) {
+ int invCount = _gdsScene->countItemsInScene2();
+ _inventory->draw(_compositionBuffer, invCount);
+ }
+
+ _compositionBuffer.transBlitFrom(_storedAreaBuffer);
+
+ _scene->drawActiveDialogBgs(&_compositionBuffer);
+
+ if (_scene->getNum() != 2 || _inventory->isZoomVisible())
+ _adsInterp->run();
- _compositionBuffer.transBlitFrom(_storedAreaBuffer);
-
- _scene->drawActiveDialogBgs(&_compositionBuffer);
-
- if (_scene->getNum() != 2 || _inventory->isZoomVisible())
- _adsInterp->run();
-
- if (mouseEvent != Common::EVENT_INVALID) {
- if (_inventory->isOpen()) {
- switch (mouseEvent) {
- case Common::EVENT_MOUSEMOVE:
- _inventory->mouseMoved(_lastMouse);
- break;
- case Common::EVENT_LBUTTONDOWN:
- _inventory->mouseLDown(_lastMouse);
- break;
- case Common::EVENT_LBUTTONUP:
- _inventory->mouseLUp(_lastMouse);
- break;
- case Common::EVENT_RBUTTONUP:
- _inventory->mouseRUp(_lastMouse);
- break;
- default:
- break;
- }
- } else {
- switch (mouseEvent) {
- case Common::EVENT_MOUSEMOVE:
- _scene->mouseMoved(_lastMouse);
- break;
- case Common::EVENT_LBUTTONDOWN:
- _scene->mouseLDown(_lastMouse);
- break;
- case Common::EVENT_LBUTTONUP:
- _scene->mouseLUp(_lastMouse);
- break;
- case Common::EVENT_RBUTTONUP:
- _scene->mouseRUp(_lastMouse);
- break;
- default:
- break;
- }
+ if (mouseEvent != Common::EVENT_INVALID) {
+ if (_inventory->isOpen()) {
+ switch (mouseEvent) {
+ case Common::EVENT_MOUSEMOVE:
+ _inventory->mouseMoved(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _inventory->mouseLDown(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _inventory->mouseLUp(_lastMouse);
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _inventory->mouseRUp(_lastMouse);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (mouseEvent) {
+ case Common::EVENT_MOUSEMOVE:
+ _scene->mouseMoved(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _scene->mouseLDown(_lastMouse);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _scene->mouseLUp(_lastMouse);
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _scene->mouseRUp(_lastMouse);
+ break;
+ default:
+ break;
}
}
+ }
- // TODO: Hard-coded logic to match Rise of the Dragon, check others
- if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
- _gdsScene->runPostTickOps();
+ // TODO: Hard-coded logic to match Rise of the Dragon, check others
+ if (getGameId() != GID_DRAGON || _scene->getNum() != 55)
+ _gdsScene->runPostTickOps();
- _scene->runPostTickOps();
- _scene->checkTriggers();
+ _scene->runPostTickOps();
+ _scene->checkTriggers();
#ifdef DUMP_FRAME_DATA
- /* For debugging, dump the frame contents.. */
- {
- Common::DumpFile outf;
- uint32 now = g_engine->getTotalPlayTime();
+ /* For debugging, dump the frame contents.. */
+ {
+ Common::DumpFile outf;
+ uint32 now = g_engine->getTotalPlayTime();
- byte palbuf[768];
- g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
+ byte palbuf[768];
+ g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
- outf.open(Common::Path(Common::String::format("/tmp/%07d-back.png", now)));
- ::Image::writePNG(outf, *_backgroundBuffer.surfacePtr(), palbuf);
- outf.close();
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-back.png", now)));
+ ::Image::writePNG(outf, *_backgroundBuffer.surfacePtr(), palbuf);
+ outf.close();
- outf.open(Common::Path(Common::String::format("/tmp/%07d-stor.png", now)));
- ::Image::writePNG(outf, *_storedAreaBuffer.surfacePtr(), palbuf);
- outf.close();
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-stor.png", now)));
+ ::Image::writePNG(outf, *_storedAreaBuffer.surfacePtr(), palbuf);
+ outf.close();
- outf.open(Common::Path(Common::String::format("/tmp/%07d-comp.png", now)));
- ::Image::writePNG(outf, *_compositionBuffer.surfacePtr(), palbuf);
- outf.close();
- }
+ outf.open(Common::Path(Common::String::format("/tmp/%07d-comp.png", now)));
+ ::Image::writePNG(outf, *_compositionBuffer.surfacePtr(), palbuf);
+ outf.close();
+ }
#endif
- if (!_inventory->isOpen()) {
- _gdsScene->drawItems(_compositionBuffer);
- checkDrawInventoryButton();
- }
-
- _clock.draw(_compositionBuffer);
- bool haveActiveDialog = _scene->checkDialogActive();
+ if (!_inventory->isOpen()) {
+ _gdsScene->drawItems(_compositionBuffer);
+ checkDrawInventoryButton();
+ }
- _scene->drawAndUpdateDialogs(&_compositionBuffer);
+ _clock.draw(_compositionBuffer);
+ bool haveActiveDialog = _scene->checkDialogActive();
- bool gameRunning = (!haveActiveDialog && _gameGlobals->getGlobal(0x57) /* TODO: && _dragItem == nullptr*/);
- _clock.update(gameRunning);
+ _scene->drawAndUpdateDialogs(&_compositionBuffer);
- } else if (getGameId() == GID_BEAMISH) {
- if (!_adsInterp->run())
- return Common::kNoError;
- }
+ bool gameRunning = (!haveActiveDialog && _gameGlobals->getGlobal(0x57) /* TODO: && _dragItem == nullptr*/);
+ _clock.update(gameRunning);
g_system->copyRectToScreen(_compositionBuffer.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g_system->updateScreen();
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index e2489b563fe..884b37022aa 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -147,7 +147,7 @@ static byte dragonDataTable[] = {
DragonDataTable::DragonDataTable() : _row(0), _col(0), _divBy4(0), _output(0) {}
-int DragonDataTable::getOffsetForVal(uint16 val) {
+int DragonDataTable::getOffsetForVal(uint16 val) const {
for (int i = 0; i < ARRAYSIZE(dragonDataTableOffsets); i++) {
if (dragonDataTableOffsets[i] == val)
return i;
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 39d8738c643..a3b444e3b83 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -126,7 +126,7 @@ public:
int16 _output;
private:
- int getOffsetForVal(uint16 val);
+ int getOffsetForVal(uint16 val) const;
};
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index b405bd6d811..e20d3aa0bde 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -1613,7 +1613,7 @@ void GDSScene::drawItems(Graphics::ManagedSurface &surf) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const Common::SharedPtr<Image> &icons = engine->getIcons();
int currentScene = engine->getScene()->getNum();
- if (icons->loadedFrameCount() < 3)
+ if (!icons || icons->loadedFrameCount() < 3)
return;
int xoff = 20;
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index cee84c2f6bf..934dd695081 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -318,8 +318,8 @@ void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, c
case 0xa030: // Copy from outside to middle
case 0xa090: // Copy from middle to outside
{
- uint halfwidth = r.width() / 2;
- uint halfheight = r.height() / 2;
+ int halfwidth = r.width() / 2;
+ int halfheight = r.height() / 2;
uint maxside = MAX(halfheight, halfwidth);
long widthScale = 1000 * halfwidth / maxside;
@@ -336,10 +336,10 @@ void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, c
return;
i++;
}
- uint xoff = widthScale * i / 1000;
- uint yoff = heightScale * i / 1000;
- uint16 xinside = (r.left + halfwidth) - xoff;
- uint16 yinside = (r.top + halfheight) - yoff;
+ int xoff = widthScale * i / 1000;
+ int yoff = heightScale * i / 1000;
+ int16 xinside = MAX((r.left + halfwidth) - xoff, 0);
+ int16 yinside = MAX((r.top + halfheight) - yoff, 0);
uint16 width = xoff * 2;
uint16 height = yoff * 2;
if (code == 0xa030) {
@@ -371,7 +371,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
//
// This appears in the credits, intro sequence, and the
- // "meanwhile" event with the factory in DRAGON. Seems it
+ // "meanwhile" event with the factory in DRAGON. It
// should reload the background image to clear any previous 0020
// event, and then save the current FG over it.
// Credits - (no scr loaded) Store large image on black bg after loading and before txt scroll
@@ -475,7 +475,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
if (seq._executed) // this is a one-shot op.
break;
uint sleep = _vm->getRandom().getRandomNumberRng(ivals[0], ivals[1]);
- // TODO: do same time fix as for 0x1020
_vm->adsInterpreter()->setScriptDelay((int)(sleep * MS_PER_FRAME));
break;
}
@@ -642,7 +641,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
break;
}
- case 0xa600: { // DRAW GETPUT
+ case 0xa600: { // DRAW GETPUT: i:int
if (seq._executed) // this is a one-shot op.
break;
int16 i = ivals[0];
@@ -749,9 +748,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
Common::SeekableReadStream *scr = env.scr;
- if (!scr)
- return false;
- if (scr->pos() >= scr->size())
+ if (!scr || scr->pos() >= scr->size())
return false;
debug(10, "TTM: Run env %d seq %d (%s) frame %d (scr offset %d, %s)", seq._enviro, seq._seqNum,
Commit: f2941d67779a29d0cb44851dfa09b6ec5761aca7
https://github.com/scummvm/scummvm/commit/f2941d67779a29d0cb44851dfa09b6ec5761aca7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix final scenes of dragon
Game can now be finished correctly with various endings.
Changed paths:
engines/dgds/clock.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index f7c8b4dec5d..4631ba5bcde 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -49,6 +49,8 @@ public:
void update(bool gameRunning);
+ int16 getMins() const { return _mins; }
+
Global *getMinsGlobal(uint16 num);
Global *getHoursGlobal(uint16 num);
Global *getDaysGlobal(uint16 num);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index e20d3aa0bde..6b45dbadbf6 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -134,8 +134,8 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpOpenGameOverMenu: return "openGameOverMenu";
case kSceneOpTiredDialog: return "openTiredDialog";
case kSceneOpArcadeTick: return "sceneOpArcadeTick";
- case kSceneOp105: return "sceneOp105";
- case kSceneOp106: return "sceneOp106";
+ case kSceneOpDrawDragonCountdown1: return "drawDragonCountdown1";
+ case kSceneOpDrawDragonCountdown2: return "drawDragonCountdown2";
case kSceneOpOpenPlaySkipIntroMenu: return "openPlaySkipIntroMovie";
case kSceneOpOpenBetterSaveGameMenu: return "openBetterSaveGameMenu";
default:
@@ -500,6 +500,16 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
}
}
+static void _drawDragonCountdown(FontManager::FontType fontType, int16 x, int16 y) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ int16 countdownEnd = engine->getGameGlobals()->getGlobal(0x22);
+ int16 currentMins = engine->getClock().getMins();
+ const Font *fnt = engine->getFontMan()->getFont(fontType);
+ Common::String str = Common::String::format("%d", countdownEnd - currentMins);
+ fnt->drawString(&engine->_compositionBuffer, str, x, y, 320 - x, 10);
+
+}
+
bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 */) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
@@ -605,16 +615,18 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
engine->getScene()->addAndShowTiredDialog();
break;
case kSceneOpArcadeTick:
- // TODO: Implement this properly! for now jsut
+ // TODO: Implement this properly! for now just
// set the global arcade state variable to the "skip" value.
warning("Setting arcade global to 8 (skip)");
g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
engine->getGameGlobals()->setGlobal(0x21, 6);
break;
- case kSceneOp105:
- error("TODO: Implement sceneOp105");
- case kSceneOp106:
- error("TODO: Implement sceneOp106");
+ case kSceneOpDrawDragonCountdown1:
+ _drawDragonCountdown(FontManager::k4x5Font, 141, 56);
+ break;
+ case kSceneOpDrawDragonCountdown2:
+ _drawDragonCountdown(FontManager::k8x8Font, 250, 42);
+ break;
case kSceneOpOpenPlaySkipIntroMenu:
static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuSkipPlayIntro);
break;
@@ -850,6 +862,9 @@ void SDSScene::addAndShowTiredDialog() {
}
+// The first row of this array corresponds to the
+// positions of buttons in game passcode
+// RYP YWP YRPWRY PBW
static const uint16 DRAGON_PASSCODE[] = {
1, 4, 3, 4, 0, 3, 4, 1, 3, 0, 1, 4, 3, 2, 0,
4, 4, 2, 3, 4, 0, 0, 4, 3, 2, 1, 1, 2, 4, 0,
@@ -866,45 +881,58 @@ void SDSScene::sceneOpUpdatePasscodeGlobal() {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int16 globalval = engine->getGDSScene()->getGlobal(0x20);
- if (globalval > 33)
+ if (globalval > 34)
return;
if (globalval >= 30) {
+ // One of the keypad buttons
if (DRAGON_PASSCODE[passcodeVal4 + passcodeBlockNum * 15] == globalval - 30) {
+ debug("sceneOpUpdatePasscodeGlobal CORRECT: variables %d %d %d %d block %d, curval %d",
+ passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
+
+ // Correct entry! Increment the expected button
passcodeVal4++;
if (passcodeVal4 < passcodeVal3) {
globalval = 0;
} else if (passcodeVal3 < 15) {
globalval = 5;
} else {
+ // Finished!
globalval = 6;
}
} else {
- passcodeVal1 = 5;
- passcodeVal2 = 0;
+ // Mistake
+ debug("sceneOpUpdatePasscodeGlobal WRONG: variables %d %d %d %d block %d, curval %d",
+ passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
+ passcodeVal1 = 0;
+ passcodeVal2 = 5;
globalval = 7;
}
} else {
- if (globalval > 4)
+ if (globalval > 4 || globalval == 0)
return;
+ debug("sceneOpUpdatePasscodeGlobal OTHER: variables %d %d %d %d block %d, curval %d",
+ passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
+
if (globalval < 4) {
- passcodeBlockNum = globalval - 1;
+ passcodeBlockNum = globalval - 1; // expect block globalval-1
passcodeVal1 = 5;
passcodeVal2 = 0;
- passcodeVal3 = 15;
+ passcodeVal3 = 15; // 15 buttons expected
passcodeVal4 = 0;
- } else if (passcodeVal1 > passcodeVal2) {
- passcodeVal2++;
- globalval = DRAGON_PASSCODE[passcodeVal2 + passcodeBlockNum * 15] + 20;
- } else if (passcodeVal1 > 14) {
- passcodeVal2 = 0;
- passcodeVal3 = passcodeVal1;
+ return;
+ } else if (passcodeVal2 > passcodeVal1) {
+ passcodeVal1++;
+ globalval = DRAGON_PASSCODE[passcodeVal1 + passcodeBlockNum * 15] + 20;
+ } else if (passcodeVal2 > 14) {
+ passcodeVal1 = 0;
+ passcodeVal3 = passcodeVal2;
passcodeVal4 = 0;
globalval = 8;
} else {
- passcodeVal1 += 5;
- passcodeVal2 = 0;
+ passcodeVal1 = 0;
+ passcodeVal2 += 5;
passcodeVal3 = passcodeVal1;
passcodeVal4 = 0;
globalval = 8;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index e389acbe84b..de22af3cd0d 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -106,8 +106,8 @@ enum SceneOpCode {
kSceneOpOpenGameOverMenu = 102, // args: none.
kSceneOpTiredDialog = 103, // args: none. Something about "boy am I tired"?
kSceneOpArcadeTick = 104, // args: none. Called in arcade post-tick.
- kSceneOp105 = 105, // args: none. Draw some number at 141, 56
- kSceneOp106 = 106, // args: none. Draw some number at 250, 42
+ kSceneOpDrawDragonCountdown1 = 105, // args: none. Draw special countdown number at 141, 56
+ kSceneOpDrawDragonCountdown2 = 106, // args: none. Draw some number at 250, 42
kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. DRAGON: Show menu 50, the "Play Introduction" / "Skip Introduction" menu.
kSceneOpOpenBetterSaveGameMenu = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
};
@@ -127,7 +127,7 @@ public:
Common::Array<SceneOp> opList5;
uint16 _altCursor;
uint16 _iconNum;
-
+
// mutable values
uint16 _inSceneNum;
uint16 _flags;
@@ -154,13 +154,13 @@ public:
ObjectInteraction(uint16 dropped, uint16 target) : _droppedItemNum(dropped), _targetItemNum(target) {}
Common::Array<SceneOp> opList;
-
+
bool matches(uint16 droppedItemNum, uint16 targetItemNum) const {
return _droppedItemNum == droppedItemNum && _targetItemNum == targetItemNum;
}
Common::String dump(const Common::String &indent) const;
-
+
private:
uint16 _droppedItemNum;
uint16 _targetItemNum;
@@ -247,6 +247,9 @@ protected:
void setItemAttrOp(const Common::Array<uint16> &args);
void setDragItemOp(const Common::Array<uint16> &args);
+ void drawDragonCountdown1();
+ void drawDragonCountdown2();
+
uint32 _magic;
Common::String _version;
Commit: bed15d2533981a902c2c1cc819902482e1e89824
https://github.com/scummvm/scummvm/commit/bed15d2533981a902c2c1cc819902482e1e89824
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Whitespace fixes
Changed paths:
engines/dgds/console.cpp
engines/dgds/dgds.h
engines/dgds/font.h
engines/dgds/image.cpp
engines/dgds/metaengine.cpp
engines/dgds/music.cpp
engines/dgds/resource.cpp
engines/dgds/scene.cpp
engines/dgds/sound.h
engines/dgds/ttm.cpp
diff --git a/engines/dgds/console.cpp b/engines/dgds/console.cpp
index 66a76048a47..0e794186120 100644
--- a/engines/dgds/console.cpp
+++ b/engines/dgds/console.cpp
@@ -145,7 +145,7 @@ bool Console::cmdFileDump(int argc, const char **argv) {
}
delete[] data;
- return true;
+ return true;
}
bool Console::dumpImageFrame(const char *fname, int frameno, const char *outpath) {
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 55d18c93cb1..bfd122bf327 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -183,15 +183,15 @@ public:
return syncGame(s);
}
- bool hasFeature(EngineFeature f) const override {
- return
- (f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime);
- };
-
- void setBackgroundFile(const Common::String &name) { _backgroundFile = name; }
- const Common::String &getBackgroundFile() const { return _backgroundFile; }
- void setMenuToTrigger(MenuId menu) { _menuToTrigger = menu; }
+ bool hasFeature(EngineFeature f) const override {
+ return
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+ };
+
+ void setBackgroundFile(const Common::String &name) { _backgroundFile = name; }
+ const Common::String &getBackgroundFile() const { return _backgroundFile; }
+ void setMenuToTrigger(MenuId menu) { _menuToTrigger = menu; }
private:
Common::Error syncGame(Common::Serializer &s);
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index d00e221d855..bf01b840faf 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -51,7 +51,7 @@ public:
int getFontHeight() const { return _h; }
int getMaxCharWidth() const { return _w; }
virtual int getCharWidth(uint32 chr) const = 0;
- void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const;
+ void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const;
static Font *load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
protected:
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 17cc56a1508..8cae809086a 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -166,7 +166,7 @@ void Image::loadBitmap(const Common::String &filename) {
mh = stream->readUint16LE();
uint32 mcount = uint32(mw) * mh;
mtxVals.resize(mcount);
- debug(" %ux%u: mtx vals", mw, mh);
+ debug(" %ux%u: mtx vals", mw, mh);
for (uint32 k = 0; k < mcount; k++) {
uint16 tile;
@@ -322,108 +322,108 @@ struct VQTDecodeState {
};
static inline uint16 _getVqtBits(struct VQTDecodeState *state, int nbits) {
- const uint32 offset = state->offset;
- const uint32 index = offset >> 3;
- const uint32 shift = offset & 7;
- state->offset += nbits;
- return (*(const uint16 *)(state->srcPtr + index) >> (shift)) & (byte)(0xff00 >> (16 - nbits));
+ const uint32 offset = state->offset;
+ const uint32 index = offset >> 3;
+ const uint32 shift = offset & 7;
+ state->offset += nbits;
+ return (*(const uint16 *)(state->srcPtr + index) >> (shift)) & (byte)(0xff00 >> (16 - nbits));
}
static void _doVqtDecode2(struct VQTDecodeState *state, const uint16 x, const uint16 y, const uint16 w, const uint16 h) {
- // Empty region -> nothing to do
- if (h == 0 || w == 0)
- return;
-
- // 1x1 region -> put the byte directly
- if (w == 1 && h == 1) {
- state->dstPtr[state->rowStarts[y] + x] = _getVqtBits(state, 8);
- return;
- }
-
- const uint losize = (w & 0xff) * (h & 0xff);
- uint bitcount1 = 8;
- if (losize < 256) {
- bitcount1 = 0;
- byte b = (byte)(losize - 1);
- do {
- bitcount1++;
- b >>= 1;
- } while (b != 0);
- }
-
- uint16 firstval = _getVqtBits(state, bitcount1);
-
- uint16 bitcount2 = 0;
- byte bval = (byte)firstval;
- while (firstval != 0) {
- bitcount2++;
- firstval >>= 1;
- }
-
- bval++;
-
- if (losize * 8 <= losize * bitcount2 + bval * 8) {
- for (int xx = x; xx < x + w; xx++) {
- for (int yy = y; yy < y + h; yy++) {
- state->dstPtr[state->rowStarts[yy] + xx] = _getVqtBits(state, 8);
- }
- }
- return;
- }
-
- if (bval == 1) {
- const uint16 val = _getVqtBits(state, 8);
- for (int yy = y; yy < y + h; yy++) {
- for (int xx = x; xx < x + w; xx++) {
- state->dstPtr[state->rowStarts[yy] + xx] = val;
- }
- }
- return;
- }
-
- byte tmpbuf[262];
- byte *ptmpbuf = tmpbuf;
- for (; bval != 0; bval--) {
- *ptmpbuf = _getVqtBits(state, 8);
- ptmpbuf++;
- }
-
- for (int xx = x; xx < x + w; xx++) {
- for (int yy = y; yy < y + h; yy++) {
- state->dstPtr[state->rowStarts[yy] + xx] = tmpbuf[_getVqtBits(state, bitcount2)];
- }
- }
+ // Empty region -> nothing to do
+ if (h == 0 || w == 0)
+ return;
+
+ // 1x1 region -> put the byte directly
+ if (w == 1 && h == 1) {
+ state->dstPtr[state->rowStarts[y] + x] = _getVqtBits(state, 8);
+ return;
+ }
+
+ const uint losize = (w & 0xff) * (h & 0xff);
+ uint bitcount1 = 8;
+ if (losize < 256) {
+ bitcount1 = 0;
+ byte b = (byte)(losize - 1);
+ do {
+ bitcount1++;
+ b >>= 1;
+ } while (b != 0);
+ }
+
+ uint16 firstval = _getVqtBits(state, bitcount1);
+
+ uint16 bitcount2 = 0;
+ byte bval = (byte)firstval;
+ while (firstval != 0) {
+ bitcount2++;
+ firstval >>= 1;
+ }
+
+ bval++;
+
+ if (losize * 8 <= losize * bitcount2 + bval * 8) {
+ for (int xx = x; xx < x + w; xx++) {
+ for (int yy = y; yy < y + h; yy++) {
+ state->dstPtr[state->rowStarts[yy] + xx] = _getVqtBits(state, 8);
+ }
+ }
+ return;
+ }
+
+ if (bval == 1) {
+ const uint16 val = _getVqtBits(state, 8);
+ for (int yy = y; yy < y + h; yy++) {
+ for (int xx = x; xx < x + w; xx++) {
+ state->dstPtr[state->rowStarts[yy] + xx] = val;
+ }
+ }
+ return;
+ }
+
+ byte tmpbuf[262];
+ byte *ptmpbuf = tmpbuf;
+ for (; bval != 0; bval--) {
+ *ptmpbuf = _getVqtBits(state, 8);
+ ptmpbuf++;
+ }
+
+ for (int xx = x; xx < x + w; xx++) {
+ for (int yy = y; yy < y + h; yy++) {
+ state->dstPtr[state->rowStarts[yy] + xx] = tmpbuf[_getVqtBits(state, bitcount2)];
+ }
+ }
}
static void _doVqtDecode(struct VQTDecodeState *state, uint16 x, uint16 y, uint16 w, uint16 h) {
- if (!w && !h)
- return;
-
- const uint16 mask = _getVqtBits(state, 4);
-
- // Top left quadrant
- if (mask & 8)
- _doVqtDecode(state, x, y, w / 2, h / 2);
- else
- _doVqtDecode2(state, x, y, w / 2, h / 2);
-
- // Top right quadrant
- if (mask & 4)
- _doVqtDecode(state, x + (w / 2), y, (w + 1) >> 1, h >> 1);
- else
- _doVqtDecode2(state, x + (w / 2), y, (w + 1) >> 1, h >> 1);
-
- // Bottom left quadrant
- if (mask & 2)
- _doVqtDecode(state, x, y + (h / 2), w / 2, (h + 1) / 2);
- else
- _doVqtDecode2(state, x, y + (h / 2), w / 2, (h + 1) / 2);
-
- // Bottom right quadrant
- if (mask & 1)
- _doVqtDecode(state, x + (w / 2), y + (h / 2), (w + 1) / 2, (h + 1) / 2);
- else
- _doVqtDecode2(state, x + (w / 2), y + (h / 2), (w + 1) / 2, (h + 1) / 2);
+ if (!w && !h)
+ return;
+
+ const uint16 mask = _getVqtBits(state, 4);
+
+ // Top left quadrant
+ if (mask & 8)
+ _doVqtDecode(state, x, y, w / 2, h / 2);
+ else
+ _doVqtDecode2(state, x, y, w / 2, h / 2);
+
+ // Top right quadrant
+ if (mask & 4)
+ _doVqtDecode(state, x + (w / 2), y, (w + 1) >> 1, h >> 1);
+ else
+ _doVqtDecode2(state, x + (w / 2), y, (w + 1) >> 1, h >> 1);
+
+ // Bottom left quadrant
+ if (mask & 2)
+ _doVqtDecode(state, x, y + (h / 2), w / 2, (h + 1) / 2);
+ else
+ _doVqtDecode2(state, x, y + (h / 2), w / 2, (h + 1) / 2);
+
+ // Bottom right quadrant
+ if (mask & 1)
+ _doVqtDecode(state, x + (w / 2), y + (h / 2), (w + 1) / 2, (h + 1) / 2);
+ else
+ _doVqtDecode2(state, x + (w / 2), y + (h / 2), (w + 1) / 2, (h + 1) / 2);
}
diff --git a/engines/dgds/metaengine.cpp b/engines/dgds/metaengine.cpp
index 83a3c4e8711..c2eaac53c64 100644
--- a/engines/dgds/metaengine.cpp
+++ b/engines/dgds/metaengine.cpp
@@ -39,11 +39,11 @@ public:
bool DgdsMetaEngine::hasFeature(MetaEngineFeature f) const {
return checkExtendedSaves(f) ||
(f == kSupportsListSaves) ||
- (f == kSupportsLoadingDuringStartup) ||
- (f == kSupportsDeleteSave) ||
- (f == kSavesSupportMetaInfo) ||
- (f == kSavesSupportThumbnail) ||
- (f == kSimpleSavesNames);
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSimpleSavesNames);
}
Common::Error DgdsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/dgds/music.cpp b/engines/dgds/music.cpp
index 9816df7829c..8d50261aceb 100644
--- a/engines/dgds/music.cpp
+++ b/engines/dgds/music.cpp
@@ -93,7 +93,7 @@ void MidiParser_DGDS::parseNextEvent(EventInfo &info) {
_position._runningStatus = info.event;
switch (info.command()) {
- case 0x9:
+ case 0x9:
info.basic.param1 = *_position._playPos++;
info.basic.param2 = *_position._playPos++;
if (info.basic.param2 == 0) {
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index fbcf4de6fc8..9c8cb1d1cd2 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -37,10 +37,10 @@ static const int FILENAME_LENGTH = 12;
ResourceManager::ResourceManager() {
const char *indexFiles[] = {
- "volume.vga", // Dragon VGA versions
- "volume.ega", // Dragon EGA versions
- "volume.rmf", // Beamish / HoC
- "volume.map" // Beamish CD
+ "volume.vga", // Dragon VGA versions
+ "volume.ega", // Dragon EGA versions
+ "volume.rmf", // Beamish / HoC
+ "volume.map" // Beamish CD
};
Common::File indexFile;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 6b45dbadbf6..8cbbe20235b 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -507,7 +507,6 @@ static void _drawDragonCountdown(FontManager::FontType fontType, int16 x, int16
const Font *fnt = engine->getFontMan()->getFont(fontType);
Common::String str = Common::String::format("%d", countdownEnd - currentMins);
fnt->drawString(&engine->_compositionBuffer, str, x, y, 320 - x, 10);
-
}
bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 */) {
@@ -925,12 +924,12 @@ void SDSScene::sceneOpUpdatePasscodeGlobal() {
} else if (passcodeVal2 > passcodeVal1) {
passcodeVal1++;
globalval = DRAGON_PASSCODE[passcodeVal1 + passcodeBlockNum * 15] + 20;
- } else if (passcodeVal2 > 14) {
+ } else if (passcodeVal2 > 14) {
passcodeVal1 = 0;
passcodeVal3 = passcodeVal2;
passcodeVal4 = 0;
globalval = 8;
- } else {
+ } else {
passcodeVal1 = 0;
passcodeVal2 += 5;
passcodeVal3 = passcodeVal1;
@@ -1599,10 +1598,10 @@ void GDSScene::globalOps(const Common::Array<uint16> &args) {
// Off means val is another global to lookup
if (op & 8)
op = op & 0xfff7;
- else
+ else
val = getGlobal((uint16)val);
- if (op == 1)
+ if (op == 1)
val = num2 + val;
else if (op == 6)
val = (val == 0);
diff --git a/engines/dgds/sound.h b/engines/dgds/sound.h
index 230e6235cd9..3d8b9e33548 100644
--- a/engines/dgds/sound.h
+++ b/engines/dgds/sound.h
@@ -81,10 +81,10 @@ private:
};
enum {
- DIGITAL_PCM = 1 << 0,
- TRACK_ADLIB = 1 << 1,
- TRACK_GM = 1 << 2,
- TRACK_MT32 = 1 << 3
+ DIGITAL_PCM = 1 << 0,
+ TRACK_ADLIB = 1 << 1,
+ TRACK_GM = 1 << 2,
+ TRACK_MT32 = 1 << 3
};
byte loadSndTrack(uint32 track, const byte** trackPtr, uint16* trackSiz, const byte *data, uint32 size);
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 934dd695081..ad31832e0e5 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-
+
#include "common/rect.h"
#include "common/serializer.h"
@@ -868,20 +868,20 @@ void TTMSeq::reset() {
_currentPalId = 0;
_currentBmpId = 0;
_currentGetPutId = 0;
- _currentFrame = _startFrame;
- _gotoFrame = -1;
- _drawColBG = 0xf;
- _drawColFG = 0xf;
- _brushNum = 0;
- _timeInterval = 0;
- _timeNext = 0;
- _runCount = 0;
- _runPlayed = 0;
- _executed = false;
- _runFlag = kRunTypeStopped;
- _scriptFlag = 0;
- _selfLoop = false;
- _drawWin = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
+ _currentFrame = _startFrame;
+ _gotoFrame = -1;
+ _drawColBG = 0xf;
+ _drawColFG = 0xf;
+ _brushNum = 0;
+ _timeInterval = 0;
+ _timeNext = 0;
+ _runCount = 0;
+ _runPlayed = 0;
+ _executed = false;
+ _runFlag = kRunTypeStopped;
+ _scriptFlag = 0;
+ _selfLoop = false;
+ _drawWin = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT);
}
Commit: a16c8955cded7deb86f40c9786211e90a6e049be
https://github.com/scummvm/scummvm/commit/a16c8955cded7deb86f40c9786211e90a6e049be
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Update includes
Changed paths:
engines/dgds/clock.h
engines/dgds/dialog.h
engines/dgds/inventory.h
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index 4631ba5bcde..17671532765 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -24,6 +24,7 @@
#include "common/types.h"
#include "common/rect.h"
+#include "common/error.h"
#include "common/serializer.h"
namespace Graphics {
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index e6246d801c1..2098df45166 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -24,6 +24,7 @@
#include "common/stream.h"
#include "common/array.h"
+#include "common/error.h"
#include "common/rect.h"
#include "common/serializer.h"
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 225e9b9cd67..6b272309baf 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -23,6 +23,7 @@
#define DGDS_INVENTORY_H
#include "common/serializer.h"
+#include "common/error.h"
#include "dgds/request.h"
namespace Graphics {
Commit: f7baf88cf2c6637cf09529d09a9e75ba42e0b4b2
https://github.com/scummvm/scummvm/commit/f7baf88cf2c6637cf09529d09a9e75ba42e0b4b2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Cleanups, remove excessive casts
Changed paths:
engines/dgds/clock.cpp
engines/dgds/dialog.cpp
engines/dgds/includes.h
engines/dgds/inventory.cpp
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index cdd8cb3a0b9..82b94802c05 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -123,8 +123,7 @@ void Clock::draw(Graphics::ManagedSurface &surf) {
const Common::String clockStr = getTimeStr();
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
+ const FontManager *fontman = static_cast<DgdsEngine *>(g_engine)->getFontMan();
const Font *font = fontman->getFont(FontManager::k4x5Font);
int width = font->getMaxCharWidth() * 12 + 3;
_drawPos.top = 0;
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 113a47369a8..d380d6a8ff5 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -84,8 +84,7 @@ static void _drawPixel(int x, int y, int color, void *data) {
const Font *Dialog::getDlgTextFont() const {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const FontManager *fontman = engine->getFontMan();
+ const FontManager *fontman = static_cast<DgdsEngine *>(g_engine)->getFontMan();
FontManager::FontType fontType = FontManager::kGameDlgFont;
if (_fontSize == 1)
fontType = FontManager::k8x8Font;
diff --git a/engines/dgds/includes.h b/engines/dgds/includes.h
index 27185991c28..40dfdbddb73 100644
--- a/engines/dgds/includes.h
+++ b/engines/dgds/includes.h
@@ -25,7 +25,6 @@
namespace Dgds {
-// TODO: Remove
#define MKTAG24(a0, a1, a2) ((uint32)((a2) | (a1) << 8 | ((a0) << 16)))
#define ID_BIN MKTAG24('B', 'I', 'N')
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index b12cddebe9a..474196f7f9c 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -230,10 +230,10 @@ void Inventory::mouseMoved(const Common::Point &pt) {
}
GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (!_itemArea)
return nullptr;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
if (_itemArea->containsPoint(pt)) {
const int imgAreaX = _itemArea->_parentX + _itemArea->_x;
@@ -258,13 +258,14 @@ GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
}
void Inventory::mouseLDown(const Common::Point &pt) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
RequestData &boxreq = _reqData._requests[0];
// Ignore this, and close on mouseup.
if (!boxreq._rect.contains(pt))
return;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
if (engine->getScene()->hasVisibleDialog() || !_itemBox->containsPoint(pt)) {
return engine->getScene()->mouseLDown(pt);
} else {
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 2deb1549b81..14f661bc6a5 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -358,8 +358,8 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
break;
case kMenuIntroSkip:
hideMenu();
- static_cast<DgdsEngine *>(g_engine)->setShowClock(true);
- static_cast<DgdsEngine *>(g_engine)->changeScene(5);
+ engine->setShowClock(true);
+ engine->changeScene(5);
break;
case kMenuQuitYes:
g_engine->quitGame();
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 4ae87a348df..5df5f00ace2 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -473,8 +473,7 @@ void SliderGadget::draw(Graphics::ManagedSurface *dst) const {
dst->fillRect(fillrect, SliderColors[6]);
// Draw the slider control in the right spot
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
+ const Image *uiCorners = RequestData::getCorners();
uiCorners->drawBitmap(SLIDER_HANDLE_FRAME, x + _handleX, y, Common::Rect(0, 0, 320, 200), *dst);
}
@@ -483,7 +482,7 @@ SliderGadget::SliderGadget() : _lock(false), _steps(0), _gadget2_i1(0),
}
int16 SliderGadget::getHandleWidth() const {
- const Common::SharedPtr<Image> uiCorners = static_cast<DgdsEngine *>(g_engine)->getUICorners();
+ const Image *uiCorners = RequestData::getCorners();
int16 handleWidth = uiCorners->width(SLIDER_HANDLE_FRAME);
return handleWidth - 2;
}
@@ -654,20 +653,17 @@ void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
/*static*/
const Font *RequestData::getMenuFont() {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- return engine->getFontMan()->getFont(FontManager::kGameFont);
+ return static_cast<DgdsEngine *>(g_engine)->getFontMan()->getFont(FontManager::kGameFont);
}
/*static*/
const Image *RequestData::getCorners() {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- return engine->getUICorners().get();
+ return static_cast<DgdsEngine *>(g_engine)->getUICorners().get();
}
/*static*/
void RequestData::drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
+ const Image *uiCorners = RequestData::getCorners();
assert(uiCorners->loadedFrameCount() > startNum + 7);
const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &cframes = uiCorners->getFrames();
const Common::SharedPtr<Graphics::ManagedSurface> *corners = cframes.data() + startNum;
@@ -722,8 +718,7 @@ void RequestData::drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, in
fillBackground(dst, x + 9, y + 8, width - 18, sliderHeight + 2, 8);
fillBackground(dst, x + 17, y + 8 + sliderHeight + 2, width - 34, height - sliderBgHeight, 32 - sliderBgHeight);
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Common::SharedPtr<Image> uiCorners = engine->getUICorners();
+ const Image *uiCorners = RequestData::getCorners();
assert(uiCorners->loadedFrameCount() >= 11);
const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &corners = uiCorners->getFrames();
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index 34c91c4a7ca..c4adc55dc0c 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -194,7 +194,7 @@ public:
void drawInvType(Graphics::ManagedSurface *dst);
static const Font *getMenuFont();
- const Image *getCorners();
+ static const Image *getCorners();
static void fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
static void drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8cbbe20235b..016a5d0d351 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -418,10 +418,10 @@ bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<Di
void Scene::setItemAttrOp(const Common::Array<uint16> &args) {
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
if (args.size() < 3)
error("Expect 3 args for item attr opcode.");
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (auto &item : engine->getGDSScene()->getGameItems()) {
if (item._num != args[0])
continue;
@@ -593,21 +593,21 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
CursorMan.showMouse(false);
break;
case kSceneOpPasscode:
- static_cast<DgdsEngine *>(g_engine)->getScene()->sceneOpUpdatePasscodeGlobal();
+ engine->getScene()->sceneOpUpdatePasscodeGlobal();
break;
case kSceneOpMeanwhile:
// TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway.
// Probably need to do something here to avoid flashing..
- //static_cast<DgdsEngine *>(g_engine)->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ //engine->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
break;
case kSceneOpShowInvButton:
- static_cast<DgdsEngine *>(g_engine)->getScene()->addInvButtonToHotAreaList();
+ engine->getScene()->addInvButtonToHotAreaList();
break;
case kSceneOpHideInvButton:
- static_cast<DgdsEngine *>(g_engine)->getScene()->removeInvButtonFromHotAreaList();
+ engine->getScene()->removeInvButtonFromHotAreaList();
break;
case kSceneOpOpenGameOverMenu:
- static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuGameOver);
+ engine->setMenuToTrigger(kMenuGameOver);
break;
case kSceneOpTiredDialog:
engine->getInventory()->close();
@@ -627,10 +627,10 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
_drawDragonCountdown(FontManager::k8x8Font, 250, 42);
break;
case kSceneOpOpenPlaySkipIntroMenu:
- static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuSkipPlayIntro);
+ engine->setMenuToTrigger(kMenuSkipPlayIntro);
break;
case kSceneOpOpenBetterSaveGameMenu:
- static_cast<DgdsEngine *>(g_engine)->setMenuToTrigger(kMenuBetterSaveGame);
+ engine->setMenuToTrigger(kMenuBetterSaveGame);
break;
default:
warning("TODO: Implement scene op %d", op._opCode);
@@ -1135,13 +1135,12 @@ void SDSScene::globalOps(const Common::Array<uint16> &args) {
void SDSScene::mouseMoved(const Common::Point &pt) {
Dialog *dlg = getVisibleDialog();
const HotArea *area = findAreaUnderMouse(pt);
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int16 cursorNum = (!dlg && area) ? area->_cursorNum : 0;
if (_dragItem)
cursorNum = _dragItem->_iconNum;
- engine->setMouseCursor(cursorNum);
+ static_cast<DgdsEngine *>(g_engine)->setMouseCursor(cursorNum);
}
void SDSScene::mouseLDown(const Common::Point &pt) {
Commit: dd0bacd947a80d861633060e4ca326e8a7f698c9
https://github.com/scummvm/scummvm/commit/dd0bacd947a80d861633060e4ca326e8a7f698c9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Improvements for China
Now plays opening credits to the end. Still some rendering artifacts.
Changed paths:
engines/dgds/dgds.h
engines/dgds/font.cpp
engines/dgds/menu.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/ttm.cpp
engines/dgds/ttm.h
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index bfd122bf327..e3072ac41ba 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -137,6 +137,7 @@ public:
Graphics::ManagedSurface &getBackgroundBuffer() { return _backgroundBuffer; }
Graphics::ManagedSurface &getStoredAreaBuffer() { return _storedAreaBuffer; }
+ // Various game engine singletons
Common::SeekableReadStream *getResource(const Common::String &name, bool ignorePatches);
ResourceManager *getResourceManager() { return _resource; }
Decompressor *getDecompressor() { return _decompressor; }
@@ -146,29 +147,29 @@ public:
const FontManager *getFontMan() const { return _fontManager; }
const Common::SharedPtr<Image> &getUICorners() { return _corners; }
const Common::SharedPtr<Image> &getIcons() { return _icons; }
- bool changeScene(int sceneNum);
GamePalettes *getGamePals() { return _gamePals; }
Globals *getGameGlobals() { return _gameGlobals; }
Inventory *getInventory() { return _inventory; }
+ Clock &getClock() { return _clock; }
+ ADSInterpreter *adsInterpreter() { return _adsInterp; }
+ Common::RandomSource &getRandom() { return _random; }
+
+ bool changeScene(int sceneNum);
void setMouseCursor(uint num);
int getTextSpeed() const { return _textSpeed; }
void setTextSpeed(int16 speed) { _textSpeed = speed; }
int16 getDifficulty() const { return _difficulty; }
- void setDetailLevel(DgdsDetailLevel level) { _detailLevel = level; }
- DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
void setDifficulty(int16 difficulty) { _difficulty = difficulty; }
+ DgdsDetailLevel getDetailLevel() const { return _detailLevel; }
+ void setDetailLevel(DgdsDetailLevel level) { _detailLevel = level; }
void setShowClock(bool val);
- ADSInterpreter *adsInterpreter() { return _adsInterp; }
bool justChangedScene1() const { return _justChangedScene1; }
bool justChangedScene2() const { return _justChangedScene2; }
- Common::RandomSource &getRandom() { return _random; }
Common::Point getLastMouse() const { return _lastMouse; }
Common::Point getLastMouseMinusHot() const;
- Clock &getClock() { return _clock; }
-
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveAutosaveCurrently() override;
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index ed373cefacc..6864ccb9651 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -226,6 +226,10 @@ FontManager::FontType FontManager::fontTypeByName(const Common::String &filename
if (filename == "WILLY.FNT") return kGameFont;
if (filename == "WVCR.FNT") return kWVCRFont;
if (filename == "COMIX_16.FNT") return kGameDlgFont;
+ if (filename == "EXIT.FNT") return kDefaultFont;
+ if (filename == "SSM1_12.FNT") return kGameFont;
+ if (filename == "SSM1_15.FNT") return kGameDlgFont;
+ if (filename == "SSM1_30.FNT") return kWVCRFont;
return FontManager::kDefaultFont;
}
@@ -233,9 +237,11 @@ FontManager::FontType FontManager::fontTypeByName(const Common::String &filename
void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompressor *decomp) {
if (gameId == GID_SQ5DEMO || gameId == GID_COMINGSOON) {
tryLoadFont("EXIT.FNT", resMgr, decomp);
- //tryLoadFont("SSM1_12.FNT", resMgr, decomp);
- //tryLoadFont("SSM1_15.FNT", resMgr, decomp);
- //tryLoadFont("SSM1_30.FNT", resMgr, decomp);
+ if (gameId == GID_SQ5DEMO) {
+ tryLoadFont("SSM1_12.FNT", resMgr, decomp);
+ tryLoadFont("SSM1_15.FNT", resMgr, decomp);
+ tryLoadFont("SSM1_30.FNT", resMgr, decomp);
+ }
return;
}
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index 73dcab82d9f..f4eaf021fe0 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -65,6 +65,8 @@ enum MenuId {
kMenuSkipPlayIntro = 18,
kMenuBetterSaveGame = 19, // save game before arcade
// 20: replay arcade
+ kMenuChina1 = 41,
+ kMenuChinaSkipCredits = 50,
};
class Menu {
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 016a5d0d351..8b405901273 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -509,6 +509,158 @@ static void _drawDragonCountdown(FontManager::FontType fontType, int16 x, int16
fnt->drawString(&engine->_compositionBuffer, str, x, y, 320 - x, 10);
}
+
+bool Scene::runSceneOp(const SceneOp &op) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ switch (op._opCode) {
+ case kSceneOpChangeScene:
+ if (engine->changeScene(op._args[0]))
+ // This probably reset the list - stop now.
+ return false;
+ break;
+ case kSceneOpNoop:
+ break;
+ case kSceneOpGlobal:
+ globalOps(op._args);
+ break;
+ case kSceneOpSegmentStateOps:
+ segmentStateOps(op._args);
+ break;
+ case kSceneOpSetItemAttr:
+ setItemAttrOp(op._args);
+ break;
+ case kSceneOpSetDragItem:
+ setDragItemOp(op._args);
+ break;
+ case kSceneOpOpenInventory:
+ engine->getInventory()->open();
+ // This implicitly changes scene num
+ return false;
+ case kSceneOpShowDlg:
+ showDialog(op._args[0]);
+ break;
+ case kSceneOpShowInvButton:
+ engine->getScene()->addInvButtonToHotAreaList();
+ break;
+ case kSceneOpHideInvButton:
+ engine->getScene()->removeInvButtonFromHotAreaList();
+ break;
+ case kSceneOpEnableTrigger:
+ enableTrigger(op._args[0]);
+ break;
+ case kSceneOpChangeSceneToStored: {
+ uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
+ if (engine->changeScene(sceneNo))
+ // This probably reset the list - stop now.
+ return false;
+ break;
+ }
+ case kSceneOpAddFlagToDragItem: {
+ GameItem *item = engine->getScene()->getDragItem();
+ if (item) {
+ item->_flags |= 1;
+ // TODO: Use hot x/y or just position?
+ Common::Point lastMouse = engine->getLastMouseMinusHot();
+ item->_rect.x = lastMouse.x;
+ item->_rect.y = lastMouse.y;
+ }
+ break;
+ }
+ case kSceneOpOpenInventoryZoom:
+ engine->getInventory()->setShowZoomBox(true);
+ engine->getInventory()->open();
+ return false;
+ case kSceneOpMoveItemsBetweenScenes: {
+ int16 fromScene = engine->getGameGlobals()->getGlobal(0x55);
+ int16 toScene = engine->getGameGlobals()->getGlobal(0x54);
+ for (auto &item : engine->getGDSScene()->getGameItems()) {
+ if (item._inSceneNum == fromScene)
+ item._inSceneNum = toScene;
+ }
+ break;
+ }
+ case kSceneOpShowClock:
+ engine->setShowClock(true);
+ break;
+ case kSceneOpHideClock:
+ engine->setShowClock(false);
+ break;
+ case kSceneOpShowMouse:
+ CursorMan.showMouse(true);
+ break;
+ case kSceneOpHideMouse:
+ CursorMan.showMouse(false);
+ break;
+ default:
+ warning("TODO: Implement generic scene op %d", op._opCode);
+ break;
+ }
+ return true;
+}
+
+bool Scene::runDragonOp(const SceneOp &op) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ switch (op._opCode) {
+ case kSceneOpPasscode:
+ engine->getScene()->sceneOpUpdatePasscodeGlobal();
+ break;
+ case kSceneOpMeanwhile:
+ // TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway.
+ // Probably need to do something here to avoid flashing..
+ //engine->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ break;
+ case kSceneOpOpenGameOverMenu:
+ engine->setMenuToTrigger(kMenuGameOver);
+ break;
+ case kSceneOpTiredDialog:
+ engine->getInventory()->close();
+ engine->getScene()->addAndShowTiredDialog();
+ break;
+ case kSceneOpArcadeTick:
+ // TODO: Implement this properly! for now just
+ // set the global arcade state variable to the "skip" value.
+ warning("Setting arcade global to 8 (skip)");
+ g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
+ engine->getGameGlobals()->setGlobal(0x21, 6);
+ break;
+ case kSceneOpDrawDragonCountdown1:
+ _drawDragonCountdown(FontManager::k4x5Font, 141, 56);
+ break;
+ case kSceneOpDrawDragonCountdown2:
+ _drawDragonCountdown(FontManager::k8x8Font, 250, 42);
+ break;
+ case kSceneOpOpenPlaySkipIntroMenu:
+ engine->setMenuToTrigger(kMenuSkipPlayIntro);
+ break;
+ case kSceneOpOpenBetterSaveGameMenu:
+ engine->setMenuToTrigger(kMenuBetterSaveGame);
+ break;
+ default:
+ error("Unexpected Dragon scene opcode %d", op._opCode);
+ break;
+ }
+ return true;
+}
+
+bool Scene::runChinaOp(const SceneOp &op) {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ switch (op._opCode) {
+ case kSceneOpOpenChinaOpenSomeMenu:
+ engine->setMenuToTrigger(kMenuChina1);
+ break;
+ case kSceneOpOpenChinaOpenSkipCreditsMenu:
+ engine->setMenuToTrigger(kMenuChinaSkipCredits);
+ break;
+ case kSceneOpOpenChinaStartIntro:
+ warning("TODO: Implement start intro opcode");
+ break;
+ default:
+ warning("TODO: Implement china-specific scene opcode %d", op._opCode);
+ break;
+ }
+ return true;
+}
+
bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 */) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
@@ -519,123 +671,25 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
engine->getClock().addGameTime(addMinuites);
addMinuites = 0;
}
- switch(op._opCode) {
- case kSceneOpChangeScene:
- if (engine->changeScene(op._args[0]))
- // This probably reset the list - stop now.
- return false;
- break;
- case kSceneOpNoop:
- break;
- case kSceneOpGlobal:
- globalOps(op._args);
- break;
- case kSceneOpSegmentStateOps:
- segmentStateOps(op._args);
- break;
- case kSceneOpSetItemAttr:
- setItemAttrOp(op._args);
- break;
- case kSceneOpSetDragItem:
- setDragItemOp(op._args);
- break;
- case kSceneOpOpenInventory:
- engine->getInventory()->open();
- // This implicitly changes scene num
- return false;
- case kSceneOpShowDlg:
- showDialog(op._args[0]);
- break;
- case kSceneOpEnableTrigger:
- enableTrigger(op._args[0]);
- break;
- case kSceneOpChangeSceneToStored: {
- uint16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
- if (engine->changeScene(sceneNo))
- // This probably reset the list - stop now.
- return false;
- break;
- }
- case kSceneOpAddFlagToDragItem: {
- GameItem *item = engine->getScene()->getDragItem();
- if (item) {
- item->_flags |= 1;
- // TODO: Use hot x/y or just position?
- Common::Point lastMouse = engine->getLastMouseMinusHot();
- item->_rect.x = lastMouse.x;
- item->_rect.y = lastMouse.y;
+ bool keepGoing = true;
+ if (op._opCode < 100) {
+ keepGoing = runSceneOp(op);
+ } else {
+ // Game-specific opcode
+ switch (engine->getGameId()) {
+ case GID_DRAGON:
+ keepGoing = runDragonOp(op);
+ break;
+ case GID_CHINA:
+ keepGoing = runChinaOp(op);
+ break;
+ default:
+ error("TODO: Implement game-specific scene op for this game");
}
- break;
+ continue;
}
- case kSceneOpOpenInventoryZoom:
- engine->getInventory()->setShowZoomBox(true);
- engine->getInventory()->open();
+ if (!keepGoing)
return false;
- case kSceneOpMoveItemsBetweenScenes: {
- int16 fromScene = engine->getGameGlobals()->getGlobal(0x55);
- int16 toScene = engine->getGameGlobals()->getGlobal(0x54);
- for (auto &item : engine->getGDSScene()->getGameItems()) {
- if (item._inSceneNum == fromScene)
- item._inSceneNum = toScene;
- }
- break;
- }
- case kSceneOpShowClock:
- engine->setShowClock(true);
- break;
- case kSceneOpHideClock:
- engine->setShowClock(false);
- break;
- case kSceneOpShowMouse:
- CursorMan.showMouse(true);
- break;
- case kSceneOpHideMouse:
- CursorMan.showMouse(false);
- break;
- case kSceneOpPasscode:
- engine->getScene()->sceneOpUpdatePasscodeGlobal();
- break;
- case kSceneOpMeanwhile:
- // TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway.
- // Probably need to do something here to avoid flashing..
- //engine->_compositionBuffer.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- break;
- case kSceneOpShowInvButton:
- engine->getScene()->addInvButtonToHotAreaList();
- break;
- case kSceneOpHideInvButton:
- engine->getScene()->removeInvButtonFromHotAreaList();
- break;
- case kSceneOpOpenGameOverMenu:
- engine->setMenuToTrigger(kMenuGameOver);
- break;
- case kSceneOpTiredDialog:
- engine->getInventory()->close();
- engine->getScene()->addAndShowTiredDialog();
- break;
- case kSceneOpArcadeTick:
- // TODO: Implement this properly! for now just
- // set the global arcade state variable to the "skip" value.
- warning("Setting arcade global to 8 (skip)");
- g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
- engine->getGameGlobals()->setGlobal(0x21, 6);
- break;
- case kSceneOpDrawDragonCountdown1:
- _drawDragonCountdown(FontManager::k4x5Font, 141, 56);
- break;
- case kSceneOpDrawDragonCountdown2:
- _drawDragonCountdown(FontManager::k8x8Font, 250, 42);
- break;
- case kSceneOpOpenPlaySkipIntroMenu:
- engine->setMenuToTrigger(kMenuSkipPlayIntro);
- break;
- case kSceneOpOpenBetterSaveGameMenu:
- engine->setMenuToTrigger(kMenuBetterSaveGame);
- break;
- default:
- warning("TODO: Implement scene op %d", op._opCode);
- break;
- }
}
return true;
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index de22af3cd0d..022fdb0638a 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -100,7 +100,7 @@ enum SceneOpCode {
kSceneOpShowMouse = 18, // args: none.
kSceneOpHideMouse = 19, // args: none.
- // From here on might be game-specific?
+ // Dragon-specific opcodes
kSceneOpPasscode = 100, // args: none.
kSceneOpMeanwhile = 101, // args: none. Clears screen and displays "meanwhile".
kSceneOpOpenGameOverMenu = 102, // args: none.
@@ -110,6 +110,11 @@ enum SceneOpCode {
kSceneOpDrawDragonCountdown2 = 106, // args: none. Draw some number at 250, 42
kSceneOpOpenPlaySkipIntroMenu = 107, // args: none. DRAGON: Show menu 50, the "Play Introduction" / "Skip Introduction" menu.
kSceneOpOpenBetterSaveGameMenu = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
+
+ // China-specific opcodes
+ kSceneOpOpenChinaOpenSomeMenu = 114, // args: none.
+ kSceneOpOpenChinaOpenSkipCreditsMenu = 115, // args: none.
+ kSceneOpOpenChinaStartIntro = 116, // args: none.
};
class SceneOp {
@@ -250,6 +255,10 @@ protected:
void drawDragonCountdown1();
void drawDragonCountdown2();
+ bool runSceneOp(const SceneOp &op);
+ bool runDragonOp(const SceneOp &op);
+ bool runChinaOp(const SceneOp &op);
+
uint32 _magic;
Common::String _version;
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index ad31832e0e5..002a9ef4be3 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -186,6 +186,8 @@ static const char *ttmOpName(uint16 op) {
case 0xa520: return "DRAW SPRITE FLIP";
case 0xa530: return "DRAW BMP4";
case 0xa600: return "DRAW GETPUT";
+ case 0xb000: return "INIT CREDITS SCROLL";
+ case 0xb010: return "DRAW CREDITS SCROLL";
case 0xf010: return "LOAD SCR";
case 0xf020: return "LOAD BMP";
case 0xf040: return "LOAD FONT";
@@ -210,8 +212,6 @@ static const char *ttmOpName(uint16 op) {
case 0xa400: return "DRAW FILLED CIRCLE";
case 0xa420: return "DRAW EMPTY CIRCLE";
case 0xa510: return "DRAW SPRITE1";
- case 0xb000: return "? (0 args)";
- case 0xb010: return "? (3 args: 30, 2, 19)";
case 0xb600: return "DRAW SCREEN";
case 0xc020: return "LOAD_SAMPLE";
case 0xc030: return "SELECT_SAMPLE";
@@ -362,6 +362,36 @@ void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, c
}
+int16 TTMInterpreter::doOpInitCreditScroll(const Image *img) {
+ assert(img);
+ int16 maxWidth = 0;
+ for (int i = 0; i < img->loadedFrameCount(); i++)
+ maxWidth = MAX(maxWidth, img->width(i));
+ return maxWidth;
+}
+
+ bool TTMInterpreter::doOpCreditsScroll(const Image *img, int16 ygap, int16 ymax, int16 xoff, int16 measuredWidth, const Common::Rect &clipRect) {
+ int nframes = img->loadedFrameCount();
+ bool scrollFinished = true;
+ int y = 200 - ymax;
+ for (int i = 0; i < nframes; i++) {
+ int width = img->width(i);
+ int height = img->height(i);
+ if (y > -measuredWidth) {
+ Common::Rect drawWin(Common::Point(xoff, y), width, height);
+ drawWin.clip(clipRect);
+ if (!drawWin.isEmpty()) {
+ img->drawBitmap(i, xoff, y, drawWin, _vm->_compositionBuffer);
+ }
+ scrollFinished = false;
+ }
+ y += ygap + height;
+ if (y > 200)
+ break;
+ }
+ return scrollFinished;
+}
+
void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
switch (op) {
case 0x0000: // FINISH: void
@@ -655,6 +685,23 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
Common::Point(r.left, r.top));
break;
}
+ case 0xb000:
+ if (seq._executed) // this is a one-shot op
+ break;
+ env._creditScrollMeasure = doOpInitCreditScroll(env._scriptShapes[seq._currentBmpId].get());
+ env._creditScrollYOffset = 0;
+ break;
+ case 0xb010: {
+ const Image *img = env._scriptShapes[seq._currentBmpId].get();
+ if (img && img->loadedFrameCount()) {
+ bool finished = doOpCreditsScroll(env._scriptShapes[seq._currentBmpId].get(), ivals[0], env._creditScrollYOffset,
+ ivals[2], env._creditScrollMeasure, seq._drawWin);
+ env._creditScrollYOffset += ivals[1];
+ if (finished)
+ _vm->adsInterpreter()->setHitTTMOp0110();
+ }
+ break;
+ }
case 0xf010: { // LOAD SCR: filename:str
if (seq._executed) // this is a one-shot op
break;
@@ -727,9 +774,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa420: // DRAW EMPTY CIRCLE
// From here on are not implemented in DRAGON
- case 0xb000: // ? (0 args) - found in HoC intro
- case 0xb010: // ? (3 args: 30, 2, 19) - found in HoC intro
- case 0xb600: // DRAW SCREEN
+ case 0xb600: // DRAW SCREEN??
case 0xc020: // LOAD_SAMPLE
case 0xc030: // SELECT_SAMPLE
case 0xc040: // DESELECT_SAMPLE
@@ -738,10 +783,11 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
default:
if (count < 15)
- warning("Unimplemented TTM opcode: 0x%04X (%d args) (ivals: %d %d %d %d)",
- op, count, ivals[0], ivals[1], ivals[2], ivals[3]);
+ warning("Unimplemented TTM opcode: 0x%04X (%s, %d args) (ivals: %d %d %d %d)",
+ op, ttmOpName(op), count, ivals[0], ivals[1], ivals[2], ivals[3]);
else
- warning("Unimplemented TTM opcode: 0x%04X (sval: %s)", op, sval.c_str());
+ warning("Unimplemented TTM opcode: 0x%04X (%s, sval: %s)", op,
+ ttmOpName(op), sval.c_str());
break;
}
}
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index 9ce917c02b2..11826ca6bfe 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -37,7 +37,8 @@ public:
class TTMEnviro : public ScriptParserData {
public:
- TTMEnviro() : _totalFrames(330), _enviro(0), ScriptParserData() {
+ TTMEnviro() : _totalFrames(330), _enviro(0), _creditScrollMeasure(0),
+ _creditScrollYOffset(0), ScriptParserData() {
ARRAYCLEAR(_scriptPals);
_fonts.push_back(FontManager::kDefaultFont); // is this right?
}
@@ -52,6 +53,8 @@ public:
int _scriptPals[6];
Common::String _strings[10];
Common::Array<FontManager::FontType> _fonts;
+ int16 _creditScrollMeasure;
+ int16 _creditScrollYOffset;
};
enum TTMRunType {
@@ -114,6 +117,8 @@ protected:
void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);
void doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, const Common::Rect &r);
+ int16 doOpInitCreditScroll(const Image *img);
+ bool doOpCreditsScroll(const Image *img, int16 ygap, int16 ymax, int16 xoff, int16 measuredWidth, const Common::Rect &clipRect);
DgdsEngine *_vm;
};
Commit: caacea6904e88f0e308a2612ac2dc3068319cc86
https://github.com/scummvm/scummvm/commit/caacea6904e88f0e308a2612ac2dc3068319cc86
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Change menus to open by ID instead of offset
Changed paths:
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 14f661bc6a5..0f954d49707 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -36,6 +36,7 @@
namespace Dgds {
+
// TODO: These are the IDs for Dragon, this code needs updates for China/Beamish/etc
enum MenuButtonIds {
kMenuMainPlay = 120,
@@ -59,8 +60,8 @@ enum MenuButtonIds {
kMenuOptionsVCR = 135,
kMenuOptionsPlay = 136,
- kMenuCalibrateJoystick = 145,
- kMenuCalibrateMouse = 146,
+ kMenuCalibrateJoystickBtn = 145,
+ kMenuCalibrateMouseBtn = 146,
kMenuCalibrateVCR = 144,
kMenuCalibratePlay = 147,
kMenuCalibrateVCRHoC = 159,
@@ -111,6 +112,12 @@ Menu::~Menu() {
_screenBuffer.free();
}
+void Menu::setRequestData(const REQFileData &data) {
+ for (auto &req : data._requests) {
+ _menuRequests[req._fileNum] = req;
+ }
+}
+
void Menu::setScreenBuffer() {
Graphics::Surface *dst = g_system->lockScreen();
_screenBuffer.copyFrom(*dst);
@@ -146,7 +153,7 @@ void Menu::drawMenu(MenuId menu) {
bool firstDraw = (_curMenu != menu);
_curMenu = menu;
- Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _menuRequests[_curMenu]._gadgets;
// Restore background when drawing submenus
g_system->copyRectToScreen(_screenBuffer.getPixels(), _screenBuffer.pitch, 0, 0, _screenBuffer.w, _screenBuffer.h);
@@ -155,7 +162,7 @@ void Menu::drawMenu(MenuId menu) {
Graphics::Surface *screen = g_system->lockScreen();
Graphics::ManagedSurface managed(screen->w, screen->h, screen->format);
managed.blitFrom(*screen);
- _reqData._requests[_curMenu].drawBg(&managed);
+ _menuRequests[_curMenu].drawBg(&managed);
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
@@ -176,8 +183,8 @@ void Menu::drawMenu(MenuId menu) {
}
void Menu::drawMenuText(Graphics::ManagedSurface &dst) {
- Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
- Common::Array<TextItem> textItems = _reqData._requests[_curMenu]._textItemList;
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _menuRequests[_curMenu]._gadgets;
+ Common::Array<TextItem> textItems = _menuRequests[_curMenu]._textItemList;
// TODO: Get the parent coordinates properly
uint16 parentX = gadgets[0].get()->_parentX;
@@ -202,7 +209,7 @@ Gadget *Menu::getClickedMenuItem(const Common::Point &mouseClick) {
if (_curMenu == kMenuNone)
return nullptr;
- Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _menuRequests[_curMenu]._gadgets;
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
@@ -296,7 +303,7 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
drawMenu(kMenuFiles);
break;
case kMenuMainQuit:
- drawMenu(kMenuQuit);
+ drawMenu(kMenuReallyQuit);
break;
case kMenuCalibrateVCR: // NOTE: same ID as kMenuIntroPlay
if (_curMenu == kMenuSkipPlayIntro) {
@@ -320,14 +327,14 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
// TODO
debug("Clicked option with ID %d", clickedMenuItem);
break;
- case kMenuCalibrateJoystick:
- drawMenu(kMenuJoystick);
+ case kMenuCalibrateJoystickBtn:
+ drawMenu(kMenuCalibrateJoystick);
break;
- case kMenuCalibrateMouse:
- drawMenu(kMenuMouse);
+ case kMenuCalibrateMouseBtn:
+ drawMenu(kMenuCalibrateMouse);
break;
case kMenuChangeDirectoryCancel:
- drawMenu(kMenuSave);
+ drawMenu(kMenuSaveDlg);
break;
case kMenuFilesRestore:
case kMenuGameOverRestore:
@@ -350,7 +357,7 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
drawMenu(_curMenu);
break;
case kMenuSaveChangeDirectory:
- drawMenu(kMenuChangeDirectory);
+ drawMenu(kMenuChangeDir);
break;
case kMenuChangeDirectoryOK:
// TODO
@@ -368,7 +375,7 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
engine->restartGame();
break;
case kMenuGameOverQuit:
- drawMenu(kMenuQuit);
+ drawMenu(kMenuReallyQuit);
break;
case kMenuGameOverRestart:
drawMenu(kMenuRestart);
@@ -399,7 +406,7 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
}
void Menu::toggleGadget(int16 gadgetId, bool enable) {
- Common::Array<Common::SharedPtr<Gadget> > gadgets = _reqData._requests[_curMenu]._gadgets;
+ Common::Array<Common::SharedPtr<Gadget> > gadgets = _menuRequests[_curMenu]._gadgets;
for (Common::SharedPtr<Gadget> &gptr : gadgets) {
Gadget *gadget = gptr.get();
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index f4eaf021fe0..f3d19d95d72 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -43,30 +43,31 @@ namespace Dgds {
class REQFileData;
enum MenuId {
- kMenuNone = -1,
- kMenuMain = 0,
- kMenuControls = 1,
- kMenuOptions = 2,
- kMenuCalibrate = 3,
- kMenuRestart = 4,
- // 5: you cannot save your game right now
- kMenuGameOver = 6, // num 41
- kMenuFiles = 7, // num 21
- // 8: save game not saved because disk is full
- // 9: all game entries are full
- kMenuSave = 10,
- // 11: change directory - create directory
- // 12: change directory - invalid directory specified
- kMenuChangeDirectory = 13,
- kMenuJoystick = 14,
- kMenuMouse = 15,
- kMenuQuit = 16,
- // 17: I'm frustrated - keep trying / win arcade
- kMenuSkipPlayIntro = 18,
- kMenuBetterSaveGame = 19, // save game before arcade
- // 20: replay arcade
- kMenuChina1 = 41,
- kMenuChinaSkipCredits = 50,
+ // Request data numbers, same in both RoTD and China VCRs
+ kMenuNone = 0,
+ kMenuMain = 5,
+ kMenuControls = 7,
+ kMenuOptions = 29,
+ kMenuCalibrate = 30,
+ kMenuFiles = 21,
+ kMenuGameOver = 41,
+ kMenuRestart = 39,
+ kMenuCantSave = 36,
+ kMenuSaveNeedName = 43,
+ kMenuNotSavedDiskFull = 42,
+ kMenuReplaceSave = 38,
+ kMenuSaveDlg = 23,
+ kMenuChangeDir = 25,
+ kMenuAskCreateDir = 26,
+ kMenuInvalidDir = 37,
+ kMenuCalibrateJoystick = 28,
+ kMenuCalibrateMouse = 32,
+ kMenuReallyQuit = 35,
+ kMenuSkipPlayIntro = 50,
+ kMenuSkipArcade = 52,
+ kMenuSaveBeforeArcade = 46,
+ kMenuReplayArcade = 45,
+ kMenuArcadeFrustrated = 47,
};
class Menu {
@@ -86,16 +87,15 @@ public:
bool menuShown() const { return _curMenu != kMenuNone; }
void hideMenu() { _curMenu = kMenuNone; }
- void setRequestData(const REQFileData &data) {
- _reqData = data;
- }
+ void setRequestData(const REQFileData &data);
private:
Gadget *getClickedMenuItem(const Common::Point &mouseClick);
void drawMenuText(Graphics::ManagedSurface &dst);
void toggleGadget(int16 gadgetId, bool enable);
void configureGadget(MenuId menu, Gadget *gadget);
- REQFileData _reqData;
+
+ Common::HashMap<int, RequestData> _menuRequests;
SliderGadget *_dragGadget;
Common::Point _dragStartPt;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 8b405901273..807e2cf42a0 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -633,7 +633,7 @@ bool Scene::runDragonOp(const SceneOp &op) {
engine->setMenuToTrigger(kMenuSkipPlayIntro);
break;
case kSceneOpOpenBetterSaveGameMenu:
- engine->setMenuToTrigger(kMenuBetterSaveGame);
+ engine->setMenuToTrigger(kMenuSaveBeforeArcade);
break;
default:
error("Unexpected Dragon scene opcode %d", op._opCode);
@@ -645,11 +645,11 @@ bool Scene::runDragonOp(const SceneOp &op) {
bool Scene::runChinaOp(const SceneOp &op) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
switch (op._opCode) {
- case kSceneOpOpenChinaOpenSomeMenu:
- engine->setMenuToTrigger(kMenuChina1);
+ case kSceneOpOpenChinaOpenGameOverMenu:
+ engine->setMenuToTrigger(kMenuGameOver);
break;
case kSceneOpOpenChinaOpenSkipCreditsMenu:
- engine->setMenuToTrigger(kMenuChinaSkipCredits);
+ engine->setMenuToTrigger(kMenuSkipPlayIntro);
break;
case kSceneOpOpenChinaStartIntro:
warning("TODO: Implement start intro opcode");
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 022fdb0638a..4afc41a1ff7 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -112,7 +112,7 @@ enum SceneOpCode {
kSceneOpOpenBetterSaveGameMenu = 108, // args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
// China-specific opcodes
- kSceneOpOpenChinaOpenSomeMenu = 114, // args: none.
+ kSceneOpOpenChinaOpenGameOverMenu = 114, // args: none.
kSceneOpOpenChinaOpenSkipCreditsMenu = 115, // args: none.
kSceneOpOpenChinaStartIntro = 116, // args: none.
};
Commit: 9fb6e47cd6b3d3906e42b2fce0957b15665becbc
https://github.com/scummvm/scummvm/commit/9fb6e47cd6b3d3906e42b2fce0957b15665becbc
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Add keymapper support
Only adds stubs, most keys are still not supported.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/metaengine.cpp
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 8a0252b41a2..ba27000ad08 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -406,25 +406,41 @@ Common::Error DgdsEngine::run() {
while (!shouldQuit()) {
Common::EventType mouseEvent = Common::EVENT_INVALID;
while (eventMan->pollEvent(ev)) {
- if (ev.type == Common::EVENT_KEYDOWN) {
- switch (ev.kbd.keycode) {
- case Common::KEYCODE_ESCAPE:
+ if (ev.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
+ switch ((DgdsKeyEvent)ev.customType) {
+ case kDgdsKeyToggleMenu:
_menuToTrigger = kMenuMain;
break;
- case Common::KEYCODE_F5:
- _menuToTrigger = kMenuMain;
- break;
- case Common::KEYCODE_s:
- if (ev.kbd.hasFlags(Common::KBD_CTRL))
- saveGameDialog();
+ case kDgdsKeySave:
+ saveGameDialog();
break;
- case Common::KEYCODE_l:
- if (ev.kbd.hasFlags(Common::KBD_CTRL))
- loadGameDialog();
+ case kDgdsKeyLoad:
+ loadGameDialog();
break;
- case Common::KEYCODE_c:
+ case kDgdsKeyToggleClock:
_clock.toggleVisibleUser();
break;
+ case kDgdsKeyNextChoice:
+ warning("TODO: Implement kDgdsKeyNextChoice");
+ break;
+ case kDgdsKeyPrevChoice:
+ warning("TODO: Implement kDgdsKeyPrevChoice");
+ break;
+ case kDgdsKeyNextItem:
+ warning("TODO: Implement kDgdsKeyNextItem");
+ break;
+ case kDgdsKeyPrevItem:
+ warning("TODO: Implement kDgdsKeyPrevItem");
+ break;
+ case kDgdsKeyPickUp:
+ warning("TODO: Implement kDgdsKeyPickUp");
+ break;
+ case kDgdsKeyLook:
+ warning("TODO: Implement kDgdsKeyLook");
+ break;
+ case kDgdsKeyActivate:
+ warning("TODO: Implement kDgdsKeyActivate");
+ break;
default:
break;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index e3072ac41ba..564ca208c48 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -75,6 +75,20 @@ enum DgdsDetailLevel {
kDgdsDetailHigh = 1
};
+enum DgdsKeyEvent {
+ kDgdsKeyLoad,
+ kDgdsKeySave,
+ kDgdsKeyToggleMenu,
+ kDgdsKeyToggleClock,
+ kDgdsKeyNextChoice,
+ kDgdsKeyPrevChoice,
+ kDgdsKeyNextItem,
+ kDgdsKeyPrevItem,
+ kDgdsKeyPickUp,
+ kDgdsKeyLook,
+ kDgdsKeyActivate,
+};
+
class DgdsEngine : public Engine {
public:
Common::Platform _platform;
diff --git a/engines/dgds/metaengine.cpp b/engines/dgds/metaengine.cpp
index c2eaac53c64..08431d1b76c 100644
--- a/engines/dgds/metaengine.cpp
+++ b/engines/dgds/metaengine.cpp
@@ -23,6 +23,12 @@
#include "base/plugins.h"
#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "common/translation.h"
+
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/keymapper.h"
+#include "backends/keymapper/standard-actions.h"
#include "dgds/dgds.h"
@@ -34,6 +40,8 @@ public:
bool hasFeature(MetaEngineFeature f) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+
+ Common::KeymapArray initKeymaps(const char *target) const override;
};
bool DgdsMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -53,6 +61,43 @@ Common::Error DgdsMetaEngine::createInstance(OSystem *syst, Engine **engine, con
return (desc != nullptr) ? Common::kNoError : Common::kUnknownError;
}
+struct KeybindingRecord {
+ Dgds::DgdsKeyEvent _action;
+ const char *_id;
+ const Common::U32String _desc;
+ const char *_key;
+ const char *_altKey;
+};
+
+Common::KeymapArray DgdsMetaEngine::initKeymaps(const char *target) const {
+ const KeybindingRecord DGDS_KEYS[] = {
+ { Dgds::kDgdsKeyLoad, "LOAD", _("Load Game"), "F7", "C+l" },
+ { Dgds::kDgdsKeySave, "SAVE", _("Save Game"), "F5", "C+s" },
+ { Dgds::kDgdsKeyToggleMenu, "TOGGLE_MENU", _("Toggle Menu"), "ESCAPE", nullptr },
+ { Dgds::kDgdsKeyToggleClock, "TOGGLE_CLOCK", _("Toggle Clock"), "c", nullptr },
+ { Dgds::kDgdsKeyNextChoice, "NEXT_CHOICE", _("Next dialog / menu item"), "DOWN", "s" },
+ { Dgds::kDgdsKeyPrevChoice, "PREV_CHOICE", _("Previous dialog / menu item"), "UP", "a" },
+ { Dgds::kDgdsKeyNextItem, "NEXT_ITEM", _("Next object"), "TAB", "w" },
+ { Dgds::kDgdsKeyPrevItem, "PREV_ITEM", _("Previous object"), "S+TAB", "q" },
+ { Dgds::kDgdsKeyPickUp, "PICK_UP", _("Pick up / Operate"), "SPACE", "KP5" },
+ { Dgds::kDgdsKeyLook, "LOOK", _("Look"), "ENTER", "," },
+ { Dgds::kDgdsKeyActivate, "ACTIVATE", _("Activate Inventory Object"), "BACKSPACE", nullptr },
+ };
+
+ Common::Keymap *map = new Common::Keymap(Common::Keymap::kKeymapTypeGame, target, _("Game Keys"));
+
+ for (const auto &k : DGDS_KEYS) {
+ Common::Action *act = new Common::Action(k._id, k._desc);
+ act->setCustomEngineActionEvent(k._action);
+ act->addDefaultInputMapping(k._key);
+ if (k._altKey)
+ act->addDefaultInputMapping(k._altKey);
+ map->addAction(act);
+ }
+
+ return Common::Keymap::arrayOf(map);
+}
+
#if PLUGIN_ENABLED_DYNAMIC(DGDS)
REGISTER_PLUGIN_DYNAMIC(DGDS, PLUGIN_TYPE_ENGINE, DgdsMetaEngine);
#else
Commit: b874625c90c7e58883c87c01886897fdf57a6e18
https://github.com/scummvm/scummvm/commit/b874625c90c7e58883c87c01886897fdf57a6e18
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Small fixes for non-interactive demos
Changed paths:
engines/dgds/ads.cpp
engines/dgds/dgds.cpp
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index 69489559a4d..21327c86a14 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -899,6 +899,12 @@ int ADSInterpreter::numArgs(uint16 opcode) const {
case 0x1090:
case 0x1380:
case 0x1390:
+ case 0x13A0:
+ case 0x13A1:
+ case 0x13B0:
+ case 0x13B1:
+ case 0x13C0:
+ case 0x13C1:
case 0x3020:
case 0xF010:
case 0xF200:
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index ba27000ad08..5863641d4a4 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -616,7 +616,9 @@ bool DgdsEngine::canLoadGameStateCurrently(Common::U32String *msg /*= nullptr*/)
bool DgdsEngine::canSaveGameStateCurrently(Common::U32String *msg /*= nullptr*/) {
- return _gdsScene && _scene && _scene->getNum() != 2
+ // Doesn't make sense to save non-interactive demos..
+ bool isSavableGame = getGameId() != GID_SQ5DEMO && getGameId() != GID_COMINGSOON;
+ return isSavableGame && _gdsScene && _scene && _scene->getNum() != 2
&& _scene->getDragItem() == nullptr && !_isLoading;
}
Commit: ffef4790f45010d7c62017e9eaf9621e5d0c66d1
https://github.com/scummvm/scummvm/commit/ffef4790f45010d7c62017e9eaf9621e5d0c66d1
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix font, music, and rendering slightly in SQ5 demo
Changed paths:
engines/dgds/clock.cpp
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/font.cpp
engines/dgds/font.h
engines/dgds/inventory.cpp
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/ttm.cpp
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index 82b94802c05..eba993dde72 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -124,7 +124,7 @@ void Clock::draw(Graphics::ManagedSurface &surf) {
const Common::String clockStr = getTimeStr();
const FontManager *fontman = static_cast<DgdsEngine *>(g_engine)->getFontMan();
- const Font *font = fontman->getFont(FontManager::k4x5Font);
+ const DgdsFont *font = fontman->getFont(FontManager::k4x5Font);
int width = font->getMaxCharWidth() * 12 + 3;
_drawPos.top = 0;
_drawPos.bottom = font->getFontHeight() + 6;
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index d380d6a8ff5..4485cfa9247 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -83,7 +83,7 @@ static void _drawPixel(int x, int y, int color, void *data) {
}
-const Font *Dialog::getDlgTextFont() const {
+const DgdsFont *Dialog::getDlgTextFont() const {
const FontManager *fontman = static_cast<DgdsEngine *>(g_engine)->getFontMan();
FontManager::FontType fontType = FontManager::kGameDlgFont;
if (_fontSize == 1)
@@ -307,7 +307,7 @@ void Dialog::drawFindSelectionXY() {
if (!_state)
return;
- const Font *font = getDlgTextFont();
+ const DgdsFont *font = getDlgTextFont();
// Find the appropriate _lastMouseX/lastMouseY value given the last _strMouseLoc.
@@ -392,7 +392,7 @@ void Dialog::drawFindSelectionTxtOffset() {
// Find the appropriate _strMouseLoc value given the last x/y position.
- const Font *font = getDlgTextFont();
+ const DgdsFont *font = getDlgTextFont();
int lastMouseX = _state->_lastMouseX;
int lastMouseY = _state->_lastMouseY;
int lineHeight = font->getFontHeight();
@@ -443,7 +443,7 @@ void Dialog::drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const
assert(_state);
Common::StringArray lines;
- const Font *font = getDlgTextFont();
+ const DgdsFont *font = getDlgTextFont();
const int h = font->getFontHeight();
font->wordWrapText(txt, _state->_loc.width, lines);
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index 2098df45166..ae40dd71bc9 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -36,7 +36,7 @@ class ManagedSurface;
namespace Dgds {
-class Font;
+class DgdsFont;
class SceneOp;
enum DialogFlags {
@@ -141,7 +141,7 @@ private:
void drawFindSelectionTxtOffset();
void drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const Common::String &txt);
- const Font *getDlgTextFont() const;
+ const DgdsFont *getDlgTextFont() const;
static int _lastSelectedDialogItemNum;
static Dialog *_lastDialogSelectionChangedFor;
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index 6864ccb9651..e1b47c14ad7 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -31,7 +31,7 @@
namespace Dgds {
-Font *Font::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
+DgdsFont *DgdsFont::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
Common::SeekableReadStream *fontFile = resourceManager->getResource(filename);
if (!fontFile) {
warning("Font file %s not found", filename.c_str());
@@ -40,7 +40,7 @@ Font *Font::load(const Common::String &filename, ResourceManager *resourceManage
DgdsChunkReader chunk(fontFile);
- Font *font = nullptr;
+ DgdsFont *font = nullptr;
while (chunk.readNextHeader(EX_FNT, filename)) {
if (chunk.isContainer()) {
@@ -67,31 +67,33 @@ Font *Font::load(const Common::String &filename, ResourceManager *resourceManage
return font;
}
-Font::Font(byte w, byte h, byte start, byte count, const byte *glyphs) : _w(w), _h(h), _start(start), _count(count), _glyphs(glyphs) { }
+DgdsFont::DgdsFont(byte w, byte h, byte start, byte count, const byte *glyphs) : _w(w), _h(h), _start(start), _count(count), _glyphs(glyphs) { }
-Font::~Font() {
+DgdsFont::~DgdsFont() {
}
-bool Font::hasChar(byte chr) const {
+bool DgdsFont::hasChar(byte chr) const {
return (chr >= _start && chr <= (_start + _count));
}
static inline uint isSet(const byte *set, uint bit) {
- return (set[bit >> 3] & (1 << (bit & 7)));
+ assert(bit >= 0);
+ return (set[bit / 8] & (1 << (bit & 7)));
}
-void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const {
- const Common::Rect destRect(x, y, x + _w, y + _h);
+void DgdsFont::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, int w, uint32 color) const {
+ const Common::Rect destRect(x, y, x + w, y + _h);
Common::Rect clippedDestRect(0, 0, dst->w, dst->h);
clippedDestRect.clip(destRect);
- const Common::Point croppedBy(clippedDestRect.left-destRect.left, clippedDestRect.top-destRect.top);
+ const Common::Point croppedBy(clippedDestRect.left - destRect.left, clippedDestRect.top - destRect.top);
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
int idx = bit + croppedBy.x;
- const byte *src = _glyphs + pos + croppedBy.y;
+ int bytesPerRow = (w + 7) / 8;
+ const byte *src = _glyphs + pos + (croppedBy.y * bytesPerRow);
byte *ptr = (byte *)dst->getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
@@ -100,11 +102,11 @@ void Font::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint
ptr[j] = color;
}
ptr += dst->pitch;
- src++;
+ src += bytesPerRow;
}
}
-FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : Font(w, h, start, count, data), _rawData(data) {
+FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : DgdsFont(w, h, start, count, data), _rawData(data) {
}
FFont::~FFont() {
@@ -121,7 +123,7 @@ void FFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 co
int pos, bit;
mapChar(chr, pos, bit);
- Font::drawChar(dst, pos, bit, x, y, color);
+ DgdsFont::drawChar(dst, pos, bit, x, y, _w, color);
}
FFont *FFont::load(Common::SeekableReadStream &input) {
@@ -133,7 +135,7 @@ FFont *FFont::load(Common::SeekableReadStream &input) {
assert((4 + size) == input.size());
- debug(" w: %u, h: %u, start: 0x%x, count: %u", w, h, start, count);
+ debug("FFont w: %u, h: %u, start: 0x%x, count: %u", w, h, start, count);
byte *data = new byte[size];
input.read(data, size);
@@ -142,8 +144,14 @@ FFont *FFont::load(Common::SeekableReadStream &input) {
}
PFont::PFont(byte w, byte h, byte start, byte count, byte *data)
-: Font(w, h, start, count, data + 3 * count), _offsets(reinterpret_cast<const uint16 *>(data)), _widths(data + 2 * count), _rawData(data)
+: DgdsFont(w, h, start, count, data + 3 * count), _offsets(reinterpret_cast<const uint16 *>(data)), _widths(data + 2 * count), _rawData(data)
{
+ debug("-- PFont dump:");
+ debug("char\tw\th\toffset");
+ for (uint c = start; c < start + count; c++) {
+ debug("'%c'\t%d\t%d\t%d", (char)c, _widths[c - start], h, _offsets[c - start]);
+ }
+ debug("-- end dump");
}
PFont::~PFont() {
@@ -161,7 +169,7 @@ void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 co
int pos, bit;
mapChar(chr, pos, bit);
- Font::drawChar(dst, pos, bit, x, y, color);
+ DgdsFont::drawChar(dst, pos, bit, x, y, getCharWidth(chr), color);
}
int PFont::getCharWidth(uint32 chr) const {
@@ -179,10 +187,8 @@ PFont *PFont::load(Common::SeekableReadStream &input, Decompressor *decompressor
byte count = input.readByte();
int size = input.readUint16LE();
- debug(" magic: 0x%x, w: %u, h: %u, unknown: %u, start: 0x%x, count: %u\n"
- " size: %u",
- magic, w, h, unknown, start, count,
- size);
+ debug("PFont magic: 0x%x, w: %u, h: %u, unk: %u, start: 0x%x, count: %u, size: %u",
+ magic, w, h, unknown, start, count, size);
assert(magic == 0xFF);
@@ -200,13 +206,13 @@ FontManager::~FontManager() {
delete entry._value;
}
-const Font *FontManager::getFont(FontType type) const {
+const DgdsFont *FontManager::getFont(FontType type) const {
return _fonts.getVal(type);
}
void FontManager::tryLoadFont(const char *fname, ResourceManager *resMgr, Decompressor *decomp) {
FontType ftype = fontTypeByName(fname);
- Font *font = Font::load(fname, resMgr, decomp);
+ DgdsFont *font = DgdsFont::load(fname, resMgr, decomp);
if (font)
_fonts.setVal(ftype, font);
else
@@ -226,22 +232,27 @@ FontManager::FontType FontManager::fontTypeByName(const Common::String &filename
if (filename == "WILLY.FNT") return kGameFont;
if (filename == "WVCR.FNT") return kWVCRFont;
if (filename == "COMIX_16.FNT") return kGameDlgFont;
- if (filename == "EXIT.FNT") return kDefaultFont;
- if (filename == "SSM1_12.FNT") return kGameFont;
- if (filename == "SSM1_15.FNT") return kGameDlgFont;
+ if (filename == "EXIT.FNT") return kGameDlgFont;
+ if (filename == "SSM1_12.FNT") return kDefaultFont;
+ if (filename == "SSM1_15.FNT") return kGameFont;
if (filename == "SSM1_30.FNT") return kWVCRFont;
+ if (filename == "RMN7_19.FNT") return kGameFont;
+ if (filename == "RMN8_11.FNT") return kDefaultFont;
return FontManager::kDefaultFont;
}
void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompressor *decomp) {
- if (gameId == GID_SQ5DEMO || gameId == GID_COMINGSOON) {
+ if (gameId == GID_SQ5DEMO) {
+ tryLoadFont("SSM1_12.FNT", resMgr, decomp);
+ tryLoadFont("SSM1_15.FNT", resMgr, decomp);
+ tryLoadFont("SSM1_30.FNT", resMgr, decomp);
+ tryLoadFont("EXIT.FNT", resMgr, decomp);
+ return;
+ } else if (gameId == GID_COMINGSOON) {
+ tryLoadFont("RMN7_19.FNT", resMgr, decomp);
+ tryLoadFont("RMN8_11.FNT", resMgr, decomp);
tryLoadFont("EXIT.FNT", resMgr, decomp);
- if (gameId == GID_SQ5DEMO) {
- tryLoadFont("SSM1_12.FNT", resMgr, decomp);
- tryLoadFont("SSM1_15.FNT", resMgr, decomp);
- tryLoadFont("SSM1_30.FNT", resMgr, decomp);
- }
return;
}
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index bf01b840faf..2376bd4c051 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -44,15 +44,14 @@ namespace Dgds {
class ResourceManager;
class Decompressor;
-class Font : public Graphics::Font {
+class DgdsFont : public Graphics::Font {
public:
- Font(byte w, byte h, byte start, byte count, const byte *glyphs);
- virtual ~Font();
- int getFontHeight() const { return _h; }
- int getMaxCharWidth() const { return _w; }
- virtual int getCharWidth(uint32 chr) const = 0;
- void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, uint32 color) const;
- static Font *load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
+ DgdsFont(byte w, byte h, byte start, byte count, const byte *glyphs);
+ virtual ~DgdsFont();
+ virtual int getFontHeight() const override { return _h; }
+ virtual int getMaxCharWidth() const override { return _w; }
+ virtual int getCharWidth(uint32 chr) const override = 0;
+ static DgdsFont *load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor);
protected:
byte _w;
@@ -61,16 +60,17 @@ protected:
byte _count;
const byte *_glyphs;
+ void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, int w, uint32 color) const;
bool hasChar(byte chr) const;
};
/* Proportional font (each char has its own width and so data is a different size) */
-class PFont : public Font {
+class PFont : public DgdsFont {
public:
PFont(byte w, byte h, byte start, byte count, byte *data);
~PFont();
- int getCharWidth(uint32 chr) const;
- void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
+ int getCharWidth(uint32 chr) const override;
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
static PFont *load(Common::SeekableReadStream &input, Decompressor *decompressor);
protected:
@@ -82,12 +82,12 @@ protected:
};
/* Fixed-width font */
-class FFont : public Font {
+class FFont : public DgdsFont {
public:
FFont(byte w, byte h, byte start, byte count, byte *data);
~FFont();
- int getCharWidth(uint32 chr) const { return _w; }
- void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const;
+ int getCharWidth(uint32 chr) const override { return _w; }
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
static FFont *load(Common::SeekableReadStream &input);
protected:
@@ -113,7 +113,7 @@ public:
FontManager() {}
~FontManager();
- const Font *getFont(FontType) const;
+ const DgdsFont *getFont(FontType) const;
FontType fontTypeByName(const Common::String &filename) const;
void loadFonts(DgdsGameId gameId, ResourceManager *resourceManager, Decompressor *decompressor);
@@ -128,7 +128,7 @@ private:
}
};
- Common::HashMap<FontType, Font*, FontTypeHash> _fonts;
+ Common::HashMap<FontType, DgdsFont*, FontTypeHash> _fonts;
};
} // End of namespace Dgds
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 474196f7f9c..ef12a58d8d6 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -90,7 +90,7 @@ void Inventory::setRequestData(const REQFileData &data) {
void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
// This really should be a text area, but it's hard-coded in the game.
- const Font *font = RequestData::getMenuFont();
+ const DgdsFont *font = RequestData::getMenuFont();
const RequestData &r = _reqData._requests[0];
static const char *title = "INVENTORY";
@@ -141,7 +141,7 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount) {
void Inventory::drawTime(Graphics::ManagedSurface &surf) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
- const Font *font = RequestData::getMenuFont();
+ const DgdsFont *font = RequestData::getMenuFont();
const Common::String timeStr = engine->getClock().getTimeStr();
Common::Point clockpos = Common::Point(_invClock->_x + _invClock->_parentX, _invClock->_y + _invClock->_parentY);
surf.fillRect(Common::Rect(clockpos, _invClock->_width, _invClock->_height), 0);
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 0f954d49707..1cb61a3e2af 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -198,7 +198,7 @@ void Menu::drawMenuText(Graphics::ManagedSurface &dst) {
continue;
}
- const Font *font = RequestData::getMenuFont();
+ const DgdsFont *font = RequestData::getMenuFont();
int w = font->getStringWidth(textItem._txt);
font->drawString(dst.surfacePtr(), textItem._txt, parentX + textItem._x, parentY + textItem._y, w, 0);
pos++;
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 5df5f00ace2..2aab07634a5 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -357,7 +357,7 @@ void ButtonGadget::draw(Graphics::ManagedSurface *dst) const {
dst->drawLine(x + 3, bottom - 3, right - 4, bottom - 3, ButtonColors[colOffset + 3]);
if (!_buttonName.empty()) {
- const Font *font = RequestData::getMenuFont();
+ const DgdsFont *font = RequestData::getMenuFont();
// TODO: Depending on some flags, the game toggles " ON " to " OFF" at the
// end of the string.
@@ -407,7 +407,7 @@ Common::String TextAreaGadget::dump() const {
}
void TextAreaGadget::draw(Graphics::ManagedSurface *dst) const {
- const Font *font = RequestData::getMenuFont();
+ const DgdsFont *font = RequestData::getMenuFont();
font->drawString(dst, _buttonName, _x + _parentX, _y + _parentY, 0, 0);
}
@@ -442,7 +442,7 @@ static const char *_sliderLabelsForGadget(uint16 num) {
static const int SLIDER_HANDLE_FRAME = 28;
void SliderGadget::draw(Graphics::ManagedSurface *dst) const {
- const Font *font = RequestData::getMenuFont();
+ const DgdsFont *font = RequestData::getMenuFont();
int16 x = _x + _parentX;
int16 y = _y + _parentY;
@@ -652,7 +652,7 @@ void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
}
/*static*/
-const Font *RequestData::getMenuFont() {
+const DgdsFont *RequestData::getMenuFont() {
return static_cast<DgdsEngine *>(g_engine)->getFontMan()->getFont(FontManager::kGameFont);
}
@@ -691,7 +691,7 @@ void RequestData::drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, ui
/*static*/
void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header) {
if (!header.empty()) {
- const Font *font = getMenuFont();
+ const DgdsFont *font = getMenuFont();
int hwidth = font->getStringWidth(header);
int hheight = font->getFontHeight();
int hleft = x + (width - hwidth) / 2;
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index c4adc55dc0c..fe06c6959ef 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -31,7 +31,7 @@
namespace Dgds {
-class Font;
+class DgdsFont;
class Image;
struct TextItem {
@@ -193,7 +193,7 @@ public:
void drawBg(Graphics::ManagedSurface *dst) const;
void drawInvType(Graphics::ManagedSurface *dst);
- static const Font *getMenuFont();
+ static const DgdsFont *getMenuFont();
static const Image *getCorners();
static void fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 807e2cf42a0..0318b07d5cf 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -504,7 +504,7 @@ static void _drawDragonCountdown(FontManager::FontType fontType, int16 x, int16
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
int16 countdownEnd = engine->getGameGlobals()->getGlobal(0x22);
int16 currentMins = engine->getClock().getMins();
- const Font *fnt = engine->getFontMan()->getFont(fontType);
+ const DgdsFont *fnt = engine->getFontMan()->getFont(fontType);
Common::String str = Common::String::format("%d", countdownEnd - currentMins);
fnt->drawString(&engine->_compositionBuffer, str, x, y, 320 - x, 10);
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 4afc41a1ff7..2768dca55f8 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -34,7 +34,7 @@ namespace Dgds {
class ResourceManager;
class Decompressor;
-class Font;
+class DgdsFont;
enum SceneCondition {
kSceneCondNone = 0,
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 002a9ef4be3..f2252b6fae8 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -138,6 +138,8 @@ static const char *ttmOpName(uint16 op) {
case 0x0090: return "FREE FONT";
case 0x00B0: return "NULLOP";
case 0x0110: return "PURGE";
+ case 0x0400: return "PALETTE SOMETHING ?";
+ case 0x0510: return "UNKNOWN 0x0510";
case 0x0ff0: return "FINISH FRAME / DRAW";
case 0x1020: return "SET DELAY";
case 0x1030: return "SET BRUSH";
@@ -154,6 +156,10 @@ static const char *ttmOpName(uint16 op) {
case 0x2000: return "SET DRAW COLORS";
case 0x2010: return "SET FRAME";
case 0x2020: return "SET RANDOM DELAY";
+ case 0x2300: return "UNKNOWN 0x23x2 series";
+ case 0x2310: return "UNKNOWN 0x23x2 series";
+ case 0x2320: return "UNKNOWN 0x23x2 series";
+ case 0x2400: return "UNKNOWN 0x2402, palette related";
case 0x4000: return "SET CLIP WINDOW";
case 0x4110: return "FADE OUT";
case 0x4120: return "FADE IN";
@@ -240,6 +246,8 @@ static void _copyRectToScreen(const Graphics::ManagedSurface &src, const Common:
if (r.isEmpty())
return;
Graphics::Surface *surf = g_system->lockScreen();
+ Common::Rect copyRect = r;
+ copyRect.clip(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT));
surf->copyRectToSurface(src.rawSurface(), r.left, r.top, r);
g_system->unlockScreen();
}
@@ -631,7 +639,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
uint strnum = (op & 0x70) >> 4;
const Common::String &str = env._strings[strnum];
const FontManager *mgr = _vm->getFontMan();
- const Font *font = mgr->getFont(env._fonts[fontno]);
+ const DgdsFont *font = mgr->getFont(env._fonts[fontno]);
// Note: ignore the y-height argument (ivals[3]) for now. If width is 0, draw as much as we can.
int width = ivals[2];
if (width == 0)
@@ -643,32 +651,36 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// DRAW SPRITE x,y:int .. how different from 0xa500??
// FALL THROUGH
case 0xa520:
- // DRAW SPRITE FLIP: x,y:int ; happens once in INTRO.TTM
+ // DRAW SPRITE FLIP: x,y:int
// FALL THROUGH
case 0xa530:
// CHINA
// DRAW BMP4: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
// arguments similar to DRAW BMP but it draws the same BMP multiple times with radial symmetry?
// you can see this in the Dynamix logo star.
- // FALL THROUGH
+ // FALL THROUGH FOR NOW
case 0xa500: {
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
- // This is kind of file system intensive, will likely have to change to store all the BMPs.
int frameno;
- if (count == 4) {
+ int bmpNo;
+ if (count == 6) {
+ frameno = ivals[2];
+ bmpNo = ivals[3];
+ warning("TODO: Implement other args %d %d of 6-arg draw function 0x%4x", ivals[4], ivals[5], op);
+ } else if (count == 4) {
frameno = ivals[2];
- // TODO: Check if the bmp id is changed here in CHINA or if a temp val is used.
- seq._currentBmpId = ivals[3];
+ bmpNo = ivals[3];
} else {
frameno = seq._brushNum;
+ bmpNo = seq._currentBmpId;
}
// DRAW BMP: x,y:int [-n,+n] (RISE)
- Common::SharedPtr<Image> img = env._scriptShapes[seq._currentBmpId];
+ Common::SharedPtr<Image> img = env._scriptShapes[bmpNo];
if (img)
img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->_compositionBuffer, op == 0xa520);
else
- warning("Trying to draw image %d in env %d which is not loaded", seq._currentBmpId, env._enviro);
+ warning("Trying to draw image %d in env %d which is not loaded", bmpNo, env._enviro);
break;
}
case 0xa600: { // DRAW GETPUT: i:int
@@ -702,6 +714,18 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
break;
}
+ case 0xc020: { // LOAD SAMPLE: filename:str
+ _vm->_soundPlayer->loadMacMusic(sval.c_str());
+ break;
+ }
+ case 0xc030: { // SELECT SAMPLE: int: i
+ // Do nothing for now?
+ break;
+ }
+ case 0xc050: { // PLAY SAMPLE: int: i
+ _vm->_soundPlayer->playMusic(ivals[0]);
+ break;
+ }
case 0xf010: { // LOAD SCR: filename:str
if (seq._executed) // this is a one-shot op
break;
@@ -772,14 +796,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa420: // DRAW EMPTY CIRCLE
-
- // From here on are not implemented in DRAGON
- case 0xb600: // DRAW SCREEN??
- case 0xc020: // LOAD_SAMPLE
- case 0xc030: // SELECT_SAMPLE
- case 0xc040: // DESELECT_SAMPLE
- case 0xc050: // PLAY_SAMPLE
- case 0xc060: // STOP_SAMPLE
+ case 0xb600: // DRAW SCREEN?? 6 args // HoC onward
+ case 0xc040: // DESELECT_SAMPLE // SQ5 demo onward
+ case 0xc060: // STOP_SAMPLE // SQ5 demo onward
default:
if (count < 15)
Commit: 7dd64b3d35b8e2cae126761fbdaca7536a1f4d40
https://github.com/scummvm/scummvm/commit/7dd64b3d35b8e2cae126761fbdaca7536a1f4d40
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix crash in sq5 demo
Changed paths:
engines/dgds/ttm.cpp
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index f2252b6fae8..38b2eb70253 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -248,7 +248,7 @@ static void _copyRectToScreen(const Graphics::ManagedSurface &src, const Common:
Graphics::Surface *surf = g_system->lockScreen();
Common::Rect copyRect = r;
copyRect.clip(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT));
- surf->copyRectToSurface(src.rawSurface(), r.left, r.top, r);
+ surf->copyRectToSurface(src.rawSurface(), copyRect.left, copyRect.top, copyRect);
g_system->unlockScreen();
}
Commit: 5531ae485a4b37cfd94844763230ad2a066e0655
https://github.com/scummvm/scummvm/commit/5531ae485a4b37cfd94844763230ad2a066e0655
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix large font rendering
Changed paths:
engines/dgds/font.cpp
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index e1b47c14ad7..9e85f98c2bc 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -76,14 +76,14 @@ bool DgdsFont::hasChar(byte chr) const {
return (chr >= _start && chr <= (_start + _count));
}
-static inline uint isSet(const byte *set, uint bit) {
+static inline bool isSet(const byte *data, uint bit) {
assert(bit >= 0);
- return (set[bit / 8] & (1 << (bit & 7)));
+ return data[bit / 8] & (1 << (7 - (bit % 8)));
}
void DgdsFont::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, int w, uint32 color) const {
- const Common::Rect destRect(x, y, x + w, y + _h);
- Common::Rect clippedDestRect(0, 0, dst->w, dst->h);
+ const Common::Rect destRect(Common::Point(x, y), w, _h);
+ Common::Rect clippedDestRect(dst->w, dst->h);
clippedDestRect.clip(destRect);
const Common::Point croppedBy(clippedDestRect.left - destRect.left, clippedDestRect.top - destRect.top);
@@ -91,14 +91,14 @@ void DgdsFont::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y,
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- int idx = bit + croppedBy.x;
+ int bitOffset = bit + croppedBy.x;
int bytesPerRow = (w + 7) / 8;
const byte *src = _glyphs + pos + (croppedBy.y * bytesPerRow);
byte *ptr = (byte *)dst->getBasePtr(clippedDestRect.left, clippedDestRect.top);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
- if (isSet(src, idx + _w - 1 - j))
+ if (isSet(src, bitOffset + j))
ptr[j] = color;
}
ptr += dst->pitch;
@@ -146,12 +146,6 @@ FFont *FFont::load(Common::SeekableReadStream &input) {
PFont::PFont(byte w, byte h, byte start, byte count, byte *data)
: DgdsFont(w, h, start, count, data + 3 * count), _offsets(reinterpret_cast<const uint16 *>(data)), _widths(data + 2 * count), _rawData(data)
{
- debug("-- PFont dump:");
- debug("char\tw\th\toffset");
- for (uint c = start; c < start + count; c++) {
- debug("'%c'\t%d\t%d\t%d", (char)c, _widths[c - start], h, _offsets[c - start]);
- }
- debug("-- end dump");
}
PFont::~PFont() {
@@ -169,7 +163,9 @@ void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 co
int pos, bit;
mapChar(chr, pos, bit);
- DgdsFont::drawChar(dst, pos, bit, x, y, getCharWidth(chr), color);
+
+ int w = getCharWidth(chr);
+ DgdsFont::drawChar(dst, pos, bit, x, y, w, color);
}
int PFont::getCharWidth(uint32 chr) const {
Commit: 5f63c5b1afc86ebc8395cac94f6c2db9cbc71309
https://github.com/scummvm/scummvm/commit/5f63c5b1afc86ebc8395cac94f6c2db9cbc71309
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fix parsing for Willy Beamish
The game now starts to play the intro. Still a few new unknown values in the
various structures.
Changed paths:
engines/dgds/ads.cpp
engines/dgds/dgds.cpp
engines/dgds/inventory.cpp
engines/dgds/resource.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/sound.cpp
engines/dgds/ttm.cpp
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index 21327c86a14..dfad55e8305 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -316,7 +316,7 @@ void ADSInterpreter::findEndOrInitOp() {
}
bool ADSInterpreter::logicOpResult(uint16 code, const TTMEnviro *env, const TTMSeq *seq) {
- const char *tag = seq ? env->_tags[seq->_seqNum].c_str() : "";
+ const char *tag = seq ? env->_tags.getValOrDefault(seq->_seqNum).c_str() : "";
int16 envNum = env ? env->_enviro : 0;
int16 seqNum = seq ? seq->_seqNum : 0;
const char *optype = (code < 0x1300 ? "while" : "if");
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 5863641d4a4..ccaaea2617c 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -336,15 +336,13 @@ void DgdsEngine::loadGameFiles() {
// TODO: Create a better type for this..
_gameGlobals = new DragonGlobals(_clock);
_gamePals->loadPalette("WILLY.PAL");
- // TODO: This doesn't parse correctly yet.
- //_gdsScene->load("WILLY.GDS", _resource, _decompressor);
+ _gdsScene->load("WILLY.GDS", _resource, _decompressor);
_rstFileName = "WILLY.RST";
loadCorners("WCORNERS.BMP");
reqParser.parse(&invRequestData, "WINV.REQ");
reqParser.parse(&vcrRequestData, "WVCR.REQ");
- //_scene->load("S34.SDS", _resource, _decompressor);
_adsInterp->load("TITLE.ADS");
break;
case GID_SQ5DEMO:
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index ef12a58d8d6..befbbb29ace 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -84,6 +84,10 @@ void Inventory::setRequestData(const REQFileData &data) {
_fullWidth = req._rect.width;
+ // TODO! Beamish doesn't have a zoom box, or it's a different ID?
+ if (static_cast<DgdsEngine *>(g_engine)->getGameId() == GID_BEAMISH)
+ _itemZoomBox = _itemBox;
+
if (!_prevPageBtn || !_nextPageBtn || !_invClock || !_itemZoomBox || !_exitButton || !_itemArea)
error("Didn't get all expected inventory gadgets");
}
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 9c8cb1d1cd2..41e93ea33e2 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -86,11 +86,12 @@ ResourceManager::ResourceManager() {
_volumes[i].skip(1); // unknown
res.size = _volumes[i].readUint32LE();
- _resources[fileName] = res;
- if (fileName == "" || res.size == 0)
+ // Some sounds in Beamish FDD have size -1, which I think just means they don't exist.
+ if (res.size > (uint32)1 << 31 || fileName == "" || res.size == 0)
continue;
+ _resources[fileName] = res;
}
}
@@ -116,6 +117,7 @@ Common::SeekableReadStream *ResourceManager::getResource(Common::String name, bo
return nullptr;
Resource res = _resources[name];
+
return new Common::SeekableSubReadStream(&_volumes[res.volume], res.pos, res.pos + res.size);
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 0318b07d5cf..158d2c7bdbe 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -210,20 +210,33 @@ Common::String PerSceneGlobal::dump(const Common::String &indent) const {
// //////////////////////////////////// //
+//
+// Check that a list length seems "sensible" so we can crash with
+// a nice error message instead of crash trying to allocate a
+// massive list.
+//
+static void _checkListNotTooLong(uint16 len, const char *list_type) {
+ if (len > 1000)
+ error("Too many %s in list (%d), scene data is likely corrupt.", list_type, len);
+}
+
Scene::Scene() : _magic(0) {
}
bool Scene::isVersionOver(const char *version) const {
+ assert(!_version.empty());
return strncmp(_version.c_str(), version, _version.size()) > 0;
}
bool Scene::isVersionUnder(const char *version) const {
+ assert(!_version.empty());
return strncmp(_version.c_str(), version, _version.size()) < 0;
}
bool Scene::readConditionList(Common::SeekableReadStream *s, Common::Array<SceneConditions> &list) const {
uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "scene conditions");
for (uint16 i = 0; i < num; i++) {
uint16 cnum = s->readUint16LE();
SceneCondition cond = static_cast<SceneCondition>(s->readUint16LE());
@@ -241,6 +254,19 @@ bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
dst._rect.height = s->readUint16LE();
dst._num = s->readUint16LE();
dst._cursorNum = s->readUint16LE();
+ if (isVersionOver(" 1.217"))
+ dst._unk1 = s->readUint16LE();
+ else
+ dst._unk1 = 0;
+
+ if (isVersionOver(" 1.218")) {
+ dst._unk2 = s->readUint16LE();
+ if (dst._unk2) {
+ dst._rect = DgdsRect();
+ }
+ } else {
+ dst._unk2 = 0;
+ }
readConditionList(s, dst.enableConditions);
readOpList(s, dst.onRClickOps);
readOpList(s, dst.onLDownOps);
@@ -251,6 +277,7 @@ bool Scene::readHotArea(Common::SeekableReadStream *s, HotArea &dst) const {
bool Scene::readHotAreaList(Common::SeekableReadStream *s, Common::List<HotArea> &list) const {
uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "hot areas");
for (uint16 i = 0; i < num; i++) {
HotArea dst;
readHotArea(s, dst);
@@ -261,7 +288,10 @@ bool Scene::readHotAreaList(Common::SeekableReadStream *s, Common::List<HotArea>
bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameItem> &list) const {
- list.resize(s->readUint16LE());
+ uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "game items");
+ list.resize(num);
+
for (GameItem &dst : list) {
readHotArea(s, dst);
}
@@ -283,6 +313,8 @@ bool Scene::readGameItemList(Common::SeekableReadStream *s, Common::Array<GameIt
bool Scene::readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const {
uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "mouse hotspots");
+
for (uint16 i = 0; i < num; i++) {
list.push_back(MouseCursor(s->readUint16LE(), s->readUint16LE()));
}
@@ -292,6 +324,8 @@ bool Scene::readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<Mo
bool Scene::readObjInteractionList(Common::SeekableReadStream *s, Common::Array<ObjectInteraction> &list) const {
uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "interactions");
+
for (uint16 i = 0; i < num; i++) {
uint16 dropped, target;
if (!isVersionOver(" 1.205")) {
@@ -310,12 +344,17 @@ bool Scene::readObjInteractionList(Common::SeekableReadStream *s, Common::Array<
bool Scene::readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const {
- list.resize(s->readUint16LE());
+ uint16 nitems = s->readUint16LE();
+ _checkListNotTooLong(nitems, "scene ops");
+ list.resize(nitems);
for (SceneOp &dst : list) {
readConditionList(s, dst._conditionList);
dst._opCode = static_cast<SceneOpCode>(s->readUint16LE());
- int nvals = s->readUint16LE();
- for (int i = 0; i < nvals / 2; i++) {
+ if (dst._opCode > kSceneOpMaxCode || dst._opCode == kSceneOpNone)
+ error("Unexpected scene opcode %d", (int)dst._opCode);
+ uint16 nvals = s->readUint16LE();
+ _checkListNotTooLong(nvals, "scene op args");
+ for (uint16 i = 0; i < nvals / 2; i++) {
dst._args.push_back(s->readUint16LE());
}
}
@@ -327,7 +366,10 @@ bool Scene::readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &li
bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list) const {
// Some data on this format here https://www.oldgamesitalia.net/forum/index.php?showtopic=24055&st=25&p=359214&#entry359214
- list.resize(s->readUint16LE());
+ uint16 nitems = s->readUint16LE();
+ _checkListNotTooLong(nitems, "dialogs");
+ list.resize(nitems);
+
for (Dialog &dst : list) {
dst._num = s->readUint16LE();
dst._rect.x = s->readUint16LE();
@@ -389,8 +431,11 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const {
uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "triggers");
for (uint16 i = 0; i < num; i++) {
list.push_back(SceneTrigger(s->readUint16LE()));
+ if (isVersionOver(" 1.219"))
+ list.back()._unk = s->readUint16LE();
readConditionList(s, list.back().conditionList);
readOpList(s, list.back().sceneOpList);
}
@@ -400,7 +445,9 @@ bool Scene::readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTr
bool Scene::readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const {
- list.resize(s->readUint16LE());
+ uint16 num = s->readUint16LE();
+ _checkListNotTooLong(num, "dialog actions");
+ list.resize(num);
// The original initializes a field in the first entry to 1 here, but it seems
// only used for memory management so we don't need it?
@@ -795,8 +842,8 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
_magic = stream->readUint32LE();
_version = stream->readString();
//if (isVersionOver(" 1.211")) { // Dragon
- if (isVersionOver(" 1.216")) { // HoC
- //if (isVersionOver(" 1.224")) { // Beamish
+ //if (isVersionOver(" 1.216")) { // HoC
+ if (isVersionOver(" 1.224")) { // Beamish
error("Unsupported scene version '%s'", _version.c_str());
}
_num = stream->readUint16LE();
@@ -819,6 +866,9 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
if (isVersionOver(" 1.203")) {
readTriggerList(stream, _triggers);
}
+ if (isVersionOver(" 1.223")) {
+ warning("TODO: Read another list here.");
+ }
return !stream->err();
}
@@ -1436,7 +1486,7 @@ Common::Error SDSScene::syncState(Common::Serializer &s) {
return Common::kNoError;
}
-GDSScene::GDSScene() {
+GDSScene::GDSScene() : _field38(0), _field3a(0), _field3c(0), _field3e(0), _field40(0) {
}
bool GDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
@@ -1607,6 +1657,20 @@ bool GDSScene::parse(Common::SeekableReadStream *stream) {
if (isVersionOver(" 1.205"))
readObjInteractionList(stream, _objInteractions1);
+ if (isVersionOver(" 1.218")) {
+ _field38 = stream->readUint16LE();
+ _field3a = stream->readUint16LE();
+ _field3c = stream->readUint16LE();
+ _field3e = stream->readUint16LE();
+ _field40 = stream->readUint16LE();
+ } else {
+ _field38 = 0;
+ _field3a = 1;
+ _field3c = 2;
+ _field3e = 0;
+ _field40 = 6;
+ }
+
return !stream->err();
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 2768dca55f8..8c42a57e3b0 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -68,6 +68,11 @@ public:
DgdsRect _rect;
uint16 _num; //
uint16 _cursorNum;
+
+ // Used in Willy Beamish
+ uint16 _unk1;
+ uint16 _unk2;
+
Common::Array<SceneConditions> enableConditions;
Common::Array<SceneOp> onRClickOps;
Common::Array<SceneOp> onLDownOps;
@@ -115,6 +120,8 @@ enum SceneOpCode {
kSceneOpOpenChinaOpenGameOverMenu = 114, // args: none.
kSceneOpOpenChinaOpenSkipCreditsMenu = 115, // args: none.
kSceneOpOpenChinaStartIntro = 116, // args: none.
+
+ kSceneOpMaxCode = 255, // for checking file load
};
class SceneOp {
@@ -179,6 +186,8 @@ public:
Common::Array<SceneConditions> conditionList;
Common::Array<SceneOp> sceneOpList;
+
+ uint16 _unk; // Only used in Beamish.
bool _enabled;
uint16 getNum() const { return _num; }
@@ -308,6 +317,13 @@ private:
Common::Array<PerSceneGlobal> _perSceneGlobals;
Common::Array<ObjectInteraction> _objInteractions1;
Common::Array<ObjectInteraction> _objInteractions2;
+
+ // Additional fields that appear in Willy Beamish (unused in others)
+ uint16 _field38;
+ uint16 _field3a;
+ uint16 _field3c;
+ uint16 _field3e;
+ uint16 _field40;
};
class SDSScene : public Scene {
diff --git a/engines/dgds/sound.cpp b/engines/dgds/sound.cpp
index 23fd3b6adf9..f9f2462fcf6 100644
--- a/engines/dgds/sound.cpp
+++ b/engines/dgds/sound.cpp
@@ -257,8 +257,10 @@ void Sound::loadMacMusic(const Common::String &filename) {
error("Unhandled music file type: %s", filename.c_str());
Common::SeekableReadStream *musicStream = _resource->getResource(filename);
- if (!musicStream)
- error("Music file %s not found", filename.c_str());
+ if (!musicStream) {
+ warning("Music file %s not found", filename.c_str());
+ return;
+ }
DgdsChunkReader chunk(musicStream);
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 38b2eb70253..2ac0f33e561 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -138,7 +138,7 @@ static const char *ttmOpName(uint16 op) {
case 0x0090: return "FREE FONT";
case 0x00B0: return "NULLOP";
case 0x0110: return "PURGE";
- case 0x0400: return "PALETTE SOMETHING ?";
+ case 0x0400: return "PALETTE RESET ?";
case 0x0510: return "UNKNOWN 0x0510";
case 0x0ff0: return "FINISH FRAME / DRAW";
case 0x1020: return "SET DELAY";
@@ -156,10 +156,10 @@ static const char *ttmOpName(uint16 op) {
case 0x2000: return "SET DRAW COLORS";
case 0x2010: return "SET FRAME";
case 0x2020: return "SET RANDOM DELAY";
- case 0x2300: return "UNKNOWN 0x23x2 series";
- case 0x2310: return "UNKNOWN 0x23x2 series";
- case 0x2320: return "UNKNOWN 0x23x2 series";
- case 0x2400: return "UNKNOWN 0x2402, palette related";
+ case 0x2300: return "PAL SET BLOCK SWAP 0";
+ case 0x2310: return "PAL SET BLOCK SWAP 1";
+ case 0x2320: return "PAL SET BLOCK SWAP 2";
+ case 0x2400: return "PAL DO BLOCK SWAP";
case 0x4000: return "SET CLIP WINDOW";
case 0x4110: return "FADE OUT";
case 0x4120: return "FADE IN";
@@ -455,6 +455,11 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
_vm->_soundPlayer->stopMusic();
break;
+ case 0x0400: // RESET PALETTE?
+ if (seq._executed) // this is a one-shot op
+ break;
+ warning("TODO: 0x0400 Reset palette");
+ break;
case 0x0ff0: // REFRESH: void
break;
case 0x1020: // SET DELAY: i:int [0..n]
@@ -516,6 +521,20 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
_vm->adsInterpreter()->setScriptDelay((int)(sleep * MS_PER_FRAME));
break;
}
+ case 0x2300:
+ case 0x2310:
+ case 0x2320: {
+ uint num = (op & 0xf) > 4;
+ uint start = ivals[0];
+ uint end = ivals[1];
+ warning("TODO: 0x%04x Palette configure block swap %d (%d - %d)", op, num, start, end);
+ break;
+ }
+ case 0x2400:
+ if (seq._executed) // this is a one-shot op.
+ break;
+ warning("TODO: 0x%04x Palette do block swaps 0x%x, 0x%x", op, ivals[0], ivals[1]);
+ break;
case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
// NOTE: params are xmax/ymax, NOT w/h
seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
@@ -789,7 +808,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
// Unimplemented / unknown
case 0x0010: // (one-shot) ??
case 0x0230: // (one-shot) reset current music? (0 args) - found in HoC intro. Sets params about current music.
- case 0x0400: // (one-shot) set palette??
case 0x1040: // Sets some global? i:int
case 0x10B0: // null op?
case 0x2010: // SET FRAME?? x,y
Commit: 21c133656c2315f21648e42a2fc63e0d8eec62cf
https://github.com/scummvm/scummvm/commit/21c133656c2315f21648e42a2fc63e0d8eec62cf
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Fixes for "coming attractions" demo
Now plays nearly perfectly.
This fixes some underlying mixups in the way fonts worked, which should make
other games better too.
Changed paths:
engines/dgds/detection.cpp
engines/dgds/detection_tables.h
engines/dgds/dgds.cpp
engines/dgds/dgds.h
engines/dgds/font.cpp
engines/dgds/font.h
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/ttm.cpp
engines/dgds/ttm.h
diff --git a/engines/dgds/detection.cpp b/engines/dgds/detection.cpp
index 7fe0e72de35..389f2850fb7 100644
--- a/engines/dgds/detection.cpp
+++ b/engines/dgds/detection.cpp
@@ -28,8 +28,8 @@ static const PlainGameDescriptor dgdsGames[] = {
{"rise", "Rise of the Dragon"},
{"china", "Heart of China"},
{"beamish", "The Adventures of Willy Beamish"},
- {"sq5", "Space Quest V CES Demo"},
- {"comingsoon", "Coming Soon from Sierra Demo"},
+ {"sq5demo", "Space Quest V Demo"},
+ {"comingattractions", "Sierra / Dynamix 1991 Coming Attractions Demo"},
{0, 0}
};
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index 78103d86557..a223b10bcda 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -190,7 +190,7 @@ static const ADGameDescription gameDescriptions[] = {
// SQ5 demo
{
- "sq5",
+ "sq5demo",
0,
{
{"cesdemo.ads", 0, "8b5d56353aae62c69fe81a3ef80c3789", 2394},
@@ -202,9 +202,9 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
- // "Coming Soon" non-interactive demo
+ // "Coming Attractions" non-interactive demo
{
- "comingsoon",
+ "comingattractions",
0,
{
{"demo.ads", 0, "bc709c5defe472f1ddc03db8cf6c83df", 94},
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index ccaaea2617c..0529ce48ec5 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -91,10 +91,10 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
_gameId = GID_CHINA;
else if (!strcmp(gameDesc->gameId, "beamish"))
_gameId = GID_BEAMISH;
- else if (!strcmp(gameDesc->gameId, "sq5"))
+ else if (!strcmp(gameDesc->gameId, "sq5demo"))
_gameId = GID_SQ5DEMO;
- else if (!strcmp(gameDesc->gameId, "comingsoon"))
- _gameId = GID_COMINGSOON;
+ else if (!strcmp(gameDesc->gameId, "comingattractions"))
+ _gameId = GID_COMINGATTRACTIONS;
else
error("Unknown game ID");
@@ -321,7 +321,7 @@ void DgdsEngine::loadGameFiles() {
break;
case GID_CHINA:
// TODO: Create a better type for this..
- _gameGlobals = new DragonGlobals(_clock);
+ _gameGlobals = new Globals(_clock);
_gamePals->loadPalette("HOC.PAL");
_gdsScene->load("HOC.GDS", _resource, _decompressor);
_rstFileName = "HOC.RST";
@@ -334,11 +334,13 @@ void DgdsEngine::loadGameFiles() {
break;
case GID_BEAMISH:
// TODO: Create a better type for this..
- _gameGlobals = new DragonGlobals(_clock);
+ _gameGlobals = new Globals(_clock);
_gamePals->loadPalette("WILLY.PAL");
_gdsScene->load("WILLY.GDS", _resource, _decompressor);
_rstFileName = "WILLY.RST";
+ debug("%s", _gdsScene->dump("").c_str());
+
loadCorners("WCORNERS.BMP");
reqParser.parse(&invRequestData, "WINV.REQ");
reqParser.parse(&vcrRequestData, "WVCR.REQ");
@@ -346,15 +348,13 @@ void DgdsEngine::loadGameFiles() {
_adsInterp->load("TITLE.ADS");
break;
case GID_SQ5DEMO:
- // TODO: Create a better type for this..
- _gameGlobals = new DragonGlobals(_clock);
+ _gameGlobals = new Globals(_clock);
_gamePals->loadPalette("NORMAL.PAL");
_adsInterp->load("CESDEMO.ADS");
_adsInterp->segmentOrState(1, 3);
break;
- case GID_COMINGSOON:
- // TODO: Create a better type for this..
- _gameGlobals = new DragonGlobals(_clock);
+ case GID_COMINGATTRACTIONS:
+ _gameGlobals = new Globals(_clock);
_gamePals->loadPalette("DYNAMIX.PAL");
_adsInterp->load("DEMO.ADS");
_adsInterp->segmentOrState(1, 3);
@@ -371,8 +371,6 @@ void DgdsEngine::loadGameFiles() {
_inventory->setRequestData(invRequestData);
_menu->setRequestData(vcrRequestData);
- //getDebugger()->attach();
-
debug("Parsed Inv Request:\n%s", invRequestData.dump().c_str());
debug("Parsed VCR Request:\n%s", vcrRequestData.dump().c_str());
}
@@ -615,7 +613,7 @@ bool DgdsEngine::canLoadGameStateCurrently(Common::U32String *msg /*= nullptr*/)
bool DgdsEngine::canSaveGameStateCurrently(Common::U32String *msg /*= nullptr*/) {
// Doesn't make sense to save non-interactive demos..
- bool isSavableGame = getGameId() != GID_SQ5DEMO && getGameId() != GID_COMINGSOON;
+ bool isSavableGame = getGameId() != GID_SQ5DEMO && getGameId() != GID_COMINGATTRACTIONS;
return isSavableGame && _gdsScene && _scene && _scene->getNum() != 2
&& _scene->getDragItem() == nullptr && !_isLoading;
}
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 564ca208c48..d33b0df494e 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -67,7 +67,7 @@ enum DgdsGameId {
GID_CHINA,
GID_BEAMISH,
GID_SQ5DEMO,
- GID_COMINGSOON,
+ GID_COMINGATTRACTIONS,
};
enum DgdsDetailLevel {
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index 9e85f98c2bc..b7ce90f0974 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -81,7 +81,7 @@ static inline bool isSet(const byte *data, uint bit) {
return data[bit / 8] & (1 << (7 - (bit % 8)));
}
-void DgdsFont::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, int w, uint32 color) const {
+void DgdsFont::drawChar(Graphics::Surface* dst, int pos, int x, int y, int w, uint32 color) const {
const Common::Rect destRect(Common::Point(x, y), w, _h);
Common::Rect clippedDestRect(dst->w, dst->h);
clippedDestRect.clip(destRect);
@@ -91,7 +91,7 @@ void DgdsFont::drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y,
const int rows = clippedDestRect.height();
const int columns = clippedDestRect.width();
- int bitOffset = bit + croppedBy.x;
+ int bitOffset = croppedBy.x;
int bytesPerRow = (w + 7) / 8;
const byte *src = _glyphs + pos + (croppedBy.y * bytesPerRow);
byte *ptr = (byte *)dst->getBasePtr(clippedDestRect.left, clippedDestRect.top);
@@ -112,18 +112,18 @@ FFont::FFont(byte w, byte h, byte start, byte count, byte *data) : DgdsFont(w, h
FFont::~FFont() {
delete [] _rawData;
}
-void FFont::mapChar(byte chr, int &pos, int &bit) const {
- pos = (chr - _start) * _h;
- bit = 8 - _w;
+
+
+int FFont::charOffset(byte chr) const {
+ return (chr - _start) * _h;
}
void FFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const {
if (!hasChar(chr))
return;
- int pos, bit;
- mapChar(chr, pos, bit);
- DgdsFont::drawChar(dst, pos, bit, x, y, _w, color);
+ int pos = charOffset(chr);
+ DgdsFont::drawChar(dst, pos, x, y, _w, color);
}
FFont *FFont::load(Common::SeekableReadStream &input) {
@@ -152,20 +152,17 @@ PFont::~PFont() {
delete [] _rawData;
}
-void PFont::mapChar(byte chr, int& pos, int& bit) const {
- pos = READ_LE_UINT16(&_offsets[chr - _start]);
- bit = 0;
+int PFont::charOffset(byte chr) const {
+ return READ_LE_UINT16(&_offsets[chr - _start]);
}
void PFont::drawChar(Graphics::Surface* dst, uint32 chr, int x, int y, uint32 color) const {
if (!hasChar(chr))
return;
- int pos, bit;
- mapChar(chr, pos, bit);
-
+ int pos = charOffset(chr);
int w = getCharWidth(chr);
- DgdsFont::drawChar(dst, pos, bit, x, y, w, color);
+ DgdsFont::drawChar(dst, pos, x, y, w, color);
}
int PFont::getCharWidth(uint32 chr) const {
@@ -226,14 +223,14 @@ FontManager::FontType FontManager::fontTypeByName(const Common::String &filename
if (filename == "CHINA.FNT") return kChinaFont;
if (filename == "CHINESE.FNT") return kGameDlgFont;
if (filename == "WILLY.FNT") return kGameFont;
- if (filename == "WVCR.FNT") return kWVCRFont;
+ if (filename == "WVCR.FNT") return kVCRFont;
if (filename == "COMIX_16.FNT") return kGameDlgFont;
- if (filename == "EXIT.FNT") return kGameDlgFont;
- if (filename == "SSM1_12.FNT") return kDefaultFont;
- if (filename == "SSM1_15.FNT") return kGameFont;
- if (filename == "SSM1_30.FNT") return kWVCRFont;
- if (filename == "RMN7_19.FNT") return kGameFont;
- if (filename == "RMN8_11.FNT") return kDefaultFont;
+ if (filename == "EXIT.FNT") return kVCRFont;
+ if (filename == "SSM1_12.FNT") return kGameFont;
+ if (filename == "SSM1_15.FNT") return kGameDlgFont;
+ if (filename == "SSM1_30.FNT") return k8x8Font;
+ if (filename == "RMN7_19.FNT") return kGameDlgFont;
+ if (filename == "RMN8_11.FNT") return kGameFont;
return FontManager::kDefaultFont;
}
@@ -244,29 +241,29 @@ void FontManager::loadFonts(DgdsGameId gameId, ResourceManager *resMgr, Decompre
tryLoadFont("SSM1_15.FNT", resMgr, decomp);
tryLoadFont("SSM1_30.FNT", resMgr, decomp);
tryLoadFont("EXIT.FNT", resMgr, decomp);
- return;
- } else if (gameId == GID_COMINGSOON) {
- tryLoadFont("RMN7_19.FNT", resMgr, decomp);
+ } else if (gameId == GID_COMINGATTRACTIONS) {
tryLoadFont("RMN8_11.FNT", resMgr, decomp);
+ tryLoadFont("RMN7_19.FNT", resMgr, decomp);
tryLoadFont("EXIT.FNT", resMgr, decomp);
+ _fonts.setVal(kDefaultFont, _fonts.getVal(kGameDlgFont));
return;
- }
-
- tryLoadFont("8X8.FNT", resMgr, decomp);
- tryLoadFont("6X6.FNT", resMgr, decomp);
- tryLoadFont("4x5.FNT", resMgr, decomp);
- if (gameId == GID_DRAGON) {
- tryLoadFont("DRAGON.FNT", resMgr, decomp);
- tryLoadFont("7X8.FNT", resMgr, decomp);
- tryLoadFont("P6X6.FNT", resMgr, decomp);
- } else if (gameId == GID_CHINA) {
- tryLoadFont("HOC.FNT", resMgr, decomp);
- tryLoadFont("CHINA.FNT", resMgr, decomp);
- tryLoadFont("CHINESE.FNT", resMgr, decomp);
- } else if (gameId == GID_BEAMISH) {
- tryLoadFont("WILLY.FNT", resMgr, decomp);
- tryLoadFont("WVCR.FNT", resMgr, decomp);
- tryLoadFont("COMIX_16.FNT", resMgr, decomp);
+ } else {
+ tryLoadFont("8X8.FNT", resMgr, decomp);
+ tryLoadFont("6X6.FNT", resMgr, decomp);
+ tryLoadFont("4x5.FNT", resMgr, decomp);
+ if (gameId == GID_DRAGON) {
+ tryLoadFont("DRAGON.FNT", resMgr, decomp);
+ tryLoadFont("7X8.FNT", resMgr, decomp);
+ tryLoadFont("P6X6.FNT", resMgr, decomp);
+ } else if (gameId == GID_CHINA) {
+ tryLoadFont("HOC.FNT", resMgr, decomp);
+ tryLoadFont("CHINA.FNT", resMgr, decomp);
+ tryLoadFont("CHINESE.FNT", resMgr, decomp);
+ } else if (gameId == GID_BEAMISH) {
+ tryLoadFont("WILLY.FNT", resMgr, decomp);
+ tryLoadFont("WVCR.FNT", resMgr, decomp);
+ tryLoadFont("COMIX_16.FNT", resMgr, decomp);
+ }
}
_fonts.setVal(kDefaultFont, _fonts.getVal(kGameFont));
diff --git a/engines/dgds/font.h b/engines/dgds/font.h
index 2376bd4c051..2ed09c56072 100644
--- a/engines/dgds/font.h
+++ b/engines/dgds/font.h
@@ -60,8 +60,9 @@ protected:
byte _count;
const byte *_glyphs;
- void drawChar(Graphics::Surface* dst, int pos, int bit, int x, int y, int w, uint32 color) const;
+ void drawChar(Graphics::Surface* dst, int pos, int x, int y, int w, uint32 color) const;
bool hasChar(byte chr) const;
+ virtual int charOffset(byte chr) const = 0;
};
/* Proportional font (each char has its own width and so data is a different size) */
@@ -78,7 +79,7 @@ protected:
const byte *_widths;
byte *_rawData;
- void mapChar(byte chr, int &pos, int &bit) const;
+ int charOffset(byte chr) const override;
};
/* Fixed-width font */
@@ -93,7 +94,7 @@ public:
protected:
byte *_rawData;
- void mapChar(byte chr, int &pos, int &bit) const;
+ int charOffset(byte chr) const override;
};
class FontManager {
@@ -106,7 +107,7 @@ public:
kGameFont, // DRAGON for Rise of the Dragon, WILLY for Willy Beamish, HOC for Heart of China.
kGameDlgFont, // P6x6 for Rise of the Dragon, COMIX_16 for Willy Beamish, CHINESE for Heart of China
k7x8Font, // Rise of the Dragon only
- kWVCRFont, // Willy Beamish only
+ kVCRFont, // Willy Beamish only
kChinaFont, // Heart of China only
};
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 158d2c7bdbe..4016ab84d08 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -95,8 +95,8 @@ Common::String SceneConditions::dump(const Common::String &indent) const {
Common::String HotArea::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sHotArea<%s num %d cursor %d",
- indent.c_str(), _rect.dump("").c_str(), _num, _cursorNum);
+ Common::String str = Common::String::format("%sHotArea<%s num %d cursor %d unk1 %d unk2 %d",
+ indent.c_str(), _rect.dump("").c_str(), _num, _cursorNum, _unk1, _unk2);
str += _dumpStructList(indent, "enableConditions", enableConditions);
str += _dumpStructList(indent, "onRClickOps", onRClickOps);
str += _dumpStructList(indent, "onLDownOps", onLDownOps);
@@ -195,7 +195,7 @@ Common::String ObjectInteraction::dump(const Common::String &indent) const {
Common::String SceneTrigger::dump(const Common::String &indent) const {
- Common::String str = Common::String::format("%sSceneTrigger<num %d %s", indent.c_str(), _num, _enabled ? "enabled" : "disabled");
+ Common::String str = Common::String::format("%sSceneTrigger<num %d %s %d", indent.c_str(), _num, _enabled ? "enabled" : "disabled", _unk);
str += _dumpStructList(indent, "conditionList", conditionList);
str += _dumpStructList(indent, "opList", sceneOpList);
str += "\n";
@@ -708,6 +708,19 @@ bool Scene::runChinaOp(const SceneOp &op) {
return true;
}
+bool Scene::runBeamishOp(const SceneOp &op) {
+ error("TODO: Implement beamish-specific scene op %d", op._opCode);
+ /*
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ switch (op._opCode) {
+ default:
+ warning("TODO: Implement beamish-specific scene opcode %d", op._opCode);
+ break;
+ }
+ return true;
+ */
+}
+
bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 */) {
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
for (const SceneOp &op : ops) {
@@ -730,6 +743,9 @@ bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 *
case GID_CHINA:
keepGoing = runChinaOp(op);
break;
+ case GID_BEAMISH:
+ keepGoing = runBeamishOp(op);
+ break;
default:
error("TODO: Implement game-specific scene op for this game");
}
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 8c42a57e3b0..5520b2fa188 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -267,6 +267,7 @@ protected:
bool runSceneOp(const SceneOp &op);
bool runDragonOp(const SceneOp &op);
bool runChinaOp(const SceneOp &op);
+ bool runBeamishOp(const SceneOp &op);
uint32 _magic;
Common::String _version;
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 2ac0f33e561..58ccd512dea 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -188,6 +188,9 @@ static const char *ttmOpName(uint16 op) {
case 0xa270: return "DRAW STRING 7";
case 0xa280: return "DRAW STRING 8";
case 0xa290: return "DRAW STRING 9";
+ case 0xa300: return "DRAW STRINGS AS DLG";
+ case 0xa400: return "DRAW FILLED CIRCLE";
+ case 0xa420: return "DRAW EMPTY CIRCLE";
case 0xa500: return "DRAW BMP";
case 0xa520: return "DRAW SPRITE FLIP";
case 0xa530: return "DRAW BMP4";
@@ -214,9 +217,6 @@ static const char *ttmOpName(uint16 op) {
case 0x00C0: return "FREE BACKGROUND";
case 0x0230: return "reset current music?";
case 0x1310: return "STOP SFX";
- case 0xa300: return "DRAW some string";
- case 0xa400: return "DRAW FILLED CIRCLE";
- case 0xa420: return "DRAW EMPTY CIRCLE";
case 0xa510: return "DRAW SPRITE1";
case 0xb600: return "DRAW SCREEN";
case 0xc020: return "LOAD_SAMPLE";
@@ -253,7 +253,7 @@ static void _copyRectToScreen(const Graphics::ManagedSurface &src, const Common:
}
-void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, const Common::Rect &r) {
+void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, TTMSeq &seq, const Common::Rect &r) {
//
// In the original games, these operations copy certain parts of the buffer on to
// the screen, and rely on the system's speed to make it happen faster than a regular
@@ -400,7 +400,58 @@ int16 TTMInterpreter::doOpInitCreditScroll(const Image *img) {
return scrollFinished;
}
-void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
+void TTMInterpreter::doDrawDialogForStrings(TTMEnviro &env, TTMSeq &seq, int16 x, int16 y, int16 width, int16 height) {
+ int16 fontno = seq._currentFontId;
+ if (fontno >= (int16)env._fonts.size()) {
+ warning("Trying to draw font no %d but only loaded %d", fontno, env._fonts.size());
+ fontno = 0;
+ }
+ const FontManager *mgr = _vm->getFontMan();
+ const DgdsFont *font = mgr->getFont(env._fonts[fontno]);
+ int16 lineHeight = font->getFontHeight();
+
+ // FIXME: this doesn't match original code but seems to be needed to make it right??
+ int16 charWidth = font->getMaxCharWidth() / 2;
+ if (lineHeight == 0 || charWidth == 0)
+ return;
+ // Black background
+ Common::Rect drawRect = Common::Rect(Common::Point(x, y), width - 3, height - 3);
+ _vm->_compositionBuffer.fillRect(drawRect, 0);
+ drawRect.grow(-1);
+ // Header area color
+ _vm->_compositionBuffer.fillRect(drawRect, seq._drawColBG);
+
+ // Main text bg
+ _vm->_compositionBuffer.fillRect(Common::Rect(Common::Point(x, y + lineHeight + 2), width - 3, height - lineHeight - 5), 0);
+ _vm->_compositionBuffer.fillRect(Common::Rect(Common::Point(x + 1, y + lineHeight + 4), width - 5, height - lineHeight - 8), seq._drawColFG);
+
+ // Drop shadow.
+ _vm->_compositionBuffer.fillRect(Common::Rect(Common::Point(x + width - 3, y + 3), 3, height - 3), 0);
+ _vm->_compositionBuffer.fillRect(Common::Rect(Common::Point(x + 3, y + height - 3), width - 3, 3), 0);
+
+ for (int i = 0; i < ARRAYSIZE(env._strings); i++) {
+ const Common::String &str = env._strings[i];
+ int16 lineX;
+ int16 lineY;
+ if ((int)str.size() * charWidth < width) {
+ if (i == 0) {
+ int16 lineWidth = font->getStringWidth(str);
+ // Heading is centered
+ lineX = x + (width - lineWidth) / 2;
+ lineY = y + 2;
+ } else {
+ if (height <= (i + 2) * lineHeight)
+ continue;
+ lineX = x + charWidth;
+ lineY = y + i * lineHeight + 5;
+ }
+ font->drawString(_vm->_compositionBuffer.surfacePtr(), str, lineX, lineY, width, 0);
+ }
+ }
+}
+
+
+void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
switch (op) {
case 0x0000: // FINISH: void
break;
@@ -652,7 +703,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0xa290: {
int16 fontno = seq._currentFontId;
if (fontno >= (int16)env._fonts.size()) {
- warning("Trying to draw font no %d but only loaded %d", seq._currentFontId, env._fonts.size());
+ warning("Trying to draw font no %d but only loaded %d", fontno, env._fonts.size());
fontno = 0;
}
uint strnum = (op & 0x70) >> 4;
@@ -666,6 +717,9 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
font->drawString(&(_vm->_compositionBuffer), str, ivals[0], ivals[1], width, seq._drawColFG);
break;
}
+ case 0xa300:
+ doDrawDialogForStrings(env, seq, ivals[0], ivals[1], ivals[2], ivals[3]);
+ break;
case 0xa510:
// DRAW SPRITE x,y:int .. how different from 0xa500??
// FALL THROUGH
@@ -766,7 +820,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
break;
const FontManager *mgr = _vm->getFontMan();
env._fonts.push_back(mgr->fontTypeByName(sval));
- seq._currentFontId = env._fonts.size() - 1;
break;
}
case 0xf050: { // LOAD PAL: filename:str
@@ -811,7 +864,6 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
case 0x1040: // Sets some global? i:int
case 0x10B0: // null op?
case 0x2010: // SET FRAME?? x,y
- case 0xa300: // DRAW some string? x,y,?,?:int
case 0xa400: // DRAW FILLED CIRCLE
case 0xa420: // DRAW EMPTY CIRCLE
case 0xb600: // DRAW SCREEN?? 6 args // HoC onward
@@ -829,7 +881,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16
}
}
-bool TTMInterpreter::run(TTMEnviro &env, struct TTMSeq &seq) {
+bool TTMInterpreter::run(TTMEnviro &env, TTMSeq &seq) {
Common::SeekableReadStream *scr = env.scr;
if (!scr || scr->pos() >= scr->size())
return false;
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index 11826ca6bfe..b6b24942586 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -40,7 +40,6 @@ public:
TTMEnviro() : _totalFrames(330), _enviro(0), _creditScrollMeasure(0),
_creditScrollYOffset(0), ScriptParserData() {
ARRAYCLEAR(_scriptPals);
- _fonts.push_back(FontManager::kDefaultFont); // is this right?
}
Common::Error syncState(Common::Serializer &s);
@@ -110,15 +109,16 @@ public:
bool load(const Common::String &filename, TTMEnviro &env);
void unload();
- bool run(TTMEnviro &env, struct TTMSeq &seq);
+ bool run(TTMEnviro &env, TTMSeq &seq);
void findAndAddSequences(TTMEnviro &scriptData, Common::Array<TTMSeq> &seqArray);
protected:
- void handleOperation(TTMEnviro &env, struct TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
+ void handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);
- void doWipeOp(uint16 code, TTMEnviro &env, struct TTMSeq &seq, const Common::Rect &r);
+ void doWipeOp(uint16 code, TTMEnviro &env, TTMSeq &seq, const Common::Rect &r);
int16 doOpInitCreditScroll(const Image *img);
bool doOpCreditsScroll(const Image *img, int16 ygap, int16 ymax, int16 xoff, int16 measuredWidth, const Common::Rect &clipRect);
+ void doDrawDialogForStrings(TTMEnviro &env, TTMSeq &seq, int16 x, int16 y, int16 width, int16 height);
DgdsEngine *_vm;
};
Commit: a80ea4c5257cb440fe43f77238faeed5e3445c90
https://github.com/scummvm/scummvm/commit/a80ea4c5257cb440fe43f77238faeed5e3445c90
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-06-30T22:49:18+03:00
Commit Message:
DGDS: Implement more required features for Willy Beamish
Added ttm 'gosub' instruction and scaled blit support.
Changed paths:
engines/dgds/ads.cpp
engines/dgds/ads.h
engines/dgds/image.cpp
engines/dgds/image.h
engines/dgds/menu.cpp
engines/dgds/menu.h
engines/dgds/parser.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
engines/dgds/ttm.cpp
engines/dgds/ttm.h
diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index dfad55e8305..aa751f55638 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -88,6 +88,8 @@ bool ADSInterpreter::load(const Common::String &filename) {
dgds.parse(_adsData, detailfile);
for (const auto &file : _adsData->_scriptNames) {
+ if (file.empty())
+ continue;
_adsData->_scriptEnvs.resize(_adsData->_scriptEnvs.size() + 1);
debug(" load TTM %s to env %d", file.c_str(), _adsData->_scriptEnvs.size());
TTMEnviro &data = _adsData->_scriptEnvs.back();
@@ -884,8 +886,8 @@ bool ADSInterpreter::runUntilBranchOpOrEnd() {
return more;
}
-void ADSInterpreter::setHitTTMOp0110() {
- _adsData->_hitTTMOp0110 = true;
+void ADSInterpreter::setHitTTMOp0110(bool val /* = true */) {
+ _adsData->_hitTTMOp0110 = val;
}
void ADSInterpreter::setGotoTarget(int32 target) {
diff --git a/engines/dgds/ads.h b/engines/dgds/ads.h
index 538e704c158..89d5a619d7f 100644
--- a/engines/dgds/ads.h
+++ b/engines/dgds/ads.h
@@ -72,7 +72,8 @@ public:
void segmentOrState(int16 seg, uint16 val);
void segmentSetState(int16 seg, uint16 val);
- void setHitTTMOp0110(); // TODO: better name for this global?
+ void setHitTTMOp0110(bool val = true); // TODO: better name for this global?
+ bool getHitTTMOp0110() const { return _adsData->_hitTTMOp0110; }
void setGotoTarget(int32 target);
int16 getStateForSceneOp(uint16 segnum);
void setScriptDelay(int16 delay) { _adsData->_scriptDelay = delay; }
diff --git a/engines/dgds/image.cpp b/engines/dgds/image.cpp
index 8cae809086a..41680980aee 100644
--- a/engines/dgds/image.cpp
+++ b/engines/dgds/image.cpp
@@ -235,48 +235,56 @@ void Image::loadBitmap(const Common::String &filename) {
delete fileStream;
}
-void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &destSurf, bool flip) const {
+void Image::drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &destSurf, bool flip, int dstWidth, int dstHeight) const {
if (frameno >= _frames.size()) {
warning("drawBitmap: Trying to draw frame %d from a %d frame image %s!", frameno, _frames.size(), _filename.c_str());
return;
}
const Common::SharedPtr<Graphics::ManagedSurface> srcFrame = _frames[frameno];
- const Common::Rect destRect(x, y, x + srcFrame->w, y + srcFrame->h);
+
+ int srcWidth = srcFrame->w;
+ int srcHeight = srcFrame->h;
+ if (dstWidth == 0)
+ dstWidth = srcWidth;
+ if (dstHeight == 0)
+ dstHeight = srcHeight;
+
+ const Common::Rect destRect(Common::Point(x, y), dstWidth, dstHeight);
Common::Rect clippedDestRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
clippedDestRect.clip(destRect);
clippedDestRect.clip(drawWin);
+ if (clippedDestRect.isEmpty())
+ return;
- Common::Point srcTopLeft(clippedDestRect.left - destRect.left, clippedDestRect.top - destRect.top);
- const int rows = clippedDestRect.height();
- const int columns = clippedDestRect.width();
+ const byte *src = (const byte *)srcFrame->getBasePtr(0, 0);
+ // Note: this is not super optimized, but it's easy to understand at least..
+ byte *dst = (byte *)destSurf.getBasePtr(x, y);
- if (!rows || !columns) {
- //debug("Draw at %d,%d frame %dx%d clipwin %d,%d-%d,%d gives null image area", x, y,
- // srcFrame->w, srcFrame->h, drawWin.left, drawWin.top, drawWin.right, drawWin.bottom);
- return;
- }
+ for (int i = 0; i < dstHeight; ++i) {
+ if (y + i < drawWin.top || y + i >= drawWin.bottom) {
+ dst += destSurf.pitch;
+ continue;
+ }
- // Flip should be applied before clip window
- if (flip)
- srcTopLeft.x = (srcFrame->w - srcTopLeft.x) - columns;
-
- const byte *src = (const byte *)srcFrame->getBasePtr(srcTopLeft.x, srcTopLeft.y);
- byte *dst = (byte *)destSurf.getBasePtr(clippedDestRect.left, clippedDestRect.top);
- for (int i = 0; i < rows; ++i) {
- if (flip) {
- for (int j = 0; j < columns; ++j) {
- if (src[columns - j - 1])
- dst[j] = src[columns - j - 1];
- }
- } else {
- for (int j = 0; j < columns; ++j) {
- if (src[j])
- dst[j] = src[j];
+ const byte *srcRow = src + srcFrame->pitch * (i * srcHeight / dstHeight);
+
+ for (int j = 0; j < dstWidth; ++j) {
+ if (flip) {
+ if (x + j < drawWin.left || x + j >= drawWin.right)
+ continue;
+ int srcX = (dstWidth - j - 1) * srcWidth / dstWidth;
+ if (srcRow[srcX])
+ dst[j] = srcRow[srcX];
+ } else {
+ if (x + j < drawWin.left || x + j >= drawWin.right)
+ continue;
+ int srcX = j * srcWidth / dstWidth;
+ if (srcRow[srcX])
+ dst[j] = srcRow[srcX];
}
}
dst += destSurf.pitch;
- src += srcFrame->pitch;
}
}
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index 9b7bdbaa52f..5a76bbce779 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -50,7 +50,7 @@ public:
void loadBitmap(const Common::String &filename);
int frameCount(const Common::String &filename);
- void drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &dst, bool flip = false) const;
+ void drawBitmap(uint frameno, int x, int y, const Common::Rect &drawWin, Graphics::ManagedSurface &dst, bool flip = false, int dstWidth = 0, int dstHeight = 0) const;
Common::SharedPtr<Graphics::ManagedSurface> getSurface(uint frameno) const;
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 1cb61a3e2af..01da6240232 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -186,6 +186,9 @@ void Menu::drawMenuText(Graphics::ManagedSurface &dst) {
Common::Array<Common::SharedPtr<Gadget> > gadgets = _menuRequests[_curMenu]._gadgets;
Common::Array<TextItem> textItems = _menuRequests[_curMenu]._textItemList;
+ if (gadgets.empty())
+ return;
+
// TODO: Get the parent coordinates properly
uint16 parentX = gadgets[0].get()->_parentX;
uint16 parentY = gadgets[0].get()->_parentY;
diff --git a/engines/dgds/menu.h b/engines/dgds/menu.h
index f3d19d95d72..4d9eb80adae 100644
--- a/engines/dgds/menu.h
+++ b/engines/dgds/menu.h
@@ -68,6 +68,7 @@ enum MenuId {
kMenuSaveBeforeArcade = 46,
kMenuReplayArcade = 45,
kMenuArcadeFrustrated = 47,
+ kMenuBeamishSkipCredits = 50,
};
class Menu {
diff --git a/engines/dgds/parser.cpp b/engines/dgds/parser.cpp
index dea7059d229..9617858dc84 100644
--- a/engines/dgds/parser.cpp
+++ b/engines/dgds/parser.cpp
@@ -136,10 +136,13 @@ bool ADSParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
for (uint16 i = 0; i < count; i++) {
uint16 idx = chunkStream->readUint16LE();
- assert(idx == (i + 1));
+ //assert(idx == (i + 1)); // not true in Willy Beamish.
+ if (idx > scriptData->_scriptNames.size())
+ scriptData->_scriptNames.resize(idx);
+
Common::String string = chunkStream->readString();
- scriptData->_scriptNames.push_back(string);
+ scriptData->_scriptNames[idx - 1] = string;
}
} break;
case ID_SCR:
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 4016ab84d08..89269597440 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -709,16 +709,16 @@ bool Scene::runChinaOp(const SceneOp &op) {
}
bool Scene::runBeamishOp(const SceneOp &op) {
- error("TODO: Implement beamish-specific scene op %d", op._opCode);
- /*
DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
switch (op._opCode) {
+ case kSceneOpOpenBeamishOpenSkipCreditsMenu:
+ engine->setMenuToTrigger(kMenuBeamishSkipCredits);
+ break;
default:
warning("TODO: Implement beamish-specific scene opcode %d", op._opCode);
break;
}
return true;
- */
}
bool Scene::runOps(const Common::Array<SceneOp> &ops, int16 addMinuites /* = 0 */) {
@@ -883,7 +883,7 @@ bool SDSScene::parse(Common::SeekableReadStream *stream) {
readTriggerList(stream, _triggers);
}
if (isVersionOver(" 1.223")) {
- warning("TODO: Read another list here.");
+ warning("TODO: SDSScene::parse read another list here for version %s", _version.c_str());
}
return !stream->err();
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 5520b2fa188..213234d1dfa 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -121,6 +121,9 @@ enum SceneOpCode {
kSceneOpOpenChinaOpenSkipCreditsMenu = 115, // args: none.
kSceneOpOpenChinaStartIntro = 116, // args: none.
+ // Beamish-specific opcodes
+ kSceneOpOpenBeamishOpenSkipCreditsMenu = 101,
+
kSceneOpMaxCode = 255, // for checking file load
};
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 58ccd512dea..96245ab6806 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -115,11 +115,12 @@ Common::Error TTMSeq::syncState(Common::Serializer &s) {
return Common::kNoError;
}
-TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm) {}
+TTMInterpreter::TTMInterpreter(DgdsEngine *vm) : _vm(vm), _stackDepth(0) {}
bool TTMInterpreter::load(const Common::String &filename, TTMEnviro &scriptData) {
TTMParser dgds(_vm->getResourceManager(), _vm->getDecompressor());
bool parseResult = dgds.parse(&scriptData, filename);
+ _stackDepth = 0;
scriptData.scr->seek(0);
@@ -160,6 +161,7 @@ static const char *ttmOpName(uint16 op) {
case 0x2310: return "PAL SET BLOCK SWAP 1";
case 0x2320: return "PAL SET BLOCK SWAP 2";
case 0x2400: return "PAL DO BLOCK SWAP";
+ case 0x3000: return "GOSUB";
case 0x4000: return "SET CLIP WINDOW";
case 0x4110: return "FADE OUT";
case 0x4120: return "FADE IN";
@@ -269,7 +271,7 @@ void TTMInterpreter::doWipeOp(uint16 code, TTMEnviro &env, TTMSeq &seq, const Co
//
switch(code) {
case 0xa010:
- // TODO: How is this different to a020?
+ warning("TODO: Implement TTM 0xa010 wipe (dissolve) op");
_copyRectToScreen(_vm->_compositionBuffer, r);
g_system->updateScreen();
break;
@@ -586,6 +588,27 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
break;
warning("TODO: 0x%04x Palette do block swaps 0x%x, 0x%x", op, ivals[0], ivals[1]);
break;
+ case 0x3000: {
+ _stackDepth++;
+ bool prevHitOp0110Val = _vm->adsInterpreter()->getHitTTMOp0110();
+ int32 target = findGOTOTarget(env, seq, ivals[2]);
+ if (target == -1)
+ error("TTM gosub to frame %d which doesn't exist", target);
+ int64 prevPos = env.scr->pos();
+ env.scr->seek(env._frameOffsets[target]);
+
+ // TODO: Set some other render-related globals here
+ warning("TODO: TTM 0x3000 GOSUB %d %d, use other args", ivals[0], ivals[1]);
+
+ run(env, seq);
+ env.scr->seek(prevPos);
+
+ if (_vm->adsInterpreter()->getHitTTMOp0110() && !prevHitOp0110Val)
+ _vm->adsInterpreter()->setHitTTMOp0110(false);
+
+ _stackDepth--;
+ break;
+ }
case 0x4000: // SET CLIP WINDOW x,y,x2,y2:int [0..320,0..200]
// NOTE: params are xmax/ymax, NOT w/h
seq._drawWin = Common::Rect(ivals[0], ivals[1], ivals[2], ivals[3]);
@@ -679,7 +702,8 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
break;
}
case 0xa100: { // DRAW FILLED RECT x,y,w,h:int [0..320,0..200]
- const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+ r.clip(seq._drawWin);
_vm->_compositionBuffer.fillRect(r, seq._drawColFG);
break;
}
@@ -736,10 +760,13 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
// DRAW BMP: x,y,tile-id,bmp-id:int [-n,+n] (CHINA)
int frameno;
int bmpNo;
+ int dstWidth = 0;
+ int dstHeight = 0;
if (count == 6) {
frameno = ivals[2];
bmpNo = ivals[3];
- warning("TODO: Implement other args %d %d of 6-arg draw function 0x%4x", ivals[4], ivals[5], op);
+ dstWidth = ivals[4];
+ dstHeight = ivals[5];
} else if (count == 4) {
frameno = ivals[2];
bmpNo = ivals[3];
@@ -751,7 +778,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
// DRAW BMP: x,y:int [-n,+n] (RISE)
Common::SharedPtr<Image> img = env._scriptShapes[bmpNo];
if (img)
- img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->_compositionBuffer, op == 0xa520);
+ img->drawBitmap(frameno, ivals[0], ivals[1], seq._drawWin, _vm->_compositionBuffer, op == 0xa520, dstWidth, dstHeight);
else
warning("Trying to draw image %d in env %d which is not loaded", bmpNo, env._enviro);
break;
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index b6b24942586..e96b75adac3 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -121,6 +121,7 @@ protected:
void doDrawDialogForStrings(TTMEnviro &env, TTMSeq &seq, int16 x, int16 y, int16 width, int16 height);
DgdsEngine *_vm;
+ int _stackDepth;
};
} // end namespace Dgds
More information about the Scummvm-git-logs
mailing list