[Scummvm-git-logs] scummvm master -> 14d40b598dd60fe8f1ac1078f96de5fcf0f98e1f

neuromancer noreply at scummvm.org
Mon Jul 13 15:23:41 UTC 2026


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
b077485c16 COLONY: missing forklift ui indicators
2c31314d8e COLONY: allow the minimap to persist between executions
14d40b598d COLONY: corrected invalid collision when there is a wall decoration


Commit: b077485c167cb45ab4792e0b7873fd36ad51457e
    https://github.com/scummvm/scummvm/commit/b077485c167cb45ab4792e0b7873fd36ad51457e
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-13T15:59:53+02:00

Commit Message:
COLONY: missing forklift ui indicators

Changed paths:
    engines/colony/colony.cpp
    engines/colony/colony.h
    engines/colony/ui.cpp


diff --git a/engines/colony/colony.cpp b/engines/colony/colony.cpp
index df1733b3671..c721852df1b 100644
--- a/engines/colony/colony.cpp
+++ b/engines/colony/colony.cpp
@@ -282,6 +282,12 @@ ColonyEngine::~ColonyEngine() {
 		_animPatternSurface->free();
 		delete _animPatternSurface;
 	}
+	for (int i = 0; i < 5; i++) {
+		if (_flIconSurf[i]) {
+			_flIconSurf[i]->free();
+			delete _flIconSurf[i];
+		}
+	}
 	delete _frameLimiter;
 	delete _gfx;
 	delete _sound;
@@ -1185,6 +1191,7 @@ Common::Error ColonyEngine::run() {
 
 		if (_gameMode == kModeBattle) {
 			renderBattle();
+			drawForkliftOverlay();
 			drawDashboardStep1();
 			drawCrosshair();
 		} else {
diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index 15678f332a5..294f276aba2 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -505,6 +505,8 @@ private:
 	Graphics::FrameLimiter *_frameLimiter = nullptr;
 	Common::RenderMode _renderMode;
 	Graphics::Surface *_savedScreen = nullptr;
+	Graphics::Surface *_flIconSurf[5] = {};
+	bool _flIconsLoaded = false;
 
 
 	int _tsin = 0, _tcos = 0;
@@ -753,6 +755,7 @@ private:
 	int automapWallFeature(int fx, int fy, int dir);
 	void automapDrawWallWithFeature(const Common::Rect &vp, int wx1, int wy1, int wx2, int wy2, int feat, int lExt, uint32 color);
 	void drawForkliftOverlay();
+	void loadForkliftIcons();
 	void drawCrosshair();
 	bool clipLineToRect(int &x1, int &y1, int &x2, int &y2, const Common::Rect &clip) const;
 	void wallLine(const float corners[4][3], float u1, float v1, float u2, float v2, uint32 color);
diff --git a/engines/colony/ui.cpp b/engines/colony/ui.cpp
index 4f41a4b0752..a71242fa50c 100644
--- a/engines/colony/ui.cpp
+++ b/engines/colony/ui.cpp
@@ -1065,6 +1065,48 @@ void ColonyEngine::drawAutomap() {
 	_gfx->drawEllipse(ccx, ccy, eyeRx, eyeRy, lineColor);
 	_gfx->fillEllipse(ccx, ccy, eyeRx >> 1, eyeRy, lineColor);
 }
+// inits.c: fl_icon[i] = GetIcon(i+1) — 32x32 1-bit ICON resources 1-5.
+// display.c PlotIcon: 1-bits are drawn black, 0-bits take the RGBBackColor —
+// white for the empty fork, the carried object's body color otherwise.
+void ColonyEngine::loadForkliftIcons() {
+	_flIconsLoaded = true;
+
+	// c_box1, c_cryo, c_teleport, c_ccore
+	static const int kBgColorIdx[5] = { -1, 84, 90, 93, 111 };
+	const uint32 white = packRGB(255, 255, 255);
+	const uint32 black = packRGB(0, 0, 0);
+
+	for (int i = 0; i < 5; i++) {
+		Common::SeekableReadStream *s = nullptr;
+		if (_colorResMan && _colorResMan->hasResFork())
+			s = _colorResMan->getResource(MKTAG('I', 'C', 'O', 'N'), i + 1);
+		if (!s && _resMan)
+			s = _resMan->getResource(MKTAG('I', 'C', 'O', 'N'), i + 1);
+		if (!s || s->size() < 128) {
+			delete s;
+			continue;
+		}
+
+		byte bits[128];
+		s->read(bits, 128);
+		delete s;
+
+		uint32 bg = white;
+		if (kBgColorIdx[i] >= 0 && isMacColorMode())
+			bg = packMacColor(_macColors[kBgColorIdx[i]].bg);
+
+		Graphics::Surface *surf = new Graphics::Surface();
+		surf->create(32, 32, renderColorFormat());
+		for (int y = 0; y < 32; y++) {
+			for (int x = 0; x < 32; x++) {
+				const bool on = (bits[y * 4 + (x >> 3)] >> (7 - (x & 7))) & 1;
+				surf->setPixel(x, y, on ? black : bg);
+			}
+		}
+		_flIconSurf[i] = surf;
+	}
+}
+
 void ColonyEngine::drawForkliftOverlay() {
 	if (_fl <= 0 || _screenR.width() <= 0 || _screenR.height() <= 0)
 		return;
@@ -1072,13 +1114,16 @@ void ColonyEngine::drawForkliftOverlay() {
 	// Original display.c: two diagonal fork arm lines when fl > 0.
 	// Left arm:  (centerX/4, 0) to (centerX/2, Height)
 	// Right arm: (Width - centerX/4, 0) to (Width - centerX/2, Height)
-	// Drawn with PenSize(2,2) in black (white in battle mode).
+	// Drawn with PenSize(2,2) in black (white pen pattern in battle mode).
 	const int left = _screenR.left;
 	const int top = _screenR.top;
 	const int w = _screenR.width();
 	const int h = _screenR.height();
 	const int cx = w / 2;
-	const uint32 color = isMacRenderMode() ? packRGB(0, 0, 0) : 0;
+	const bool isMac = isMacRenderMode();
+	const bool battle = (_gameMode == kModeBattle);
+	const uint32 color = isMac ? (battle ? packRGB(255, 255, 255) : packRGB(0, 0, 0))
+		: (battle ? 15 : 0);
 
 	const int tx2 = cx >> 2;  // centerX/4
 	const int tx1 = cx >> 1;  // centerX/2
@@ -1089,10 +1134,45 @@ void ColonyEngine::drawForkliftOverlay() {
 	// Right fork arm
 	_gfx->drawLine(left + w - tx2, top, left + w - tx1, top + h - 1, color);
 	_gfx->drawLine(left + w - tx2 - 1, top, left + w - tx1 - 1, top + h - 1, color);
+
+	// Fork status: fl==1 → empty fork, fl==2 → carried object type.
+	int fnum = 0;
+	if (_fl != 1) {
+		switch (_carryType) {
+		case kObjBox1:
+		case kObjBox2:     fnum = 1; break;
+		case kObjCryo:     fnum = 2; break;
+		case kObjTeleport: fnum = 3; break;
+		case kObjReactor:  fnum = 4; break;
+		default: break;
+		}
+	}
+
+	if (isMac) {
+		// display.c: PlotIcon(&fl_rect, fl_icon[fnum]);
+		// inits.c: fl_rect = (32, Height-64)-(64, Height-32), window-local.
+		if (!_flIconsLoaded)
+			loadForkliftIcons();
+		if (_flIconSurf[fnum])
+			_gfx->drawSurface(_flIconSurf[fnum], left + 32, _screenR.bottom - 64);
+	} else {
+		// IBM_DISP.C: framed white box at the bottom center naming the
+		// fork state, black text on vINTWHITE.
+		static const char *fltext[5] = { "EMPTY", "BOX", "CRYO", "TELEPORT", "REACTOR" };
+		Graphics::DosFont font;
+		const int half = 4 + font.getStringWidth(fltext[fnum]) / 2;
+		const Common::Rect r(_centerX - half, _screenR.bottom - 15, _centerX + half, _screenR.bottom - 1);
+		_gfx->fillRect(r, 15);
+		_gfx->drawRect(r, 0);
+		_gfx->drawString(&font, fltext[fnum], _centerX,
+			_screenR.bottom - 8 - font.getFontHeight() / 2, 0, Graphics::kTextAlignCenter);
+	}
 }
 
 void ColonyEngine::drawCrosshair() {
-	if (!_crosshair || _screenR.width() <= 0 || _screenR.height() <= 0)
+	// display.c / IBM_DISP.C: "if(fl){...} else if(crosshair)" — no aim
+	// crosshair while driving the forklift (you cannot shoot from it).
+	if (!_crosshair || _fl > 0 || _screenR.width() <= 0 || _screenR.height() <= 0)
 		return;
 
 	const bool isMac = isMacRenderMode();


Commit: 2c31314d8eb4342bd6f1843d2b8f616cee9daae0
    https://github.com/scummvm/scummvm/commit/2c31314d8eb4342bd6f1843d2b8f616cee9daae0
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-13T17:02:27+02:00

Commit Message:
COLONY: allow the minimap to persist between executions

Changed paths:
    engines/colony/savegame.cpp


diff --git a/engines/colony/savegame.cpp b/engines/colony/savegame.cpp
index f3117164866..93be2061633 100644
--- a/engines/colony/savegame.cpp
+++ b/engines/colony/savegame.cpp
@@ -374,6 +374,14 @@ Common::Error ColonyEngine::saveGameStream(Common::WriteStream *stream, bool isA
 		}
 	}
 
+	// Minimap fog-of-war, all levels
+	for (uint lv = 0; lv < ARRAYSIZE(_visited); lv++) {
+		for (int y = 0; y < 32; y++) {
+			for (int x = 0; x < 32; x++)
+				stream->writeByte(_visited[lv][x][y] ? 1 : 0);
+		}
+	}
+
 	stream->writeUint32LE(_objects.size());
 	for (uint i = 0; i < _objects.size(); i++)
 		writeThing(stream, _objects[i]);
@@ -484,6 +492,14 @@ Common::Error ColonyEngine::loadGameStream(Common::SeekableReadStream *stream) {
 		}
 	}
 
+	// Minimap fog-of-war, all levels
+	for (uint lv = 0; lv < ARRAYSIZE(_visited); lv++) {
+		for (int y = 0; y < 32; y++) {
+			for (int x = 0; x < 32; x++)
+				_visited[lv][x][y] = stream->readByte() != 0;
+		}
+	}
+
 	const uint32 objectCount = stream->readUint32LE();
 	if (objectCount > kMaxSaveObjects)
 		return makeCorruptSaveError(Common::String::format("object count %u exceeds max %u", objectCount, kMaxSaveObjects).c_str());


Commit: 14d40b598dd60fe8f1ac1078f96de5fcf0f98e1f
    https://github.com/scummvm/scummvm/commit/14d40b598dd60fe8f1ac1078f96de5fcf0f98e1f
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-13T17:21:50+02:00

Commit Message:
COLONY: corrected invalid collision when there is a wall decoration

Changed paths:
    engines/colony/movement.cpp


diff --git a/engines/colony/movement.cpp b/engines/colony/movement.cpp
index a632df766db..f0c5f85e096 100644
--- a/engines/colony/movement.cpp
+++ b/engines/colony/movement.cpp
@@ -414,10 +414,11 @@ void ColonyEngine::clampToWalls(Locate *p) {
 }
 
 void ColonyEngine::clampToDiagonalWalls(Locate *p) {
-	// CWall/FWall objects are diagonal corner fills not registered in _robotArray.
-	// Enforce geometric collision: the CWall inner face is the line lx+ly=kThreshold
-	// in the object's local coordinate space.  The player must stay on the room side.
-	const int kThreshold = 120; // inner face ~112 + padding
+	// CWall/FWall diagonal fills (not in _robotArray). Object space is ang+32,
+	// as in the renderer. INITOBJ.C: cwall face at lx+ly=112 with the room
+	// below; fwall sits on lx+ly=0 with rooms on both sides.
+	const int kCWallLimit = 112 - 8; // face minus clearance
+	const int kFWallClearance = 20;
 	for (uint i = 0; i < _objects.size(); i++) {
 		const Thing &obj = _objects[i];
 		if (!obj.alive)
@@ -425,52 +426,40 @@ void ColonyEngine::clampToDiagonalWalls(Locate *p) {
 		if (obj.type != kObjCWall && obj.type != kObjFWall)
 			continue;
 
-		// Quick reject: skip objects more than 1 cell away
 		if (ABS(p->xloc - obj.where.xloc) > 300 || ABS(p->yloc - obj.where.yloc) > 300)
 			continue;
 
-		// Transform player position into object's local space (inverse rotation)
+		const uint8 objAng = (uint8)(obj.where.ang + 32);
 		const int wx = p->xloc - obj.where.xloc;
 		const int wy = p->yloc - obj.where.yloc;
-		const uint8 invAng = (uint8)(0 - obj.where.ang);
+		const uint8 invAng = (uint8)(0 - objAng);
 		const int lx = (int)(((int32)wx * _cost[invAng] - (int32)wy * _sint[invAng]) >> 7);
 		const int ly = (int)(((int32)wx * _sint[invAng] + (int32)wy * _cost[invAng]) >> 7);
 
-		// Also reject if clearly outside the cell (local coords span -128..128)
 		if (lx < -140 || lx > 140 || ly < -140 || ly > 140)
 			continue;
 
 		const int diag = lx + ly;
+		int push = 0; // applied to both local axes, so diag moves by 2*push
 		if (obj.type == kObjCWall) {
-			if (diag >= kThreshold)
-				continue; // already on room side
-
-			// Push player along normal (1,1) in local space to reach threshold
-			const int push = (kThreshold - diag + 1) / 2;
-			const int nlx = lx + push;
-			const int nly = ly + push;
-
-			// Transform back to world space
-			const uint8 ang = obj.where.ang;
-			p->xloc = obj.where.xloc + (int)(((int32)nlx * _cost[ang] - (int32)nly * _sint[ang]) >> 7);
-			p->yloc = obj.where.yloc + (int)(((int32)nlx * _sint[ang] + (int32)nly * _cost[ang]) >> 7);
-			p->xindex = p->xloc >> 8;
-			p->yindex = p->yloc >> 8;
-		} else { // kObjFWall — flat wall along the diagonal
-			const int kFWallThreshold = 20;
-			if (diag >= kFWallThreshold)
+			if (diag <= kCWallLimit)
 				continue;
-
-			const int push = (kFWallThreshold - diag + 1) / 2;
-			const int nlx = lx + push;
-			const int nly = ly + push;
-
-			const uint8 ang = obj.where.ang;
-			p->xloc = obj.where.xloc + (int)(((int32)nlx * _cost[ang] - (int32)nly * _sint[ang]) >> 7);
-			p->yloc = obj.where.yloc + (int)(((int32)nlx * _sint[ang] + (int32)nly * _cost[ang]) >> 7);
-			p->xindex = p->xloc >> 8;
-			p->yindex = p->yloc >> 8;
+			push = -((diag - kCWallLimit + 1) / 2);
+		} else { // kObjFWall
+			if (ABS(diag) >= kFWallClearance)
+				continue;
+			if (diag >= 0)
+				push = (kFWallClearance - diag + 1) / 2;
+			else
+				push = -((kFWallClearance + diag + 1) / 2);
 		}
+
+		const int nlx = lx + push;
+		const int nly = ly + push;
+		p->xloc = obj.where.xloc + (int)(((int32)nlx * _cost[objAng] - (int32)nly * _sint[objAng]) >> 7);
+		p->yloc = obj.where.yloc + (int)(((int32)nlx * _sint[objAng] + (int32)nly * _cost[objAng]) >> 7);
+		p->xindex = p->xloc >> 8;
+		p->yindex = p->yloc >> 8;
 	}
 }
 




More information about the Scummvm-git-logs mailing list