[Scummvm-git-logs] scummvm master -> f34306632812142ccf2c6b26eebdec0e44db30e2
neuromancer
noreply at scummvm.org
Mon Jul 13 19:52:11 UTC 2026
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
e9bc2e1b28 COLONY: allow to exit the animation using the exit button in mac
f343066328 COLONY: added decoder window to allow player to type the correct symbols
Commit: e9bc2e1b282677cd4e106153e22507349493a547
https://github.com/scummvm/scummvm/commit/e9bc2e1b282677cd4e106153e22507349493a547
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-13T21:51:56+02:00
Commit Message:
COLONY: allow to exit the animation using the exit button in mac
Changed paths:
engines/colony/animation.cpp
engines/colony/colony.h
diff --git a/engines/colony/animation.cpp b/engines/colony/animation.cpp
index 4636d660682..b257543733b 100644
--- a/engines/colony/animation.cpp
+++ b/engines/colony/animation.cpp
@@ -32,6 +32,10 @@
#include "common/stream.h"
#include "common/system.h"
#include "graphics/cursorman.h"
+#include "graphics/fontman.h"
+#include "graphics/macgui/macfontmanager.h"
+#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/managed_surface.h"
#include "graphics/surface.h"
#include "colony/colony.h"
@@ -395,6 +399,8 @@ void ColonyEngine::playAnimation() {
_rotateRight = false;
_animationRunning = true;
+ _animExitPressed = _animExitInside = false;
+ _animExitStrip = _animExitButton = Common::Rect();
_system->lockMouse(false);
warpMouseLogical(_centerX, _centerY);
const char *cursorName = "default arrow cursor";
@@ -590,9 +596,27 @@ void ColonyEngine::playAnimation() {
_gfx->computeScreenViewport();
needsDraw = true;
} else if (event.type == Common::EVENT_LBUTTONDOWN) {
- int item = whichSprite(eventMouseToLogical(event.mouse));
- if (item > 0) {
- handleAnimationClick(item);
+ const Common::Point pt = eventMouseToLogical(event.mouse);
+ if (!_animExitStrip.isEmpty() && _animExitStrip.contains(pt)) {
+ // gamesprt.c TestButton(): strip clicks never reach sprites
+ if (_animExitButton.contains(pt)) {
+ _animExitPressed = _animExitInside = true;
+ needsDraw = true;
+ }
+ } else {
+ int item = whichSprite(pt);
+ if (item > 0) {
+ handleAnimationClick(item);
+ needsDraw = true;
+ }
+ }
+ } else if (event.type == Common::EVENT_LBUTTONUP) {
+ if (_animExitPressed) {
+ if (_animExitInside) {
+ debugC(1, kColonyDebugAnimation, "Animation: EXIT button");
+ _animationRunning = false;
+ }
+ _animExitPressed = _animExitInside = false;
needsDraw = true;
}
} else if (event.type == Common::EVENT_RBUTTONDOWN) {
@@ -602,6 +626,13 @@ void ColonyEngine::playAnimation() {
_animationRunning = false;
} else if (event.type == Common::EVENT_MOUSEMOVE) {
const Common::Point logical = eventMouseToLogical(event.mouse);
+ if (_animExitPressed) {
+ const bool inside = _animExitButton.contains(logical);
+ if (inside != _animExitInside) {
+ _animExitInside = inside;
+ needsDraw = true;
+ }
+ }
debugC(5, kColonyDebugAnimation, "Animation Mouse: %d, %d", logical.x, logical.y);
} else if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
if (event.customType == kActionEscape) {
@@ -820,6 +851,49 @@ void ColonyEngine::drawAnimation() {
if (_lSprites[i]->onoff)
drawComplexSprite(i, ox, oy);
}
+
+ drawAnimationExitButton(ox, oy);
+}
+
+// gamesprt.c DrawButton(): 30px strip below the 416x264 scene with a framed
+// "EXIT" default button; TestButton() inverts it while pressed inside.
+void ColonyEngine::drawAnimationExitButton(int ox, int oy) {
+ if (!isMacRenderMode())
+ return;
+
+ Graphics::MacFont systemFont(Graphics::kMacFontSystem, 12);
+ const Graphics::Font *font = (_wm && _wm->_fontMan) ? _wm->_fontMan->getFont(systemFont) : nullptr;
+ if (!font)
+ font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ if (!font)
+ return;
+
+ Graphics::ManagedSurface strip;
+ strip.create(416, 30, _gfx->getPixelFormat());
+ const uint32 white = strip.format.ARGBToColor(255, 255, 255, 255);
+ const uint32 black = strip.format.ARGBToColor(255, 0, 0, 0);
+ strip.fillRect(Common::Rect(0, 0, 416, 30), white);
+ strip.hLine(0, 0, 415, black);
+
+ const int wd = font->getStringWidth("EXIT") / 2;
+ const Common::Rect button(208 - (wd + 15), 6, 208 + (wd + 15), 24);
+ const bool invert = _animExitPressed && _animExitInside;
+ strip.drawRoundRect(button, 8, black, invert);
+ Common::Rect ring(button.left - 3, button.top - 3, button.right + 3, button.bottom + 3);
+ strip.drawRoundRect(ring, 11, black, false);
+ ring.grow(-1);
+ strip.drawRoundRect(ring, 10, black, false);
+
+ const int textY = button.top + (button.height() - font->getFontHeight()) / 2 + 1;
+ font->drawString(&strip, "EXIT", button.left, textY, button.width(),
+ invert ? white : black, Graphics::kTextAlignCenter);
+
+ _gfx->drawSurface(&strip.rawSurface(), ox, oy + 264);
+ strip.free();
+
+ _animExitStrip = Common::Rect(ox, oy + 264, ox + 416, oy + 294);
+ _animExitButton = button;
+ _animExitButton.translate(ox, oy + 264);
}
void ColonyEngine::drawComplexSprite(int index, int ox, int oy) {
diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index 294f276aba2..2d87254937c 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -802,6 +802,10 @@ private:
Common::Array<int16> _animBMColors;
bool _animationRunning;
int _animationResult;
+ bool _animExitPressed = false;
+ bool _animExitInside = false;
+ Common::Rect _animExitStrip;
+ Common::Rect _animExitButton;
bool _doorOpen;
int _liftObject = 0; // sprite index for the carried object in lift animation
bool _liftUp = false; // current lift state: true=raised, false=lowered
@@ -825,6 +829,7 @@ private:
void playAnimation();
void updateAnimation();
void drawAnimation();
+ void drawAnimationExitButton(int ox, int oy);
void drawComplexSprite(int index, int ox, int oy);
void drawAnimationImage(Image *img, Image *mask, int x, int y, uint32 fillColor,
Graphics::Surface *&bakedCache, uint64 &bakedCacheKey);
Commit: f34306632812142ccf2c6b26eebdec0e44db30e2
https://github.com/scummvm/scummvm/commit/f34306632812142ccf2c6b26eebdec0e44db30e2
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-13T21:51:56+02:00
Commit Message:
COLONY: added decoder window to allow player to type the correct symbols
Changed paths:
engines/colony/animation.cpp
engines/colony/colony.cpp
engines/colony/colony.h
diff --git a/engines/colony/animation.cpp b/engines/colony/animation.cpp
index b257543733b..f2c7fca3f8f 100644
--- a/engines/colony/animation.cpp
+++ b/engines/colony/animation.cpp
@@ -401,6 +401,12 @@ void ColonyEngine::playAnimation() {
_animationRunning = true;
_animExitPressed = _animExitInside = false;
_animExitStrip = _animExitButton = Common::Rect();
+ _coderCursor = 0;
+ for (int i = 0; i < 4; i++)
+ _coderPick[i] = 0;
+ _coderWin = Common::Rect();
+ _coderPressed = -1;
+ _coderPressInside = false;
_system->lockMouse(false);
warpMouseLogical(_centerX, _centerY);
const char *cursorName = "default arrow cursor";
@@ -597,7 +603,9 @@ void ColonyEngine::playAnimation() {
needsDraw = true;
} else if (event.type == Common::EVENT_LBUTTONDOWN) {
const Common::Point pt = eventMouseToLogical(event.mouse);
- if (!_animExitStrip.isEmpty() && _animExitStrip.contains(pt)) {
+ if (handleColonyCoderClick(pt)) {
+ needsDraw = true;
+ } else if (!_animExitStrip.isEmpty() && _animExitStrip.contains(pt)) {
// gamesprt.c TestButton(): strip clicks never reach sprites
if (_animExitButton.contains(pt)) {
_animExitPressed = _animExitInside = true;
@@ -611,6 +619,20 @@ void ColonyEngine::playAnimation() {
}
}
} else if (event.type == Common::EVENT_LBUTTONUP) {
+ if (_coderPressed >= 0) {
+ if (_coderPressInside) {
+ if (_coderCursor >= 4) {
+ for (int j = 0; j < 4; j++)
+ _coderPick[j] = 0;
+ _coderCursor = 0;
+ }
+ _coderPick[_coderCursor++] = _coderPressed + 1;
+ _sound->play(Sound::kDit);
+ }
+ _coderPressed = -1;
+ _coderPressInside = false;
+ needsDraw = true;
+ }
if (_animExitPressed) {
if (_animExitInside) {
debugC(1, kColonyDebugAnimation, "Animation: EXIT button");
@@ -626,6 +648,13 @@ void ColonyEngine::playAnimation() {
_animationRunning = false;
} else if (event.type == Common::EVENT_MOUSEMOVE) {
const Common::Point logical = eventMouseToLogical(event.mouse);
+ if (_coderPressed >= 0) {
+ const bool inside = _coderIconRects[_coderPressed].contains(logical);
+ if (inside != _coderPressInside) {
+ _coderPressInside = inside;
+ needsDraw = true;
+ }
+ }
if (_animExitPressed) {
const bool inside = _animExitButton.contains(logical);
if (inside != _animExitInside) {
@@ -853,6 +882,7 @@ void ColonyEngine::drawAnimation() {
}
drawAnimationExitButton(ox, oy);
+ drawColonyCoder(ox, oy);
}
// gamesprt.c DrawButton(): 30px strip below the 416x264 scene with a framed
@@ -896,6 +926,226 @@ void ColonyEngine::drawAnimationExitButton(int ox, int oy) {
_animExitButton.translate(ox, oy + 264);
}
+void ColonyEngine::loadCoderTiles() {
+ _coderTilesLoaded = true;
+
+ Common::SeekableReadStream *file = Common::MacResManager::openFileOrDataFork(Common::Path("security"));
+ if (!file)
+ return;
+ Common::SeekableReadStreamEndianWrapper stream(file, true, DisposeAfterUse::YES);
+
+ byte bg[8];
+ stream.read(bg, 8);
+ stream.read(bg, 8);
+ stream.readSint16();
+ if (stream.readSint16() != 0) {
+ readRect(stream);
+ readRect(stream);
+ delete loadImage(stream);
+ delete loadImage(stream);
+ }
+
+ Common::Array<Image *> imgs;
+ const int16 maxsprite = stream.readSint16();
+ stream.readSint16();
+ for (int i = 0; i < maxsprite && !stream.err(); i++) {
+ imgs.push_back(loadImage(stream));
+ delete loadImage(stream); // mask
+ stream.readSint16();
+ readRect(stream);
+ readRect(stream);
+ }
+
+ // Object 2 (a digit key) provides the button faces (states 1..2),
+ // object 27 the four symbol tiles (states 2..5).
+ const int16 maxl = stream.readSint16();
+ stream.readSint16();
+ for (int i = 0; i < maxl && !stream.err(); i++) {
+ const int16 size = stream.readSint16();
+ for (int j = 0; j < size; j++) {
+ const int16 spritenum = stream.readSint16();
+ stream.readSint16();
+ stream.readSint16();
+ if (stream.err() || spritenum < 0 || spritenum >= (int16)imgs.size())
+ continue;
+ if (i == 1 && j == 0 && !_coderBtnUp) {
+ _coderBtnUp = imgs[spritenum];
+ imgs[spritenum] = nullptr;
+ } else if (i == 1 && j == 1 && !_coderBtnDown) {
+ _coderBtnDown = imgs[spritenum];
+ imgs[spritenum] = nullptr;
+ } else if (i == 26 && j >= 1 && j <= 4 && !_coderTiles[j - 1]) {
+ _coderTiles[j - 1] = imgs[spritenum];
+ imgs[spritenum] = nullptr;
+ }
+ }
+ readRect(stream);
+ for (int k = 0; k < 7; k++)
+ stream.readSint16();
+ stream.readByte();
+ stream.readByte();
+ stream.readByte();
+ stream.readSint16();
+ stream.readSint16();
+ stream.readSint16();
+ }
+
+ for (uint i = 0; i < imgs.size(); i++)
+ delete imgs[i];
+}
+
+static void drawCoderTile(Graphics::ManagedSurface &s, const Image *img, int x, int y, uint32 fg, uint32 bg) {
+ if (!img || !img->data)
+ return;
+ for (int r = 0; r < img->height; r++) {
+ for (int c = 0; c < img->width; c++) {
+ const bool on = (img->data[r * img->rowBytes + (c >> 3)] >> (7 - (c & 7))) & 1;
+ s.setPixel(x + c, y + r, on ? fg : bg);
+ }
+ }
+}
+
+void ColonyEngine::drawColonyCoder(int animOx, int animOy) {
+ if (!isMacRenderMode())
+ return;
+ if (_animationName != "security" && _animationName != "reactor")
+ return;
+
+ if (!_coderTilesLoaded)
+ loadCoderTiles();
+ if (!_coderTiles[0] || !_coderTiles[1] || !_coderTiles[2] || !_coderTiles[3] ||
+ !_coderBtnUp || !_coderBtnDown)
+ return;
+
+ Graphics::MacFont systemFont(Graphics::kMacFontSystem, 12);
+ const Graphics::Font *font = (_wm && _wm->_fontMan) ? _wm->_fontMan->getFont(systemFont) : nullptr;
+ if (!font)
+ font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ if (!font)
+ return;
+ Graphics::MacFont genevaFont(Graphics::kMacFontGeneva, 9);
+ const Graphics::Font *instrFont = (_wm && _wm->_fontMan) ? _wm->_fontMan->getFont(genevaFont) : nullptr;
+ if (!instrFont)
+ instrFont = font;
+
+ const int contentW = 172;
+ const char *instrText = (_animationName == "security")
+ ? "Press the symbols as shown on the display to determine the correct value."
+ : "Press the symbols from the desk in reverse order to determine the correct value.";
+ Common::Array<Common::U32String> instrLines;
+ instrFont->wordWrapText(Common::U32String(instrText), contentW - 16, instrLines);
+ const int instrLineH = instrFont->getFontHeight() + 1;
+
+ const int btnSize = _coderBtnUp->width;
+ const int tile = _coderTiles[0]->width;
+ const int pitch = btnSize + 4;
+ const int x0 = (contentW - (3 * pitch + btnSize)) / 2;
+ const int btnY = 8;
+ const int slotY = btnY + btnSize + 9;
+ const int codeY = slotY + tile + 16;
+ const int instrY = codeY + font->getFontHeight() + 8;
+ const int contentH = instrY + (int)instrLines.size() * instrLineH + 8;
+
+ Graphics::MacWindowBorder border;
+ Graphics::BorderOffsets offsets;
+ bool hasBorder = false;
+ if (_wm) {
+ border.setWindowManager(_wm);
+ border.setBorderType(Graphics::kWindowWindow);
+ if (border.hasBorder(Graphics::kWindowBorderActive) && border.hasOffsets()) {
+ hasBorder = true;
+ offsets = border.getOffset();
+ }
+ }
+ const int offL = hasBorder ? offsets.left : 2;
+ const int offR = hasBorder ? offsets.right : 2;
+ const int offT = hasBorder ? offsets.top : 2;
+ const int offB = hasBorder ? offsets.bottom : 2;
+ const int winW = contentW + offL + offR;
+ const int winH = contentH + offT + offB;
+
+ // Right of the scene, vertically centered on the 416x294 animation window
+ int wx = animOx + 416 + 4;
+ if (wx + winW > _screenR.right)
+ wx = MAX<int>(_screenR.left, _screenR.right - winW - 2);
+ int wy = animOy + (294 - winH) / 2;
+ wy = MAX<int>(_screenR.top, wy);
+
+ Graphics::ManagedSurface win;
+ win.create(winW, winH, _gfx->getPixelFormat());
+ const uint32 white = win.format.ARGBToColor(255, 255, 255, 255);
+ const uint32 black = win.format.ARGBToColor(255, 0, 0, 0);
+ win.fillRect(Common::Rect(0, 0, winW, winH), white);
+ if (hasBorder) {
+ border.setTitle("Colony Coder", winW);
+ border.blitBorderInto(win, Graphics::kWindowBorderActive);
+ } else {
+ win.frameRect(Common::Rect(0, 0, winW, winH), black);
+ win.frameRect(Common::Rect(1, 1, winW - 1, winH - 1), black);
+ }
+
+ // Keypad buttons with the symbol tile covering the digit
+ const int inset = (btnSize - tile) / 2;
+ for (int i = 0; i < 4; i++) {
+ const int bx = offL + x0 + i * pitch;
+ const bool pressed = (_coderPressed == i && _coderPressInside);
+ drawCoderTile(win, pressed ? _coderBtnDown : _coderBtnUp, bx, offT + btnY, black, white);
+ drawCoderTile(win, _coderTiles[i], bx + inset, offT + btnY + inset,
+ pressed ? white : black, pressed ? black : white);
+ _coderIconRects[i] = Common::Rect(wx + bx, wy + offT + btnY, wx + bx + btnSize, wy + offT + btnY + btnSize);
+
+ const int sx = bx + inset;
+ const Common::Rect slot(sx - 2, offT + slotY - 2, sx + tile + 2, offT + slotY + tile + 2);
+ win.frameRect(slot, black);
+ if (_coderPick[i] > 0)
+ drawCoderTile(win, _coderTiles[_coderPick[i] - 1], sx, offT + slotY, black, white);
+ }
+
+ if (_coderCursor < 4) {
+ const int cx = offL + x0 + _coderCursor * pitch + inset;
+ win.fillRect(Common::Rect(cx, offT + slotY + tile + 6, cx + tile, offT + slotY + tile + 8), black);
+ }
+
+ bool complete = true;
+ for (int i = 0; i < 4; i++) {
+ if (_coderPick[i] == 0)
+ complete = false;
+ }
+ Common::String text;
+ if (complete) {
+ uint8 code[6];
+ cryptArray(code, _coderPick[0] - 1, _coderPick[1] - 1, _coderPick[2] - 1, _coderPick[3] - 1);
+ for (int i = 0; i < 6; i++)
+ text += (char)('0' + code[i] - 2);
+ } else {
+ text = "- - - - - -";
+ }
+ font->drawString(&win, text, offL, offT + codeY, contentW, black, Graphics::kTextAlignCenter);
+
+ for (uint i = 0; i < instrLines.size(); i++)
+ instrFont->drawString(&win, instrLines[i], offL + 8, offT + instrY + (int)i * instrLineH,
+ contentW - 16, black, Graphics::kTextAlignCenter);
+
+ _gfx->drawSurface(&win.rawSurface(), wx, wy);
+ win.free();
+
+ _coderWin = Common::Rect(wx, wy, wx + winW, wy + winH);
+}
+
+// Mouse-down half of the button tracking; commit happens on mouse-up.
+bool ColonyEngine::handleColonyCoderClick(const Common::Point &pt) {
+ if (_coderWin.isEmpty() || !_coderWin.contains(pt))
+ return false;
+ for (int i = 0; i < 4; i++) {
+ if (_coderIconRects[i].contains(pt)) {
+ _coderPressed = i;
+ _coderPressInside = true;
+ break;
+ }
+ }
+ return true;
+}
+
void ColonyEngine::drawComplexSprite(int index, int ox, int oy) {
ComplexSprite *ls = _lSprites[index];
if (!ls->onoff)
diff --git a/engines/colony/colony.cpp b/engines/colony/colony.cpp
index c721852df1b..e20b86d44dc 100644
--- a/engines/colony/colony.cpp
+++ b/engines/colony/colony.cpp
@@ -288,6 +288,10 @@ ColonyEngine::~ColonyEngine() {
delete _flIconSurf[i];
}
}
+ for (int i = 0; i < 4; i++)
+ delete _coderTiles[i];
+ delete _coderBtnUp;
+ delete _coderBtnDown;
delete _frameLimiter;
delete _gfx;
delete _sound;
diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index 2d87254937c..32a68aa8a37 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -806,6 +806,16 @@ private:
bool _animExitInside = false;
Common::Rect _animExitStrip;
Common::Rect _animExitButton;
+ int _coderPick[4] = {};
+ int _coderCursor = 0;
+ int _coderPressed = -1;
+ bool _coderPressInside = false;
+ Image *_coderTiles[4] = {};
+ Image *_coderBtnUp = nullptr;
+ Image *_coderBtnDown = nullptr;
+ bool _coderTilesLoaded = false;
+ Common::Rect _coderWin;
+ Common::Rect _coderIconRects[4];
bool _doorOpen;
int _liftObject = 0; // sprite index for the carried object in lift animation
bool _liftUp = false; // current lift state: true=raised, false=lowered
@@ -830,6 +840,9 @@ private:
void updateAnimation();
void drawAnimation();
void drawAnimationExitButton(int ox, int oy);
+ void drawColonyCoder(int animOx, int animOy);
+ void loadCoderTiles();
+ bool handleColonyCoderClick(const Common::Point &pt);
void drawComplexSprite(int index, int ox, int oy);
void drawAnimationImage(Image *img, Image *mask, int x, int y, uint32 fillColor,
Graphics::Surface *&bakedCache, uint64 &bakedCacheKey);
More information about the Scummvm-git-logs
mailing list