[Scummvm-git-logs] scummvm master -> e997e181e40ae1b9469c26f5591ee1137dfc0e0d

neuromancer noreply at scummvm.org
Fri Jun 5 19:36:44 UTC 2026


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

Summary:
4f7951f86e SCUMM: RA1: center mouse at the start and default to easy dificulty
07cc2c95cc SCUMM: RA: improved mouse input for both game with more effective centering when they start
25c4577531 COLONY: better rendering of enemies
114ad8c194 COLONY: more fluent animations for grow/shrink enemies
8ff586d3dd COLONY: better detection for aiming enemies
e997e181e4 COLONY: better detection collision detection with static objects


Commit: 4f7951f86edbfbc2e8289bf35d71468861dff7d5
    https://github.com/scummvm/scummvm/commit/4f7951f86edbfbc2e8289bf35d71468861dff7d5
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-05T16:17:57+02:00

Commit Message:
SCUMM: RA1: center mouse at the start and default to easy dificulty

Changed paths:
    engines/scumm/insane/rebel1/rebel.cpp
    engines/scumm/insane/rebel1/runlevels.cpp


diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index c61b0c8aa65..828fb601216 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -238,8 +238,8 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	_turretFrameShipCenterValid = false;
 	_driftParam = 0;
 
-	// Original startup initializes the options difficulty/tuning index to 1.
-	_difficulty = 1;
+	// Start new games on the least punishing original tuning by default.
+	_difficulty = 0;
 	loadTuningForLevel(0);
 
 	_perspectiveX = 0;
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 11499e20973..09f0ff68cd9 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -1774,8 +1774,11 @@ void InsaneRebel1::captureInteractiveVideoInput() {
 		// On touchscreen devices the DOS recenter-the-cursor aiming model does not apply;
 		// warping/locking the system mouse there injects spurious motion that drifts
 		// direct touch aiming and on-screen controls.
-		if (!isTouchscreenActive())
+		if (!isTouchscreenActive()) {
+			_vm->_mouse.x = kRA1CenterX;
+			_vm->_mouse.y = kRA1CenterY;
 			smush_warpMouse(160, 100, -1);
+		}
 		_mouseVirtualRawX = 0x140;
 		_mouseVirtualRawY = 100;
 		_mouseVirtualPrevLogicalX = kRA1CenterX;


Commit: 07cc2c95cc0800c8201ecbb516326894f5231d8f
    https://github.com/scummvm/scummvm/commit/07cc2c95cc0800c8201ecbb516326894f5231d8f
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-05T16:17:57+02:00

Commit Message:
SCUMM: RA: improved mouse input for both game with more effective centering when they start

Changed paths:
    engines/scumm/insane/rebel1/iact.cpp
    engines/scumm/insane/rebel1/menu.cpp
    engines/scumm/insane/rebel1/rebel.cpp
    engines/scumm/insane/rebel1/rebel.h
    engines/scumm/insane/rebel1/runlevels.cpp
    engines/scumm/insane/rebel2/iact.cpp
    engines/scumm/insane/rebel2/levels.cpp
    engines/scumm/insane/rebel2/rebel.cpp
    engines/scumm/insane/rebel2/rebel.h


diff --git a/engines/scumm/insane/rebel1/iact.cpp b/engines/scumm/insane/rebel1/iact.cpp
index 7065bdc8a8b..4ae3706e857 100644
--- a/engines/scumm/insane/rebel1/iact.cpp
+++ b/engines/scumm/insane/rebel1/iact.cpp
@@ -46,6 +46,10 @@ inline int16 smoothRebel1Op0BAnalogInput(int16 inputValue, int16 &filteredValue,
 	return filteredValue;
 }
 
+inline int16 scaleRebel1CenteredMouseAxis(int16 value, int16 center, int axisMax) {
+	return (int16)CLIP<int32>(((int32)(value - center) * axisMax) / center, -axisMax, axisMax);
+}
+
 int16 shapeRebel1Op0BGamepadAxis(int16 inputValue, int16 axisMax) {
 	const int axis = CLIP<int>(inputValue, -axisMax, axisMax);
 	const int absAxis = ABS(axis);
@@ -77,6 +81,10 @@ const int kRA1DosMouseSafeLeft = 0x0AA;
 const int kRA1DosMouseSafeRight = 0x1D6;
 const int kRA1DosMouseSafeTop = 0x32;
 const int kRA1DosMouseSafeBottom = 0x96;
+const int kRA1DosFlightMouseMaxX = kRA1DosMouseCenterX >> 2;
+const int kRA1DosFlightMouseMaxY = kRA1DosMouseCenterY >> 1;
+const int kRA1EnhancedFlightDirectMaxX = (kRA1DosFlightMouseMaxX * 4) / 5;
+const int kRA1EnhancedFlightDirectMaxY = (kRA1DosFlightMouseMaxY * 4) / 5;
 
 // Level 15 final approach 0x5D damage/event codes consumed by
 // RunLevel1GameLoop. The latch stores the raw GAME parameter; no translation is
@@ -950,8 +958,9 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 		if (usedJoystick)
 			*usedJoystick = true;
 
-		inputX = joyX * 127;
-		inputY = joyY * 127;
+		const bool enhancedFlightInput = _optEnhancedControls && getEffectiveGameOpcode() == 0x07;
+		inputX = joyX * (enhancedFlightInput ? kRA1EnhancedFlightDirectMaxX : 127);
+		inputY = joyY * (enhancedFlightInput ? kRA1EnhancedFlightDirectMaxY : 127);
 
 		if (_optControlsYFlip)
 			inputY = -inputY;
@@ -965,8 +974,11 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 			*usedJoystick = true;
 
 		if (analogAxisX != 0 || analogAxisY != 0) {
-			inputX = CLIP<int32>(((int32)analogAxisX * 127) / Common::JOYAXIS_MAX, -127, 127);
-			inputY = CLIP<int32>(((int32)analogAxisY * 127) / Common::JOYAXIS_MAX, -127, 127);
+			const bool enhancedFlightInput = _optEnhancedControls && getEffectiveGameOpcode() == 0x07;
+			const int axisMaxX = enhancedFlightInput ? kRA1EnhancedFlightDirectMaxX : 127;
+			const int axisMaxY = enhancedFlightInput ? kRA1EnhancedFlightDirectMaxY : 127;
+			inputX = CLIP<int32>(((int32)analogAxisX * axisMaxX) / Common::JOYAXIS_MAX, -axisMaxX, axisMaxX);
+			inputY = CLIP<int32>(((int32)analogAxisY * axisMaxY) / Common::JOYAXIS_MAX, -axisMaxY, axisMaxY);
 		} else {
 			inputX = 0;
 			inputY = 0;
@@ -1006,8 +1018,15 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 		_mousePrevBiasX = 0;
 		_mousePrevBiasY = 0;
 
-		inputX = (int16)CLIP<int32>(((int32)(logicalX - kRA1CenterX) * 127) / kRA1CenterX, -127, 127);
-		inputY = (int16)CLIP<int32>(((int32)(logicalY - kRA1CenterY) * 127) / kRA1CenterY, -127, 127);
+		if (getEffectiveGameOpcode() == 0x07) {
+			// Direct flight input lacks the DOS recenter path's offset decay, so keep
+			// held-edge steering below the raw DOS full-deflection bias.
+			inputX = scaleRebel1CenteredMouseAxis(logicalX, kRA1CenterX, kRA1EnhancedFlightDirectMaxX);
+			inputY = scaleRebel1CenteredMouseAxis(logicalY, kRA1CenterY, kRA1EnhancedFlightDirectMaxY);
+		} else {
+			inputX = (int16)CLIP<int32>(((int32)(logicalX - kRA1CenterX) * 127) / kRA1CenterX, -127, 127);
+			inputY = (int16)CLIP<int32>(((int32)(logicalY - kRA1CenterY) * 127) / kRA1CenterY, -127, 127);
+		}
 
 		// These handlers negate DAT_756E internally, so direct touch needs the
 		// opposite baseline while the menu option still toggles the result.
@@ -1053,9 +1072,7 @@ void InsaneRebel1::preprocessMouseAxes(int16 &inputX, int16 &inputY, bool *usedJ
 		_mouseVirtualRawY = rawY;
 		_mouseVirtualPrevLogicalX = kRA1CenterX;
 		_mouseVirtualPrevLogicalY = kRA1CenterY;
-		_vm->_mouse.x = kRA1CenterX;
-		_vm->_mouse.y = kRA1CenterY;
-		smush_warpMouse(kRA1CenterX, kRA1CenterY, -1);
+		warpGameplayMouseNow(kRA1CenterX, kRA1CenterY);
 		debug(2, "RA1 original input virtual recenter: offset=(%d,%d) mouse=(%d,%d)",
 			_mouseOffsetX, _mouseOffsetY, logicalX, logicalY);
 	}
diff --git a/engines/scumm/insane/rebel1/menu.cpp b/engines/scumm/insane/rebel1/menu.cpp
index 45eb5a1d6e5..9b7f374073e 100644
--- a/engines/scumm/insane/rebel1/menu.cpp
+++ b/engines/scumm/insane/rebel1/menu.cpp
@@ -54,6 +54,12 @@ const int kRA1LevelSelectLeftX      = 20;
 const int kRA1LevelSelectRightX     = 170;
 const int kRA1LevelSelectColW       = 130;
 const uint32 kRA1JoystickAxisEscGuardMs = 250;
+const int kRA1GameplayMouseSettleJumpThreshold = 40;
+const int kRA1GameplayMouseSettleRelativeThreshold = 40;
+const int kRA1GameplayMouseSettleEdgeMargin = 16;
+const int kRA1GameplayMouseMaxX = 319;
+const int kRA1GameplayMouseMaxY = 199;
+const uint32 kRA1GameplayMouseSettleExtendMs = 1000;
 // Original picker traversal uses fixed max indices, not strlen(): passcodes
 // stop at 0x1d and high-score names stop at 0x37.
 const char kRA1TextEntryPickerChars[] = "^`_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -632,6 +638,42 @@ bool InsaneRebel1::notifyEvent(const Common::Event &event) {
 		return true;
 	}
 
+	if (_interactiveVideoActive && !_menuActive && !isTouchscreenActive() &&
+			getEffectiveGameOpcode() == 0x07 &&
+			event.type == Common::EVENT_MOUSEMOVE && _gameplayMouseSettleUntil != 0) {
+		const uint32 now = _vm->_system->getMillis();
+		if (now < _gameplayMouseSettleUntil) {
+			const int jumpX = event.mouse.x - _vm->_mouse.x;
+			const int jumpY = event.mouse.y - _vm->_mouse.y;
+			const bool largeAbsoluteJump =
+				ABS(jumpX) >= kRA1GameplayMouseSettleJumpThreshold ||
+				ABS(jumpY) >= kRA1GameplayMouseSettleJumpThreshold;
+			const bool smallRelativeMove =
+				ABS((int)event.relMouse.x) < kRA1GameplayMouseSettleRelativeThreshold &&
+				ABS((int)event.relMouse.y) < kRA1GameplayMouseSettleRelativeThreshold;
+			const bool nearWindowEdge =
+				event.mouse.x <= kRA1GameplayMouseSettleEdgeMargin ||
+				event.mouse.x >= kRA1GameplayMouseMaxX - kRA1GameplayMouseSettleEdgeMargin ||
+				event.mouse.y <= kRA1GameplayMouseSettleEdgeMargin ||
+				event.mouse.y >= kRA1GameplayMouseMaxY - kRA1GameplayMouseSettleEdgeMargin;
+
+			if (largeAbsoluteJump && smallRelativeMove && nearWindowEdge) {
+				const int recenterX = _vm->_mouse.x;
+				const int recenterY = _vm->_mouse.y;
+				_gameplayMouseSettleUntil = now + kRA1GameplayMouseSettleExtendMs;
+				warpGameplayMouseNow(recenterX, recenterY);
+
+				debugC(DEBUG_INSANE, "RA1 mouse settle: suppress pos=(%d,%d) rel=(%d,%d) current=(%d,%d) until=%u opcode=0x%X",
+					event.mouse.x, event.mouse.y, event.relMouse.x, event.relMouse.y,
+					_vm->_mouse.x, _vm->_mouse.y, _gameplayMouseSettleUntil,
+					getEffectiveGameOpcode());
+				return true;
+			}
+		}
+
+		_gameplayMouseSettleUntil = 0;
+	}
+
 	if (event.type == Common::EVENT_MOUSEMOVE && !_mouseRecentering) {
 		if (_gamepadAimActive && usesRelativeGamepadAimForCurrentLevel() &&
 				_interactiveVideoActive && !_menuActive &&
diff --git a/engines/scumm/insane/rebel1/rebel.cpp b/engines/scumm/insane/rebel1/rebel.cpp
index 828fb601216..004840569e1 100644
--- a/engines/scumm/insane/rebel1/rebel.cpp
+++ b/engines/scumm/insane/rebel1/rebel.cpp
@@ -279,6 +279,7 @@ InsaneRebel1::InsaneRebel1(ScummEngine_v7 *scumm) : Insane(), _vm(scumm) {
 	_gamepadAimAxisX = 0;
 	_gamepadAimAxisY = 0;
 	_gamepadAimActive = false;
+	_gameplayMouseSettleUntil = 0;
 	_activeInputSource = kInputSourceMouse;
 
 	_currentLevel = 0;
@@ -479,6 +480,20 @@ void InsaneRebel1::setCurrentSmushFrame(int32 frame) {
 	_currentSmushFrame = frame;
 }
 
+void InsaneRebel1::warpGameplayMouseNow(int x, int y) {
+	Common::EventManager *eventMan = _vm->_system->getEventManager();
+	if (eventMan)
+		eventMan->purgeMouseEvents();
+
+	_vm->_mouse.x = x;
+	_vm->_mouse.y = y;
+	_vm->_system->warpMouse(_vm->_macScreen ? x * 2 : x,
+		_vm->_macScreen ? y * 2 + 2 * _vm->_macScreenDrawOffset : y);
+
+	if (eventMan)
+		eventMan->purgeMouseEvents();
+}
+
 InsaneRebel1::~InsaneRebel1() {
 	_vm->_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
 	terminateAudio();
diff --git a/engines/scumm/insane/rebel1/rebel.h b/engines/scumm/insane/rebel1/rebel.h
index 781d916bc74..6622e884873 100644
--- a/engines/scumm/insane/rebel1/rebel.h
+++ b/engines/scumm/insane/rebel1/rebel.h
@@ -119,6 +119,7 @@ public:
 	bool hasFrameGameOpcode(uint16 opcode) const {
 		return opcode < 32 && (_frameGameOpcodeMask & (1u << opcode)) != 0;
 	}
+	void warpGameplayMouseNow(int x, int y);
 	int16 getPerspectiveX() const { return _perspectiveX; }
 	int16 getPerspectiveY() const { return _perspectiveY; }
 	void projectGameplayPoint(int16 &x, int16 &y) const;
@@ -377,6 +378,8 @@ private:
 	int16 _gamepadAimAxisX; // Relative gamepad 0x0B aim in preprocessed input space
 	int16 _gamepadAimAxisY;
 	bool _gamepadAimActive;
+	// Suppress delayed lock/warp mousemove artifacts after centering interactive gameplay.
+	uint32 _gameplayMouseSettleUntil;
 	enum InputSource {
 		kInputSourceMouse,
 		kInputSourceJoystickAnalog,
diff --git a/engines/scumm/insane/rebel1/runlevels.cpp b/engines/scumm/insane/rebel1/runlevels.cpp
index 09f0ff68cd9..29792d1ad45 100644
--- a/engines/scumm/insane/rebel1/runlevels.cpp
+++ b/engines/scumm/insane/rebel1/runlevels.cpp
@@ -33,6 +33,8 @@
 
 namespace Scumm {
 
+static const uint32 kRA1GameplayMouseSettleMs = 1000;
+
 int32 findAnimFrameChunkOffset(ScummEngine_v7 *vm, const char *filename, int32 targetFrame) {
 	if (targetFrame <= 0)
 		return 0;
@@ -1771,26 +1773,34 @@ void InsaneRebel1::captureInteractiveVideoInput() {
 	// Some replays happen inside one original gameplay loop, so keep the current
 	// input state instead of recentering between route clips.
 	if (!preserveInputState) {
+		_gameplayMouseSettleUntil = 0;
 		// On touchscreen devices the DOS recenter-the-cursor aiming model does not apply;
 		// warping/locking the system mouse there injects spurious motion that drifts
 		// direct touch aiming and on-screen controls.
 		if (!isTouchscreenActive()) {
-			_vm->_mouse.x = kRA1CenterX;
-			_vm->_mouse.y = kRA1CenterY;
-			smush_warpMouse(160, 100, -1);
+			warpGameplayMouseNow(kRA1CenterX, kRA1CenterY);
+			_gameplayMouseSettleUntil = _vm->_system->getMillis() + kRA1GameplayMouseSettleMs;
 		}
 		_mouseVirtualRawX = 0x140;
 		_mouseVirtualRawY = 100;
 		_mouseVirtualPrevLogicalX = kRA1CenterX;
 		_mouseVirtualPrevLogicalY = kRA1CenterY;
 		_mouseVirtualValid = false;
+	} else {
+		_gameplayMouseSettleUntil = 0;
 	}
 	CursorMan.showMouse(false);
 	if (!isTouchscreenActive())
 		g_system->lockMouse(true);
+
+	debugC(DEBUG_INSANE, "RA1 centerGameplayAim: mouse=(%d,%d) joystick=(%d,%d) gamepadAim=%d settleUntil=%u preserve=%d",
+		_vm->_mouse.x, _vm->_mouse.y, _joystickAxisX, _joystickAxisY,
+		_gamepadAimActive ? 1 : 0, _gameplayMouseSettleUntil,
+		preserveInputState ? 1 : 0);
 }
 
 void InsaneRebel1::releaseInteractiveVideoInput() {
+	_gameplayMouseSettleUntil = 0;
 	g_system->lockMouse(false);
 }
 
diff --git a/engines/scumm/insane/rebel2/iact.cpp b/engines/scumm/insane/rebel2/iact.cpp
index 854fcf100df..8122855a018 100644
--- a/engines/scumm/insane/rebel2/iact.cpp
+++ b/engines/scumm/insane/rebel2/iact.cpp
@@ -34,6 +34,9 @@
 
 namespace Scumm {
 
+const int kRA2Handler7DirectInputNumerator = 4;
+const int kRA2Handler7DirectInputDenominator = 5;
+
 static bool readLevel2BackgroundChunkHeader(Common::SeekableReadStream &stream, int64 containerEnd, const char *context,
 		uint32 &tag, uint32 &chunkSize, int64 &dataEnd, int64 &nextChunkPos) {
 	const int64 headerPos = stream.pos();
@@ -830,8 +833,10 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
 	// Step 1: Raw mouse input as offset from screen center.
 	// DAT_0047a7e0 = mouseX - 160, DAT_0047a7e2 = mouseY - 100.
 	// Handler 7 applies DAT_0047a7fe to its local vertical input after clamping.
-	int16 inputX = (int16)(_vm->_mouse.x - 160);  // DAT_0047a7e0
-	int16 inputY = (int16)(_vm->_mouse.y - 100);  // DAT_0047a7e2
+	const int16 mouseX = _vm->_mouse.x;
+	const int16 mouseY = _vm->_mouse.y;
+	int16 inputX = (int16)(mouseX - 160);  // DAT_0047a7e0
+	int16 inputY = (int16)(mouseY - 100);  // DAT_0047a7e2
 
 	// Clamp: mouse mode uses [-160, 160] for X, [-127, 127] for Y (lines 55-70).
 	if (inputX > 160)
@@ -848,6 +853,14 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
 	int16 scaledInputX = (int16)((inputX * 127) / 160);
 	int16 scaledInputY = _optControlsFlipped ? (int16)-inputY : inputY;  // local_14
 
+	// ScummVM direct mouse/touch/gamepad aiming can hold the cursor at an edge
+	// indefinitely. Keep this sensitivity concession local to Handler 7
+	// third-person ship steering.
+	scaledInputX = (int16)((scaledInputX * kRA2Handler7DirectInputNumerator) /
+		kRA2Handler7DirectInputDenominator);
+	scaledInputY = (int16)((scaledInputY * kRA2Handler7DirectInputNumerator) /
+		kRA2Handler7DirectInputDenominator);
+
 	// Step 3: Velocity history + smoothed average (lines 141-157).
 	for (int i = 24; i > 0; i--) {
 		_velocityHistory[i] = _velocityHistory[i - 1];
@@ -1063,7 +1076,9 @@ void InsaneRebel2::handleOpcode6Handler7(Common::SeekableReadStream &b, int16 pa
 		((_vm->VAR(_vm->VAR_LEFTBTN_HOLD) != 0) ||
 		 _vm->getActionState(kScummActionInsaneAttack));
 
-	debug("Rebel2 H7: pos=(%d,%d) vel=%d vIn=%d dx=%d dir=%d mode=%d",
+	debugC(DEBUG_INSANE, "Rebel2 H7: mouse=(%d,%d) raw=(%d,%d) scaled=(%d,%d) pos=(%d,%d) "
+		"vel=%d vIn=%d dx=%d dir=%d mode=%d",
+		mouseX, mouseY, inputX, inputY, scaledInputX, scaledInputY,
 		_flyShipScreenX, _flyShipScreenY, _smoothedVelocity,
 		_verticalInput, positionDeltaX, _shipDirectionIndex, _flyControlMode);
 }
diff --git a/engines/scumm/insane/rebel2/levels.cpp b/engines/scumm/insane/rebel2/levels.cpp
index 8b010dca334..062ec934395 100644
--- a/engines/scumm/insane/rebel2/levels.cpp
+++ b/engines/scumm/insane/rebel2/levels.cpp
@@ -34,6 +34,7 @@ namespace Scumm {
 
 static const int kRebel2GameplayAimCenterX = 160;
 static const int kRebel2GameplayAimCenterY = 100;
+static const uint32 kRebel2GameplayMouseSettleMs = 1000;
 
 static void purgeRebel2GameplayInputEvents(Common::EventManager *eventMan) {
 	if (!eventMan)
@@ -385,15 +386,32 @@ void InsaneRebel2::centerGameplayAim() {
 	Common::EventManager *eventMan = _vm->_system->getEventManager();
 	purgeRebel2GameplayInputEvents(eventMan);
 
-	_vm->_mouse.x = kRebel2GameplayAimCenterX;
-	_vm->_mouse.y = kRebel2GameplayAimCenterY;
-
 	_joystickAxisX = 0;
 	_joystickAxisY = 0;
 	_gamepadAimActive = false;
 
-	smush_warpMouse(kRebel2GameplayAimCenterX, kRebel2GameplayAimCenterY, -1);
+	warpGameplayMouseNow(kRebel2GameplayAimCenterX, kRebel2GameplayAimCenterY);
 	purgeRebel2GameplayInputEvents(eventMan);
+	_gameplayMouseSettleUntil = _vm->_system->getMillis() + kRebel2GameplayMouseSettleMs;
+
+	debugC(DEBUG_INSANE, "Rebel2 centerGameplayAim: mouse=(%d,%d) joystick=(%d,%d) gamepadAim=%d settleUntil=%u",
+		_vm->_mouse.x, _vm->_mouse.y,
+		_joystickAxisX, _joystickAxisY, _gamepadAimActive ? 1 : 0,
+		_gameplayMouseSettleUntil);
+}
+
+void InsaneRebel2::warpGameplayMouseNow(int x, int y) {
+	Common::EventManager *eventMan = _vm->_system->getEventManager();
+	if (eventMan)
+		eventMan->purgeMouseEvents();
+
+	_vm->_mouse.x = x;
+	_vm->_mouse.y = y;
+	_vm->_system->warpMouse(_vm->_macScreen ? x * 2 : x,
+		_vm->_macScreen ? y * 2 + 2 * _vm->_macScreenDrawOffset : y);
+
+	if (eventMan)
+		eventMan->purgeMouseEvents();
 }
 
 // runLevel -- Main level dispatcher, calls per-level handlers.
diff --git a/engines/scumm/insane/rebel2/rebel.cpp b/engines/scumm/insane/rebel2/rebel.cpp
index 4d125c67016..ae1f86099ac 100644
--- a/engines/scumm/insane/rebel2/rebel.cpp
+++ b/engines/scumm/insane/rebel2/rebel.cpp
@@ -54,6 +54,12 @@ namespace Scumm {
 const int kRA2MenuAxisThreshold = Common::JOYAXIS_MAX / 5;
 const uint32 kRA2MenuGamepadNavigationDebounceMs = 250;
 const uint32 kRA2MenuGamepadMouseSuppressMs = 250;
+const int kRA2Handler7MouseSettleJumpThreshold = 40;
+const int kRA2Handler7MouseSettleRelativeThreshold = 40;
+const int kRA2Handler7MouseSettleEdgeMargin = 16;
+const int kRA2GameplayMouseMaxX = 319;
+const int kRA2GameplayMouseMaxY = 199;
+const uint32 kRA2Handler7MouseSettleExtendMs = 1000;
 
 bool rebel2UsesRelativeGamepadAim(int selectedLevel) {
 	return selectedLevel == 1 || selectedLevel == 5 || selectedLevel == 14;
@@ -542,6 +548,7 @@ InsaneRebel2::InsaneRebel2(ScummEngine_v7 *scumm) {
 	_joystickAxisY = 0;
 	_gamepadAimActive = false;
 	_gameplaySectionActive = false;
+	_gameplayMouseSettleUntil = 0;
 	_lastGameplayMenuCloseTime = 0;
 	_lastMenuGamepadNavigationTime = 0;
 	_handler8HudGlyph = '#';
@@ -645,6 +652,46 @@ bool InsaneRebel2::notifyEvent(const Common::Event &event) {
 	if (_vm->isPaused())
 		return false;
 
+	if (_gameState == kStateGameplay && _rebelHandler == 7 &&
+			event.type == Common::EVENT_MOUSEMOVE) {
+		if (_gameplayMouseSettleUntil != 0) {
+			const uint32 now = _vm->_system->getMillis();
+			if (now < _gameplayMouseSettleUntil) {
+				const int jumpX = event.mouse.x - _vm->_mouse.x;
+				const int jumpY = event.mouse.y - _vm->_mouse.y;
+				const bool largeAbsoluteJump =
+					ABS(jumpX) >= kRA2Handler7MouseSettleJumpThreshold ||
+					ABS(jumpY) >= kRA2Handler7MouseSettleJumpThreshold;
+				const bool smallRelativeMove =
+					ABS((int)event.relMouse.x) < kRA2Handler7MouseSettleRelativeThreshold &&
+					ABS((int)event.relMouse.y) < kRA2Handler7MouseSettleRelativeThreshold;
+				const bool nearWindowEdge =
+					event.mouse.x <= kRA2Handler7MouseSettleEdgeMargin ||
+					event.mouse.x >= kRA2GameplayMouseMaxX - kRA2Handler7MouseSettleEdgeMargin ||
+					event.mouse.y <= kRA2Handler7MouseSettleEdgeMargin ||
+					event.mouse.y >= kRA2GameplayMouseMaxY - kRA2Handler7MouseSettleEdgeMargin;
+
+				if (largeAbsoluteJump && smallRelativeMove && nearWindowEdge) {
+					const int recenterX = _vm->_mouse.x;
+					const int recenterY = _vm->_mouse.y;
+					_gameplayMouseSettleUntil = now + kRA2Handler7MouseSettleExtendMs;
+					warpGameplayMouseNow(recenterX, recenterY);
+
+					debugC(DEBUG_INSANE, "Rebel2 H7 mouse settle: suppress pos=(%d,%d) rel=(%d,%d) current=(%d,%d) until=%u",
+						event.mouse.x, event.mouse.y, event.relMouse.x, event.relMouse.y,
+						_vm->_mouse.x, _vm->_mouse.y, _gameplayMouseSettleUntil);
+					return true;
+				}
+			}
+
+			_gameplayMouseSettleUntil = 0;
+		}
+
+		debugC(DEBUG_INSANE, "Rebel2 H7 mouse event: pos=(%d,%d) rel=(%d,%d) gamepadAim=%d menuInput=%d",
+			event.mouse.x, event.mouse.y, event.relMouse.x, event.relMouse.y,
+			_gamepadAimActive ? 1 : 0, _menuInputActive ? 1 : 0);
+	}
+
 	// Keep the gamepad reticle authoritative against stray pointer events. During
 	// gameplay the cursor is locked ~screen-center (levels.cpp lockMouse), so any
 	// spurious pointer event — e.g. a gamepad "fire" surfacing as a button-down —
diff --git a/engines/scumm/insane/rebel2/rebel.h b/engines/scumm/insane/rebel2/rebel.h
index 913e4465656..41cdec1c5be 100644
--- a/engines/scumm/insane/rebel2/rebel.h
+++ b/engines/scumm/insane/rebel2/rebel.h
@@ -509,6 +509,7 @@ public:
 	// (on-screen/physical gamepad dpad, keyboard arrows) instead of snapping it to a screen
 	// edge. Call once per frame; getGameplayAimPoint() stays a pure getter.
 	void updateGameplayAimFromGamepad();
+	void warpGameplayMouseNow(int x, int y);
 
 	// Analog stick state, ingested from EVENT_CUSTOM_BACKEND_ACTION_AXIS in notifyEvent()
 	// and read (with a deadzone) by updateGameplayAimFromGamepad(). Signed; 0 = centered.
@@ -520,6 +521,8 @@ public:
 	// recenter the reticle (the cursor is locked ~center during gameplay, so a gamepad
 	// "click" lands at center). See notifyEvent()/updateGameplayAimFromGamepad().
 	bool _gamepadAimActive;
+	// Suppress delayed lock/warp mousemove artifacts after centering Handler 7 gameplay.
+	uint32 _gameplayMouseSettleUntil;
 	uint32 _lastGameplayMenuCloseTime;
 	uint32 _lastMenuGamepadNavigationTime;
 	void openGameplayMainMenu(SmushPlayer *splayer);


Commit: 25c4577531182786f743f4d7599aec8d7db1f7cc
    https://github.com/scummvm/scummvm/commit/25c4577531182786f743f4d7599aec8d7db1f7cc
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-05T17:50:51+02:00

Commit Message:
COLONY: better rendering of enemies

Changed paths:
    engines/colony/animation.cpp
    engines/colony/render_objects.cpp


diff --git a/engines/colony/animation.cpp b/engines/colony/animation.cpp
index e04f5c6629b..98fdba9fb25 100644
--- a/engines/colony/animation.cpp
+++ b/engines/colony/animation.cpp
@@ -610,12 +610,18 @@ void ColonyEngine::playAnimation() {
 					needsDraw = true;
 				}
 			} else if (event.type == Common::EVENT_KEYDOWN) {
+				if (event.kbd.keycode == Common::KEYCODE_RETURN) {
+					// Original Mac AnimControl(): Return closes the animation window.
+					_animationRunning = false;
+					continue;
+				}
+
 				int item = 0;
 				if (event.kbd.keycode >= Common::KEYCODE_0 && event.kbd.keycode <= Common::KEYCODE_9) {
 					item = 1 + (event.kbd.keycode - Common::KEYCODE_0);
 				} else if (event.kbd.keycode >= Common::KEYCODE_KP0 && event.kbd.keycode <= Common::KEYCODE_KP9) {
 					item = 1 + (event.kbd.keycode - Common::KEYCODE_KP0);
-				} else if (event.kbd.keycode == Common::KEYCODE_RETURN || event.kbd.keycode == Common::KEYCODE_KP_ENTER) {
+				} else if (event.kbd.keycode == Common::KEYCODE_KP_ENTER) {
 					item = 12; // Enter
 				} else if (event.kbd.keycode == Common::KEYCODE_BACKSPACE || event.kbd.keycode == Common::KEYCODE_DELETE) {
 					item = 11; // Clear
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index a93feac780c..60cbf8bfde0 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -43,6 +43,8 @@ int mapEyeOverlayColorToMacColor(int colorIdx, int level) {
 	case kColorIris:         return 35; // c_iris
 	case kColorEyeIris:      return 32; // c_eye
 	case kColorMiniEyeIris:  return 33; // c_meye
+	case kColorDroneEye:     return 51; // c_edrone
+	case kColorSoldierEye:   return 53; // c_esoldier
 	case kColorQueenEye:     return 49; // c_equeen
 	default:                 return 6;  // c_dwall fallback
 	}
@@ -58,6 +60,8 @@ uint8 mapEyeOverlayColorToDOSFill(int colorIdx, int level) {
 	case kColorIris:
 	case kColorEyeIris:
 	case kColorMiniEyeIris:
+	case kColorDroneEye:
+	case kColorSoldierEye:
 	case kColorQueenEye:
 		return 1;
 	default:
@@ -79,6 +83,8 @@ int mapEyeOverlayColorToMacPattern(int colorIdx) {
 	case kColorIris:
 	case kColorEyeIris:
 	case kColorMiniEyeIris:
+	case kColorDroneEye:
+	case kColorSoldierEye:
 	case kColorQueenEye: // fallthrough: explicitly grouped with default
 	default:
 		return kPatternGray;
@@ -1100,7 +1106,7 @@ const int kDAbdomenSurf[8][8] = {
 	{kColorDrone, 3, 5, 2, 1, 5, 0, 0}, {kColorDrone, 3, 5, 3, 2, 5, 0, 0},
 	{kColorDrone, 3, 5, 4, 3, 5, 0, 0}, {kColorDrone, 3, 5, 1, 4, 5, 0, 0}
 };
-// Drone static pincers (llPincer/rrPincer)
+// Base jaw points used by the Soldier pincer animation.
 const int kDLLPincerPts[4][3] = {
 	{0, 0, 130}, {50, -2, 130}, {35, -20, 140}, {35, -20, 120}
 };
@@ -1115,25 +1121,8 @@ const int kDRPincerSurf[4][8] = {
 	{kColorClaw1, 3, 0, 1, 2, 0, 0, 0}, {kColorClaw1, 3, 0, 3, 1, 0, 0, 0},
 	{kColorClaw2, 3, 0, 2, 3, 0, 0, 0}, {kColorClaw2, 3, 1, 3, 2, 1, 0, 0}
 };
-// Drone eyes
-const int kDLEyePts[3][3] = {
-	{60, 0, 150}, {60, 50, 130}, {60, 25, 150}
-};
-const int kDLEyeSurf[2][8] = {
-	{kColorDroneEye, 3, 0, 1, 2, 0, 0, 0}, {kColorDroneEye, 3, 0, 2, 1, 0, 0, 0}
-};
-const int kDREyePts[3][3] = {
-	{60, 0, 150}, {60, -50, 130}, {60, -25, 150}
-};
-const int kDREyeSurf[2][8] = {
-	{kColorDroneEye, 3, 0, 1, 2, 0, 0, 0}, {kColorDroneEye, 3, 0, 2, 1, 0, 0, 0}
-};
 
 const Colony::ColonyEngine::PrismPartDef kDAbdomenDef = {6, kDAbdomenPts, 8, kDAbdomenSurf};
-const Colony::ColonyEngine::PrismPartDef kDLLPincerDef = {4, kDLLPincerPts, 4, kDLPincerSurf};
-const Colony::ColonyEngine::PrismPartDef kDRRPincerDef = {4, kDRRPincerPts, 4, kDRPincerSurf};
-const Colony::ColonyEngine::PrismPartDef kDLEyeDef = {3, kDLEyePts, 2, kDLEyeSurf};
-const Colony::ColonyEngine::PrismPartDef kDREyeDef = {3, kDREyePts, 2, kDREyeSurf};
 
 // --- Snoop (type 20) ---
 const int kSnoopAbdomenPts[4][3] = {
@@ -1173,6 +1162,142 @@ void resetObjectBounds(const Common::Rect &screenR, Locate &loc) {
 	loc.zmx = screenR.top;
 }
 
+void mergeObjectBounds(Locate &dst, const Locate &src) {
+	dst.xmn = MIN(dst.xmn, src.xmn);
+	dst.xmx = MAX(dst.xmx, src.xmx);
+	dst.zmn = MIN(dst.zmn, src.zmn);
+	dst.zmx = MAX(dst.zmx, src.zmx);
+}
+
+bool prismSurfaceVisible(const Common::Rect &screenR, const Colony::Thing &thing,
+		const Colony::ColonyEngine::PrismPartDef &def, int surfaceIndex,
+		uint8 cameraLook, int8 cameraLookY, int cameraX, int cameraY,
+		const int *sint, const int *cost) {
+	return isProjectedPrismSurfaceVisible(screenR, thing, def, false, surfaceIndex,
+		cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+}
+
+int droneBodyOrder(const Common::Rect &screenR, const Colony::Thing &thing,
+		uint8 cameraLook, int8 cameraLookY, int cameraX, int cameraY,
+		const int *sint, const int *cost) {
+	const bool v0 = prismSurfaceVisible(screenR, thing, kDAbdomenDef, 0, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const bool v1 = prismSurfaceVisible(screenR, thing, kDAbdomenDef, 1, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const bool v2 = prismSurfaceVisible(screenR, thing, kDAbdomenDef, 2, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const bool v3 = prismSurfaceVisible(screenR, thing, kDAbdomenDef, 3, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+
+	int body = 1;
+	if (v0 && v1)
+		body = 1;
+	if (v2 && v3)
+		body = 1;
+	if (v0 && v3)
+		body = 0;
+	if (v1 && v2)
+		body = 2;
+	return body;
+}
+
+int queenBodyOrder(const Common::Rect &screenR, const Colony::Thing &thing,
+		uint8 cameraLook, int8 cameraLookY, int cameraX, int cameraY,
+		const int *sint, const int *cost) {
+	const bool v0 = prismSurfaceVisible(screenR, thing, kQAbdomenDef, 0, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const bool v1 = prismSurfaceVisible(screenR, thing, kQAbdomenDef, 1, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const bool v4 = prismSurfaceVisible(screenR, thing, kQAbdomenDef, 4, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const bool v5 = prismSurfaceVisible(screenR, thing, kQAbdomenDef, 5, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+
+	int body = 1;
+	if (v0 && v4)
+		body = 1;
+	if (v1 && v5)
+		body = 1;
+	if (v0 && v1)
+		body = 0;
+	if (v4 && v5)
+		body = 2;
+	return body;
+}
+
+float prismPointForwardDepth(const Colony::Thing &thing, const Colony::ColonyEngine::PrismPartDef &def, int pointIndex,
+		uint8 cameraLook, int cameraX, int cameraY, const int *sint, const int *cost) {
+	if (pointIndex < 0 || pointIndex >= def.pointCount)
+		return 0.0f;
+
+	const uint8 objAng = thing.where.ang + 32;
+	const int32 rotCos = cost[objAng];
+	const int32 rotSin = sint[objAng];
+	const int ox = def.points[pointIndex][0];
+	const int oy = def.points[pointIndex][1];
+	const int32 rx = ((int32)ox * rotCos - (int32)oy * rotSin) >> 7;
+	const int32 ry = ((int32)ox * rotSin + (int32)oy * rotCos) >> 7;
+	const float dx = (float)(rx + thing.where.xloc - cameraX);
+	const float dy = (float)(ry + thing.where.yloc - cameraY);
+
+	return dx * (cost[cameraLook] / 128.0f) + dy * (sint[cameraLook] / 128.0f);
+}
+
+struct EnemyEyePair {
+	Thing left;
+	Thing right;
+	bool leftFirst;
+};
+
+int projectedEnemyEyeDiameter(const Common::Rect &screenR, const Colony::Thing &eye,
+		uint8 cameraLook, int8 cameraLookY, int cameraX, int cameraY,
+		const int *sint, const int *cost) {
+	int bottomX = 0;
+	int bottomY = 0;
+	int centerX = 0;
+	int centerY = 0;
+	if (!projectCorridorPointRaw(screenR, cameraLook, cameraLookY, sint, cost, cameraX, cameraY,
+			(float)eye.where.xloc, (float)eye.where.yloc, 130.0f - 160.0f, bottomX, bottomY)) {
+		return -1;
+	}
+	if (!projectCorridorPointRaw(screenR, cameraLook, cameraLookY, sint, cost, cameraX, cameraY,
+			(float)eye.where.xloc, (float)eye.where.yloc, 155.0f - 160.0f, centerX, centerY)) {
+		return -1;
+	}
+	return ABS(bottomY - centerY);
+}
+
+EnemyEyePair buildEnemyEyePair(const Common::Rect &screenR, const Colony::Thing &obj,
+		uint8 cameraLook, int8 cameraLookY, int cameraX, int cameraY,
+		const int *sint, const int *cost) {
+	EnemyEyePair eyes;
+	eyes.left = obj;
+	eyes.right = obj;
+
+	const int32 s1 = sint[obj.where.ang] >> 1;
+	const int32 c1 = cost[obj.where.ang] >> 1;
+	const int32 s2 = s1 >> 1;
+	const int32 c2 = c1 >> 1;
+	const int32 eyeBaseX = obj.where.xloc + c1;
+	const int32 eyeBaseY = obj.where.yloc + s1;
+
+	eyes.left.where.xloc = (int)(eyeBaseX - s2);
+	eyes.left.where.yloc = (int)(eyeBaseY + c2);
+	resetObjectBounds(screenR, eyes.left.where);
+
+	eyes.right.where.xloc = (int)(eyeBaseX + s2);
+	eyes.right.where.yloc = (int)(eyeBaseY - c2);
+	resetObjectBounds(screenR, eyes.right.where);
+
+	const int leftDiameter = projectedEnemyEyeDiameter(screenR, eyes.left, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	const int rightDiameter = projectedEnemyEyeDiameter(screenR, eyes.right, cameraLook, cameraLookY, cameraX, cameraY, sint, cost);
+	if (leftDiameter >= 0 && rightDiameter >= 0) {
+		eyes.leftFirst = leftDiameter < rightDiameter;
+	} else {
+		const int32 leftDx = eyes.left.where.xloc - cameraX;
+		const int32 leftDy = eyes.left.where.yloc - cameraY;
+		const int32 rightDx = eyes.right.where.xloc - cameraX;
+		const int32 rightDy = eyes.right.where.yloc - cameraY;
+		const int64 leftDist = (int64)leftDx * leftDx + (int64)leftDy * leftDy;
+		const int64 rightDist = (int64)rightDx * rightDx + (int64)rightDy * rightDy;
+		eyes.leftFirst = leftDist >= rightDist;
+	}
+
+	return eyes;
+}
+
 void ColonyEngine::drawStaticObjects() {
 	for (uint i = 0; i < _objects.size(); i++) {
 		Thing &obj = _objects[i];
@@ -1689,101 +1814,98 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
 		break;
 	case kRobQueen:
 		{
-			const int32 s1 = _sint[obj.where.ang] >> 1;
-			const int32 c1 = _cost[obj.where.ang] >> 1;
-			const int32 s2 = s1 >> 1;
-			const int32 c2 = c1 >> 1;
-			const int32 eyeBaseX = obj.where.xloc + c1;
-			const int32 eyeBaseY = obj.where.yloc + s1;
-
-			Thing leftEye = obj;
-			leftEye.where.xloc = (int)(eyeBaseX - s2);
-			leftEye.where.yloc = (int)(eyeBaseY + c2);
-			resetObjectBounds(_screenR, leftEye.where);
-
-			Thing rightEye = obj;
-			rightEye.where.xloc = (int)(eyeBaseX + s2);
-			rightEye.where.yloc = (int)(eyeBaseY - c2);
-			resetObjectBounds(_screenR, rightEye.where);
-
-			const int32 leftDist = (leftEye.where.xloc - _me.xloc) * (leftEye.where.xloc - _me.xloc) +
-				(leftEye.where.yloc - _me.yloc) * (leftEye.where.yloc - _me.yloc);
-			const int32 rightDist = (rightEye.where.xloc - _me.xloc) * (rightEye.where.xloc - _me.xloc) +
-				(rightEye.where.yloc - _me.yloc) * (rightEye.where.yloc - _me.yloc);
-			const bool leftFirst = leftDist >= rightDist;
-			Thing &farEye = leftFirst ? leftEye : rightEye;
-			Thing &nearEye = leftFirst ? rightEye : leftEye;
-			const PrismPartDef &farWing = leftFirst ? kQLWingDef : kQRWingDef;
-			const PrismPartDef &nearWing = leftFirst ? kQRWingDef : kQLWingDef;
+			EnemyEyePair eyes = buildEnemyEyePair(_screenR, obj, _me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+			Thing &firstEye = eyes.leftFirst ? eyes.left : eyes.right;
+			Thing &secondEye = eyes.leftFirst ? eyes.right : eyes.left;
+			const PrismPartDef &firstWing = eyes.leftFirst ? kQLWingDef : kQRWingDef;
+			const PrismPartDef &secondWing = eyes.leftFirst ? kQRWingDef : kQLWingDef;
 			const int wingColor = (!isMacRenderMode() && _level == 7) ? kColorQueenWingRed : kColorClear;
-
-			// DOS draweyes(): queen eyeball is RED fill + WHITE outline
-			// (hardcoded, not from color table). Iris is GREEN.
-			const int queenEyeballColor = 5; // vRED (EGA index 4 = kColorRed... use raw 5 = cRED index)
-			draw3DPrism(obj, farWing, false, wingColor, true, true);
-			draw3DSphere(farEye, 0, 0, 130, 0, 0, 155, queenEyeballColor, kColorBlack, true);
-			drawEyeOverlays3D(farEye, kQIrisDef, -1, kQPupilDef, pupilColor, true);
-			if (farEye.where.xmn < obj.where.xmn)
-				obj.where.xmn = farEye.where.xmn;
-			if (farEye.where.xmx > obj.where.xmx)
-				obj.where.xmx = farEye.where.xmx;
-			if (farEye.where.zmn < obj.where.zmn)
-				obj.where.zmn = farEye.where.zmn;
-			if (farEye.where.zmx > obj.where.zmx)
-				obj.where.zmx = farEye.where.zmx;
-
-			draw3DPrism(obj, kQThoraxDef, false, -1, true, false);
-			draw3DPrism(obj, kQAbdomenDef, false, -1, true, false);
-
-			draw3DPrism(obj, nearWing, false, wingColor, true, true);
-			draw3DSphere(nearEye, 0, 0, 130, 0, 0, 155, queenEyeballColor, kColorBlack, true);
-			drawEyeOverlays3D(nearEye, kQIrisDef, -1, kQPupilDef, pupilColor, true);
-			if (nearEye.where.xmn < obj.where.xmn)
-				obj.where.xmn = nearEye.where.xmn;
-			if (nearEye.where.xmx > obj.where.xmx)
-				obj.where.xmx = nearEye.where.xmx;
-			if (nearEye.where.zmn < obj.where.zmn)
-				obj.where.zmn = nearEye.where.zmn;
-			if (nearEye.where.zmx > obj.where.zmx)
-				obj.where.zmx = nearEye.where.zmx;
+			const int enemyEyeballColor = isMacRenderMode() ? eyeballColor : 5;
+			int layer = 12;
+			auto setNextDepthRange = [&]() {
+				_gfx->setDepthRange((layer--) * 0.002f, 1.0f);
+			};
+
+			auto drawEye = [&](Thing &eye) {
+				draw3DSphere(eye, 0, 0, 130, 0, 0, 155, enemyEyeballColor, kColorBlack, true);
+				drawEyeOverlays3D(eye, kQIrisDef, kColorQueenEye, kQPupilDef, pupilColor, true);
+				mergeObjectBounds(obj.where, eye.where);
+			};
+			auto drawWingEye = [&](Thing &eye, const PrismPartDef &wing) {
+				setNextDepthRange();
+				draw3DPrism(obj, wing, false, wingColor, true, true);
+				setNextDepthRange();
+				drawEye(eye);
+			};
+			auto drawThorax = [&]() {
+				setNextDepthRange();
+				draw3DPrism(obj, kQThoraxDef, false, -1, true, false);
+			};
+			auto drawAbdomen = [&]() {
+				setNextDepthRange();
+				draw3DPrism(obj, kQAbdomenDef, false, -1, true, false);
+			};
+
+			const int body = queenBodyOrder(_screenR, obj, _me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+			if (body == 0) {
+				drawThorax();
+				drawAbdomen();
+			}
+			drawWingEye(firstEye, firstWing);
+			if (body == 1) {
+				const bool abdomenBackVisible = prismSurfaceVisible(_screenR, obj, kQAbdomenDef, 8,
+					_me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+				if (abdomenBackVisible) {
+					drawAbdomen();
+					drawThorax();
+				} else {
+					drawThorax();
+					drawAbdomen();
+				}
+			}
+			drawWingEye(secondEye, secondWing);
+			if (body == 2) {
+				drawAbdomen();
+				drawThorax();
+			}
+			_gfx->setDepthRange(0.0f, 1.0f);
 		}
 		break;
 	case kRobDrone:
 		{
-			// DOS DRONE.C: body + seteyes()/draweyes() — same two-eye
-			// system as Queen, positioned at offsets from body center.
-			const int32 s1 = _sint[obj.where.ang] >> 1;
-			const int32 c1 = _cost[obj.where.ang] >> 1;
-			const int32 s2 = s1 >> 1;
-			const int32 c2 = c1 >> 1;
-			const int32 eyeBaseX = obj.where.xloc + c1;
-			const int32 eyeBaseY = obj.where.yloc + s1;
-
-			Thing leftEye = obj;
-			leftEye.where.xloc = (int)(eyeBaseX - s2);
-			leftEye.where.yloc = (int)(eyeBaseY + c2);
-			resetObjectBounds(_screenR, leftEye.where);
-			Thing rightEye = obj;
-			rightEye.where.xloc = (int)(eyeBaseX + s2);
-			rightEye.where.yloc = (int)(eyeBaseY - c2);
-			resetObjectBounds(_screenR, rightEye.where);
-
-			// DOS draweyes(): shared with Queen — RED eyeball, GREEN iris
-			draw3DPrism(obj, kDAbdomenDef, false, -1, true, false);
-			draw3DPrism(obj, kDLLPincerDef, false, -1, true, false);
-			draw3DPrism(obj, kDRRPincerDef, false, -1, true, false);
-			draw3DPrism(obj, kDLEyeDef, false, -1, true, false);
-			draw3DPrism(obj, kDREyeDef, false, -1, true, false);
-			draw3DSphere(leftEye, 0, 0, 130, 0, 0, 155, 5, kColorBlack, true);
-			drawEyeOverlays3D(leftEye, kQIrisDef, -1, kQPupilDef, pupilColor, true);
-			draw3DSphere(rightEye, 0, 0, 130, 0, 0, 155, 5, kColorBlack, true);
-			drawEyeOverlays3D(rightEye, kQIrisDef, -1, kQPupilDef, pupilColor, true);
+			EnemyEyePair eyes = buildEnemyEyePair(_screenR, obj, _me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+			Thing &firstEye = eyes.leftFirst ? eyes.left : eyes.right;
+			Thing &secondEye = eyes.leftFirst ? eyes.right : eyes.left;
+			const int enemyEyeballColor = isMacRenderMode() ? eyeballColor : 5;
+			int layer = 6;
+			auto setNextDepthRange = [&]() {
+				_gfx->setDepthRange((layer--) * 0.002f, 1.0f);
+			};
+			auto drawBody = [&]() {
+				setNextDepthRange();
+				draw3DPrism(obj, kDAbdomenDef, false, -1, true, false);
+			};
+			auto drawEye = [&](Thing &eye) {
+				setNextDepthRange();
+				draw3DSphere(eye, 0, 0, 130, 0, 0, 155, enemyEyeballColor, kColorBlack, true);
+				drawEyeOverlays3D(eye, kQIrisDef, kColorDroneEye, kQPupilDef, pupilColor, true);
+				mergeObjectBounds(obj.where, eye.where);
+			};
+
+			const int body = droneBodyOrder(_screenR, obj, _me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+			if (body == 0)
+				drawBody();
+			drawEye(firstEye);
+			if (body == 1)
+				drawBody();
+			drawEye(secondEye);
+			if (body == 2)
+				drawBody();
+			_gfx->setDepthRange(0.0f, 1.0f);
 		}
 		break;
 	case kRobSoldier:
 		{
-			// DOS DRONE.C MakeSoldier(): body + animated pincers +
-			// seteyes()/draweyes() — same two-eye system as Queen.
 			int leftPincerPts[4][3];
 			int rightPincerPts[4][3];
 			const int lookAmount = (obj.where.lookx < 0) ? -obj.where.lookx : obj.where.lookx;
@@ -1800,32 +1922,63 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
 			const PrismPartDef leftPincerDef = {4, leftPincerPts, 4, kDLPincerSurf};
 			const PrismPartDef rightPincerDef = {4, rightPincerPts, 4, kDRPincerSurf};
 
-			const int32 s1 = _sint[obj.where.ang] >> 1;
-			const int32 c1 = _cost[obj.where.ang] >> 1;
-			const int32 s2 = s1 >> 1;
-			const int32 c2 = c1 >> 1;
-			const int32 eyeBaseX = obj.where.xloc + c1;
-			const int32 eyeBaseY = obj.where.yloc + s1;
-
-			Thing leftEye = obj;
-			leftEye.where.xloc = (int)(eyeBaseX - s2);
-			leftEye.where.yloc = (int)(eyeBaseY + c2);
-			resetObjectBounds(_screenR, leftEye.where);
-			Thing rightEye = obj;
-			rightEye.where.xloc = (int)(eyeBaseX + s2);
-			rightEye.where.yloc = (int)(eyeBaseY - c2);
-			resetObjectBounds(_screenR, rightEye.where);
-
-			draw3DPrism(obj, kDAbdomenDef, false, kColorSoldierBody, true, false);
-			draw3DPrism(obj, leftPincerDef, false, -1, true, false);
-			draw3DPrism(obj, rightPincerDef, false, -1, true, false);
-			// DOS draweyes(): shared with Queen — RED eyeball, GREEN iris
-			draw3DPrism(obj, kDLEyeDef, false, kColorSoldierEye, true, false);
-			draw3DPrism(obj, kDREyeDef, false, kColorSoldierEye, true, false);
-			draw3DSphere(leftEye, 0, 0, 130, 0, 0, 155, 5, kColorBlack, true);
-			drawEyeOverlays3D(leftEye, kQIrisDef, -1, kQPupilDef, pupilColor, true);
-			draw3DSphere(rightEye, 0, 0, 130, 0, 0, 155, 5, kColorBlack, true);
-			drawEyeOverlays3D(rightEye, kQIrisDef, -1, kQPupilDef, pupilColor, true);
+			EnemyEyePair eyes = buildEnemyEyePair(_screenR, obj, _me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+			Thing &firstEye = eyes.leftFirst ? eyes.left : eyes.right;
+			Thing &secondEye = eyes.leftFirst ? eyes.right : eyes.left;
+			const int enemyEyeballColor = isMacRenderMode() ? eyeballColor : 5;
+			const float leftPincerDepth = prismPointForwardDepth(obj, leftPincerDef, 1, _me.look, _me.xloc, _me.yloc, _sint, _cost);
+			const float rightPincerDepth = prismPointForwardDepth(obj, rightPincerDef, 1, _me.look, _me.xloc, _me.yloc, _sint, _cost);
+			int layer = 8;
+			auto setNextDepthRange = [&]() {
+				_gfx->setDepthRange((layer--) * 0.002f, 1.0f);
+			};
+			auto drawBody = [&]() {
+				setNextDepthRange();
+				draw3DPrism(obj, kDAbdomenDef, false, kColorSoldierBody, true, false);
+			};
+			auto drawEye = [&](Thing &eye) {
+				setNextDepthRange();
+				draw3DSphere(eye, 0, 0, 130, 0, 0, 155, enemyEyeballColor, kColorBlack, true);
+				drawEyeOverlays3D(eye, kQIrisDef, kColorSoldierEye, kQPupilDef, pupilColor, true);
+				mergeObjectBounds(obj.where, eye.where);
+			};
+			auto drawPincers = [&]() {
+				if (leftPincerDepth < rightPincerDepth) {
+					setNextDepthRange();
+					draw3DPrism(obj, rightPincerDef, false, -1, true, false);
+					setNextDepthRange();
+					draw3DPrism(obj, leftPincerDef, false, -1, true, false);
+				} else {
+					setNextDepthRange();
+					draw3DPrism(obj, leftPincerDef, false, -1, true, false);
+					setNextDepthRange();
+					draw3DPrism(obj, rightPincerDef, false, -1, true, false);
+				}
+			};
+
+			const int body = droneBodyOrder(_screenR, obj, _me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost);
+			switch (body) {
+			case 0:
+				drawBody();
+				drawEye(firstEye);
+				drawEye(secondEye);
+				drawPincers();
+				break;
+			case 1:
+				drawEye(firstEye);
+				drawBody();
+				drawPincers();
+				drawEye(secondEye);
+				break;
+			case 2:
+			default:
+				drawEye(firstEye);
+				drawEye(secondEye);
+				drawPincers();
+				drawBody();
+				break;
+			}
+			_gfx->setDepthRange(0.0f, 1.0f);
 		}
 		break;
 	case kRobSnoop:


Commit: 114ad8c194f440fc166840900be0b5c1cced3962
    https://github.com/scummvm/scummvm/commit/114ad8c194f440fc166840900be0b5c1cced3962
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-05T19:28:08+02:00

Commit Message:
COLONY: more fluent animations for grow/shrink enemies

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


diff --git a/engines/colony/colony.cpp b/engines/colony/colony.cpp
index abdeed7de21..c0f53f56991 100644
--- a/engines/colony/colony.cpp
+++ b/engines/colony/colony.cpp
@@ -849,6 +849,7 @@ Common::Error ColonyEngine::run() {
 	bool mouseMoved = false;
 	uint32 lastMoveTick = _system->getMillis();
 	uint32 lastColonyTick = lastMoveTick;
+	_lastColonyThinkTime = lastColonyTick;
 	uint32 lastBattleTick = lastMoveTick;
 	uint32 lastCenterTick = lastMoveTick;
 	while (!shouldQuit()) {
@@ -876,6 +877,7 @@ Common::Error ColonyEngine::run() {
 		// 125ms (~8fps) matches the original balance for robot aggression.
 		if (_gameMode == kModeColony && now - lastColonyTick >= 125) {
 			lastColonyTick = now;
+			_lastColonyThinkTime = now;
 			cThink();
 		}
 
diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index f3de2a2e2df..fa50a5435c8 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -557,6 +557,7 @@ private:
 	uint32 _blackoutColor = 0;
 	uint32 _lastClickTime = 0;
 	uint32 _displayCount = 0; // Frame counter for COLOR wall animation (Mac: count)
+	uint32 _lastColonyThinkTime = 0; // Last 125ms CThink tick, for render-only interpolation
 	uint32 _lastHotfootTime = 0;  // Time-gate for HOTFOOT damage (~8fps)
 	uint32 _lastAnimUpdate = 0;
 	uint32 _lastWarningChimeTime = 0;
@@ -654,6 +655,10 @@ private:
 	void drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool useLook, int colorOverride, bool forceVisible = false);
 	void drawEyeOverlays3D(Thing &thing, const PrismPartDef &irisDef, int irisColorOverride,
 		const PrismPartDef &pupilDef, int pupilColorOverride, bool useLook);
+	float growRenderTickFraction() const;
+	bool drawInterpolatedGrowRobot(Thing &obj, int eyeballColor, int pupilColor);
+	void drawInterpolatedGrowPrism(Thing &obj, const PrismPartDef &fromDef, const PrismPartDef &toDef, float progress);
+	void drawInterpolatedGrowEye(Thing &obj, int fromStage, int toStage, float progress, int eyeballColor, int pupilColor);
 	bool drawStaticObjectPrisms3D(Thing &obj);
 	void initRobots();
 	void renderCorridor3D();
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index 60cbf8bfde0..b5d55332ac9 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -1452,6 +1452,180 @@ void ColonyEngine::drawEyeOverlays3D(Thing &thing, const PrismPartDef &irisDef,
 	drawPrismOval3D(thing, pupilDef, useLook, pupilColorOverride, true);
 }
 
+namespace {
+
+int interpolatedRobotPoint(int from, int to, float progress) {
+	return (int)roundf((float)from + ((float)to - (float)from) * progress);
+}
+
+bool robotGrowShapeAndStage(int type, int &shape, int &stage) {
+	if (type < kRobEye || type > kRobMUPyramid)
+		return false;
+
+	shape = (type - kRobEye) & 3;
+	stage = (type - kRobEye) >> 2;
+	return true;
+}
+
+const ColonyEngine::PrismPartDef *growPrismDefForStage(int shape, int stage) {
+	switch (shape) {
+	case 1:
+		switch (stage) {
+		case 0: return &kPyramidBodyDef;
+		case 1: return &kFPyramidBodyDef;
+		case 2: return &kSPyramidBodyDef;
+		case 3: return &kMPyramidBodyDef;
+		default: return nullptr;
+		}
+	case 2:
+		switch (stage) {
+		case 0: return &kCubeBodyDef;
+		case 1: return &kFCubeBodyDef;
+		case 2: return &kSCubeBodyDef;
+		case 3: return &kMCubeBodyDef;
+		default: return nullptr;
+		}
+	case 3:
+		switch (stage) {
+		case 0: return &kUPyramidBodyDef;
+		case 1: return &kFUPyramidBodyDef;
+		case 2: return &kSUPyramidBodyDef;
+		case 3: return &kMUPyramidBodyDef;
+		default: return nullptr;
+		}
+	default:
+		return nullptr;
+	}
+}
+
+const ColonyEngine::PrismPartDef &growEyeIrisDefForStage(int stage) {
+	switch (stage) {
+	case 0: return kEyeIrisDef;
+	case 1: return kFEyeIrisDef;
+	case 2: return kSEyeIrisDef;
+	case 3:
+	default:
+		return kMEyeIrisDef;
+	}
+}
+
+const ColonyEngine::PrismPartDef &growEyePupilDefForStage(int stage) {
+	switch (stage) {
+	case 0: return kEyePupilDef;
+	case 1: return kFEyePupilDef;
+	case 2: return kSEyePupilDef;
+	case 3:
+	default:
+		return kMEyePupilDef;
+	}
+}
+
+} // namespace
+
+float ColonyEngine::growRenderTickFraction() const {
+	const uint32 kColonyThinkIntervalMs = 125;
+	const uint32 now = _system->getMillis();
+
+	if (_lastColonyThinkTime == 0 || now <= _lastColonyThinkTime)
+		return 0.0f;
+
+	const uint32 elapsed = now - _lastColonyThinkTime;
+	if (elapsed >= kColonyThinkIntervalMs)
+		return 1.0f;
+
+	return (float)elapsed / (float)kColonyThinkIntervalMs;
+}
+
+void ColonyEngine::drawInterpolatedGrowPrism(Thing &obj, const PrismPartDef &fromDef, const PrismPartDef &toDef, float progress) {
+	if (fromDef.pointCount != toDef.pointCount || fromDef.surfaceCount != toDef.surfaceCount)
+		return;
+
+	int points[8][3];
+	assert(fromDef.pointCount <= ARRAYSIZE(points));
+	for (int i = 0; i < fromDef.pointCount; ++i) {
+		points[i][0] = interpolatedRobotPoint(fromDef.points[i][0], toDef.points[i][0], progress);
+		points[i][1] = interpolatedRobotPoint(fromDef.points[i][1], toDef.points[i][1], progress);
+		points[i][2] = interpolatedRobotPoint(fromDef.points[i][2], toDef.points[i][2], progress);
+	}
+
+	const PrismPartDef def = {fromDef.pointCount, points, fromDef.surfaceCount, fromDef.surfaces};
+	draw3DPrism(obj, def, false, -1, true, false);
+}
+
+void ColonyEngine::drawInterpolatedGrowEye(Thing &obj, int fromStage, int toStage, float progress, int eyeballColor, int pupilColor) {
+	const int sphereZ[4][2] = {
+		{100, 200},
+		{0, 100},
+		{0, 50},
+		{0, 25}
+	};
+	int irisPoints[4][3];
+	int pupilPoints[4][3];
+
+	fromStage = CLIP(fromStage, 0, 3);
+	toStage = CLIP(toStage, 0, 3);
+
+	const int z0 = interpolatedRobotPoint(sphereZ[fromStage][0], sphereZ[toStage][0], progress);
+	const int z1 = interpolatedRobotPoint(sphereZ[fromStage][1], sphereZ[toStage][1], progress);
+	draw3DSphere(obj, 0, 0, z0, 0, 0, z1, eyeballColor, kColorBlack, true);
+
+	const PrismPartDef &fromIris = growEyeIrisDefForStage(fromStage);
+	const PrismPartDef &toIris = growEyeIrisDefForStage(toStage);
+	const PrismPartDef &fromPupil = growEyePupilDefForStage(fromStage);
+	const PrismPartDef &toPupil = growEyePupilDefForStage(toStage);
+	for (int i = 0; i < 4; ++i) {
+		irisPoints[i][0] = interpolatedRobotPoint(fromIris.points[i][0], toIris.points[i][0], progress);
+		irisPoints[i][1] = interpolatedRobotPoint(fromIris.points[i][1], toIris.points[i][1], progress);
+		irisPoints[i][2] = interpolatedRobotPoint(fromIris.points[i][2], toIris.points[i][2], progress);
+		pupilPoints[i][0] = interpolatedRobotPoint(fromPupil.points[i][0], toPupil.points[i][0], progress);
+		pupilPoints[i][1] = interpolatedRobotPoint(fromPupil.points[i][1], toPupil.points[i][1], progress);
+		pupilPoints[i][2] = interpolatedRobotPoint(fromPupil.points[i][2], toPupil.points[i][2], progress);
+	}
+
+	const PrismPartDef irisDef = {4, irisPoints, fromIris.surfaceCount, fromIris.surfaces};
+	const PrismPartDef pupilDef = {4, pupilPoints, fromPupil.surfaceCount, fromPupil.surfaces};
+	const int irisColor = (toStage == 3 && progress >= 0.5f) ? kColorMiniEyeIris : -1;
+	drawEyeOverlays3D(obj, irisDef, irisColor, pupilDef, pupilColor, false);
+}
+
+bool ColonyEngine::drawInterpolatedGrowRobot(Thing &obj, int eyeballColor, int pupilColor) {
+	int shape = 0;
+	int stage = 0;
+	if (obj.grow == 0 || !robotGrowShapeAndStage(obj.type, shape, stage))
+		return false;
+
+	int targetStage = stage;
+	if (obj.grow > 0) {
+		if (stage <= 0 || stage >= 3)
+			return false;
+		targetStage = stage - 1;
+	} else {
+		if (stage <= 0 || stage >= 3)
+			return false;
+		targetStage = stage + 1;
+	}
+
+	const int count = CLIP(obj.count, 0, 3);
+	float progress = ((float)count + growRenderTickFraction()) * 0.25f;
+	if (progress < 0.0f)
+		progress = 0.0f;
+	if (progress > 1.0f)
+		progress = 1.0f;
+
+	if (shape == 0) {
+		drawInterpolatedGrowEye(obj, stage, targetStage, progress, eyeballColor, pupilColor);
+		return true;
+	}
+
+	const PrismPartDef *fromDef = growPrismDefForStage(shape, stage);
+	const PrismPartDef *toDef = growPrismDefForStage(shape, targetStage);
+	if (!fromDef || !toDef)
+		return false;
+
+	drawInterpolatedGrowPrism(obj, *fromDef, *toDef, progress);
+	return true;
+}
+
 bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
 	const int eyeballColor = (_level == 1 || _level == 7) ? kColorPupil : kColorEyeball;
 	const int pupilColor = (_level == 1 || _level == 7) ? kColorEyeball : kColorPupil;
@@ -1774,42 +1948,66 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
 		_gfx->setDepthRange(0.0f, 1.0f);
 		break;
 	case kRobFEye:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DSphere(obj, 0, 0, 0, 0, 0, 100, eyeballColor, kColorBlack, true);
 		drawEyeOverlays3D(obj, kFEyeIrisDef, -1, kFEyePupilDef, pupilColor, false);
 		break;
 	case kRobFPyramid:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kFPyramidBodyDef, false, -1, true, false);
 		break;
 	case kRobFCube:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kFCubeBodyDef, false, -1, true, false);
 		break;
 	case kRobFUPyramid:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kFUPyramidBodyDef, false, -1, true, false);
 		break;
 	case kRobSEye:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DSphere(obj, 0, 0, 0, 0, 0, 50, eyeballColor, kColorBlack, true);
 		drawEyeOverlays3D(obj, kSEyeIrisDef, -1, kSEyePupilDef, pupilColor, false);
 		break;
 	case kRobSPyramid:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kSPyramidBodyDef, false, -1, true, false);
 		break;
 	case kRobSCube:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kSCubeBodyDef, false, -1, true, false);
 		break;
 	case kRobSUPyramid:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kSUPyramidBodyDef, false, -1, true, false);
 		break;
 	case kRobMEye:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DSphere(obj, 0, 0, 0, 0, 0, 25, eyeballColor, kColorBlack, true);
 		drawEyeOverlays3D(obj, kMEyeIrisDef, kColorMiniEyeIris, kMEyePupilDef, pupilColor, false);
 		break;
 	case kRobMPyramid:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kMPyramidBodyDef, false, -1, true, false);
 		break;
 	case kRobMCube:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kMCubeBodyDef, false, -1, true, false);
 		break;
 	case kRobMUPyramid:
+		if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
+			break;
 		draw3DPrism(obj, kMUPyramidBodyDef, false, -1, true, false);
 		break;
 	case kRobQueen:


Commit: 8ff586d3ddef50330ac7903bac42326b4b846bc6
    https://github.com/scummvm/scummvm/commit/8ff586d3ddef50330ac7903bac42326b4b846bc6
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-05T19:42:52+02:00

Commit Message:
COLONY: better detection for aiming enemies

Changed paths:
    engines/colony/colony.h
    engines/colony/interaction.cpp
    engines/colony/render_objects.cpp


diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index fa50a5435c8..9650a513ad9 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -689,6 +689,10 @@ private:
 	// shoot.c: shooting and power management
 	void setPower(int p0, int p1, int p2);
 	void cShoot();
+	bool isShootableRobotType(int type) const;
+	bool isShotBlockingObjectType(int type) const;
+	int findAimedObject(const Common::Point &aim, bool *isBlocker = nullptr, int *targetDist = nullptr) const;
+	bool hasAimedRobotTarget() const;
 	void destroyRobot(int num);
 	void doShootCircles(int cx, int cy);
 	void doBurnHole(int cx, int cy, int radius);
diff --git a/engines/colony/interaction.cpp b/engines/colony/interaction.cpp
index 3f791c564d4..f786284222a 100644
--- a/engines/colony/interaction.cpp
+++ b/engines/colony/interaction.cpp
@@ -342,6 +342,62 @@ void ColonyEngine::setPower(int p0, int p1, int p2) {
 	}
 }
 
+bool ColonyEngine::isShootableRobotType(int type) const {
+	return (type >= kRobEye && type <= kRobUPyramid) ||
+		type == kRobQueen || type == kRobDrone || type == kRobSoldier;
+}
+
+bool ColonyEngine::isShotBlockingObjectType(int type) const {
+	return type == kObjForkLift || type == kObjTeleport || type == kObjPToilet ||
+		type == kObjBox2 || type == kObjReactor || type == kObjScreen;
+}
+
+int ColonyEngine::findAimedObject(const Common::Point &aim, bool *isBlocker, int *targetDist) const {
+	int bestIdx = -1;
+	int bestDist = INT_MAX;
+	bool bestIsBlocker = false;
+
+	for (uint i = 0; i < _objects.size(); i++) {
+		const Thing &obj = _objects[i];
+		if (!obj.alive)
+			continue;
+
+		if (obj.where.xmn > obj.where.xmx || obj.where.zmn > obj.where.zmx)
+			continue;
+		if (obj.where.xmn > aim.x || obj.where.xmx < aim.x ||
+			obj.where.zmn > aim.y || obj.where.zmx < aim.y)
+			continue;
+
+		const int type = obj.type;
+		const bool isRobot = isShootableRobotType(type);
+		const bool isBlockerObject = isShotBlockingObjectType(type);
+		if (!isRobot && !isBlockerObject)
+			continue;
+
+		const int dx = obj.where.xloc - _me.xloc;
+		const int dy = obj.where.yloc - _me.yloc;
+		const int dist = (int)sqrtf((float)(dx * dx + dy * dy));
+
+		if (dist < bestDist) {
+			bestDist = dist;
+			bestIdx = (int)i + 1; // 1-based object index
+			bestIsBlocker = isBlockerObject;
+		}
+	}
+
+	if (isBlocker)
+		*isBlocker = bestIsBlocker;
+	if (targetDist)
+		*targetDist = bestDist;
+	return bestIdx;
+}
+
+bool ColonyEngine::hasAimedRobotTarget() const {
+	bool blocker = false;
+	const int target = findAimedObject(getAimPoint(), &blocker);
+	return target > 0 && !blocker && isShootableRobotType(_objects[target - 1].type);
+}
+
 // shoot.c CShoot(): player fires weapon at the cursor or screen center.
 // Original hit detection uses the rendered object bounds on screen.
 void ColonyEngine::cShoot() {
@@ -368,39 +424,9 @@ void ColonyEngine::cShoot() {
 	// Drain weapons power: -(1 << level) per shot
 	setPower(-(1 << _level), 0, 0);
 
-	int bestIdx = -1;
-	int bestDist = INT_MAX;
 	bool bestIsBlocker = false;
-
-	for (uint i = 0; i < _objects.size(); i++) {
-		const Thing &obj = _objects[i];
-		if (!obj.alive)
-			continue;
-
-		if (obj.where.xmn > obj.where.xmx || obj.where.zmn > obj.where.zmx)
-			continue;
-		if (obj.where.xmn > cx || obj.where.xmx < cx ||
-			obj.where.zmn > cy || obj.where.zmx < cy)
-			continue;
-
-		int t = obj.type;
-		bool isRobot = (t >= kRobEye && t <= kRobUPyramid) ||
-			t == kRobQueen || t == kRobDrone || t == kRobSoldier;
-		bool blocksShot = (t == kObjForkLift || t == kObjTeleport || t == kObjPToilet ||
-			t == kObjBox2 || t == kObjReactor || t == kObjScreen);
-		if (!isRobot && !blocksShot)
-			continue;
-
-		int dx = obj.where.xloc - _me.xloc;
-		int dy = obj.where.yloc - _me.yloc;
-		int dist = (int)sqrtf((float)(dx * dx + dy * dy));
-
-		if (dist < bestDist) {
-			bestDist = dist;
-			bestIdx = (int)i + 1; // 1-based robot index
-			bestIsBlocker = blocksShot;
-		}
-	}
+	int bestDist = INT_MAX;
+	const int bestIdx = findAimedObject(aim, &bestIsBlocker, &bestDist);
 
 	if (bestIdx > 0 && !bestIsBlocker) {
 		const Thing &target = _objects[bestIdx - 1];
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index b5d55332ac9..5d49db97a8e 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -1309,15 +1309,11 @@ void ColonyEngine::drawStaticObjects() {
 		if (ox < 0 || ox >= 32 || oy < 0 || oy >= 32 || !_visibleCell[ox][oy])
 			continue;
 		drawStaticObjectPrisms3D(obj);
-		// MAKEROBO.C: if shootable robot straddles centerX, set insight
-		// (narrows crosshair brackets to indicate a target is in the line of fire)
-		int t = obj.type;
-		if ((t >= kRobEye && t <= kRobUPyramid) ||
-			(t >= kRobQueen && t <= kRobSoldier)) {
-			if (obj.where.xmn < _centerX && obj.where.xmx > _centerX)
-				_insight = true;
-		}
 	}
+
+	// Use the same rendered-bounds target selection as cShoot() so the
+	// narrowed crosshair only appears for a shot that would select a robot.
+	_insight = _weapons > 0 && hasAimedRobotTarget();
 }
 
 void ColonyEngine::drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool useLook, int colorOverride, bool forceVisible) {


Commit: e997e181e40ae1b9469c26f5591ee1137dfc0e0d
    https://github.com/scummvm/scummvm/commit/e997e181e40ae1b9469c26f5591ee1137dfc0e0d
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-05T21:36:22+02:00

Commit Message:
COLONY: better detection collision detection with static objects

Changed paths:
    engines/colony/colony.cpp
    engines/colony/colony.h
    engines/colony/interaction.cpp
    engines/colony/map.cpp
    engines/colony/movement.cpp
    engines/colony/render_objects.cpp
    engines/colony/savegame.cpp
    engines/colony/sound.cpp


diff --git a/engines/colony/colony.cpp b/engines/colony/colony.cpp
index c0f53f56991..df1733b3671 100644
--- a/engines/colony/colony.cpp
+++ b/engines/colony/colony.cpp
@@ -51,8 +51,6 @@
 
 namespace Colony {
 
-namespace {
-
 const float kMouseLookSensitivity = 0.25f;
 const float kKeyboardTurnSpeed = 30.0f; // angle units per second
 
@@ -131,8 +129,6 @@ Graphics::Cursor *cloneAndScaleCursor(const Graphics::Cursor &src, int scale) {
 		src.getPaletteStartIndex(), src.getPaletteCount(), scale);
 }
 
-} // anonymous namespace
-
 ColonyEngine::ColonyEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd), _randomSource("colony") {
 	_level = 0;
 	_robotNum = 0;
diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index 9650a513ad9..15678f332a5 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -466,6 +466,9 @@ public:
 	int checkwallMoveTo(int xnew, int ynew, int xind2, int yind2, Locate *pobject, uint8 trailCode);
 	int checkwallTryFeature(int xnew, int ynew, int xind2, int yind2, Locate *pobject, int dir);
 	int checkwall(int xnew, int ynew, Locate *pobject);
+	void clearPlayerCellMarker();
+	void setPlayerCellMarker();
+	bool playerIntersectsObjectFootprint(const Thing &obj, int xloc, int yloc) const;
 	void cCommand(int xnew, int ynew, bool allowInteraction);
 	bool scrollInfo(const Graphics::Font *macFont = nullptr);
 	bool checkSkipRequested();
@@ -668,7 +671,7 @@ private:
 	void getWallFace3D(int cellX, int cellY, int direction, float corners[4][3]);
 	void getCellFace3D(int cellX, int cellY, bool ceiling, float corners[4][3]);
 
-	int occupiedObjectAt(int x, int y, const Locate *pobject);
+	int occupiedObjectAt(int xnew, int ynew, int x, int y, const Locate *pobject);
 	void interactWithObject(int objNum);
 
 	// Convert a mouse coord delivered by the event manager into engine
diff --git a/engines/colony/interaction.cpp b/engines/colony/interaction.cpp
index f786284222a..57709656628 100644
--- a/engines/colony/interaction.cpp
+++ b/engines/colony/interaction.cpp
@@ -175,10 +175,10 @@ void ColonyEngine::interactWithObject(int objNum) {
 		_me.xloc = (targetX << 8) + 128;
 		_me.yloc = (targetY << 8) + 128;
 		_me.ang = _me.look;
-		if (oldX >= 0 && oldX < 32 && oldY >= 0 && oldY < 32)
+		if (oldX >= 0 && oldX < 32 && oldY >= 0 && oldY < 32 &&
+				_robotArray[oldX][oldY] == kMeNum)
 			_robotArray[oldX][oldY] = 0;
-		if (_me.xindex >= 0 && _me.xindex < 32 && _me.yindex >= 0 && _me.yindex < 32)
-			_robotArray[_me.xindex][_me.yindex] = kMeNum;
+		setPlayerCellMarker();
 		break;
 	}
 	case kObjDrawer:
diff --git a/engines/colony/map.cpp b/engines/colony/map.cpp
index 538cd08c28d..e488ed58ac5 100644
--- a/engines/colony/map.cpp
+++ b/engines/colony/map.cpp
@@ -164,8 +164,7 @@ void ColonyEngine::loadMap(int mnum) {
 	doPatch();  // apply object relocations from patch table
 	initRobots();  // spawn robot objects for this level
 
-	if (_me.xindex >= 0 && _me.xindex < 32 && _me.yindex >= 0 && _me.yindex < 32)
-		_robotArray[_me.xindex][_me.yindex] = kMeNum;
+	setPlayerCellMarker();
 	debugC(1, kColonyDebugMap, "Successfully loaded map %d (objects: %d)", mnum, (int)_objects.size());
 }
 
diff --git a/engines/colony/movement.cpp b/engines/colony/movement.cpp
index fd550ab45ed..85179c9cdf8 100644
--- a/engines/colony/movement.cpp
+++ b/engines/colony/movement.cpp
@@ -151,6 +151,118 @@ int tunnelClipCode(const Common::Rect &rect, int x, int y) {
 	return code;
 }
 
+struct ObjectFootprint {
+	int centerX;
+	int centerY;
+	int halfX;
+	int halfY;
+};
+
+bool objectFootprintForType(int type, ObjectFootprint &fp) {
+	fp.centerX = 0;
+	fp.centerY = 0;
+	fp.halfX = 128;
+	fp.halfY = 128;
+
+	switch (type) {
+	case kObjPlant:
+		fp.halfX = 45;
+		fp.halfY = 45;
+		return true;
+	case kObjCChair:
+		fp.halfX = 55;
+		fp.halfY = 65;
+		return true;
+	case kObjChair:
+		fp.centerX = -15;
+		fp.halfX = 70;
+		fp.halfY = 75;
+		return true;
+	case kObjCouch:
+		fp.centerX = -15;
+		fp.halfX = 80;
+		fp.halfY = 128;
+		return true;
+	case kObjTV:
+		fp.halfX = 35;
+		fp.halfY = 65;
+		return true;
+	case kObjScreen:
+		fp.halfX = 20;
+		fp.halfY = 70;
+		return true;
+	case kObjConsole:
+		fp.centerX = -55;
+		fp.halfX = 55;
+		fp.halfY = 75;
+		return true;
+	case kObjDrawer:
+		fp.centerX = -40;
+		fp.halfX = 45;
+		fp.halfY = 75;
+		return true;
+	case kObjTub:
+		fp.centerX = -64;
+		fp.halfX = 70;
+		fp.halfY = 128;
+		return true;
+	case kObjSink:
+		fp.centerX = -90;
+		fp.halfX = 45;
+		fp.halfY = 60;
+		return true;
+	case kObjToilet:
+		fp.centerX = -75;
+		fp.halfX = 60;
+		fp.halfY = 50;
+		return true;
+	case kObjBench:
+		fp.halfX = 65;
+		fp.halfY = 128;
+		return true;
+	case kObjCBench:
+		fp.centerX = 35;
+		fp.centerY = -35;
+		fp.halfX = 100;
+		fp.halfY = 100;
+		return true;
+	case kObjProjector:
+		fp.halfX = 60;
+		fp.halfY = 60;
+		return true;
+	case kObjPowerSuit:
+		fp.halfX = 120;
+		fp.halfY = 120;
+		return true;
+	case kObjBox1:
+	case kObjBox2:
+		fp.halfX = 55;
+		fp.halfY = 55;
+		return true;
+	case kObjForkLift:
+		fp.halfX = 100;
+		fp.halfY = 120;
+		return true;
+	case kObjCryo:
+		fp.halfX = 128;
+		fp.halfY = 75;
+		return true;
+	case kObjTeleport:
+		fp.halfX = 105;
+		fp.halfY = 105;
+		return true;
+	case kObjDesk:
+	case kObjBed:
+	case kObjBBed:
+	case kObjTable:
+	case kObjReactor:
+	case kObjPToilet:
+		return true;
+	default:
+		return false;
+	}
+}
+
 void drawTunnelLine(Renderer *gfx, const Common::Rect &rect, int x1, int y1, int x2, int y2, uint32 color) {
 	if (rect.isEmpty())
 		return;
@@ -208,7 +320,44 @@ void drawTunnelLine(Renderer *gfx, const Common::Rect &rect, int x1, int y1, int
 	}
 }
 
-int ColonyEngine::occupiedObjectAt(int x, int y, const Locate *pobject) {
+void ColonyEngine::clearPlayerCellMarker() {
+	if (_me.xindex >= 0 && _me.xindex < 32 && _me.yindex >= 0 && _me.yindex < 32 &&
+			_robotArray[_me.xindex][_me.yindex] == kMeNum)
+		_robotArray[_me.xindex][_me.yindex] = 0;
+}
+
+void ColonyEngine::setPlayerCellMarker() {
+	if (_me.xindex < 0 || _me.xindex >= 32 || _me.yindex < 0 || _me.yindex >= 32)
+		return;
+
+	const int rnum = _robotArray[_me.xindex][_me.yindex];
+	if (rnum > 0 && rnum != kMeNum && rnum <= (int)_objects.size()) {
+		const Thing &obj = _objects[rnum - 1];
+		if (obj.alive && obj.where.xindex == _me.xindex && obj.where.yindex == _me.yindex)
+			return;
+	}
+
+	_robotArray[_me.xindex][_me.yindex] = kMeNum;
+}
+
+bool ColonyEngine::playerIntersectsObjectFootprint(const Thing &obj, int xloc, int yloc) const {
+	ObjectFootprint fp;
+	if (!objectFootprintForType(obj.type, fp))
+		return true;
+
+	const int kPlayerObjectPad = 32;
+	const int objAng = (obj.where.ang + 32) & 0xFF;
+	const uint8 invAng = (uint8)(0 - objAng);
+	const int wx = xloc - obj.where.xloc;
+	const int wy = yloc - obj.where.yloc;
+	const int lx = (int)(((int32)wx * _cost[invAng] - (int32)wy * _sint[invAng]) >> 7) - fp.centerX;
+	const int ly = (int)(((int32)wx * _sint[invAng] + (int32)wy * _cost[invAng]) >> 7) - fp.centerY;
+
+	return ABS(lx) <= fp.halfX + kPlayerObjectPad &&
+		ABS(ly) <= fp.halfY + kPlayerObjectPad;
+}
+
+int ColonyEngine::occupiedObjectAt(int xnew, int ynew, int x, int y, const Locate *pobject) {
 	if (x < 0 || x >= 32 || y < 0 || y >= 32)
 		return -1;
 	const int rnum = _robotArray[x][y];
@@ -216,6 +365,12 @@ int ColonyEngine::occupiedObjectAt(int x, int y, const Locate *pobject) {
 		return 0;
 	if (pobject == &_me && rnum <= (int)_objects.size()) {
 		Thing &obj = _objects[rnum - 1];
+		// Only the player gets tight static-object footprints. Robots,
+		// snoops, and scan rays keep full-cell blocking so enemies cannot
+		// enter or path through cells occupied by objects.
+		if (obj.type > kBaseObject && obj.type != kObjCWall && obj.type != kObjFWall &&
+				!playerIntersectsObjectFootprint(obj, xnew, ynew))
+			return 0;
 		if (obj.type <= kBaseObject)
 			obj.where.look = obj.where.ang = _me.ang + 128;
 	}
@@ -320,7 +475,7 @@ void ColonyEngine::clampToDiagonalWalls(Locate *p) {
 }
 
 int ColonyEngine::checkwallMoveTo(int xnew, int ynew, int xind2, int yind2, Locate *pobject, uint8 trailCode) {
-	const int rnum = occupiedObjectAt(xind2, yind2, pobject);
+	const int rnum = occupiedObjectAt(xnew, ynew, xind2, yind2, pobject);
 	if (rnum)
 		return rnum;
 	if (trailCode != 0 && pobject->type == kMeNum &&
@@ -345,7 +500,7 @@ int ColonyEngine::checkwallTryFeature(int xnew, int ynew, int xind2, int yind2,
 	if (r == 2)
 		return 0; // teleported  position already updated by the feature
 	if (r == 1) {
-		const int rnum = occupiedObjectAt(xind2, yind2, pobject);
+		const int rnum = occupiedObjectAt(xnew, ynew, xind2, yind2, pobject);
 		if (rnum) {
 			const bool showDoorText = (pobject == &_me && feature &&
 				(feature[0] == kWallFeatureDoor || feature[0] == kWallFeatureAirlock));
@@ -392,11 +547,18 @@ int ColonyEngine::checkwall(int xnew, int ynew, Locate *pobject) {
 
 	if (xind2 == pobject->xindex) {
 		if (yind2 == pobject->yindex) {
+			if (pobject == &_me) {
+				const int rnum = occupiedObjectAt(xnew, ynew, xind2, yind2, pobject);
+				if (rnum)
+					return rnum;
+			}
 			pobject->dx = xnew - pobject->xloc;
 			pobject->dy = ynew - pobject->yloc;
 			pobject->xloc = xnew;
 			pobject->yloc = ynew;
 			clampToWalls(pobject);
+			if (pobject == &_me)
+				clampToDiagonalWalls(pobject);
 			return 0;
 		}
 
@@ -588,9 +750,7 @@ int ColonyEngine::goToDestination(const uint8 *map, Locate *pobject) {
 			return 0;
 		}
 
-		if (_me.xindex >= 0 && _me.xindex < 32 &&
-			_me.yindex >= 0 && _me.yindex < 32)
-			_robotArray[_me.xindex][_me.yindex] = 0;
+		clearPlayerCellMarker();
 
 		_gameMode = kModeBattle;
 		_projon = false;
@@ -1041,7 +1201,7 @@ void ColonyEngine::fallThroughHole() {
 		if (targetMap == 0 && _robotArray[targetX][targetY] != 0)
 			return;
 
-		_robotArray[_me.xindex][_me.yindex] = 0;
+		clearPlayerCellMarker();
 
 		// Preserve sub-cell offset (DOS: xmod = xloc - (xindex<<8))
 		int xmod = _me.xloc - (_me.xindex << 8);
@@ -1051,7 +1211,7 @@ void ColonyEngine::fallThroughHole() {
 		_me.yloc = (targetY << 8) + ymod;
 		_me.yindex = targetY;
 
-		_robotArray[targetX][targetY] = kMeNum;
+		setPlayerCellMarker();
 	}
 
 	// DOS: if(map) load_mapnum(map, TRUE)  always reload when map != 0
@@ -1134,8 +1294,7 @@ void ColonyEngine::playCollisionSound() {
 }
 
 void ColonyEngine::cCommand(int xnew, int ynew, bool allowInteraction) {
-	if (_me.xindex >= 0 && _me.xindex < 32 && _me.yindex >= 0 && _me.yindex < 32)
-		_robotArray[_me.xindex][_me.yindex] = 0;
+	clearPlayerCellMarker();
 
 	const int oldXIndex = _me.xindex;
 	const int oldYIndex = _me.yindex;
@@ -1149,8 +1308,7 @@ void ColonyEngine::cCommand(int xnew, int ynew, bool allowInteraction) {
 			(_me.xloc != xnew || _me.yloc != ynew))
 		playCollisionSound();
 
-	if (_me.xindex >= 0 && _me.xindex < 32 && _me.yindex >= 0 && _me.yindex < 32)
-		_robotArray[_me.xindex][_me.yindex] = kMeNum;
+	setPlayerCellMarker();
 
 	_suppressCollisionSound = false;
 }
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index 5d49db97a8e..afa5e4458e4 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -1448,8 +1448,6 @@ void ColonyEngine::drawEyeOverlays3D(Thing &thing, const PrismPartDef &irisDef,
 	drawPrismOval3D(thing, pupilDef, useLook, pupilColorOverride, true);
 }
 
-namespace {
-
 int interpolatedRobotPoint(int from, int to, float progress) {
 	return (int)roundf((float)from + ((float)to - (float)from) * progress);
 }
@@ -1516,8 +1514,6 @@ const ColonyEngine::PrismPartDef &growEyePupilDefForStage(int stage) {
 	}
 }
 
-} // namespace
-
 float ColonyEngine::growRenderTickFraction() const {
 	const uint32 kColonyThinkIntervalMs = 125;
 	const uint32 now = _system->getMillis();
diff --git a/engines/colony/savegame.cpp b/engines/colony/savegame.cpp
index 1f423247887..f3117164866 100644
--- a/engines/colony/savegame.cpp
+++ b/engines/colony/savegame.cpp
@@ -28,8 +28,6 @@
 
 namespace Colony {
 
-namespace {
-
 const uint32 kSaveVersion = 1;
 const uint32 kMaxSaveObjects = 4096;
 const uint32 kMaxSavePatches = 100;
@@ -274,8 +272,6 @@ bool findInvalidActiveObjectSlot(const Common::Array<Thing> &objects, uint32 &in
 	return false;
 }
 
-} // anonymous namespace
-
 bool ColonyEngine::hasFeature(EngineFeature f) const {
 	return f == kSupportsReturnToLauncher ||
 		f == kSupportsLoadingDuringRuntime ||
diff --git a/engines/colony/sound.cpp b/engines/colony/sound.cpp
index 9ab0459219d..d72708bbe05 100644
--- a/engines/colony/sound.cpp
+++ b/engines/colony/sound.cpp
@@ -34,8 +34,6 @@
 
 namespace Colony {
 
-namespace {
-
 struct MelodyStep {
 	uint32 divider;
 	uint8 ticks;
@@ -99,8 +97,6 @@ const int kBeamMeRamp1Steps = 20;
 const int kBeamMeRamp2Steps = 20;
 const int kBeamMeRamp3Steps = 80;
 
-} // namespace
-
 Sound::Sound(ColonyEngine *vm) : _vm(vm), _resMan(nullptr), _appResMan(nullptr) {
 	_speaker = new Audio::PCSpeaker();
 	_speaker->init();




More information about the Scummvm-git-logs mailing list