[Scummvm-git-logs] scummvm master -> 8dac7f3d320207e11ee23034341f0059f5bca869
sluicebox
noreply at scummvm.org
Thu Jan 15 01:28:22 UTC 2026
This automated email contains information about 13 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
9a9b735026 HUGO: Use default EGA palette on DOS versions
9c63b10708 HUGO: Fix off-by-one in displayRect()
ece405f10a HUGO: Fix drawRectangle() inaccuracies
9eb69e9ef4 HUGO: Use DOS font for status bar and input prompt
fbf2768f41 HUGO: Use enum for TTS options, reduce bool parameters
1e39c02156 HUGO: Rename status and prompt line variables
c3dfddd31c HUGO: Fix CRLF handling when reading HELP.DAT
775e451f32 HUGO: Format copyright string for DOS message box
c5d61499c0 HUGO: Format advertisement string for DOS message box
c48a876291 HUGO: Add DOS message boxes and prompts
4d57d28195 HUGO: Update DOS inventory message box
509c85e67b HUGO: Disable mouse when not using Windows interface
8dac7f3d32 HUGO: Add config option for Windows interface in DOS
Commit: 9a9b735026c9c25b69a8cf46493a8a0276d95df8
https://github.com/scummvm/scummvm/commit/9a9b735026c9c25b69a8cf46493a8a0276d95df8
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Use default EGA palette on DOS versions
DOS versions now use their original colors instead
of our modified version of the Windows palette.
Existing saves will still use previous colors,
as the save files contain the current palette.
Changed paths:
engines/hugo/display.cpp
engines/hugo/display.h
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index 6ff37bc76ed..9675c141f67 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -546,18 +546,6 @@ void Screen::initNewScreenDisplay() {
_vm->getGameStatus()._newScreenFl = true;
}
-/**
- * Load palette from Hugo.dat
- */
-void Screen::loadPalette(Common::ReadStream &in) {
- // Read palette
- _paletteSize = in.readUint16BE();
- _mainPalette = (byte *)malloc(sizeof(byte) * _paletteSize);
- _curPalette = (byte *)malloc(sizeof(byte) * _paletteSize);
- for (int i = 0; i < _paletteSize; i++)
- _curPalette[i] = _mainPalette[i] = in.readByte();
-}
-
/**
* Free fonts, main and current palettes
*/
@@ -778,6 +766,23 @@ OverlayState Screen_v1d::findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) {
return kOvlBackground; // No bits set, must be background
}
+/**
+ * Load default EGA palette. Skip Windows palette from Hugo.dat
+ */
+void Screen_v1d::loadPalette(Common::SeekableReadStream &in) {
+ // Skip Windows palette
+ uint16 winPaletteSize = in.readUint16BE();
+ in.skip(winPaletteSize);
+
+ // Load default EGA palette
+ Graphics::Palette egaPalette = Graphics::Palette::createEGAPalette();
+ _paletteSize = egaPalette.size() * 3;
+ _mainPalette = (byte *)malloc(_paletteSize);
+ _curPalette = (byte *)malloc(_paletteSize);
+ memcpy(_mainPalette, egaPalette.data(), _paletteSize);
+ memcpy(_curPalette, egaPalette.data(), _paletteSize);
+}
+
Screen_v1w::Screen_v1w(HugoEngine *vm) : Screen(vm) {
}
@@ -882,4 +887,16 @@ OverlayState Screen_v1w::findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) {
return kOvlBackground; // No bits set, must be background
}
+/**
+ * Load Windows palette from Hugo.dat
+ */
+void Screen_v1w::loadPalette(Common::SeekableReadStream &in) {
+ // Read palette
+ _paletteSize = in.readUint16BE();
+ _mainPalette = (byte *)malloc(sizeof(byte) * _paletteSize);
+ _curPalette = (byte *)malloc(sizeof(byte) * _paletteSize);
+ for (int i = 0; i < _paletteSize; i++)
+ _curPalette[i] = _mainPalette[i] = in.readByte();
+}
+
} // End of namespace Hugo
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index 1982634e9c3..f346219e02a 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -31,6 +31,7 @@
namespace Common {
class ReadStream;
+class SeekableReadStream;
class WriteStream;
}
@@ -70,7 +71,7 @@ public:
void hideCursor();
void initDisplay();
void initNewScreenDisplay();
- void loadPalette(Common::ReadStream &in);
+ virtual void loadPalette(Common::SeekableReadStream &in) = 0;
void moveImage(ImagePtr srcImage, const int16 x1, const int16 y1, const int16 dx, int16 dy, const int16 width1, ImagePtr dstImage, const int16 x2, const int16 y2, const int16 width2);
void remapPal(uint16 oldIndex, uint16 newIndex);
void resetInventoryObjId();
@@ -109,8 +110,10 @@ protected:
byte _fnt; // Current font number
byte _fontdata[kNumFonts][kFontSize]; // Font data
byte *_font[kNumFonts][kFontLength]; // Ptrs to each char
- byte *_mainPalette;
int16 _arrayFontSize[kNumFonts];
+ byte *_mainPalette;
+ byte *_curPalette;
+ byte _paletteSize;
Viewdib _frontBuffer;
@@ -119,9 +122,7 @@ protected:
inline bool isOverlapping(const Rect *rectA, const Rect *rectB) const;
private:
- byte *_curPalette;
byte _iconImage[kInvDx * kInvDy];
- byte _paletteSize;
Icondib _iconBuffer; // Inventory icon DIB
@@ -153,6 +154,8 @@ public:
void loadFontArr(Common::ReadStream &in) override;
void displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) override;
+
+ void loadPalette(Common::SeekableReadStream &in) override;
protected:
OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y);
};
@@ -166,6 +169,8 @@ public:
void loadFontArr(Common::ReadStream &in) override;
void displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) override;
+
+ void loadPalette(Common::SeekableReadStream &in) override;
protected:
OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y);
};
Commit: 9c63b10708e07d7189a13600c888058ac8bbad69
https://github.com/scummvm/scummvm/commit/9c63b10708e07d7189a13600c888058ac8bbad69
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Fix off-by-one in displayRect()
Fixes rectangles not be being drawn in the right column or bottom row.
Changed paths:
engines/hugo/display.cpp
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index 9675c141f67..543b313b384 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -187,7 +187,7 @@ void Screen::displayRect(const int16 x, const int16 y, const int16 dx, const int
int16 xClip, yClip;
xClip = CLIP<int16>(x, 0, 319);
yClip = CLIP<int16>(y, 0, 199);
- g_system->copyRectToScreen(&_frontBuffer[xClip + yClip * 320], 320, xClip, yClip, CLIP<int16>(dx, 0, 319 - xClip), CLIP<int16>(dy, 0, 199 - yClip));
+ g_system->copyRectToScreen(&_frontBuffer[xClip + yClip * 320], 320, xClip, yClip, CLIP<int16>(dx, 0, 320 - xClip), CLIP<int16>(dy, 0, 200 - yClip));
}
/**
Commit: ece405f10ac8bab14b67d35d16ed4f174aab113b
https://github.com/scummvm/scummvm/commit/ece405f10ac8bab14b67d35d16ed4f174aab113b
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Fix drawRectangle() inaccuracies
Rectangles in HUGO1 intro are now drawn correctly
- Coordinates are now correctly treated as inclusive
- Unfilled rectangles are now correctly clipped
- Unfilled rectangles now draw their lower right pixel
Changed paths:
engines/hugo/display.cpp
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index 543b313b384..fd3ba053ec7 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -508,28 +508,34 @@ void Screen::drawShape(const int x, const int y, const int color1, const int col
}
}
}
+
/**
- * Display rectangle (filles or empty)
+ * Display rectangle (filled or empty)
+ *
+ * x1,y1: upper left of rectangle.
+ * x2,y2: lower right of rectangle.
+ *
+ * This is used by DOS code as a replacement for _rectangle() from QuickC
*/
void Screen::drawRectangle(const bool filledFl, const int16 x1, const int16 y1, const int16 x2, const int16 y2, const int color) {
assert(x1 <= x2);
assert(y1 <= y2);
- int16 x2Clip = CLIP<int16>(x2, 0, 320);
- int16 y2Clip = CLIP<int16>(y2, 0, 200);
+ int16 x2Clip = CLIP<int16>(x2, 0, 319);
+ int16 y2Clip = CLIP<int16>(y2, 0, 199);
if (filledFl) {
- for (int i = y1; i < y2Clip; i++) {
- for (int j = x1; j < x2Clip; j++)
+ for (int i = y1; i <= y2Clip; i++) {
+ for (int j = x1; j <= x2Clip; j++)
_frontBuffer[320 * i + j] = color;
}
} else {
- for (int i = y1; i < y2Clip; i++) {
+ for (int i = y1; i <= y2Clip; i++) {
_frontBuffer[320 * i + x1] = color;
- _frontBuffer[320 * i + x2] = color;
+ _frontBuffer[320 * i + x2Clip] = color;
}
for (int i = x1; i < x2Clip; i++) {
_frontBuffer[320 * y1 + i] = color;
- _frontBuffer[320 * y2 + i] = color;
+ _frontBuffer[320 * y2Clip + i] = color;
}
}
}
Commit: 9eb69e9ef4cf8a0f0aede18753eae12507c2092f
https://github.com/scummvm/scummvm/commit/9eb69e9ef4cf8a0f0aede18753eae12507c2092f
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Use DOS font for status bar and input prompt
Changed paths:
engines/hugo/display.cpp
engines/hugo/display.h
engines/hugo/hugo.h
engines/hugo/parser.cpp
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index fd3ba053ec7..e825b84a898 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -106,6 +106,8 @@ Screen::Screen(HugoEngine *vm) : _vm(vm) {
}
_fnt = 0;
_paletteSize = 0;
+
+ _frontSurface.init(320, 200, 320, _frontBuffer, Graphics::PixelFormat::createFormatCLUT8());
}
Screen::~Screen() {
@@ -475,23 +477,13 @@ void Screen::userHelp() const {
void Screen::drawStatusText() {
debugC(4, kDebugDisplay, "drawStatusText()");
- loadFont(U_FONT8);
- uint16 sdx = stringLength(_vm->_statusLine);
- uint16 sdy = fontHeight() + 1; // + 1 for shadow
- uint16 posX = 0;
- uint16 posY = kYPix - sdy;
-
- // Display the string and add rect to display list
- writeStr(posX, posY, _vm->_statusLine, _TLIGHTYELLOW);
- displayList(kDisplayAdd, posX, posY, sdx, sdy);
-
- sdx = stringLength(_vm->_scoreLine);
- posY = 0;
+ // Draw score line at top row
+ Common::Rect scoreRect = drawDosText(0, 0, _vm->_scoreLine, _TCYAN);
+ displayList(kDisplayAdd, scoreRect.left, scoreRect.top, scoreRect.width(), scoreRect.height());
- //Display a black behind the score line
- _vm->_screen->drawRectangle(true, 0, 0, kXPix, 8, _TBLACK);
- writeStr(posX, posY, _vm->_scoreLine, _TCYAN);
- displayList(kDisplayAdd, posX, posY, sdx, sdy);
+ // Draw status line at bottom row
+ Common::Rect statusRect = drawDosText(0, kMaxTextRows - 1, _vm->_statusLine, _TLIGHTYELLOW);
+ displayList(kDisplayAdd, statusRect.left, statusRect.top, statusRect.width(), statusRect.height());
}
void Screen::drawShape(const int x, const int y, const int color1, const int color2) {
@@ -540,6 +532,35 @@ void Screen::drawRectangle(const bool filledFl, const int16 x1, const int16 y1,
}
}
+/**
+ * Draws text to the screen using DOS font with a black background
+ *
+ * Coordinates are in text: x = 0-39, y = 0-24.
+ * Returns screen rectangle of drawn text so that it can be invalidated.
+ */
+Common::Rect Screen::drawDosText(byte x, byte y, const char *text, byte color) {
+ // Calculate text length
+ assert(x < kMaxTextCols);
+ assert(y < kMaxTextRows);
+ int textLength = strlen(text);
+ if (x + textLength > kMaxTextCols) {
+ textLength = kMaxTextCols - x;
+ }
+
+ // Draw black background
+ int sx = x * 8;
+ int sy = y * 8;
+ Common::Rect rect(sx, sy, sx + (textLength * 8), sy + 8);
+ _frontSurface.fillRect(rect, _TBLACK);
+
+ // Draw text
+ for (int i = 0; i < textLength; i++) {
+ _dosFont.drawChar(&_frontSurface, (byte)text[i], sx, sy, color);
+ sx += 8;
+ }
+ return rect;
+}
+
/**
* Initialize screen components and display results
*/
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index f346219e02a..fc30b269b05 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -29,6 +29,9 @@
#ifndef HUGO_DISPLAY_H
#define HUGO_DISPLAY_H
+#include "graphics/surface.h"
+#include "graphics/fonts/dosfont.h"
+
namespace Common {
class ReadStream;
class SeekableReadStream;
@@ -84,6 +87,7 @@ public:
void showCursor();
void userHelp() const;
void writeStr(int16 sx, const int16 sy, const char *s, const byte color);
+ Common::Rect drawDosText(byte x, byte y, const char *text, byte color);
Icondib &getIconBuffer();
Viewdib &getBackBuffer();
@@ -115,7 +119,10 @@ protected:
byte *_curPalette;
byte _paletteSize;
+ Graphics::DosFont _dosFont;
+
Viewdib _frontBuffer;
+ Graphics::Surface _frontSurface;
inline bool isInX(const int16 x, const Rect *rect) const;
inline bool isInY(const int16 y, const Rect *rect) const;
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index c17dea64782..267c1c91d8f 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -66,9 +66,10 @@ static const int kViewSizeX = kXPix; // Width of window view
static const int kViewSizeY = 192; // Height of window view. In original game: 184
static const int kDibOffY = 0; // Offset into dib SrcY (old status line area). In original game: 8
static const int kCompLineSize = 40; // number of bytes in a compressed line
-static const int kMaxLineSize = kCompLineSize - 2; // Max length of user input line
+static const int kMaxTextCols = 40; // Number of text lines in display
static const int kMaxTextRows = 25; // Number of text lines in display
-static const int kMaxBoxChar = kMaxLineSize * kMaxTextRows; // Max chars on screen
+static const int kMaxLineSize = kMaxTextCols - 2; // Max length of user input line
+static const int kMaxBoxChar = kMaxTextCols * kMaxTextRows; // Max chars on screen
static const int kOvlSize = kCompLineSize * kYPix; // Size of an overlay file
static const int kStateDontCare = 0xFF; // Any state allowed in command verb
static const int kHeroIndex = 0; // In all enums, HERO is the first element
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index 1c047e45b8e..2dbb9e64f36 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -275,8 +275,17 @@ void Parser::charHandler() {
_cmdLineIndex = strlen(_cmdLine);
}
+ // Format status line, pad with spaces to fill row
Common::sprintf_s(_vm->_statusLine, ">%s%c", _cmdLine, _cmdLineCursor);
- Common::sprintf_s(_vm->_scoreLine, "F1-Help %s Score: %d of %d Sound %s", (_vm->_config._turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(), (_vm->_config._soundFl) ? "On" : "Off");
+ for (int i = strlen(_vm->_statusLine); i < kMaxTextCols; i++) {
+ _vm->_statusLine[i] = ' ';
+ }
+ _vm->_statusLine[kMaxTextCols] = '\0';
+
+ // Format score line
+ Common::sprintf_s(_vm->_scoreLine, "F1-Help %s Score: %3d of %3d Sound %3s",
+ (_vm->_config._turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(),
+ (_vm->_config._soundFl) ? "on" : "off");
#ifdef USE_TTS
if (_vm->_previousScore != _vm->getScore()) {
Commit: fbf2768f4122a562e6337204479e2ac7bf9aee12
https://github.com/scummvm/scummvm/commit/fbf2768f4122a562e6337204479e2ac7bf9aee12
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Use enum for TTS options, reduce bool parameters
Changed paths:
engines/hugo/display.cpp
engines/hugo/hugo.cpp
engines/hugo/hugo.h
engines/hugo/parser.cpp
engines/hugo/util.cpp
engines/hugo/util.h
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index e825b84a898..f11450611ce 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -471,7 +471,7 @@ void Screen::userHelp() const {
message[kHelpFirstNewlineIndex] = '\n';
#endif
- Utils::notifyBox(message, false);
+ Utils::notifyBox(message, kTtsNoSpeech);
}
void Screen::drawStatusText() {
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index 3f0a30b4bb7..23e8c8ba7dd 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -727,7 +727,7 @@ void HugoEngine::endGame() {
if (_boot._registered != kRegRegistered)
Utils::notifyBox(_text->getTextEngine(kEsAdvertise));
- Utils::notifyBox(Common::String::format("%s\n%s", _episode, getCopyrightString()), true, false);
+ Utils::notifyBox(Common::String::format("%s\n%s", _episode, getCopyrightString()), kTtsSpeech);
_status._viewState = kViewExit;
}
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index 267c1c91d8f..406efe08296 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -196,6 +196,12 @@ struct Hotspot {
int16 _viewx, _viewy, _direction; // Used in auto-route mode
};
+enum TtsOptions {
+ kTtsNoSpeech = 0,
+ kTtsSpeech = (1 << 0),
+ kTtsReplaceNewlines = ((1 << 1) | kTtsSpeech)
+};
+
class FileManager;
class Scheduler;
class Screen;
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index 2dbb9e64f36..493ff87c304 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -544,7 +544,7 @@ void Parser::showDosInventory() const {
ttsMessage += Common::String(_vm->_text->getTextParser(kTBOutro));
_vm->sayText(ttsMessage, Common::TextToSpeechManager::INTERRUPT);
#endif
- Utils::notifyBox(buffer.c_str(), false);
+ Utils::notifyBox(buffer, kTtsNoSpeech);
}
void Parser::endGamePrompt() {
diff --git a/engines/hugo/util.cpp b/engines/hugo/util.cpp
index 748d1035ec5..7cd15bf78f8 100644
--- a/engines/hugo/util.cpp
+++ b/engines/hugo/util.cpp
@@ -30,6 +30,7 @@
#include "common/util.h"
#include "gui/message.h"
+#include "hugo/hugo.h"
#include "hugo/dialogs.h"
#include "hugo/util.h"
@@ -85,10 +86,11 @@ void reverseByte(byte *data) {
*data = result;
}
-void notifyBox(const Common::String &msg, bool ttsVoiceText, bool ttsReplaceNewlines) {
+void notifyBox(const Common::String &msg, TtsOptions ttsOptions) {
#ifdef USE_TTS
- if (ttsVoiceText) {
- sayText(msg, Common::TextToSpeechManager::QUEUE, ttsReplaceNewlines);
+ if (ttsOptions & kTtsSpeech) {
+ bool replaceNewlines = ((ttsOptions & kTtsReplaceNewlines) == kTtsReplaceNewlines);
+ sayText(msg, Common::TextToSpeechManager::QUEUE, replaceNewlines);
}
#endif
diff --git a/engines/hugo/util.h b/engines/hugo/util.h
index ed270033db9..4c516e251c6 100644
--- a/engines/hugo/util.h
+++ b/engines/hugo/util.h
@@ -46,7 +46,7 @@ void reverseByte(byte *data);
* Show a dialog notifying the user about something, with
* only a simple "OK" button to dismiss it.
*/
-void notifyBox(const Common::String &msg, bool ttsVoiceText = true, bool ttsReplaceNewlines = true); // Redirect to call notifyBox with u32strings
+void notifyBox(const Common::String &msg, TtsOptions ttsOptions = kTtsReplaceNewlines); // Redirect to call notifyBox with u32strings
void notifyBox(const Common::U32String &msg);
/**
Commit: 1e39c021563b9b767cb6da0f38be0915b803328a
https://github.com/scummvm/scummvm/commit/1e39c021563b9b767cb6da0f38be0915b803328a
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Rename status and prompt line variables
The top line of text is the status line, the bottom is the prompt line.
We have been calling the prompt line status and the status line score.
Changed paths:
engines/hugo/display.cpp
engines/hugo/hugo.h
engines/hugo/parser.cpp
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index f11450611ce..08f1ab54a5e 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -477,13 +477,13 @@ void Screen::userHelp() const {
void Screen::drawStatusText() {
debugC(4, kDebugDisplay, "drawStatusText()");
- // Draw score line at top row
- Common::Rect scoreRect = drawDosText(0, 0, _vm->_scoreLine, _TCYAN);
- displayList(kDisplayAdd, scoreRect.left, scoreRect.top, scoreRect.width(), scoreRect.height());
-
- // Draw status line at bottom row
- Common::Rect statusRect = drawDosText(0, kMaxTextRows - 1, _vm->_statusLine, _TLIGHTYELLOW);
+ // Draw status line at top row
+ Common::Rect statusRect = drawDosText(0, 0, _vm->_statusLine, _TCYAN);
displayList(kDisplayAdd, statusRect.left, statusRect.top, statusRect.width(), statusRect.height());
+
+ // Draw prompt line at bottom row
+ Common::Rect promptRect = drawDosText(0, kMaxTextRows - 1, _vm->_promptLine, _TLIGHTYELLOW);
+ displayList(kDisplayAdd, promptRect.left, promptRect.top, promptRect.width(), promptRect.height());
}
void Screen::drawShape(const int x, const int y, const int color1, const int color2) {
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index 406efe08296..5d9883e6247 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -251,8 +251,8 @@ public:
const char *_episode;
Common::Path _picDir;
- Command _statusLine;
- Command _scoreLine;
+ Command _statusLine; // text at top row of screen
+ Command _promptLine; // text at bottom row of screen
#ifdef USE_TTS
bool _voiceScoreLine;
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index 493ff87c304..bba523a92bf 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -275,15 +275,15 @@ void Parser::charHandler() {
_cmdLineIndex = strlen(_cmdLine);
}
- // Format status line, pad with spaces to fill row
- Common::sprintf_s(_vm->_statusLine, ">%s%c", _cmdLine, _cmdLineCursor);
- for (int i = strlen(_vm->_statusLine); i < kMaxTextCols; i++) {
- _vm->_statusLine[i] = ' ';
+ // Format prompt line, pad with spaces to fill row
+ Common::sprintf_s(_vm->_promptLine, ">%s%c", _cmdLine, _cmdLineCursor);
+ for (int i = strlen(_vm->_promptLine); i < kMaxTextCols; i++) {
+ _vm->_promptLine[i] = ' ';
}
- _vm->_statusLine[kMaxTextCols] = '\0';
+ _vm->_promptLine[kMaxTextCols] = '\0';
- // Format score line
- Common::sprintf_s(_vm->_scoreLine, "F1-Help %s Score: %3d of %3d Sound %3s",
+ // Format status line
+ Common::sprintf_s(_vm->_statusLine, "F1-Help %s Score: %3d of %3d Sound %3s",
(_vm->_config._turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(),
(_vm->_config._soundFl) ? "on" : "off");
Commit: c3dfddd31c2f88dd6ccc77d92e17cd7e038cf492
https://github.com/scummvm/scummvm/commit/c3dfddd31c2f88dd6ccc77d92e17cd7e038cf492
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Fix CRLF handling when reading HELP.DAT
The original translated CRLF line endings to LF via Microsoft's CRT,
now we do too. This does not matter much when using the ScummVM GUI
for message boxes, but it is necessary for DOS message boxes.
Changed paths:
engines/hugo/file_v1d.cpp
diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp
index 3ba7874dfab..2e965fa6fa4 100644
--- a/engines/hugo/file_v1d.cpp
+++ b/engines/hugo/file_v1d.cpp
@@ -104,25 +104,40 @@ const char *FileManager_v1d::fetchString(const int index) {
* Only in DOS versions
*/
void FileManager_v1d::instructions() const {
+ // Note: HELP.DAT uses CRLF line endings. The original used `open()` from
+ // Microsoft's CRT in non-binary mode, so `read()` translated these to LF.
+ // This is necessary because the DOS message boxes only expect LF characters.
+ // The original source code's comments call the surviving character "CR",
+ // but it is really LF. We have copied these comments, so when you see a
+ // comment refer to "CR", such as later in this function, it means LF.
Common::File f;
if (!f.open("help.dat")) {
warning("help.dat not found");
return;
}
- char readBuf[2];
- while (f.read(readBuf, 1)) {
+ char readBuf;
+ while (f.read(&readBuf, 1)) {
+ if (readBuf == '\r') {
+ continue; // skip '\r'
+ }
char line[1024], *wrkLine;
wrkLine = line;
- wrkLine[0] = readBuf[0];
+ wrkLine[0] = readBuf;
wrkLine++;
do {
f.read(wrkLine, 1);
+ if (*wrkLine == '\r') {
+ f.read(wrkLine, 1); // skip '\r'
+ }
} while (*wrkLine++ != '#'); // '#' is EOP
wrkLine[-2] = '\0'; // Remove EOP and previous CR
Utils::notifyBox(line);
wrkLine = line;
- f.read(readBuf, 2); // Remove CRLF after EOP
+ f.read(&readBuf, 1); // Remove CR after EOP
+ if (readBuf == '\r') {
+ f.read(&readBuf, 1); // skip '\r'
+ }
}
f.close();
}
Commit: 775e451f326b095efffca6c33c491cd073bdb83f
https://github.com/scummvm/scummvm/commit/775e451f326b095efffca6c33c491cd073bdb83f
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Format copyright string for DOS message box
Separate string into two lines for 38 character DOS line limit
Changed paths:
engines/hugo/hugo.cpp
engines/hugo/hugo.h
engines/hugo/intro.cpp
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index 23e8c8ba7dd..e11f916212e 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -183,8 +183,12 @@ bool HugoEngine::hasFeature(EngineFeature f) const {
return (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
}
-const char *HugoEngine::getCopyrightString() const {
- return "Copyright 1989-1997 David P Gray, All Rights Reserved.";
+const char *HugoEngine::getCopyrightString1() const {
+ return "Copyright 1989-1997 David P Gray,";
+}
+
+const char *HugoEngine::getCopyrightString2() const {
+ return "All Rights Reserved.";
}
GameType HugoEngine::getGameType() const {
@@ -727,7 +731,9 @@ void HugoEngine::endGame() {
if (_boot._registered != kRegRegistered)
Utils::notifyBox(_text->getTextEngine(kEsAdvertise));
- Utils::notifyBox(Common::String::format("%s\n%s", _episode, getCopyrightString()), kTtsSpeech);
+ Common::String text = Common::String::format("%s\n\n%s\n%s",
+ _episode, getCopyrightString1(), getCopyrightString2());
+ Utils::notifyBox(text, kTtsSpeech);
_status._viewState = kViewExit;
}
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index 5d9883e6247..60714ccc044 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -302,7 +302,8 @@ public:
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
Common::Error loadGameState(int slot) override;
bool hasFeature(EngineFeature f) const override;
- const char *getCopyrightString() const;
+ const char *getCopyrightString1() const;
+ const char *getCopyrightString2() const;
Common::String getSaveStateName(int slot) const override;
uint16 **loadLongArray(Common::SeekableReadStream &in);
diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp
index 5f98342d712..5e8014a5bc5 100644
--- a/engines/hugo/intro.cpp
+++ b/engines/hugo/intro.cpp
@@ -149,6 +149,7 @@ bool intro_v1d::introPlay() {
return false;
}
+ Common::String copyright;
Common::String ttsMessage;
#endif
if (_introTicks < introSize) {
@@ -177,13 +178,16 @@ bool intro_v1d::introPlay() {
error("Unknown registration flag in hugo.bsf: %d", _vm->_boot._registered);
_font.drawString(&_surf, buffer, 0, 163, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter);
- _font.drawString(&_surf, _vm->getCopyrightString(), 0, 176, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter);
+ copyright = Common::String::format("%s %s", _vm->getCopyrightString1(), _vm->getCopyrightString2());
+ _font.drawString(&_surf, copyright, 0, 176, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter);
#ifdef USE_TTS
ttsMessage = "Hugo's House of Horrors\n\n";
ttsMessage += buffer;
ttsMessage += '\n';
- ttsMessage += _vm->getCopyrightString();
+ ttsMessage += _vm->getCopyrightString1();
+ ttsMessage += ' ';
+ ttsMessage += _vm->getCopyrightString2();
#endif
if ((*_vm->_boot._distrib != '\0') && (scumm_stricmp(_vm->_boot._distrib, "David P. Gray"))) {
@@ -348,9 +352,9 @@ void intro_v2d::introInit() {
error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 8");
if (_vm->_boot._registered)
- Common::sprintf_s(buffer, "%s Registered Version", _vm->getCopyrightString());
+ Common::sprintf_s(buffer, "%s %s Registered Version", _vm->getCopyrightString1(), _vm->getCopyrightString2());
else
- Common::sprintf_s(buffer, "%s Shareware Version", _vm->getCopyrightString());
+ Common::sprintf_s(buffer, "%s %s Shareware Version", _vm->getCopyrightString1(), _vm->getCopyrightString2());
_font.drawString(&_surf, buffer, 0, 186, 320, _TLIGHTRED, Graphics::kTextAlignCenter);
@@ -403,9 +407,9 @@ void intro_v3d::introInit() {
char buffer[128];
if (_vm->_boot._registered)
- Common::sprintf_s(buffer, "%s Registered Version", _vm->getCopyrightString());
+ Common::sprintf_s(buffer, "%s %s Registered Version", _vm->getCopyrightString1(), _vm->getCopyrightString2());
else
- Common::sprintf_s(buffer,"%s Shareware Version", _vm->getCopyrightString());
+ Common::sprintf_s(buffer,"%s %s Shareware Version", _vm->getCopyrightString1(), _vm->getCopyrightString2());
// TROMAN, size 10-5
if (!_font.loadFromFON("TMSRB.FON", Graphics::WinFontDirEntry("Tms Rmn", 8)))
Commit: c5d61499c05647f628a77ce24570d55966760161
https://github.com/scummvm/scummvm/commit/c5d61499c05647f628a77ce24570d55966760161
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Format advertisement string for DOS message box
String now fits within 38 character DOS line limit
Changed paths:
devtools/create_hugo/staticengine.h
dists/engine-data/hugo.dat
diff --git a/devtools/create_hugo/staticengine.h b/devtools/create_hugo/staticengine.h
index 590e9acff9e..8ef1648a108 100644
--- a/devtools/create_hugo/staticengine.h
+++ b/devtools/create_hugo/staticengine.h
@@ -39,8 +39,8 @@ const char *textEngine[NUM_ENGINE_TEXT] = {
"game but bigger and better!\n\n"
"Call 1-800-2424-PsL now to order the\n"
"Hugo Trilogy for Windows for only $36!\n"
- "(Note: This number is for ORDERS only).\n\n"
- "It includes all 3 games plus the 30-page\n"
+ "(Note: This number is for ORDERS only)\n\n"
+ "It includes all 3 games + the 30-page\n"
"answer book. See Ordering information\n"
"for more details and some screenshots."
};
diff --git a/dists/engine-data/hugo.dat b/dists/engine-data/hugo.dat
index 164594a20de..4a526a9f061 100644
Binary files a/dists/engine-data/hugo.dat and b/dists/engine-data/hugo.dat differ
Commit: c48a87629117c324166d77f6d455909d35b7491f
https://github.com/scummvm/scummvm/commit/c48a87629117c324166d77f6d455909d35b7491f
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Add DOS message boxes and prompts
Changed paths:
engines/hugo/display.cpp
engines/hugo/display.h
engines/hugo/file.cpp
engines/hugo/file_v1d.cpp
engines/hugo/file_v2w.cpp
engines/hugo/game.h
engines/hugo/hugo.cpp
engines/hugo/hugo.h
engines/hugo/intro.cpp
engines/hugo/object.cpp
engines/hugo/parser.cpp
engines/hugo/parser.h
engines/hugo/parser_v1d.cpp
engines/hugo/parser_v1w.cpp
engines/hugo/parser_v2d.cpp
engines/hugo/parser_v3d.cpp
engines/hugo/schedule.cpp
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index 08f1ab54a5e..6e7c011402b 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -29,6 +29,7 @@
// Display.c - DIB related code for HUGOWIN
#include "common/debug.h"
+#include "common/events.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "graphics/cursorman.h"
@@ -40,6 +41,7 @@
#include "hugo/inventory.h"
#include "hugo/util.h"
#include "hugo/object.h"
+#include "hugo/parser.h"
#include "hugo/mouse.h"
namespace Hugo {
@@ -471,19 +473,68 @@ void Screen::userHelp() const {
message[kHelpFirstNewlineIndex] = '\n';
#endif
- Utils::notifyBox(message, kTtsNoSpeech);
+ Common::KeyCode keyCode = _vm->notifyBox(message, false, kTtsNoSpeech);
+
+ // DOS: If the help message was dismissed with F1 then show instructions
+ if (keyCode == Common::KEYCODE_F1) {
+ _vm->_file->instructions();
+ }
+}
+
+void Screen::updateStatusText() {
+ // Format status line
+ Common::sprintf_s(_vm->_statusLine, "F1-Help %s Score: %3d of %3d Sound %3s",
+ (_vm->_config._turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(),
+ (_vm->_config._soundFl) ? "on" : "off");
+}
+
+void Screen::updatePromptText(const char *command, char cursor) {
+ // Format prompt line, pad with spaces to fill row
+ Common::sprintf_s(_vm->_promptLine, ">%s%c", command, cursor);
+ for (int i = strlen(_vm->_promptLine); i < kMaxTextCols; i++) {
+ _vm->_promptLine[i] = ' ';
+ }
+ _vm->_promptLine[kMaxTextCols] = '\0';
}
+/**
+ * Draw status line at top row and add to blit list
+ */
void Screen::drawStatusText() {
debugC(4, kDebugDisplay, "drawStatusText()");
- // Draw status line at top row
- Common::Rect statusRect = drawDosText(0, 0, _vm->_statusLine, _TCYAN);
- displayList(kDisplayAdd, statusRect.left, statusRect.top, statusRect.width(), statusRect.height());
+ Common::Rect r = drawDosText(0, 0, _vm->_statusLine, _TCYAN);
+ displayList(kDisplayAdd, r.left, r.top, r.width(), r.height());
+}
+
+/**
+ * Draw status line at top row and display on the screen
+ */
+void Screen::displayStatusText() {
+ debugC(4, kDebugDisplay, "displayStatusText()");
- // Draw prompt line at bottom row
- Common::Rect promptRect = drawDosText(0, kMaxTextRows - 1, _vm->_promptLine, _TLIGHTYELLOW);
- displayList(kDisplayAdd, promptRect.left, promptRect.top, promptRect.width(), promptRect.height());
+ Common::Rect r = drawDosText(0, 0, _vm->_statusLine, _TCYAN);
+ _vm->_system->copyRectToScreen(_frontBuffer, 320, r.left, r.top, r.width(), r.height());
+}
+
+/**
+ * Draw prompt line at bottom row and add to blit list
+ */
+void Screen::drawPromptText() {
+ debugC(4, kDebugDisplay, "drawPromptText()");
+
+ Common::Rect r = drawDosText(0, kMaxTextRows - 1, _vm->_promptLine, _TLIGHTYELLOW);
+ displayList(kDisplayAdd, r.left, r.top, r.width(), r.height());
+}
+
+/**
+ * Draw prompt line at bottom row and display on the screen
+ */
+void Screen::displayPromptText() {
+ debugC(4, kDebugDisplay, "displayPromptText()");
+
+ Common::Rect r = drawDosText(0, kMaxTextRows - 1, _vm->_promptLine, _TLIGHTYELLOW);
+ _vm->_system->copyRectToScreen(&_frontBuffer[r.top * 320], 320, r.left, r.top, r.width(), r.height());
}
void Screen::drawShape(const int x, const int y, const int color1, const int color2) {
@@ -561,6 +612,266 @@ Common::Rect Screen::drawDosText(byte x, byte y, const char *text, byte color) {
return rect;
}
+/**
+ * Returns the DOS message box border color for the current game
+ */
+byte Screen::getDosMessageBoxBorder() const {
+ switch (_vm->getGameType()) {
+ case kGameTypeHugo1: return _TLIGHTRED;
+ case kGameTypeHugo2: return _TBLUE;
+ default: return _TGREEN;
+ }
+}
+
+/**
+ * Display DOS message box
+ *
+ * Returns the KeyState of the keydown event that dismissed the message box.
+ * Callers can use this to implement original behavior such as applying that
+ * key to an input prompt, such as dosPromptBox(), or detecting an F1 press
+ * on the help screen so that the instructions
+ */
+Common::KeyState Screen::dosMessageBox(const Common::String &text, bool protect, TtsOptions ttsOptions) {
+ if (text.empty()) {
+ return Common::KeyState();
+ }
+
+ // Handle TTS the same as Utils::notifyBox()
+#ifdef USE_TTS
+ if (ttsOptions & kTtsSpeech) {
+ bool replaceNewlines = ((ttsOptions & kTtsReplaceNewlines) == kTtsReplaceNewlines);
+ Utils::sayText(text, Common::TextToSpeechManager::QUEUE, replaceNewlines);
+ }
+#endif
+
+ // Draw the status bar, as the score may have just been changed.
+ // The DOS original updated the status text on screen immediately, but we
+ // add it to the list of rectangles to eventually blit to the screen,
+ // similar to how the Windows version draws. In order to replicate the
+ // DOS behavior of displaying the new score with the message, we draw
+ // the status bar directly to the screen when showing a message box.
+ if (_vm->getGameStatus()._viewState == kViewPlay) {
+ displayStatusText();
+ }
+
+ // Compute size of formatted text for box size
+ int16 width = 0;
+ int16 x = 0;
+ int16 y = 1;
+ for (uint i = 0; i < text.size(); i++) {
+ if (text[i] != '\n') {
+ x++;
+ } else {
+ y++;
+ if (x > width)
+ width = x;
+ x = 0;
+ }
+ }
+
+ // Get width, height of text
+ int16 height = y;
+ if (x > width)
+ width = x;
+ width += 2; // Border text by +- one char
+ height += 2;
+ if (width > kMaxTextCols || height > kMaxTextRows) {
+ warning("text too long: %s", text.c_str());
+ return Common::KeyState();
+ }
+
+ // Get x,y text start coords
+ int16 xOffset = (_vm->getGameType() == kGameTypeHugo1) ? 0 : 1;
+ x = (kMaxTextCols - width + xOffset) / 2;
+ y = (kMaxTextRows - height) / 2;
+ // Adjust one based coordinates from original code to zero based
+ x--;
+ y--;
+ x = MAX<int>(x, 0);
+ y = MAX<int>(y, 0);
+ // Get screen start coordinates and dimensions
+ int16 sx1 = x * 8;
+ int16 sy1 = y * 8;
+ int16 sx2 = (x + width) * 8;
+ int16 sy2 = (y + height) * 8;
+ // If box reaches the right edge of screen, reduce by one pixel
+ // for the right border. The original games did not have messages
+ // this wide, but we display a large advertisement when exiting.
+ if (sx2 >= 320) {
+ sx2 = kXPix - 1;
+ }
+
+ // Save screen
+ int16 boxWidth = sx2 - sx1 + 1;
+ int16 boxHeight = sy2 - sy1 + 1;
+ if (sx1 + boxWidth > 320) {
+ boxWidth = 320 - sx1;
+ }
+ if (sy1 + boxHeight > 200) {
+ boxHeight = 200 - sy1;
+ }
+ moveImage(_frontBuffer, sx1, sy1, boxWidth, boxHeight, 320, _frontBufferBoxBackup, sx1, sy1, 320);
+
+ // Draw box
+ drawRectangle(true, sx1, sy1, sx2, sy2, _TBLACK);
+ drawRectangle(false, sx1, sy1, sx2, sy2, getDosMessageBoxBorder());
+ char c[] = "X"; // A dummy string with 2nd byte null
+ int16 xTextPos = x + 1;
+ int16 yTextPos = y + 1;
+ for (uint i = 0; i < text.size(); i++) {
+ if (text[i] == '\n') {
+ xTextPos = x + 1;
+ yTextPos++;
+ } else {
+ c[0] = text[i];
+ drawDosText(xTextPos, yTextPos, c, _TLIGHTCYAN);
+ xTextPos++;
+ }
+ }
+ _vm->_system->copyRectToScreen(&_frontBuffer[320 * sy1 + sx1], 320, sx1, sy1, boxWidth, boxHeight);
+
+ // Wait for key
+ const uint32 startTime = _vm->_system->getMillis();
+ Common::KeyState keyState = getKey();
+
+ // Protect mode: there is a short duration in which keys are ignored
+ // unless they are Enter or Escape. This is used with messages that
+ // occur on timers so that the user doesn't accidentally dismiss the
+ // message while in the middle of typing a command.
+ if (protect) {
+ const uint32 delay = 3 * (1000 / _vm->getTPS());
+ while (keyState.keycode != Common::KEYCODE_RETURN &&
+ keyState.keycode != Common::KEYCODE_ESCAPE &&
+ _vm->_system->getMillis() - startTime < delay) {
+ keyState = getKey();
+ }
+ }
+
+ // Restore screen
+ moveImage(_frontBufferBoxBackup, sx1, sy1, boxWidth, boxHeight, 320, _frontBuffer, sx1, sy1, 320);
+ _vm->_system->copyRectToScreen(&_frontBuffer[320 * sy1 + sx1], 320, sx1, sy1, boxWidth, boxHeight);
+
+ // Handle TTS the same as Utils::notifyBox()
+#ifdef USE_TTS
+ Utils::stopTextToSpeech();
+#endif
+
+ return keyState;
+}
+
+/**
+ * Display DOS message box and prompt for a response
+ *
+ * Returns the text entered by the user.
+ */
+Common::String Screen::dosPromptBox(const Common::String &text) {
+ if (text.empty()) {
+ return Common::String();
+ }
+
+ // Show the message box until it is dismissed with a printable key
+ Common::KeyState keyState;
+ while (!Common::isPrint(keyState.ascii)) {
+ keyState = dosMessageBox(text);
+ if (_vm->shouldQuit()) {
+ return Common::String();
+ }
+ }
+
+ // Initialize command with the key used to dismiss the message box
+ char command[kMaxLineSize + 1];
+ int index = 0;
+ command[index++] = keyState.ascii;
+ command[index] = '\0';
+ updatePromptText(command, ' ');
+ displayPromptText();
+
+ // Keyboard input loop
+ while (!_vm->shouldQuit()) {
+ keyState = getKey();
+
+ if (keyState.keycode == Common::KEYCODE_RETURN) {
+ break;
+ } else if (keyState.keycode == Common::KEYCODE_BACKSPACE) {
+ if (index > 0) {
+ command[--index] = '\0';
+ updatePromptText(command, ' ');
+ displayPromptText();
+ }
+ } else if (Common::isPrint(keyState.ascii)) {
+ if (index < ARRAYSIZE(command) - 1) {
+ command[index++] = keyState.ascii;
+ command[index] = '\0';
+ updatePromptText(command, ' ');
+ displayPromptText();
+ }
+ }
+ }
+
+ // Clear the prompt text
+ Common::String response = command;
+ command[0] = '\0';
+ updatePromptText(command, ' ');
+ displayPromptText();
+ _vm->_parser->resetCommandLine();
+
+ // Handle TTS the same as Utils::promptBox()
+#ifdef USE_TTS
+ Utils::sayText(response);
+#endif
+
+ return response;
+}
+
+/**
+ * Get key from keyboard
+ *
+ * This function roughly mimics getch(). It returns the keystate of the first
+ * keydown message for a printable key or one of the specific keys that callers
+ * expect: enter, backspace, escape, and F1.
+ */
+Common::KeyState Screen::getKey() {
+ while (!_vm->shouldQuit()) {
+ Common::Event event;
+ while (_vm->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ // Ignore keydown if modifier other than shift is pressed
+ if (event.kbd.flags & (Common::KBD_NON_STICKY & ~Common::KBD_SHIFT)) {
+ continue;
+ }
+ // Enter, backspace, and printable keys are acceptable
+ if (event.kbd.keycode == Common::KEYCODE_RETURN ||
+ event.kbd.keycode == Common::KEYCODE_BACKSPACE ||
+ Common::isPrint(event.kbd.ascii)) {
+ return event.kbd;
+ }
+ break;
+
+ // Several keys that we wish to return have been turned into
+ // actions for the keymapper. Translate them back into their
+ // original keycodes for the caller to test like any other key.
+ case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+ switch (event.customType) {
+ case kActionEscape:
+ return Common::KeyState(Common::KEYCODE_ESCAPE);
+ case kActionUserHelp:
+ return Common::KeyState(Common::KEYCODE_F1);
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(10);
+ }
+ return Common::KeyState();
+}
+
/**
* Initialize screen components and display results
*/
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index fc30b269b05..8aa696a66ce 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -69,7 +69,12 @@ public:
void drawBoundaries();
void drawRectangle(const bool filledFl, const int16 x1, const int16 y1, const int16 x2, const int16 y2, const int color);
void drawShape(const int x, const int y, const int color1, const int color2);
+ void updateStatusText();
+ void updatePromptText(const char *command, char cursor);
void drawStatusText();
+ void displayStatusText();
+ void drawPromptText();
+ void displayPromptText();
void freeScreen();
void hideCursor();
void initDisplay();
@@ -88,6 +93,10 @@ public:
void userHelp() const;
void writeStr(int16 sx, const int16 sy, const char *s, const byte color);
Common::Rect drawDosText(byte x, byte y, const char *text, byte color);
+ byte getDosMessageBoxBorder() const;
+ Common::KeyState dosMessageBox(const Common::String &text, bool protect = false, TtsOptions ttsOptions = kTtsReplaceNewlines);
+ Common::String dosPromptBox(const Common::String &text);
+ Common::KeyState getKey();
Icondib &getIconBuffer();
Viewdib &getBackBuffer();
@@ -139,6 +148,7 @@ private:
Viewdib _backBuffer;
Viewdib _GUIBuffer; // User interface images
Viewdib _backBufferBackup; // Backup _backBuffer during inventory
+ Viewdib _frontBufferBoxBackup; // Backup _frontBuffer during DOS message boxes
// Formerly static variables used by displayList()
int16 _dlAddIndex, _dlRestoreIndex; // Index into add/restore lists
diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp
index 0e4a3908308..6e8d7ce8017 100644
--- a/engines/hugo/file.cpp
+++ b/engines/hugo/file.cpp
@@ -509,14 +509,14 @@ void FileManager::readBootFile() {
_vm->_boot._registered = kRegShareware;
return;
} else {
- Utils::notifyBox(Common::String::format("Missing startup file '%s'", getBootFilename()));
+ _vm->notifyBox(Common::String::format("Missing startup file '%s'", getBootFilename()));
_vm->getGameStatus()._doQuitFl = true;
return;
}
}
if (ofp.size() < (int32)sizeof(_vm->_boot)) {
- Utils::notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename()));
+ _vm->notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename()));
_vm->getGameStatus()._doQuitFl = true;
return;
}
@@ -537,7 +537,7 @@ void FileManager::readBootFile() {
}
if (checksum) {
- Utils::notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename()));
+ _vm->notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename()));
_vm->getGameStatus()._doQuitFl = true;
}
}
diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp
index 2e965fa6fa4..19536e0cf35 100644
--- a/engines/hugo/file_v1d.cpp
+++ b/engines/hugo/file_v1d.cpp
@@ -132,7 +132,7 @@ void FileManager_v1d::instructions() const {
}
} while (*wrkLine++ != '#'); // '#' is EOP
wrkLine[-2] = '\0'; // Remove EOP and previous CR
- Utils::notifyBox(line);
+ _vm->notifyBox(line);
wrkLine = line;
f.read(&readBuf, 1); // Remove CR after EOP
if (readBuf == '\r') {
diff --git a/engines/hugo/file_v2w.cpp b/engines/hugo/file_v2w.cpp
index 6050b820406..ea9627bd72d 100644
--- a/engines/hugo/file_v2w.cpp
+++ b/engines/hugo/file_v2w.cpp
@@ -44,7 +44,7 @@ FileManager_v2w::~FileManager_v2w() {
* Same comment than in SCI: maybe in the future we can implement this, but for now this message should suffice
*/
void FileManager_v2w::instructions() const {
- Utils::notifyBox(Common::String::format("Please use an external viewer to open the game's help file: HUGOWIN%d.HLP", _vm->_gameVariant + 1));
+ _vm->notifyBox(Common::String::format("Please use an external viewer to open the game's help file: HUGOWIN%d.HLP", _vm->_gameVariant + 1));
}
} // End of namespace Hugo
diff --git a/engines/hugo/game.h b/engines/hugo/game.h
index 90344fd8f97..0f73f51b947 100644
--- a/engines/hugo/game.h
+++ b/engines/hugo/game.h
@@ -39,7 +39,8 @@ class SeekableReadStream;
namespace Hugo {
// Game specific equates
-#define TAKE_TEXT "Picked up the %s ok."
+#define TAKE_TEXT_DOS "Ok"
+#define TAKE_TEXT_WINDOWS "Picked up the %s ok."
enum {LOOK_NAME = 1, TAKE_NAME}; // Index of name used in showing takeables and in confirming take
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index e11f916212e..f1fad7fb4ea 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -86,6 +86,7 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy
_gameType = kGameTypeNone;
_platform = Common::kPlatformUnknown;
_packedFl = false;
+ _windowsInterfaceFl = (gd->desc.platform == Common::kPlatformWindows);
_numVariant = 0;
_gameVariant = kGameVariantNone;
@@ -203,11 +204,15 @@ bool HugoEngine::isPacked() const {
return _packedFl;
}
+bool HugoEngine::useWindowsInterface() const {
+ return _windowsInterfaceFl;
+}
+
/**
* Print options for user when dead
*/
void HugoEngine::gameOverMsg() {
- Utils::notifyBox(_text->getTextUtil(kGameOver));
+ notifyBox(_text->getTextUtil(kGameOver));
}
Common::Error HugoEngine::run() {
@@ -419,6 +424,7 @@ void HugoEngine::runMachine() {
_screen->displayList(kDisplayRestore); // Restore previous background
_object->updateImages(); // Draw into _frontBuffer, compile display list
_screen->drawStatusText();
+ _screen->drawPromptText();
_screen->displayList(kDisplayDisplay); // Blit the display list to screen
_sound->checkMusic();
break;
@@ -730,10 +736,10 @@ void HugoEngine::endGame() {
debugC(1, kDebugEngine, "endGame");
if (_boot._registered != kRegRegistered)
- Utils::notifyBox(_text->getTextEngine(kEsAdvertise));
+ notifyBox(_text->getTextEngine(kEsAdvertise));
Common::String text = Common::String::format("%s\n\n%s\n%s",
_episode, getCopyrightString1(), getCopyrightString2());
- Utils::notifyBox(text, kTtsSpeech);
+ notifyBox(text, false, kTtsSpeech);
_status._viewState = kViewExit;
}
@@ -759,6 +765,47 @@ Common::String HugoEngine::getSaveStateName(int slot) const {
return _targetName + Common::String::format("-%02d.SAV", slot);
}
+Common::KeyCode HugoEngine::notifyBox(const Common::String &text, bool protect, TtsOptions ttsOptions) {
+ if (useWindowsInterface()) {
+ Utils::notifyBox(text, ttsOptions);
+ return Common::KEYCODE_INVALID;
+ } else {
+ Common::KeyState keyState = _screen->dosMessageBox(text, protect, ttsOptions);
+ return keyState.keycode;
+ }
+}
+
+Common::String HugoEngine::promptBox(const Common::String &text) {
+ if (useWindowsInterface()) {
+ return Utils::promptBox(text);
+ } else {
+ return _screen->dosPromptBox(text);
+ }
+}
+
+bool HugoEngine::yesNoBox(const Common::String &text, bool useFirstKey) {
+ if (useWindowsInterface()) {
+ return Utils::yesNoBox(text);
+ } else {
+ if (useFirstKey) {
+ Common::KeyState keyState = _screen->dosMessageBox(text);
+ return (keyState.keycode == Common::KEYCODE_y);
+ } else {
+ Common::String response = _screen->dosPromptBox(text);
+ response.trim();
+ return response.equalsIgnoreCase("yes");
+ }
+ }
+}
+
+void HugoEngine::takeObjectBox(const char *name) {
+ if (useWindowsInterface()) {
+ notifyBox(Common::String::format(TAKE_TEXT_WINDOWS, name));
+ } else {
+ notifyBox(TAKE_TEXT_DOS);
+ }
+}
+
#ifdef USE_TTS
void HugoEngine::sayText(const Common::String &text, Common::TextToSpeechManager::Action action) {
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index 60714ccc044..8105ab7c577 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -270,6 +270,7 @@ public:
GameType getGameType() const;
Common::Platform getPlatform() const;
bool isPacked() const;
+ bool useWindowsInterface() const;
// Used by the qsort function
static HugoEngine &get() {
@@ -308,6 +309,11 @@ public:
Common::String getSaveStateName(int slot) const override;
uint16 **loadLongArray(Common::SeekableReadStream &in);
+ Common::KeyCode notifyBox(const Common::String &text, bool protect = false, TtsOptions ttsOptions = kTtsReplaceNewlines);
+ Common::String promptBox(const Common::String &text);
+ bool yesNoBox(const Common::String &text, bool useFirstKey);
+ void takeObjectBox(const char *name);
+
#ifdef USE_TTS
void sayText(const Common::String &text, Common::TextToSpeechManager::Action action = Common::TextToSpeechManager::INTERRUPT);
#endif
@@ -342,6 +348,7 @@ private:
GameType _gameType;
Common::Platform _platform;
bool _packedFl;
+ bool _windowsInterfaceFl;
int _score; // Holds current score
int _maxscore; // Holds maximum score
diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp
index 5e8014a5bc5..4aaaab14acc 100644
--- a/engines/hugo/intro.cpp
+++ b/engines/hugo/intro.cpp
@@ -465,13 +465,13 @@ bool intro_v3d::introPlay() {
// Text boxes at various times
switch (_introTicks) {
case 4:
- Utils::notifyBox(_vm->_text->getTextIntro(kIntro1));
+ _vm->notifyBox(_vm->_text->getTextIntro(kIntro1), true);
break;
case 9:
- Utils::notifyBox(_vm->_text->getTextIntro(kIntro2));
+ _vm->notifyBox(_vm->_text->getTextIntro(kIntro2), true);
break;
case 35:
- Utils::notifyBox(_vm->_text->getTextIntro(kIntro3));
+ _vm->notifyBox(_vm->_text->getTextIntro(kIntro3), true);
break;
default:
break;
@@ -557,13 +557,13 @@ bool intro_v3w::introPlay() {
// Text boxes at various times
switch (_introTicks) {
case 4:
- Utils::notifyBox(_vm->_text->getTextIntro(kIntro1));
+ _vm->notifyBox(_vm->_text->getTextIntro(kIntro1), true);
break;
case 9:
- Utils::notifyBox(_vm->_text->getTextIntro(kIntro2));
+ _vm->notifyBox(_vm->_text->getTextIntro(kIntro2), true);
break;
case 35:
- Utils::notifyBox(_vm->_text->getTextIntro(kIntro3));
+ _vm->notifyBox(_vm->_text->getTextIntro(kIntro3), true);
break;
default:
break;
diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp
index e8bb63a7a1b..9b1e2b3207c 100644
--- a/engines/hugo/object.cpp
+++ b/engines/hugo/object.cpp
@@ -371,7 +371,7 @@ void ObjectHandler::showTakeables() {
if ((obj->_cycling != kCycleInvisible) &&
(obj->_screenIndex == *_vm->_screenPtr) &&
(((TAKE & obj->_genericCmd) == TAKE) || obj->_objValue)) {
- Utils::notifyBox(Common::String::format("You can also see:\n%s.", _vm->_text->getNoun(obj->_nounIndex, LOOK_NAME)));
+ _vm->notifyBox(Common::String::format("You can also see:\n%s.", _vm->_text->getNoun(obj->_nounIndex, LOOK_NAME)));
}
}
}
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index bba523a92bf..c8e9bee3854 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -264,8 +264,13 @@ void Parser::charHandler() {
}
// See if time to blink cursor, set cursor character
- if ((_cmdLineTick++ % (_vm->getTPS() / kBlinksPerSec)) == 0)
- _cmdLineCursor = (_cmdLineCursor == '_') ? ' ' : '_';
+ if (_vm->useWindowsInterface()) {
+ if ((_cmdLineTick++ % (_vm->getTPS() / kBlinksPerSec)) == 0)
+ _cmdLineCursor = (_cmdLineCursor == '_') ? ' ' : '_';
+ } else {
+ // DOS: No blinking cursor
+ _cmdLineCursor = ' ';
+ }
// See if recall button pressed
if (gameStatus._recallFl) {
@@ -275,17 +280,8 @@ void Parser::charHandler() {
_cmdLineIndex = strlen(_cmdLine);
}
- // Format prompt line, pad with spaces to fill row
- Common::sprintf_s(_vm->_promptLine, ">%s%c", _cmdLine, _cmdLineCursor);
- for (int i = strlen(_vm->_promptLine); i < kMaxTextCols; i++) {
- _vm->_promptLine[i] = ' ';
- }
- _vm->_promptLine[kMaxTextCols] = '\0';
-
- // Format status line
- Common::sprintf_s(_vm->_statusLine, "F1-Help %s Score: %3d of %3d Sound %3s",
- (_vm->_config._turboFl) ? "T" : " ", _vm->getScore(), _vm->getMaxScore(),
- (_vm->_config._soundFl) ? "on" : "off");
+ _vm->_screen->updateStatusText();
+ _vm->_screen->updatePromptText(_cmdLine, _cmdLineCursor);
#ifdef USE_TTS
if (_vm->_previousScore != _vm->getScore()) {
@@ -346,11 +342,17 @@ void Parser::actionHandler(Common::Event event) {
switch (event.customType) {
case kActionUserHelp:
- if (_checkDoubleF1Fl)
- gameStatus._helpFl = true;
- else
+ if (_vm->useWindowsInterface()) {
+ // Windows: Track double-F1 with a flag
+ if (_checkDoubleF1Fl)
+ gameStatus._helpFl = true;
+ else
+ _vm->_screen->userHelp();
+ _checkDoubleF1Fl = !_checkDoubleF1Fl;
+ } else {
+ // DOS: userHelp() handles double-F1
_vm->_screen->userHelp();
- _checkDoubleF1Fl = !_checkDoubleF1Fl;
+ }
break;
case kActionToggleSound:
_vm->_sound->toggleSound();
@@ -370,10 +372,15 @@ void Parser::actionHandler(Common::Event event) {
case kActionRestoreGame:
_vm->_file->restoreGame(-1);
break;
- case kActionNewGame:
- if (Utils::yesNoBox("Are you sure you want to start a new game?"))
+ case kActionNewGame: {
+ // DOS requires shorter text for message boxes
+ const char *message = _vm->useWindowsInterface() ?
+ "Are you sure you want to start a new game?" :
+ "Are you sure you want to RESTART?";
+ if (_vm->yesNoBox(message, true))
_vm->_file->restoreGame(99);
break;
+ }
case kActionInventory:
showInventory();
break;
@@ -446,6 +453,10 @@ void Parser::command(const char *format, ...) {
lineHandler();
}
+void Parser::resetCommandLine() {
+ _cmdLine[_cmdLineIndex = 0] = '\0';
+}
+
/**
* Locate any member of object name list appearing in command line
*/
@@ -544,11 +555,11 @@ void Parser::showDosInventory() const {
ttsMessage += Common::String(_vm->_text->getTextParser(kTBOutro));
_vm->sayText(ttsMessage, Common::TextToSpeechManager::INTERRUPT);
#endif
- Utils::notifyBox(buffer, kTtsNoSpeech);
+ _vm->notifyBox(buffer, false, kTtsNoSpeech);
}
void Parser::endGamePrompt() {
- if (Utils::yesNoBox(_vm->_text->getTextParser(kTBExit_1d))) {
+ if (_vm->yesNoBox(_vm->_text->getTextParser(kTBExit_1d), true)) {
_vm->endGame();
}
}
diff --git a/engines/hugo/parser.h b/engines/hugo/parser.h
index 86a6d8b2543..5172c35f19a 100644
--- a/engines/hugo/parser.h
+++ b/engines/hugo/parser.h
@@ -86,6 +86,7 @@ public:
void charHandler();
void command(const char *format, ...);
+ void resetCommandLine();
void freeParser();
void keyHandler(Common::Event event);
void actionHandler(Common::Event event);
diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp
index 05b6f11dcc4..1c821131629 100644
--- a/engines/hugo/parser_v1d.cpp
+++ b/engines/hugo/parser_v1d.cpp
@@ -32,6 +32,7 @@
#include "common/system.h"
#include "hugo/hugo.h"
+#include "hugo/display.h"
#include "hugo/parser.h"
#include "hugo/file.h"
#include "hugo/schedule.h"
@@ -148,25 +149,25 @@ bool Parser_v1d::isGenericVerb_v1(const char *word, Object *obj) {
// Following is equivalent to switch, but couldn't do one
if (word == _vm->_text->getVerb(_vm->_look, 0)) {
if ((LOOK & obj->_genericCmd) == LOOK)
- Utils::notifyBox(_vm->_text->getTextData(obj->_dataIndex));
+ _vm->notifyBox(_vm->_text->getTextData(obj->_dataIndex));
else
- Utils::notifyBox(_vm->_text->getTextParser(kTBUnusual_1d));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBUnusual_1d));
} else if (word == _vm->_text->getVerb(_vm->_take, 0)) {
if (obj->_carriedFl)
- Utils::notifyBox(_vm->_text->getTextParser(kTBHave));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBHave));
else if ((TAKE & obj->_genericCmd) == TAKE)
takeObject(obj);
else if (!obj->_verbOnlyFl) // Make sure not taking object in context!
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoUse));
else
return false;
} else if (word == _vm->_text->getVerb(_vm->_drop, 0)) {
if (!obj->_carriedFl)
- Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBDontHave));
else if ((DROP & obj->_genericCmd) == DROP)
dropObject(obj);
else
- Utils::notifyBox(_vm->_text->getTextParser(kTBNeed));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNeed));
} else { // It was not a generic cmd
return false;
}
@@ -203,7 +204,7 @@ bool Parser_v1d::isObjectVerb_v1(const char *word, Object *obj) {
uint16 *reqs = _arrayReqs[cmnd->_reqIndex]; // ptr to list of required objects
for (i = 0; reqs[i]; i++) { // for each obj
if (!_vm->_object->isCarrying(reqs[i])) {
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex));
return true;
}
}
@@ -211,14 +212,14 @@ bool Parser_v1d::isObjectVerb_v1(const char *word, Object *obj) {
// Required objects are present, now check state is correct
if ((obj->_state != cmnd->_reqState) && (cmnd->_reqState != kStateDontCare)){
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex));
return true;
}
// Everything checked. Change the state and carry out any actions
if (cmnd->_reqState != kStateDontCare) // Don't change new state if required state didn't care
obj->_state = cmnd->_newState;
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex));
_vm->_scheduler->insertActionList(cmnd->_actIndex);
// Special case if verb is Take or Drop. Assume additional generic actions
if ((word == _vm->_text->getVerb(_vm->_take, 0)) || (word == _vm->_text->getVerb(_vm->_drop, 0)))
@@ -238,7 +239,7 @@ bool Parser_v1d::isBackgroundWord_v1(const char *noun, const char *verb, ObjectL
for (int i = 0; obj[i]._verbIndex; i++) {
if ((verb == _vm->_text->getVerb(obj[i]._verbIndex, 0)) && (noun == _vm->_text->getNoun(obj[i]._nounIndex, 0))) {
- Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
+ _vm->notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
return true;
}
}
@@ -256,8 +257,8 @@ void Parser_v1d::takeObject(Object *obj) {
obj->_cycling = kCycleAlmostInvisible;
_vm->adjustScore(obj->_objValue);
-
- Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->_nounIndex, TAKE_NAME)));
+ _vm->_screen->updateStatusText();
+ _vm->takeObjectBox(_vm->_text->getNoun(obj->_nounIndex, TAKE_NAME));
}
/**
@@ -273,7 +274,8 @@ void Parser_v1d::dropObject(Object *obj) {
obj->_x = _vm->_hero->_x - 1;
obj->_y = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - 1;
_vm->adjustScore(-obj->_objValue);
- Utils::notifyBox(_vm->_text->getTextParser(kTBOk));
+ _vm->_screen->updateStatusText();
+ _vm->notifyBox("Ok");
}
/**
@@ -288,7 +290,7 @@ bool Parser_v1d::isCatchallVerb_v1(bool testNounFl, const char *noun, const char
for (int i = 0; obj[i]._verbIndex; i++) {
if ((verb == _vm->_text->getVerb(obj[i]._verbIndex, 0)) && ((noun == _vm->_text->getNoun(obj[i]._nounIndex, 0)) || (obj[i]._nounIndex == 0))) {
- Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
+ _vm->notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
return true;
}
}
@@ -301,6 +303,10 @@ bool Parser_v1d::isCatchallVerb_v1(bool testNounFl, const char *noun, const char
void Parser_v1d::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
+ // Reset the prompt on screen (DOS only)
+ _vm->_screen->updatePromptText("", ' ');
+ _vm->_screen->displayPromptText();
+
Status &gameStatus = _vm->getGameStatus();
// Toggle God Mode
@@ -411,11 +417,11 @@ void Parser_v1d::lineHandler() {
}
noun = findNextNoun(noun);
if (*farComment != '\0') // An object matched but not near enough
- Utils::notifyBox(farComment);
+ _vm->notifyBox(farComment);
else if (!isCatchallVerb_v1(true, noun, verb, _catchallList) &&
!isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screenPtr]) &&
!isCatchallVerb_v1(false, noun, verb, _catchallList))
- Utils::notifyBox(_vm->_text->getTextParser(kTBEh_1d));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBEh_1d));
}
void Parser_v1d::showInventory() const {
diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp
index 7a4ea4c5b03..35b46bfab5c 100644
--- a/engines/hugo/parser_v1w.cpp
+++ b/engines/hugo/parser_v1w.cpp
@@ -176,7 +176,7 @@ void Parser_v1w::lineHandler() {
// If a not-near comment was generated, print it
if (*farComment != '\0') {
- Utils::notifyBox(farComment);
+ _vm->notifyBox(farComment);
return;
}
@@ -184,16 +184,16 @@ void Parser_v1w::lineHandler() {
const char *verb = findVerb();
const char *noun = findNoun();
if (verb == _vm->_text->getVerb(_vm->_look, 0) && _vm->_maze._enabledFl) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBMaze));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBMaze));
_vm->_object->showTakeables();
} else if (verb && noun) { // A combination I didn't think of
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoPoint));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoPoint));
} else if (noun) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoun));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoun));
} else if (verb) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBVerb));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBVerb));
} else {
- Utils::notifyBox(_vm->_text->getTextParser(kTBEh));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBEh));
}
}
diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp
index 4a695d7ec63..c36fed06f27 100644
--- a/engines/hugo/parser_v2d.cpp
+++ b/engines/hugo/parser_v2d.cpp
@@ -32,6 +32,7 @@
#include "common/system.h"
#include "hugo/hugo.h"
+#include "hugo/display.h"
#include "hugo/parser.h"
#include "hugo/file.h"
#include "hugo/schedule.h"
@@ -54,6 +55,10 @@ Parser_v2d::~Parser_v2d() {
void Parser_v2d::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
+ // Reset the prompt on screen (DOS only)
+ _vm->_screen->updatePromptText("", ' ');
+ _vm->_screen->displayPromptText();
+
Status &gameStatus = _vm->getGameStatus();
// Toggle God Mode
@@ -169,16 +174,16 @@ void Parser_v2d::lineHandler() {
&& !isCatchallVerb_v2(false, noun, verb, _backgroundObjects[*_vm->_screenPtr])
&& !isCatchallVerb_v2(false, noun, verb, _catchallList)) {
if (*farComment != '\0') { // An object matched but not near enough
- Utils::notifyBox(farComment);
+ _vm->notifyBox(farComment);
} else if (_vm->_maze._enabledFl && (verb == _vm->_text->getVerb(_vm->_look, 0))) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBMaze));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBMaze));
_vm->_object->showTakeables();
} else if (verb && noun) { // A combination I didn't think of
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse_2d));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoUse_2d));
} else if (verb || noun) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoun));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoun));
} else {
- Utils::notifyBox(_vm->_text->getTextParser(kTBEh_2d));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBEh_2d));
}
}
}
@@ -198,29 +203,29 @@ bool Parser_v2d::isGenericVerb_v2(const char *word, Object *obj) {
if (word == _vm->_text->getVerb(_vm->_look, 0)) {
if ((LOOK & obj->_genericCmd) == LOOK)
if (obj->_dataIndex != 0)
- Utils::notifyBox(_vm->_text->getTextData(obj->_dataIndex));
+ _vm->notifyBox(_vm->_text->getTextData(obj->_dataIndex));
else
return false;
else
- Utils::notifyBox(_vm->_text->getTextParser(kTBUnusual_1d));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBUnusual_1d));
} else if (word == _vm->_text->getVerb(_vm->_take, 0)) {
if (obj->_carriedFl)
- Utils::notifyBox(_vm->_text->getTextParser(kTBHave));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBHave));
else if ((TAKE & obj->_genericCmd) == TAKE)
takeObject(obj);
else if (obj->_cmdIndex) // No comment if possible commands
return false;
else if (!obj->_verbOnlyFl) // Make sure not taking object in context!
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoUse));
else
return false;
} else if (word == _vm->_text->getVerb(_vm->_drop, 0)) {
if (!obj->_carriedFl)
- Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBDontHave));
else if ((DROP & obj->_genericCmd) == DROP)
dropObject(obj);
else
- Utils::notifyBox(_vm->_text->getTextParser(kTBNeed));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNeed));
} else { // It was not a generic cmd
return false;
}
@@ -257,7 +262,7 @@ bool Parser_v2d::isObjectVerb_v2(const char *word, Object *obj) {
uint16 *reqs = _arrayReqs[cmnd->_reqIndex]; // ptr to list of required objects
for (i = 0; reqs[i]; i++) { // for each obj
if (!_vm->_object->isCarrying(reqs[i])) {
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex));
return true;
}
}
@@ -265,14 +270,14 @@ bool Parser_v2d::isObjectVerb_v2(const char *word, Object *obj) {
// Required objects are present, now check state is correct
if ((obj->_state != cmnd->_reqState) && (cmnd->_reqState != kStateDontCare)){
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex));
return true;
}
// Everything checked. Change the state and carry out any actions
if (cmnd->_reqState != kStateDontCare) // Don't change new state if required state didn't care
obj->_state = cmnd->_newState;
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex));
_vm->_scheduler->insertActionList(cmnd->_actIndex);
// Special case if verb is Take or Drop. Assume additional generic actions
if ((word == _vm->_text->getVerb(_vm->_take, 0)) || (word == _vm->_text->getVerb(_vm->_drop, 0)))
@@ -299,7 +304,7 @@ bool Parser_v2d::isBackgroundWord_v2(const char *noun, const char *verb, ObjectL
if ((verb == _vm->_text->getVerb(obj[i]._verbIndex, 0)) && (noun == _vm->_text->getNoun(obj[i]._nounIndex, 0)) &&
(obj[i]._roomState == kStateDontCare ||
obj[i]._roomState == _vm->_screenStates[*_vm->_screenPtr])) {
- Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
+ _vm->notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
_vm->_scheduler->processBonus(obj[i]._bonusIndex);
return true;
}
@@ -333,7 +338,7 @@ bool Parser_v2d::isCatchallVerb_v2(bool testNounFl, const char *noun, const char
(obj[i]._roomState == kStateDontCare ||
obj[i]._roomState == _vm->_screenStates[*_vm->_screenPtr])) {
- Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
+ _vm->notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
_vm->_scheduler->processBonus(obj[i]._bonusIndex);
// If this is LOOK without a noun, show any takeable objects
if (!noun && verb == _vm->_text->getVerb(_vm->_look, 0))
diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp
index f2b48eaf560..af1a2d23470 100644
--- a/engines/hugo/parser_v3d.cpp
+++ b/engines/hugo/parser_v3d.cpp
@@ -32,6 +32,7 @@
#include "common/system.h"
#include "hugo/hugo.h"
+#include "hugo/display.h"
#include "hugo/parser.h"
#include "hugo/file.h"
#include "hugo/schedule.h"
@@ -54,6 +55,10 @@ Parser_v3d::~Parser_v3d() {
void Parser_v3d::lineHandler() {
debugC(1, kDebugParser, "lineHandler()");
+ // Reset the prompt on screen (DOS only)
+ _vm->_screen->updatePromptText("", ' ');
+ _vm->_screen->displayPromptText();
+
Status &gameStatus = _vm->getGameStatus();
// Toggle God Mode
@@ -178,7 +183,7 @@ void Parser_v3d::lineHandler() {
// If a not-near comment was generated, print it
if (*farComment != '\0') {
- Utils::notifyBox(farComment);
+ _vm->notifyBox(farComment);
return;
}
@@ -187,13 +192,13 @@ void Parser_v3d::lineHandler() {
const char *noun = findNoun();
if (verb && noun) { // A combination I didn't think of
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoPoint));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoPoint));
} else if (noun) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoun));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoun));
} else if (verb) {
- Utils::notifyBox(_vm->_text->getTextParser(kTBVerb));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBVerb));
} else {
- Utils::notifyBox(_vm->_text->getTextParser(kTBEh));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBEh));
}
}
@@ -230,7 +235,7 @@ bool Parser_v3d::isObjectVerb_v3(Object *obj, char *comment) {
uint16 *reqs = _arrayReqs[cmnd->_reqIndex]; // ptr to list of required objects
for (i = 0; reqs[i]; i++) { // for each obj
if (!_vm->_object->isCarrying(reqs[i])) {
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataNoCarryIndex));
return true;
}
}
@@ -238,14 +243,14 @@ bool Parser_v3d::isObjectVerb_v3(Object *obj, char *comment) {
// Required objects are present, now check state is correct
if ((obj->_state != cmnd->_reqState) && (cmnd->_reqState != kStateDontCare)) {
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataWrongIndex));
return true;
}
// Everything checked. Change the state and carry out any actions
if (cmnd->_reqState != kStateDontCare) // Don't change new state if required state didn't care
obj->_state = cmnd->_newState;
- Utils::notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex));
+ _vm->notifyBox(_vm->_text->getTextData(cmnd->_textDataDoneIndex));
_vm->_scheduler->insertActionList(cmnd->_actIndex);
// See if any additional generic actions
@@ -267,35 +272,35 @@ bool Parser_v3d::isGenericVerb_v3(Object *obj, char *comment) {
if (isWordPresent(_vm->_text->getVerbArray(_vm->_look)) && isNear_v3(obj, _vm->_text->getVerb(_vm->_look, 0), comment)) {
// Test state-dependent look before general look
if ((obj->_genericCmd & LOOK_S) == LOOK_S) {
- Utils::notifyBox(_vm->_text->getTextData(obj->_stateDataIndex[obj->_state]));
+ _vm->notifyBox(_vm->_text->getTextData(obj->_stateDataIndex[obj->_state]));
} else {
if ((LOOK & obj->_genericCmd) == LOOK) {
if (obj->_dataIndex != 0)
- Utils::notifyBox(_vm->_text->getTextData(obj->_dataIndex));
+ _vm->notifyBox(_vm->_text->getTextData(obj->_dataIndex));
else
return false;
} else {
- Utils::notifyBox(_vm->_text->getTextParser(kTBUnusual));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBUnusual));
}
}
} else if (isWordPresent(_vm->_text->getVerbArray(_vm->_take)) && isNear_v3(obj, _vm->_text->getVerb(_vm->_take, 0), comment)) {
if (obj->_carriedFl)
- Utils::notifyBox(_vm->_text->getTextParser(kTBHave));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBHave));
else if ((TAKE & obj->_genericCmd) == TAKE)
takeObject(obj);
else if (obj->_cmdIndex) // No comment if possible commands
return false;
else if (!obj->_verbOnlyFl && (TAKE & obj->_genericCmd) == TAKE) // Make sure not taking object in context!
- Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNoUse));
else
return false;
} else if (isWordPresent(_vm->_text->getVerbArray(_vm->_drop))) {
if (!obj->_carriedFl && ((DROP & obj->_genericCmd) == DROP))
- Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBDontHave));
else if (obj->_carriedFl && ((DROP & obj->_genericCmd) == DROP))
dropObject(obj);
else if (obj->_cmdIndex == 0)
- Utils::notifyBox(_vm->_text->getTextParser(kTBNeed));
+ _vm->notifyBox(_vm->_text->getTextParser(kTBNeed));
else
return false;
} else { // It was not a generic cmd
@@ -374,10 +379,11 @@ void Parser_v3d::takeObject(Object *obj) {
obj->_cycling = kCycleInvisible;
}
_vm->adjustScore(obj->_objValue);
+ _vm->_screen->updateStatusText();
if (obj->_seqNumb > 0) // If object has an image, force walk to dropped
obj->_viewx = -1; // (possibly moved) object next time taken!
- Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->_nounIndex, TAKE_NAME)));
+ _vm->takeObjectBox(_vm->_text->getNoun(obj->_nounIndex, TAKE_NAME));
}
/**
@@ -396,7 +402,8 @@ void Parser_v3d::dropObject(Object *obj) {
obj->_y = _vm->_hero->_y + _vm->_hero->_currImagePtr->_y2 - 1;
obj->_y = (obj->_y + obj->_currImagePtr->_y2 < kYPix) ? obj->_y : kYPix - obj->_currImagePtr->_y2 - 10;
_vm->adjustScore(-obj->_objValue);
- Utils::notifyBox(_vm->_text->getTextParser(kTBOk));
+ _vm->_screen->updateStatusText();
+ _vm->notifyBox(_vm->_text->getTextParser(kTBOk));
}
/**
@@ -418,7 +425,7 @@ bool Parser_v3d::isCatchallVerb_v3(ObjectList obj) const {
(!obj[i]._matchFl || !findNoun()) &&
((obj[i]._roomState == kStateDontCare) ||
(obj[i]._roomState == _vm->_screenStates[*_vm->_screenPtr]))) {
- Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
+ _vm->notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
_vm->_scheduler->processBonus(obj[i]._bonusIndex);
// If this is LOOK (without a noun), show any takeable objects
@@ -448,7 +455,7 @@ bool Parser_v3d::isBackgroundWord_v3(ObjectList obj) const {
isWordPresent(_vm->_text->getNounArray(obj[i]._nounIndex)) &&
((obj[i]._roomState == kStateDontCare) ||
(obj[i]._roomState == _vm->_screenStates[*_vm->_screenPtr]))) {
- Utils::notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
+ _vm->notifyBox(_vm->_file->fetchString(obj[i]._commentIndex));
_vm->_scheduler->processBonus(obj[i]._bonusIndex);
return true;
}
diff --git a/engines/hugo/schedule.cpp b/engines/hugo/schedule.cpp
index d5ab53aeb7c..fce35d8e735 100644
--- a/engines/hugo/schedule.cpp
+++ b/engines/hugo/schedule.cpp
@@ -162,6 +162,7 @@ void Scheduler::processBonus(const int bonusIndex) {
if (!_points[bonusIndex]._scoredFl) {
_vm->adjustScore(_points[bonusIndex]._score);
_points[bonusIndex]._scoredFl = true;
+ _vm->_screen->updateStatusText();
}
}
@@ -1258,7 +1259,9 @@ Event *Scheduler::doAction(Event *curEvent) {
insertActionList(action->_a11._actFailIndex);
break;
case TEXT: // act12: Text box (CF WARN)
- Utils::notifyBox(_vm->_file->fetchString(action->_a12._stringIndex)); // Fetch string from file
+ // Text boxes are protected in Hugo1 and Hugo2. Hugo3 added WARN action.
+ _vm->notifyBox(_vm->_file->fetchString(action->_a12._stringIndex), // Fetch string from file
+ _vm->getGameType() != kGameTypeHugo3);
break;
case SWAP_IMAGES: // act13: Swap 2 object images
_vm->_object->swapImages(action->_a13._objIndex1, action->_a13._objIndex2, false);
@@ -1326,9 +1329,11 @@ Event *Scheduler::doAction(Event *curEvent) {
break;
case ADD_SCORE: // act27: Add object's value to score
_vm->adjustScore(_vm->_object->_objects[action->_a27._objIndex]._objValue);
+ _vm->_screen->updateStatusText();
break;
case SUB_SCORE: // act28: Subtract object's value from score
_vm->adjustScore(-_vm->_object->_objects[action->_a28._objIndex]._objValue);
+ _vm->_screen->updateStatusText();
break;
case COND_CARRY: // act29: Conditional on object being carried
if (_vm->_object->isCarried(action->_a29._objIndex))
@@ -1383,7 +1388,7 @@ Event *Scheduler::doAction(Event *curEvent) {
gameStatus._storyModeFl = action->_a39._storyModeFl;
break;
case WARN: // act40: Text box (CF TEXT)
- Utils::notifyBox(_vm->_file->fetchString(action->_a40._stringIndex));
+ _vm->notifyBox(_vm->_file->fetchString(action->_a40._stringIndex), true);
break;
case COND_BONUS: // act41: Perform action if got bonus
if (_points[action->_a41._bonusIndex]._scoredFl)
@@ -1392,10 +1397,10 @@ Event *Scheduler::doAction(Event *curEvent) {
insertActionList(action->_a41._actFailIndex);
break;
case TEXT_TAKE: // act42: Text box with "take" message
- Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(_vm->_object->_objects[action->_a42._objIndex]._nounIndex, TAKE_NAME)));
+ _vm->takeObjectBox(_vm->_text->getNoun(_vm->_object->_objects[action->_a42._objIndex]._nounIndex, TAKE_NAME));
break;
case YESNO: // act43: Prompt user for Yes or No
- if (Utils::yesNoBox(_vm->_file->fetchString(action->_a43._promptIndex)))
+ if (_vm->yesNoBox(_vm->_file->fetchString(action->_a43._promptIndex), false))
insertActionList(action->_a43._actYesIndex);
else
insertActionList(action->_a43._actNoIndex);
@@ -1547,7 +1552,7 @@ void Scheduler_v1d::runScheduler() {
void Scheduler_v1d::promptAction(Act *action) {
Common::String response;
- response = Utils::promptBox(_vm->_file->fetchString(action->_a3._promptIndex));
+ response = _vm->promptBox(_vm->_file->fetchString(action->_a3._promptIndex));
#ifdef USE_TTS
_vm->_queueAllVoicing = true;
@@ -1594,7 +1599,7 @@ const char *Scheduler_v2d::getCypher() const {
void Scheduler_v2d::promptAction(Act *action) {
Common::String response;
- response = Utils::promptBox(_vm->_file->fetchString(action->_a3._promptIndex));
+ response = _vm->promptBox(_vm->_file->fetchString(action->_a3._promptIndex));
response.toLowercase();
#ifdef USE_TTS
Commit: 4d57d28195b893be1bf4505ea0fa9dc5310f0c06
https://github.com/scummvm/scummvm/commit/4d57d28195b893be1bf4505ea0fa9dc5310f0c06
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Update DOS inventory message box
- Extract TTS code into separate function
- Use correct noun strings for inventory items
- Apply HUGO3 differences
Changed paths:
engines/hugo/parser.cpp
engines/hugo/parser.h
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index c8e9bee3854..c1066c4a5e3 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -509,55 +509,79 @@ void Parser::showDosInventory() const {
debugC(1, kDebugParser, "showDosInventory()");
static const char *const blanks = " ";
uint16 index = 0, len1 = 0, len2 = 0;
+ const char *intro = _vm->_text->getTextParser(kTBIntro);
+ const char *outro = _vm->_text->getTextParser(kTBOutro);
+ if (_vm->getGameType() == kGameTypeHugo3) {
+ outro = "\nPress any key to continue";
+ }
+ const int nounIndex2 = (_vm->getGameType() <= kGameTypeHugo2) ? 0 : 1;
for (int i = 0; i < _vm->_object->_numObj; i++) { // Find widths of 2 columns
if (_vm->_object->isCarried(i)) {
- uint16 len = strlen(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2));
+ uint16 len = strlen(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, nounIndex2));
if (index++ & 1) // Right hand column
len2 = (len > len2) ? len : len2;
else
len1 = (len > len1) ? len : len1;
}
}
- len1 += 1; // For gap between columns
-
- if (len1 + len2 < (uint16)strlen(_vm->_text->getTextParser(kTBOutro)))
- len1 = strlen(_vm->_text->getTextParser(kTBOutro));
Common::String buffer;
- assert(len1 + len2 - strlen(_vm->_text->getTextParser(kTBIntro)) / 2 < strlen(blanks));
- buffer = Common::String(blanks, (len1 + len2 - strlen(_vm->_text->getTextParser(kTBIntro))) / 2);
+ if (_vm->getGameType() <= kGameTypeHugo2) {
+ len1 += 1; // For gap between columns
+ if (len1 + len2 < (uint16)strlen(outro)) {
+ len1 = strlen(outro);
+ }
+ assert(len1 + len2 - strlen(intro) / 2 < strlen(blanks));
+ buffer = Common::String(blanks, (len1 + len2 - strlen(intro)) / 2);
+ } else {
+ len1 += 4; // For gap between columns
+ if (len1 + len2 > (uint16)strlen(intro)) {
+ assert(len1 + len2 - strlen(intro) / 2 < strlen(blanks));
+ buffer = Common::String(blanks, (len1 + len2 - strlen(intro)) / 2);
+ }
+ }
- buffer += Common::String(_vm->_text->getTextParser(kTBIntro)) + "\n";
+ buffer += intro;
+ buffer += '\n';
index = 0;
-#ifdef USE_TTS
- Common::String ttsMessage = buffer;
-#endif
for (int i = 0; i < _vm->_object->_numObj; i++) { // Assign strings
if (_vm->_object->isCarried(i)) {
+ const char *objectName = _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, nounIndex2);
+ buffer += objectName;
if (index++ & 1) {
- buffer += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)) + "\n";
-#ifdef USE_TTS
- ttsMessage += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)) + "\n";
-#endif
+ buffer += '\n';
} else {
- buffer += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)) + Common::String(blanks, len1 - strlen(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)));
-#ifdef USE_TTS
- ttsMessage += Common::String(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)) + "\n" + Common::String(blanks, len1 - strlen(_vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 2)));
-#endif
+ buffer += Common::String(blanks, len1 - strlen(objectName));
}
}
}
if (index & 1)
- buffer += "\n";
- buffer += Common::String(_vm->_text->getTextParser(kTBOutro));
+ buffer += '\n';
+ buffer += outro;
+
#ifdef USE_TTS
- ttsMessage += Common::String(_vm->_text->getTextParser(kTBOutro));
- _vm->sayText(ttsMessage, Common::TextToSpeechManager::INTERRUPT);
+ sayInventory(intro, outro, nounIndex2);
#endif
+
_vm->notifyBox(buffer, false, kTtsNoSpeech);
}
+#ifdef USE_TTS
+void Parser::sayInventory(const char *intro, const char *outro, int nounIndex2) const {
+ Common::String text = intro;
+ for (int i = 0; i < _vm->_object->_numObj; i++) {
+ if (_vm->_object->isCarried(i)) {
+ text += '\n';
+ text += _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, nounIndex2);
+ }
+ }
+ text += '\n';
+ text += outro;
+ _vm->sayText(text, Common::TextToSpeechManager::INTERRUPT);
+}
+#endif
+
void Parser::endGamePrompt() {
if (_vm->yesNoBox(_vm->_text->getTextParser(kTBExit_1d), true)) {
_vm->endGame();
diff --git a/engines/hugo/parser.h b/engines/hugo/parser.h
index 5172c35f19a..bff7bf9bed8 100644
--- a/engines/hugo/parser.h
+++ b/engines/hugo/parser.h
@@ -121,7 +121,10 @@ protected:
void readBG(Common::ReadStream &in, Background &curBG);
void readCmd(Common::ReadStream &in, cmd &curCmd);
void showDosInventory() const;
- void endGamePrompt();
+#ifdef USE_TTS
+ void sayInventory(const char *intro, const char *outro, int nounIndex2) const;
+#endif
+ void endGamePrompt();
bool _checkDoubleF1Fl; // Flag used to display user help or instructions
uint16 _getIndex; // Index into ring buffer
Commit: 509c85e67b94acf25c58e1303a067406d8f79aae
https://github.com/scummvm/scummvm/commit/509c85e67b94acf25c58e1303a067406d8f79aae
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Disable mouse when not using Windows interface
Changed paths:
engines/hugo/hugo.cpp
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index f1fad7fb4ea..ef0997fbba5 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -294,8 +294,10 @@ Common::Error HugoEngine::run() {
return Common::kUnknownError;
// Use Windows-looking mouse cursor
- _screen->setCursorPal();
- _screen->resetInventoryObjId();
+ if (useWindowsInterface()) {
+ _screen->setCursorPal();
+ _screen->resetInventoryObjId();
+ }
_scheduler->initCypher();
@@ -363,7 +365,9 @@ Common::Error HugoEngine::run() {
_file->instructions();
}
- _mouse->mouseHandler(); // Mouse activity - adds to display list
+ if (useWindowsInterface()) {
+ _mouse->mouseHandler(); // Mouse activity - adds to display list
+ }
_screen->displayList(kDisplayDisplay); // Blit the display list to screen
_status._doQuitFl |= shouldQuit(); // update game quit flag
}
@@ -417,7 +421,9 @@ void HugoEngine::runMachine() {
}
break;
case kViewPlay: // Playing game
- _screen->showCursor();
+ if (useWindowsInterface()) {
+ _screen->showCursor();
+ }
_parser->charHandler(); // Process user cmd input
_object->moveObjects(); // Process object movement
_scheduler->runScheduler(); // Process any actions
Commit: 8dac7f3d320207e11ee23034341f0059f5bca869
https://github.com/scummvm/scummvm/commit/8dac7f3d320207e11ee23034341f0059f5bca869
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-14T17:28:13-08:00
Commit Message:
HUGO: Add config option for Windows interface in DOS
Changed paths:
engines/hugo/detection.cpp
engines/hugo/detection.h
engines/hugo/hugo.cpp
engines/hugo/metaengine.cpp
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index e6a2ea27f99..70b9162ae6f 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -59,7 +59,7 @@ static const HugoGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
- GUIO1(GAMEOPTION_TTS)
+ GUIO2(GAMEOPTION_TTS, GAMEOPTION_WINDOWS_INTERFACE)
},
kGameTypeHugo1
},
@@ -83,7 +83,7 @@ static const HugoGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
GF_PACKED,
- GUIO1(GAMEOPTION_TTS)
+ GUIO2(GAMEOPTION_TTS, GAMEOPTION_WINDOWS_INTERFACE)
},
kGameTypeHugo2
},
@@ -107,7 +107,7 @@ static const HugoGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
GF_PACKED,
- GUIO1(GAMEOPTION_TTS)
+ GUIO2(GAMEOPTION_TTS, GAMEOPTION_WINDOWS_INTERFACE)
},
kGameTypeHugo3
},
diff --git a/engines/hugo/detection.h b/engines/hugo/detection.h
index 19faef9af1a..c86f95ce860 100644
--- a/engines/hugo/detection.h
+++ b/engines/hugo/detection.h
@@ -55,6 +55,7 @@ struct HugoGameDescription {
};
#define GAMEOPTION_TTS GUIO_GAMEOPTIONS1
+#define GAMEOPTION_WINDOWS_INTERFACE GUIO_GAMEOPTIONS2
} // End of namespace Hugo
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index ef0997fbba5..e4272a1b9a6 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -86,7 +86,8 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy
_gameType = kGameTypeNone;
_platform = Common::kPlatformUnknown;
_packedFl = false;
- _windowsInterfaceFl = (gd->desc.platform == Common::kPlatformWindows);
+ _windowsInterfaceFl = (gd->desc.platform == Common::kPlatformWindows) ||
+ ConfMan.getBool("use_windows_interface");
_numVariant = 0;
_gameVariant = kGameVariantNone;
diff --git a/engines/hugo/metaengine.cpp b/engines/hugo/metaengine.cpp
index 9bb3a893e71..777bf077c43 100644
--- a/engines/hugo/metaengine.cpp
+++ b/engines/hugo/metaengine.cpp
@@ -39,6 +39,17 @@ namespace Hugo {
#ifdef USE_TTS
static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_WINDOWS_INTERFACE,
+ {
+ _s("Use Windows interface"),
+ _s("Use mouse and toolbar from Windows version"),
+ "use_windows_interface",
+ false,
+ 0,
+ 0
+ }
+ },
{
GAMEOPTION_TTS,
{
More information about the Scummvm-git-logs
mailing list