[Scummvm-git-logs] scummvm master -> 7cc77e1185a29088b0bdf35794fa48f9933caf96
sev-
noreply at scummvm.org
Wed Jul 8 18:20:26 UTC 2026
This automated email contains information about 27 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
67383a5afd DM: Fix sensor unlinking by correctly updating lastProcessedThing in the loop
655ee980d1 DM: Implement DisplayMan::shadeScreenBox
0986681801 DM: Implement palette translation in blitToBitmapShrinkWithPalChange
f027547b51 DM: Fix source pixel width in getExplosionBitmap
55e9518549 DM: Remove cast warning in GroupMan::addGroupEvent
a53dd7c95d DM: Fix pixel color corruption in blitBoxFilledWithMaskedBitmap
753e8f7b20 DM: Fix spellcasting tabs display by changing highlight screen box XOR mask to 0x04
74e2f492e9 DM: Fix infinite loop and freeze
4168feae04 DM: Fix memory copy size for flipped explosion and projectile sprites
349cef0e00 DM: Fix crash when decoding text scrolls
3727f7ee45 DM: Remove mouse pointer request count startup warning
3ba93b70a9 DM: Add translatation for 'LOAD' in the save menu
20f1d79447 DM: Fix left shift of negative value runtime error
ead34bc5f4 DM: Fix crash in fuse sequence by updating loop iterator after unlinking fluxcage
73c2dec4ec DM: Fix text corruption in message by resetting string for each word
8dbf7e13c3 DM: Fix message area text cutoff
b8e0b25f5c DM: Increase fuse sequence animation delay to match original pacing
b083c6cda2 DM: Fix typo incrementing a prarmeter twice
d9a6378524 DM: Fix endgame flow by waiting for input on portraits screen
ff01ea57e9 DM: Support return to launcher on exit
0fd953410a DM: Initialize _doNotDrawFluxcagesDuringEndgame in DisplayMan
8db0088be6 DM: Prevent final endgame explosion from disappearing
4400d18634 DM: Correctly initialize _thingNone to prevent crashes
f732a10688 `DM: Fix crash when renaming champion by ignoring out-of-bounds clicks`
7306244681 DM: Implement support for extended saves
c049b6ca99 DM: Show load save dialog on game restart instead of loading slot 1
7cc77e1185 DM: Update TODO
Commit: 67383a5afd1e7d15902483ccbf4ed86fc2fd1f14
https://github.com/scummvm/scummvm/commit/67383a5afd1e7d15902483ccbf4ed86fc2fd1f14
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix sensor unlinking by correctly updating lastProcessedThing in the loop
Changed paths:
engines/dm/movesens.cpp
diff --git a/engines/dm/movesens.cpp b/engines/dm/movesens.cpp
index cfee2e9fd16..4c7c8197d2e 100644
--- a/engines/dm/movesens.cpp
+++ b/engines/dm/movesens.cpp
@@ -70,8 +70,8 @@ bool MovesensMan::sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16
thingBeingProcessed = dungeon.getNextThing(thingBeingProcessed);
}
- for (thingBeingProcessed = squareFirstThing; thingBeingProcessed != _vm->_thingEndOfList; thingBeingProcessed = dungeon.getNextThing(thingBeingProcessed)) {
- Thing lastProcessedThing = thingBeingProcessed;
+ Thing lastProcessedThing = squareFirstThing;
+ for (thingBeingProcessed = squareFirstThing; thingBeingProcessed != _vm->_thingEndOfList; lastProcessedThing = thingBeingProcessed, thingBeingProcessed = dungeon.getNextThing(thingBeingProcessed)) {
uint16 ProcessedThingType = thingBeingProcessed.getType();
if (ProcessedThingType == kDMThingTypeSensor) {
int16 cellIdx = thingBeingProcessed.getCell();
Commit: 655ee980d19a0f3933406049b4222c74044e5bd7
https://github.com/scummvm/scummvm/commit/655ee980d19a0f3933406049b4222c74044e5bd7
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Implement DisplayMan::shadeScreenBox
Changed paths:
engines/dm/gfx.cpp
engines/dm/gfx.h
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index 8a8fbb856cf..9fb0aa9820b 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -1055,6 +1055,23 @@ void DisplayMan::fillScreenBox(Box &box, Color color) {
memset(_bitmapScreen + y * _screenWidth + box._rect.left, color, sizeof(byte) * width);
}
+void DisplayMan::shadeScreenBox(Box *box, Color color) {
+ if (!box)
+ return;
+
+ int16 x1 = MAX<int16>(0, box->_rect.left);
+ int16 x2 = MIN<int16>(_screenWidth - 1, box->_rect.right);
+ int16 y1 = MAX<int16>(0, box->_rect.top);
+ int16 y2 = MIN<int16>(_screenHeight - 1, box->_rect.bottom);
+
+ for (int16 y = y1; y <= y2; ++y) {
+ for (int16 x = x1; x <= x2; ++x) {
+ if ((x + y) % 2 == 0)
+ _bitmapScreen[y * _screenWidth + x] = color;
+ }
+ }
+}
+
void DisplayMan::fillBoxBitmap(byte *destBitmap, Box &box, Color color, int16 byteWidth, int16 height) {
for (int16 y = box._rect.top; y < box._rect.bottom + 1; ++y) // + 1 for inclusive boundaries
memset(destBitmap + y * byteWidth * 2 + box._rect.left, color, sizeof(byte) * (box._rect.right - box._rect.left + 1)); // + 1 for inclusive boundaries
diff --git a/engines/dm/gfx.h b/engines/dm/gfx.h
index 34c84ae2f5f..babc1470466 100644
--- a/engines/dm/gfx.h
+++ b/engines/dm/gfx.h
@@ -825,7 +825,7 @@ public:
uint16 getDarkenedColor(uint16 RGBcolor);
void startEndFadeToPalette(uint16 *P0849_pui_Palette); // @ F0436_STARTEND_FadeToPalette
void buildPaletteChangeCopperList(uint16 *middleScreen, uint16 *topAndBottom); // @ F0508_AMIGA_BuildPaletteChangeCopperList
- void shadeScreenBox(Box *box, Color color) { warning("STUB METHOD: shadeScreenBox"); } // @ F0136_VIDEO_ShadeScreenBox
+ void shadeScreenBox(Box *box, Color color); // @ F0136_VIDEO_ShadeScreenBox
private:
void initConstants();
Commit: 09866818014a9d703b6d824137e07264c0ee2d58
https://github.com/scummvm/scummvm/commit/09866818014a9d703b6d824137e07264c0ee2d58
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Implement palette translation in blitToBitmapShrinkWithPalChange
Changed paths:
engines/dm/gfx.cpp
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index 9fb0aa9820b..a7c1b9f4641 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -2879,10 +2879,6 @@ bool DisplayMan::isDrawnWallOrnAnAlcove(int16 wallOrnOrd, ViewWall viewWallIndex
void DisplayMan::blitToBitmapShrinkWithPalChange(byte *srcBitmap, byte *destBitmap,
int16 srcPixelWidth, int16 srcHeight,
int16 destPixelWidth, int16 destHeight, byte *palChange) {
- warning("DUMMY CODE: f129_blitToBitmapShrinkWithPalChange");
- warning("MISSING CODE: No palette change takes place in f129_blitToBitmapShrinkWithPalChange");
-
-
destPixelWidth = (destPixelWidth + 1) & 0xFFFE;
uint32 scaleX = (kScaleThreshold * srcPixelWidth) / destPixelWidth;
@@ -2895,8 +2891,13 @@ void DisplayMan::blitToBitmapShrinkWithPalChange(byte *srcBitmap, byte *destBitm
byte *destLine = &destBitmap[destY * destStride];
// Loop through drawing the pixels of the row
- for (uint32 destX = 0, xCtr = 0, scaleXCtr = 0; destX < (uint32)destPixelWidth; ++destX, ++xCtr, scaleXCtr += scaleX)
- destLine[xCtr] = srcLine[scaleXCtr / kScaleThreshold];
+ for (uint32 destX = 0, xCtr = 0, scaleXCtr = 0; destX < (uint32)destPixelWidth; ++destX, ++xCtr, scaleXCtr += scaleX) {
+ byte srcPixel = srcLine[scaleXCtr / kScaleThreshold];
+ if (palChange)
+ destLine[xCtr] = palChange[srcPixel] / 10; // Palette values are stored as multiples of 10
+ else
+ destLine[xCtr] = srcPixel;
+ }
}
}
Commit: f027547b51930bbb38ef3801bf0c7c4265c795d0
https://github.com/scummvm/scummvm/commit/f027547b51930bbb38ef3801bf0c7c4265c795d0
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix source pixel width in getExplosionBitmap
Changed paths:
engines/dm/gfx.cpp
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index a7c1b9f4641..b4c732a6524 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -1140,7 +1140,7 @@ byte *DisplayMan::getExplosionBitmap(uint16 explosionAspIndex, uint16 scale, int
else {
byte *nativeBitmap = getNativeBitmapOrGraphic(MIN(explosionAspIndex, (uint16)kDMExplosionAspectPoison) + kDMGraphicIdxFirstExplosion);
bitmap = getDerivedBitmap(derBitmapIndex);
- blitToBitmapShrinkWithPalChange(nativeBitmap, bitmap, explAsp->_byteWidth, explAsp->_height, pixelWidth * 2, height,
+ blitToBitmapShrinkWithPalChange(nativeBitmap, bitmap, explAsp->_byteWidth * 2, explAsp->_height, pixelWidth * 2, height,
(explosionAspIndex == kDMExplosionAspectSmoke) ? _palChangeSmoke : _palChangesNoChanges);
addDerivedBitmap(derBitmapIndex);
}
Commit: 55e9518549541f09393232bb4b4eb215116c9e29
https://github.com/scummvm/scummvm/commit/55e9518549541f09393232bb4b4eb215116c9e29
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Remove cast warning in GroupMan::addGroupEvent
DMEngine::filterTime masks the time with 0x00FFFFFF clearing the most significant 8 bits, so the returned value is always a non-negative number.
Changed paths:
engines/dm/group.cpp
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index 5a58ac0f20a..d965c81f1bb 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -1403,7 +1403,6 @@ void GroupMan::setGroupDirection(ActiveGroup *activeGroup, int16 dir, int16 crea
}
void GroupMan::addGroupEvent(TimelineEvent *event, uint32 time) {
- warning("potentially dangerous cast to uint32 below");
if (time < (uint32)_vm->filterTime(event->_mapTime)) {
int16 tmpType = event->_type - 5;
event->_type = (TimelineEventType)tmpType;
Commit: a53dd7c95d07efa1c470c25c37732e4427d6f640
https://github.com/scummvm/scummvm/commit/a53dd7c95d07efa1c470c25c37732e4427d6f640
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix pixel color corruption in blitBoxFilledWithMaskedBitmap
Changed paths:
engines/dm/gfx.cpp
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index b4c732a6524..c7a6b2bc501 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -1091,12 +1091,17 @@ void DisplayMan::blitBoxFilledWithMaskedBitmap(byte *src, byte *dest, byte *mask
byte *nextDestPixel = dest + next_y * destByteWidth * 2 + next_x;
byte nextSrcPixel = src[nextUnitIndex];
- if (nextSrcPixel != transparent) {
- if (useMask && mask && *mask++) {
- *nextDestPixel = *mask & nextSrcPixel;
- } else
- *nextDestPixel = nextSrcPixel;
- }
+ byte pixelVal = kDMColorBlack;
+ if (useMask && mask && *mask != kDMColorWhite)
+ pixelVal = *mask;
+ else if (nextSrcPixel != transparent)
+ pixelVal = nextSrcPixel;
+
+ if (useMask && mask)
+ mask++;
+
+ if (pixelVal != kDMColorBlack)
+ *nextDestPixel = pixelVal;
if (++nextUnitIndex >= lastUnitIndex)
nextUnitIndex = 0; // 0 is not an error
Commit: 753e8f7b20352e99ef9f49f9779b9afa9f94782e
https://github.com/scummvm/scummvm/commit/753e8f7b20352e99ef9f49f9779b9afa9f94782e
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix spellcasting tabs display by changing highlight screen box XOR mask to 0x04
Changed paths:
engines/dm/eventman.cpp
diff --git a/engines/dm/eventman.cpp b/engines/dm/eventman.cpp
index 214cec3347b..3080b0d85ad 100644
--- a/engines/dm/eventman.cpp
+++ b/engines/dm/eventman.cpp
@@ -1688,7 +1688,7 @@ void EventManager::highlightScreenBox(int16 x1, int16 x2, int16 y1, int16 y2) {
for (int16 y = y1; y <= y2; ++y) {
for (int16 x = x1; x <= x2; ++x) {
- screen[y * pitch + x] ^= 0x0F;
+ screen[y * pitch + x] ^= 0x04;
}
}
}
Commit: 74e2f492e94327da19f635d10ed6b5961195e7dd
https://github.com/scummvm/scummvm/commit/74e2f492e94327da19f635d10ed6b5961195e7dd
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix infinite loop and freeze
Changed paths:
engines/dm/group.cpp
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index d965c81f1bb..83d7307bcbb 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -1811,7 +1811,7 @@ void GroupMan::addAllActiveGroups() {
break;
}
curThing = dungeon.getNextThing(curThing);
- } while (curThing != _vm->_thingEndOfList);
+ } while (curThing != _vm->_thingEndOfList && curThing != _vm->_thingNone);
}
}
}
Commit: 4168feae0416ee41d2fd06bc0811e9ab36155e10
https://github.com/scummvm/scummvm/commit/4168feae0416ee41d2fd06bc0811e9ab36155e10
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix memory copy size for flipped explosion and projectile sprites
Changed paths:
engines/dm/gfx.cpp
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index c7a6b2bc501..83caa28d8c5 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -3724,7 +3724,7 @@ T0115129_DrawProjectiles:
if (flipHorizontal || flipVertical) {
AL_4_normalizdByteWidth = getNormalizedByteWidth(byteWidth);
if (bitmapRedBanana != _tmpBitmap) {
- memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * AL_4_normalizdByteWidth * heightRedEagle);
+ memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * AL_4_normalizdByteWidth * 2 * heightRedEagle);
bitmapRedBanana = _tmpBitmap;
}
if (flipVertical)
@@ -3881,7 +3881,7 @@ T0115200_DrawExplosion:
byteWidth = getNormalizedByteWidth(byteWidth);
if (flipHorizontal || flipVertical) {
- memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * byteWidth * heightRedEagle);
+ memcpy(_tmpBitmap, bitmapRedBanana, sizeof(byte) * byteWidth * 2 * heightRedEagle);
bitmapRedBanana = _tmpBitmap;
}
Commit: 349cef0e0050cfba95b61db64cc7e9cf613bbc13
https://github.com/scummvm/scummvm/commit/349cef0e0050cfba95b61db64cc7e9cf613bbc13
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix crash when decoding text scrolls
When decoding scrolls, the text index is passed wrapped in a type-less Thing.
Using the index-based getTextString overload avoids the failed type assertion.
Changed paths:
engines/dm/dungeonman.cpp
diff --git a/engines/dm/dungeonman.cpp b/engines/dm/dungeonman.cpp
index 87b98c02152..fe04b9aaa9e 100644
--- a/engines/dm/dungeonman.cpp
+++ b/engines/dm/dungeonman.cpp
@@ -1424,7 +1424,7 @@ void DungeonMan::decodeText(char *destString, size_t maxSize, Thing thing, int16
{0, 0, 0, 0, 0, 0, 0, 0}
};
- TextString &textString = *getTextString(thing);
+ TextString &textString = *getTextString(thing.getIndex());
if ((textString.isVisible()) || (type & kDMMaskDecodeEvenIfInvisible)) {
type &= ~kDMMaskDecodeEvenIfInvisible;
char sepChar;
Commit: 3727f7ee452a1931a148cdb4f35612da10aa2312
https://github.com/scummvm/scummvm/commit/3727f7ee452a1931a148cdb4f35612da10aa2312
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Remove mouse pointer request count startup warning
The warning is obsolete because ScummVM inverted the original show/hide request logic, making 0 the correct starting value instead of 1.
Changed paths:
engines/dm/eventman.cpp
diff --git a/engines/dm/eventman.cpp b/engines/dm/eventman.cpp
index 3080b0d85ad..f701ea3c19f 100644
--- a/engines/dm/eventman.cpp
+++ b/engines/dm/eventman.cpp
@@ -377,7 +377,6 @@ EventManager::EventManager(DMEngine *vm) : _vm(vm) {
_primaryKeyboardInput = nullptr;
_secondaryKeyboardInput = nullptr;
_ignoreMouseMovements = false;
- warning("_g587_hideMousePointerRequestCount should start with value 1");
_hideMousePointerRequestCount = 0;
_mouseButtonStatus = 0;
_highlightScreenBox.setToZero();
Commit: 3ba93b70a9ff7eb0a801206d869c3f81e5af7aab
https://github.com/scummvm/scummvm/commit/3ba93b70a9ff7eb0a801206d869c3f81e5af7aab
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Add translatation for 'LOAD' in the save menu
German and French
Changed paths:
engines/dm/loadsave.cpp
diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp
index bef83562b9e..84b4b2892e2 100644
--- a/engines/dm/loadsave.cpp
+++ b/engines/dm/loadsave.cpp
@@ -169,10 +169,10 @@ void DMEngine::saveGame() {
_dialog->dialogDraw(nullptr, nullptr, "SAVE AND PLAY", "SAVE AND QUIT", "CANCEL", "LOAD", false, false, false);
break;
case Common::DE_DEU:
- _dialog->dialogDraw(nullptr, nullptr, "SICHERN/SPIEL", "SICHERN/ENDEN", "WIDERRUFEN", "LOAD", false, false, false);
+ _dialog->dialogDraw(nullptr, nullptr, "SICHERN/SPIEL", "SICHERN/ENDEN", "WIDERRUFEN", "LADEN", false, false, false);
break;
case Common::FR_FRA:
- _dialog->dialogDraw(nullptr, nullptr, "GARDER/JOUER", "GARDER/SORTIR", "ANNULLER", "LOAD", false, false, false);
+ _dialog->dialogDraw(nullptr, nullptr, "GARDER/JOUER", "GARDER/SORTIR", "ANNULLER", "CHARGER", false, false, false);
break;
}
Commit: 20f1d7944789fa8b7922bfa8d4da6dbca884d792
https://github.com/scummvm/scummvm/commit/20f1d7944789fa8b7922bfa8d4da6dbca884d792
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix left shift of negative value runtime error
Fixes potential undefined behaviour
Changed paths:
engines/dm/dungeonman.cpp
engines/dm/group.cpp
engines/dm/inventory.cpp
diff --git a/engines/dm/dungeonman.cpp b/engines/dm/dungeonman.cpp
index fe04b9aaa9e..d0c23d86b97 100644
--- a/engines/dm/dungeonman.cpp
+++ b/engines/dm/dungeonman.cpp
@@ -1192,7 +1192,7 @@ void DungeonMan::setSquareAspectOrnOrdinals(uint16 *aspectArray, bool leftAllowe
}
int16 DungeonMan::getRandomOrnOrdinal(bool allowed, int16 count, int16 mapX, int16 mapY, int16 modulo) {
- int16 randomOrnamentIndex = getRandomOrnamentIndex((int16)2000 + (mapX << 5) + mapY, (int16)3000 + (_currMapIndex << (int16)6) + _currMapWidth + _currMapHeight, modulo);
+ int16 randomOrnamentIndex = getRandomOrnamentIndex((int16)2000 + (mapX * 32) + mapY, (int16)3000 + (_currMapIndex * 64) + _currMapWidth + _currMapHeight, modulo);
if (allowed && (randomOrnamentIndex < count))
return _vm->indexToOrdinal(randomOrnamentIndex);
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index 83d7307bcbb..9ac68b90049 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -1256,10 +1256,10 @@ int16 GroupMan::getDistanceBetweenUnblockedSquares(int16 srcMapX, int16 srcMapY,
if (isDistanceXSmallerThanDistanceY) {
largestAxisDistance = pathMapY - srcMapY;
- valueC = (largestAxisDistance ? ((pathMapX - srcMapX) << 6) / largestAxisDistance : 128);
+ valueC = (largestAxisDistance ? ((pathMapX - srcMapX) * 64) / largestAxisDistance : 128);
} else {
largestAxisDistance = pathMapX - srcMapX;
- valueC = (largestAxisDistance ? ((pathMapY - srcMapY) << 6) / largestAxisDistance : 128);
+ valueC = (largestAxisDistance ? ((pathMapY - srcMapY) * 64) / largestAxisDistance : 128);
}
/* 128 when the creature is on the same row or column as the party */
@@ -1271,11 +1271,11 @@ int16 GroupMan::getDistanceBetweenUnblockedSquares(int16 srcMapX, int16 srcMapY,
return 0;
} else {
if (isDistanceXSmallerThanDistanceY) {
- valueA = ABS(((pathMapY - srcMapY) ? ((pathMapX + axisStepX - srcMapX) << 6) / largestAxisDistance : 128) - valueC);
- valueB = ABS(((pathMapY + axisStepY - srcMapY) ? ((pathMapX - srcMapX) << 6) / largestAxisDistance : 128) - valueC);
+ valueA = ABS(((pathMapY - srcMapY) ? ((pathMapX + axisStepX - srcMapX) * 64) / largestAxisDistance : 128) - valueC);
+ valueB = ABS(((pathMapY + axisStepY - srcMapY) ? ((pathMapX - srcMapX) * 64) / largestAxisDistance : 128) - valueC);
} else {
- valueA = ABS(((pathMapX + axisStepX - srcMapX) ? ((pathMapY - srcMapY) << 6) / largestAxisDistance : 128) - valueC);
- valueB = ABS(((pathMapX - srcMapX) ? ((pathMapY + axisStepY - srcMapY) << 6) / largestAxisDistance : 128) - valueC);
+ valueA = ABS(((pathMapX + axisStepX - srcMapX) ? ((pathMapY - srcMapY) * 64) / largestAxisDistance : 128) - valueC);
+ valueB = ABS(((pathMapX - srcMapX) ? ((pathMapY + axisStepY - srcMapY) * 64) / largestAxisDistance : 128) - valueC);
}
if (valueA < valueB)
diff --git a/engines/dm/inventory.cpp b/engines/dm/inventory.cpp
index 4d1ae04dda7..e77c76186ef 100644
--- a/engines/dm/inventory.cpp
+++ b/engines/dm/inventory.cpp
@@ -404,7 +404,7 @@ void InventoryMan::drawIconToViewport(IconIndice iconIndex, int16 xPos, int16 yP
void InventoryMan::buildObjectAttributeString(int16 potentialAttribMask, int16 actualAttribMask, const char **attribStrings, char *destString, const char *prefixString, const char *suffixString) {
uint16 identicalBitCount = 0;
- int16 attribMask = 1;
+ uint16 attribMask = 1;
for (uint16 stringIndex = 0; stringIndex < 16; stringIndex++, attribMask <<= 1) {
if (attribMask & potentialAttribMask & actualAttribMask)
identicalBitCount++;
Commit: ead34bc5f46016931e6f39e6b2c097ce610d867e
https://github.com/scummvm/scummvm/commit/ead34bc5f46016931e6f39e6b2c097ce610d867e
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix crash in fuse sequence by updating loop iterator after unlinking fluxcage
Changed paths:
engines/dm/dm.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 29c8894d6e1..94cbba94a54 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -938,6 +938,7 @@ void DMEngine::fuseSequence() {
if (curExplosion->getType() == kDMExplosionTypeFluxcage) {
_dungeonMan->unlinkThingFromList(curThing, Thing(0), fluxCageMapX, fluxcageMapY);
curExplosion->setNextThing(_thingNone);
+ curThing = _dungeonMan->getSquareFirstObject(fluxCageMapX, fluxcageMapY);
continue;
}
}
Commit: 73c2dec4ec39755c501f0e4ab032b031f90fc47d
https://github.com/scummvm/scummvm/commit/73c2dec4ec39755c501f0e4ab032b031f90fc47d
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix text corruption in message by resetting string for each word
Reset wrkString inside the loop so it only prints the current word, and removed the redundant manual \0 append which blocked reading past the first word.
Changed paths:
engines/dm/text.cpp
diff --git a/engines/dm/text.cpp b/engines/dm/text.cpp
index 4ac98ec21dd..47cceaf483b 100644
--- a/engines/dm/text.cpp
+++ b/engines/dm/text.cpp
@@ -107,7 +107,6 @@ void TextMan::printLineFeed() {
void TextMan::printMessage(Color color, const char *string, bool printWithScroll) {
uint16 characterIndex;
- Common::String wrkString;
while (*string) {
if (*string == '\n') { /* New line */
@@ -122,12 +121,12 @@ void TextMan::printMessage(Color color, const char *string, bool printWithScroll
printString(color, " "); // I'm not sure if this is like the original
}
} else {
+ Common::String wrkString;
characterIndex = 0;
do {
wrkString += *string++;
characterIndex++;
} while (*string && (*string != ' ') && (*string != '\n')); /* End of string, space or New line */
- wrkString += '\0';
if (_messageAreaCursorColumn + characterIndex > 53) {
_messageAreaCursorColumn = 2;
createNewRow();
Commit: 8dbf7e13c3267efd4deecd7c5fc15e4676bc9aeb
https://github.com/scummvm/scummvm/commit/8dbf7e13c3267efd4deecd7c5fc15e4676bc9aeb
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix message area text cutoff
Pauses createNewRow() if text is scrolling to ensure the current line buffer is drawn to the screen before clearing it for the next line.
Changed paths:
engines/dm/text.cpp
diff --git a/engines/dm/text.cpp b/engines/dm/text.cpp
index 47cceaf483b..47d8a782d87 100644
--- a/engines/dm/text.cpp
+++ b/engines/dm/text.cpp
@@ -137,6 +137,9 @@ void TextMan::printMessage(Color color, const char *string, bool printWithScroll
}
void TextMan::createNewRow() {
+ while (_isScrolling)
+ _vm->delay(10);
+
if (_messageAreaCursorRow == 3) {
isTextScrolling(&_textScroller, true);
memset(_bitmapMessageAreaNewRow, kDMColorBlack, 320 * 7);
Commit: b8e0b25f5c2cd8baad8c6f77e42222b445dcd447
https://github.com/scummvm/scummvm/commit/b8e0b25f5c2cd8baad8c6f77e42222b445dcd447
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Increase fuse sequence animation delay to match original pacing
Changed paths:
engines/dm/dm.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 94cbba94a54..7678a4a5647 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -1032,7 +1032,7 @@ void DMEngine::fuseSequenceUpdate() {
_sound->playPendingSound();
_eventMan->discardAllInput();
_displayMan->updateScreen();
- delay(2);
+ delay(6);
_gameTime++; /* BUG0_71 Some timings are too short on fast computers.
The ending animation when Lord Chaos is fused plays too quickly because the execution speed is not limited */
}
Commit: b083c6cda2e78afddc149c75e6be38cd632e6acd
https://github.com/scummvm/scummvm/commit/b083c6cda2e78afddc149c75e6be38cd632e6acd
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix typo incrementing a prarmeter twice
Changed paths:
engines/dm/dm.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 7678a4a5647..c6f63282c40 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -658,7 +658,7 @@ void DMEngine::endGame(bool doNotDrawCreditsOnly) {
championMirrorBox._rect.top += 48;
championMirrorBox._rect.bottom += 48;
championPortraitBox._rect.top += 48;
- championPortraitBox._rect.top += 48;
+ championPortraitBox._rect.bottom += 48;
}
_displayMan->startEndFadeToPalette(_displayMan->_paletteTopAndBottomScreen);
_engineShouldQuit = true;
Commit: d9a6378524d1dd7363fa7ee7db9bf2f9f45fa6ac
https://github.com/scummvm/scummvm/commit/d9a6378524d1dd7363fa7ee7db9bf2f9f45fa6ac
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Fix endgame flow by waiting for input on portraits screen
Changed paths:
engines/dm/dm.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index c6f63282c40..511bbffb331 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -661,8 +661,8 @@ void DMEngine::endGame(bool doNotDrawCreditsOnly) {
championPortraitBox._rect.bottom += 48;
}
_displayMan->startEndFadeToPalette(_displayMan->_paletteTopAndBottomScreen);
+ _eventMan->waitForMouseOrKeyActivity();
_engineShouldQuit = true;
- return;
}
T0444017:
_displayMan->fillScreen(kDMColorBlack);
Commit: ff01ea57e9ae683f2d9e190e2109e75440870fc3
https://github.com/scummvm/scummvm/commit/ff01ea57e9ae683f2d9e190e2109e75440870fc3
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Support return to launcher on exit
Changed paths:
engines/dm/dm.cpp
engines/dm/eventman.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 511bbffb331..abc9b2d7103 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -206,7 +206,8 @@ DMEngine::~DMEngine() {
bool DMEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsSavingDuringRuntime) ||
- (f == kSupportsLoadingDuringRuntime);
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsReturnToLauncher);
}
Common::Error DMEngine::loadGameState(int slot) {
diff --git a/engines/dm/eventman.cpp b/engines/dm/eventman.cpp
index f701ea3c19f..d7678fee3f9 100644
--- a/engines/dm/eventman.cpp
+++ b/engines/dm/eventman.cpp
@@ -661,6 +661,7 @@ Common::EventType EventManager::processInput(Common::Event *grabKey, Common::Eve
break;
}
case Common::EVENT_QUIT:
+ case Common::EVENT_RETURN_TO_LAUNCHER:
_vm->_engineShouldQuit = true;
break;
default:
@@ -1438,7 +1439,7 @@ void EventManager::drawSleepScreen() {
void EventManager::discardAllInput() {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event) && !_vm->_engineShouldQuit) {
- if (event.type == Common::EVENT_QUIT)
+ if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RETURN_TO_LAUNCHER)
_vm->_engineShouldQuit = true;
}
_commandQueue.clear();
@@ -1649,6 +1650,7 @@ void EventManager::waitForMouseOrKeyActivity() {
if (g_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_QUIT:
+ case Common::EVENT_RETURN_TO_LAUNCHER:
_vm->_engineShouldQuit = true;
case Common::EVENT_KEYDOWN: // Intentional fall through
case Common::EVENT_LBUTTONDOWN:
Commit: 0fd953410abcbc30e8456c079a8d880b59c88083
https://github.com/scummvm/scummvm/commit/0fd953410abcbc30e8456c079a8d880b59c88083
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Initialize _doNotDrawFluxcagesDuringEndgame in DisplayMan
Changed paths:
engines/dm/gfx.cpp
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index 83caa28d8c5..c98d4019290 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -164,6 +164,7 @@ DisplayMan::DisplayMan(DMEngine *dmEngine) : _vm(dmEngine) {
_paletteFadeTemporary[i] = 0;
_refreshDungeonViewPaleteRequested = false;
+ _doNotDrawFluxcagesDuringEndgame = false;
initConstants();
}
Commit: 8db0088be609c6118299f3a5a4590ea348e37388
https://github.com/scummvm/scummvm/commit/8db0088be609c6118299f3a5a4590ea348e37388
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Prevent final endgame explosion from disappearing
Changed paths:
engines/dm/dm.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index abc9b2d7103..3902553c785 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -1019,6 +1019,8 @@ void DMEngine::fuseSequence() {
for (int16 attackId = 55; attackId <= 255; attackId += 40) {
_projexpl->createExplosion(_thingExplHarmNonMaterial, attackId, lordChaosMapX, lordChaosMapY, kDMCreatureTypeSingleCenteredCreature);
+ if (attackId == 255)
+ continue;
fuseSequenceUpdate();
}
Commit: 4400d18634cf223b0379e8fe2dfcef862c48ef9c
https://github.com/scummvm/scummvm/commit/4400d18634cf223b0379e8fe2dfcef862c48ef9c
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Correctly initialize _thingNone to prevent crashes
Changed paths:
engines/dm/champion.cpp
engines/dm/dm.cpp
engines/dm/dm.h
engines/dm/dungeonman.cpp
engines/dm/dungeonman.h
engines/dm/eventman.cpp
engines/dm/group.cpp
engines/dm/group.h
engines/dm/inventory.cpp
engines/dm/loadsave.cpp
engines/dm/menus.cpp
engines/dm/movesens.cpp
engines/dm/projexpl.cpp
engines/dm/timeline.cpp
diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp
index 299c7ec550d..f35d1feb9a2 100644
--- a/engines/dm/champion.cpp
+++ b/engines/dm/champion.cpp
@@ -171,7 +171,7 @@ ChampionMan::ChampionMan(DMEngine *vm) : _vm(vm) {
}
_partyChampionCount = 0;
_partyDead = false;
- _leaderHandObject = Thing(0);
+ _leaderHandObject = Thing(0xFFFF);
_leaderIndex = kDMChampionNone;
_candidateChampionOrdinal = 0;
_partyIsSleeping = false;
@@ -1806,8 +1806,10 @@ void ChampionMan::loadPartyPart2(Common::InSaveFile *file) {
for (uint16 y = 0; y < 7; ++y)
for (uint16 x = 0; x < 3; ++x)
champ->_statistics[y][x] = file->readByte();
- for (uint16 j = 0; j < 30; ++j)
- champ->_slots[j] = Thing(file->readUint16BE());
+ for (uint16 j = 0; j < 30; ++j) {
+ uint16 val = file->readUint16BE();
+ champ->_slots[j] = (val == 0) ? _vm->_thingNone : Thing(val);
+ }
for (uint16 j = 0; j < 20; ++j) {
champ->_skills[j]._temporaryExperience = file->readSint16BE();
champ->_skills[j]._experience = file->readSint32BE();
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 3902553c785..d10bdde19f3 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -119,7 +119,7 @@ int16 DMEngine::getDistance(int16 mapx1, int16 mapy1, int16 mapx2, int16 mapy2)
DMEngine::DMEngine(OSystem *syst, const DMADGameDescription *desc) :
Engine(syst), _console(nullptr), _gameVersion(desc),
- _thingNone(0), _thingEndOfList(0xFFFE), _thingFirstExplosion(0xFF80),
+ _thingNone(0xFFFF), _thingEndOfList(0xFFFE), _thingFirstExplosion(0xFF80),
_thingExplFireBall(0xFF80), _thingExplSlime(0xFF81), _thingExplLightningBolt(0xFF82),
_thingExplHarmNonMaterial(0xFF83), _thingExplOpenDoor(0xFF84), _thingExplPoisonBolt(0xFF86),
_thingExplPoisonCloud(0xFF87), _thingExplSmoke(0xFFA8), _thingExplFluxcage(0xFFB2),
@@ -937,7 +937,7 @@ void DMEngine::fuseSequence() {
if (curThing.getType() == kDMThingTypeExplosion) {
Explosion *curExplosion = _dungeonMan->getExplosion(curThing);
if (curExplosion->getType() == kDMExplosionTypeFluxcage) {
- _dungeonMan->unlinkThingFromList(curThing, Thing(0), fluxCageMapX, fluxcageMapY);
+ _dungeonMan->unlinkThingFromList(curThing, Thing(0xFFFF), fluxCageMapX, fluxcageMapY);
curExplosion->setNextThing(_thingNone);
curThing = _dungeonMan->getSquareFirstObject(fluxCageMapX, fluxcageMapY);
continue;
diff --git a/engines/dm/dm.h b/engines/dm/dm.h
index fe62df76d7a..d4a141d1c25 100644
--- a/engines/dm/dm.h
+++ b/engines/dm/dm.h
@@ -136,7 +136,7 @@ class Thing {
public:
uint16 _data;
- Thing() : _data(0) {}
+ Thing() : _data(0xFFFF) {}
explicit Thing(uint16 d) { set(d); }
void set(uint16 d) {
diff --git a/engines/dm/dungeonman.cpp b/engines/dm/dungeonman.cpp
index d0c23d86b97..4695d2ca418 100644
--- a/engines/dm/dungeonman.cpp
+++ b/engines/dm/dungeonman.cpp
@@ -448,7 +448,7 @@ DungeonMan::DungeonMan(DMEngine *dmEngine) : _vm(dmEngine) {
_dungeonFileHeader._squareFirstThingCount = 0;
for (uint16 i = 0; i < 5; ++i)
- _pileTopObject[i] = Thing(0);
+ _pileTopObject[i] = Thing(0xFFFF);
for (uint16 i = 0; i < 2; ++i)
_currMapDoorInfo[i].resetToZero();
for (uint16 i = 0; i < 16; i++)
@@ -776,7 +776,8 @@ void DungeonMan::loadDungeonFile(Common::InSaveFile *file) {
case kDMThingTypeGroup: {
Group &grp = _groups[i];
grp._nextThing = Thing(dunDataStream->readUint16BE());
- grp._slot = Thing(dunDataStream->readUint16BE());
+ uint16 slotVal = dunDataStream->readUint16BE();
+ grp._slot = (slotVal == 0) ? _vm->_thingNone : Thing(slotVal);
if (!file) {
grp._type = (CreatureType)dunDataStream->readByte();
grp._cells = dunDataStream->readByte();
@@ -818,7 +819,8 @@ void DungeonMan::loadDungeonFile(Common::InSaveFile *file) {
case kDMThingTypeContainer: {
Container &cont = _containers[i];
cont._nextThing = Thing(dunDataStream->readUint16BE());
- cont._slot = Thing(dunDataStream->readUint16BE());
+ uint16 slotVal = dunDataStream->readUint16BE();
+ cont._slot = (slotVal == 0) ? _vm->_thingNone : Thing(slotVal);
cont._type = dunDataStream->readUint16BE();
dunDataStream->readUint16BE(); // unused 4th word
break;
@@ -832,7 +834,8 @@ void DungeonMan::loadDungeonFile(Common::InSaveFile *file) {
case kDMThingTypeProjectile: {
Projectile &proj = _projectiles[i];
proj._nextThing = Thing(dunDataStream->readUint16BE());
- proj._slot = Thing(dunDataStream->readUint16BE());
+ uint16 slotVal = dunDataStream->readUint16BE();
+ proj._slot = (slotVal == 0) ? _vm->_thingNone : Thing(slotVal);
if (!file) {
proj._kineticEnergy = dunDataStream->readByte();
proj._attack = dunDataStream->readByte();
@@ -1816,7 +1819,7 @@ Thing DungeonMan::getDiscardThing(uint16 thingType) {
groupMan.groupDelete(currMapX, currMapY);
} else {
projExpl.projectileDeleteEvent(squareThing);
- unlinkThingFromList(squareThing, Thing(0), currMapX, currMapY);
+ unlinkThingFromList(squareThing, Thing(0xFFFF), currMapX, currMapY);
projExpl.projectileDelete(squareThing, nullptr, currMapX, currMapY);
}
break;
diff --git a/engines/dm/dungeonman.h b/engines/dm/dungeonman.h
index fdf859a8b26..2b25cf15f85 100644
--- a/engines/dm/dungeonman.h
+++ b/engines/dm/dungeonman.h
@@ -336,7 +336,7 @@ class Door {
public:
Thing _nextThing;
uint16 _attributes;
- Door() : _nextThing(0), _attributes(0) {}
+ Door() : _nextThing(0xFFFF), _attributes(0) {}
Thing getNextThing() { return _nextThing; }
bool isMeleeDestructible() { return (_attributes >> 8) & 1; }
bool isMagicDestructible() { return (_attributes >> 7) & 1; }
@@ -351,7 +351,7 @@ public:
Thing _nextThing;
uint16 _attributes;
uint16 _destMapIndex;
- Teleporter() : _nextThing(0), _attributes(0), _destMapIndex(0) {}
+ Teleporter() : _nextThing(0xFFFF), _attributes(0), _destMapIndex(0) {}
Thing getNextThing() { return _nextThing; }
bool isAudible() { return (_attributes >> 15) & 1; }
TeleporterScope getScope() { return (TeleporterScope)((_attributes >> 13) & 3); }
@@ -366,7 +366,7 @@ class TextString {
public:
Thing _nextThing;
uint16 _textDataRef;
- TextString() : _nextThing(0), _textDataRef(0) {}
+ TextString() : _nextThing(0xFFFF), _textDataRef(0) {}
Thing getNextThing() { return _nextThing; }
uint16 getWordOffset() { return _textDataRef >> 3; }
@@ -380,7 +380,7 @@ public:
uint16 _datAndType;
uint16 _attributes; // A
uint16 _action; // B
- Sensor() : _nextThing(0), _datAndType(0), _attributes(0), _action(0) {}
+ Sensor() : _nextThing(0xFFFF), _datAndType(0), _attributes(0), _action(0) {}
Thing getNextThing() { return _nextThing; }
void setNextThing(Thing thing) { _nextThing = thing; }
@@ -416,7 +416,7 @@ class Weapon {
public:
Thing _nextThing;
uint16 _desc;
- Weapon() : _nextThing(0), _desc(0) {}
+ Weapon() : _nextThing(0xFFFF), _desc(0) {}
WeaponType getType() { return (WeaponType)(_desc & 0x7F); }
void setType(uint16 val) { _desc = (_desc & ~0x7F) | (val & 0x7F); }
@@ -443,7 +443,7 @@ class Armour {
public:
Thing _nextThing;
uint16 _attributes;
- Armour() : _nextThing(0), _attributes(0) {}
+ Armour() : _nextThing(0xFFFF), _attributes(0) {}
ArmourType getType() { return (ArmourType)(_attributes & 0x7F); }
Thing getNextThing() { return _nextThing; }
@@ -460,7 +460,7 @@ class Scroll {
public:
Thing _nextThing;
uint16 _attributes;
- Scroll() : _nextThing(0), _attributes(0) {}
+ Scroll() : _nextThing(0xFFFF), _attributes(0) {}
void set(Thing next, uint16 attribs) {
_nextThing = next;
_attributes = attribs;
@@ -480,7 +480,7 @@ class Potion {
public:
Thing _nextThing;
uint16 _attributes;
- Potion() : _nextThing(0), _attributes(0) {}
+ Potion() : _nextThing(0xFFFF), _attributes(0) {}
PotionType getType() { return (PotionType)((_attributes >> 8) & 0x7F); }
void setType(PotionType val) { _attributes = (_attributes & ~(0x7F << 8)) | ((val & 0x7F) << 8); }
@@ -495,7 +495,7 @@ public:
Thing _nextThing;
Thing _slot;
uint16 _type;
- Container() : _nextThing(0), _slot(0), _type(0) {}
+ Container() : _nextThing(0xFFFF), _slot(0xFFFF), _type(0) {}
uint16 getType() { return (_type >> 1) & 0x3; }
Thing &getSlot() { return _slot; }
@@ -506,7 +506,7 @@ class Junk {
public:
Thing _nextThing;
uint16 _attributes;
- Junk() : _nextThing(0), _attributes(0) {}
+ Junk() : _nextThing(0xFFFF), _attributes(0) {}
JunkType getType() { return (JunkType)(_attributes & 0x7F); }
void setType(uint16 val) { _attributes = (_attributes & ~0x7F) | (val & 0x7F); }
@@ -527,7 +527,7 @@ public:
uint16 _kineticEnergy;
uint16 _attack;
uint16 _eventIndex;
- Projectile() : _nextThing(0), _slot(0), _kineticEnergy(0), _attack(0), _eventIndex(0) {}
+ Projectile() : _nextThing(0xFFFF), _slot(0xFFFF), _kineticEnergy(0), _attack(0), _eventIndex(0) {}
}; // @ PROJECTILE
@@ -535,7 +535,7 @@ class Explosion {
public:
Thing _nextThing;
uint16 _attributes;
- Explosion() : _nextThing(0), _attributes(0) {}
+ Explosion() : _nextThing(0xFFFF), _attributes(0) {}
Thing getNextThing() { return _nextThing; }
Thing setNextThing(Thing val) { return _nextThing = val; }
diff --git a/engines/dm/eventman.cpp b/engines/dm/eventman.cpp
index d7678fee3f9..d2ac431f680 100644
--- a/engines/dm/eventman.cpp
+++ b/engines/dm/eventman.cpp
@@ -1272,7 +1272,7 @@ void EventManager::commandProcessCommands160To162ClickInResurrectReincarnatePane
for (uint16 slotIndex = kDMSlotReadyHand; slotIndex < kDMSlotChest1; slotIndex++) {
Thing thing = champ->getSlot((ChampionSlot)slotIndex);
if (thing != _vm->_thingNone) {
- _vm->_dungeonMan->unlinkThingFromList(thing, Thing(0), mapX, mapY);
+ _vm->_dungeonMan->unlinkThingFromList(thing, Thing(0xFFFF), mapX, mapY);
}
}
Thing thing = dunMan.getSquareFirstThing(mapX, mapY);
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index 9ac68b90049..c82be1b7363 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -50,13 +50,13 @@ GroupMan::GroupMan(DMEngine *vm) : _vm(vm) {
_fluxCages[i] = 0;
_currentGroupMapX = 0;
_currentGroupMapY = 0;
- _currGroupThing = Thing(0);
+ _currGroupThing = Thing(0xFFFF);
for (uint16 i = 0; i < 4; ++i)
_groupMovementTestedDirections[i] = 0;
_currGroupDistanceToParty = 0;
_currGroupPrimaryDirToParty = 0;
_currGroupSecondaryDirToParty = 0;
- _groupMovementBlockedByGroupThing = Thing(0);
+ _groupMovementBlockedByGroupThing = Thing(0xFFFF);
_groupMovementBlockedByDoor = false;
_groupMovementBlockedByParty = false;
_groupMovBlockedByWallStairsPitFakeWalFluxCageTeleporter = false;
@@ -1987,7 +1987,7 @@ void GroupMan::fluxCageAction(int16 mapX, int16 mapY) {
if (unusedThing == _vm->_thingNone)
return;
- dungeon.linkThingToList(unusedThing, Thing(0), mapX, mapY);
+ dungeon.linkThingToList(unusedThing, Thing(0xFFFF), mapX, mapY);
dungeon.getExplosion(unusedThing)->setType(kDMExplosionTypeFluxcage);
TimelineEvent newEvent;
newEvent._mapTime = _vm->setMapAndTime(dungeon._currMapIndex, _vm->_gameTime + 100);
diff --git a/engines/dm/group.h b/engines/dm/group.h
index 43785a5ae09..a50756c7ecb 100644
--- a/engines/dm/group.h
+++ b/engines/dm/group.h
@@ -132,7 +132,7 @@ public:
uint16 _cells;
uint16 _health[4];
uint16 _flags;
- Group() : _nextThing(0), _slot(0), _type((CreatureType)0), _cells(0), _flags(0) {
+ Group() : _nextThing(0xFFFF), _slot(0xFFFF), _type((CreatureType)0), _cells(0), _flags(0) {
_health[0] = _health[1] = _health[2] = _health[3] = 0;
}
diff --git a/engines/dm/inventory.cpp b/engines/dm/inventory.cpp
index e77c76186ef..0326e9445e9 100644
--- a/engines/dm/inventory.cpp
+++ b/engines/dm/inventory.cpp
@@ -72,7 +72,7 @@ InventoryMan::InventoryMan(DMEngine *vm) : _vm(vm) {
_inventoryChampionOrdinal = 0;
_panelContent = kDMPanelContentFoodWaterPoisoned;
for (uint16 i = 0; i < 8; ++i)
- _chestSlots[i] = Thing(0);
+ _chestSlots[i] = Thing(0xFFFF);
_openChest = _vm->_thingNone;
_objDescTextXpos = 0;
_objDescTextYpos = 0;
diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp
index 84b4b2892e2..1a9aca722ac 100644
--- a/engines/dm/loadsave.cpp
+++ b/engines/dm/loadsave.cpp
@@ -106,7 +106,8 @@ LoadgameResult DMEngine::loadgame(int16 slot) {
_disabledMovementTicks = file->readSint16BE();
_projectileDisableMovementTicks = file->readSint16BE();
_lastProjectileDisabledMovementDirection = file->readSint16BE();
- _championMan->_leaderHandObject = Thing(file->readUint16BE());
+ uint16 handVal = file->readUint16BE();
+ _championMan->_leaderHandObject = (handVal == 0) ? _thingNone : Thing(handVal);
_groupMan->_maxActiveGroupCount = file->readUint16BE();
if (!_restartGameRequest) {
_timeline->initTimeline();
diff --git a/engines/dm/menus.cpp b/engines/dm/menus.cpp
index d6c5c584b7c..77ee0274009 100644
--- a/engines/dm/menus.cpp
+++ b/engines/dm/menus.cpp
@@ -154,7 +154,7 @@ MenuMan::MenuMan(DMEngine *vm) : _vm(vm) {
_actionList.resetToZero();
_bitmapSpellAreaLine = new byte[96 * 12];
_bitmapSpellAreaLines = new byte[3 * 96 * 12];
- _actionTargetGroupThing = Thing(0);
+ _actionTargetGroupThing = Thing(0xFFFF);
_actionCount = 0;
initConstants();
diff --git a/engines/dm/movesens.cpp b/engines/dm/movesens.cpp
index 4c7c8197d2e..b30f9df7059 100644
--- a/engines/dm/movesens.cpp
+++ b/engines/dm/movesens.cpp
@@ -135,14 +135,14 @@ bool MovesensMan::sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16
if (leaderHandObject == _vm->_thingNone)
continue;
- dungeon.unlinkThingFromList(leaderHandObject, Thing(0), mapX, mapY);
+ dungeon.unlinkThingFromList(leaderHandObject, Thing(0xFFFF), mapX, mapY);
_vm->_championMan->putObjectInLeaderHand(leaderHandObject, true);
} else {
if ((_vm->_objectMan->getObjectType(leaderHandObject) != sensorData) || (getObjectOfTypeInCell(mapX, mapY, cellIdx, sensorData) != _vm->_thingNone))
continue;
_vm->_championMan->getObjectRemovedFromLeaderHand();
- dungeon.linkThingToList(_vm->thingWithNewCell(leaderHandObject, cellIdx), Thing(0), mapX, mapY);
+ dungeon.linkThingToList(_vm->thingWithNewCell(leaderHandObject, cellIdx), Thing(0xFFFF), mapX, mapY);
leaderHandObject = _vm->_thingNone;
}
triggerLocalEffect(kDMSensorEffectToggle, mapX, mapY, cellIdx); /* This will cause a rotation of the sensors at the specified cell on the specified square after all sensors have been processed */
@@ -160,9 +160,9 @@ bool MovesensMan::sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16
if ((_vm->_objectMan->getObjectType(leaderHandObject) != sensorData) || (thingOnSquare == _vm->_thingNone))
continue;
- dungeon.unlinkThingFromList(thingOnSquare, Thing(0), mapX, mapY);
+ dungeon.unlinkThingFromList(thingOnSquare, Thing(0xFFFF), mapX, mapY);
_vm->_championMan->getObjectRemovedFromLeaderHand();
- dungeon.linkThingToList(_vm->thingWithNewCell(leaderHandObject, cellIdx), Thing(0), mapX, mapY);
+ dungeon.linkThingToList(_vm->thingWithNewCell(leaderHandObject, cellIdx), Thing(0xFFFF), mapX, mapY);
_vm->_championMan->putObjectInLeaderHand(thingOnSquare, true);
doNotTriggerSensor = false;
}
@@ -456,7 +456,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
moveGroupResult = true;
}
if (thingLevitates)
- dungeon.linkThingToList(thing, Thing(0), destMapX, destMapY);
+ dungeon.linkThingToList(thing, Thing(0xFFFF), destMapX, destMapY);
else
processThingAdditionOrRemoval(destMapX, destMapY, thing, false, true);
@@ -474,7 +474,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
}
dungeon.setCurrentMap(mapIndexDestination);
if (thingType == kDMThingTypeProjectile) /* BUG0_29 An explosion can trigger a floor sensor. Explosions do not trigger floor sensors on the square where they are created. However, if an explosion is moved by a teleporter (or by falling into a pit, see BUG0_26) after it was created, it can trigger floor sensors on the destination square. This is because explosions are not considered as levitating in the code, while projectiles are. The condition here should be (L0713_B_ThingLevitates) so that explosions would not start sensor processing on their destination square as they should be Levitating. This would work if F0264_MOVE_IsLevitating returned true for explosions (see BUG0_26) */
- dungeon.linkThingToList(thing, Thing(0), destMapX, destMapY);
+ dungeon.linkThingToList(thing, Thing(0xFFFF), destMapX, destMapY);
else
processThingAdditionOrRemoval(destMapX, destMapY, thing, (dungeon._currMapIndex == dungeon._partyMapIndex) && (destMapX == dungeon._partyMapX) && (destMapY == dungeon._partyMapY), true);
@@ -712,7 +712,7 @@ void MovesensMan::processThingAdditionOrRemoval(uint16 mapX, uint16 mapY, Thing
}
if ((!addThing) && (thingType != kDMThingTypeParty))
- dungeon.unlinkThingFromList(thing, Thing(0), mapX, mapY);
+ dungeon.unlinkThingFromList(thing, Thing(0xFFFF), mapX, mapY);
Square curSquare = Square(dungeon._currMapData[mapX][mapY]);
int16 sensorTriggeredCell;
@@ -752,7 +752,7 @@ void MovesensMan::processThingAdditionOrRemoval(uint16 mapX, uint16 mapY, Thing
}
}
if (addThing && (thingType != kDMThingTypeParty))
- dungeon.linkThingToList(thing, Thing(0), mapX, mapY);
+ dungeon.linkThingToList(thing, Thing(0xFFFF), mapX, mapY);
for (curThing = dungeon.getSquareFirstThing(mapX, mapY); curThing != _vm->_thingEndOfList; curThing = dungeon.getNextThing(curThing)) {
uint16 curThingType = curThing.getType();
@@ -980,7 +980,7 @@ void MovesensMan::processRotationEffect() {
}
if (lastSensorThing == _vm->_thingEndOfList)
break;
- dungeon.unlinkThingFromList(firstSensorThing, Thing(0), _sensorRotationEffMapX, _sensorRotationEffMapY);
+ dungeon.unlinkThingFromList(firstSensorThing, Thing(0xFFFF), _sensorRotationEffMapX, _sensorRotationEffMapY);
Sensor *lastSensor = dungeon.getSensor(lastSensorThing);
lastSensorThing = dungeon.getNextThing(lastSensorThing);
while (((lastSensorThing != _vm->_thingEndOfList) && (lastSensorThing.getType() == kDMThingTypeSensor))) {
diff --git a/engines/dm/projexpl.cpp b/engines/dm/projexpl.cpp
index 369fb37f00f..06b91401581 100644
--- a/engines/dm/projexpl.cpp
+++ b/engines/dm/projexpl.cpp
@@ -54,7 +54,7 @@ void ProjExpl::createProjectile(Thing thing, int16 mapX, int16 mapY, uint16 cell
projectilePtr->_slot = thing;
projectilePtr->_kineticEnergy = MIN((int16)kineticEnergy, (int16)255);
projectilePtr->_attack = attack;
- _vm->_dungeonMan->linkThingToList(projectileThing, Thing(0), mapX, mapY); /* Projectiles are added on the square and not 'moved' onto the square. In the case of a projectile launcher sensor, this means that the new projectile traverses the square in front of the launcher without any trouble: there is no impact if it is a wall, the projectile direction is not changed if it is a teleporter. Impacts with creatures and champions are still processed */
+ _vm->_dungeonMan->linkThingToList(projectileThing, Thing(0xFFFF), mapX, mapY); /* Projectiles are added on the square and not 'moved' onto the square. In the case of a projectile launcher sensor, this means that the new projectile traverses the square in front of the launcher without any trouble: there is no impact if it is a wall, the projectile direction is not changed if it is a teleporter. Impacts with creatures and champions are still processed */
TimelineEvent newEvent;
newEvent._mapTime = _vm->setMapAndTime(_vm->_dungeonMan->_currMapIndex, _vm->_gameTime + 1);
if (_createLauncherProjectile)
@@ -228,7 +228,7 @@ T0217044:
potion->_nextThing = _vm->_thingNone;
projectileThingData->_slot = explosionThing;
}
- _vm->_dungeonMan->unlinkThingFromList(projectileThing, Thing(0), projectileMapX, projectileMapY);
+ _vm->_dungeonMan->unlinkThingFromList(projectileThing, Thing(0xFFFF), projectileMapX, projectileMapY);
projectileDelete(projectileThing, curGroupSlot, projectileMapX, projectileMapY);
return true;
}
@@ -312,7 +312,7 @@ void ProjExpl::createExplosion(Thing explThing, uint16 attack, uint16 mapXCombo,
} else if (explThing != _vm->_thingExplSmoke)
_vm->_sound->requestPlay(kDMSoundIndexSpell, projectileMapX, projectileMapY, kDMSoundModePlayIfPrioritized);
- _vm->_dungeonMan->linkThingToList(unusedThing, Thing(0), projectileMapX, projectileMapY);
+ _vm->_dungeonMan->linkThingToList(unusedThing, Thing(0xFFFF), projectileMapX, projectileMapY);
TimelineEvent newEvent;
newEvent._mapTime = _vm->setMapAndTime(_vm->_dungeonMan->_currMapIndex, _vm->_gameTime + ((explThing == _vm->_thingExplRebirthStep1) ? 5 : 1));
newEvent._type = kDMEventTypeExplosion;
@@ -415,7 +415,7 @@ void ProjExpl::processEvents48To49(TimelineEvent *event) {
uint16 stepEnergy = curEvent->_Cu._projectile.getStepEnergy();
if (projectile->_kineticEnergy <= stepEnergy) {
- _vm->_dungeonMan->unlinkThingFromList(projectileThingNewCell = projectileThing, Thing(0), destinationMapX, destinationMapY);
+ _vm->_dungeonMan->unlinkThingFromList(projectileThingNewCell = projectileThing, Thing(0xFFFF), destinationMapX, destinationMapY);
projectileDelete(projectileThingNewCell, nullptr, destinationMapX, destinationMapY);
return;
}
@@ -462,8 +462,8 @@ void ProjExpl::processEvents48To49(TimelineEvent *event) {
if ((Square(_vm->_dungeonMan->getSquare(destinationMapX, destinationMapY)).getType() == kDMElementTypeDoor) && hasProjectileImpactOccurred(kDMElementTypeDoor, destinationMapX, destinationMapY, projectileNewCell, projectileThing))
return;
- _vm->_dungeonMan->unlinkThingFromList(projectileThingNewCell, Thing(0), destinationMapX, destinationMapY);
- _vm->_dungeonMan->linkThingToList(projectileThingNewCell, Thing(0), destinationMapX, destinationMapY);
+ _vm->_dungeonMan->unlinkThingFromList(projectileThingNewCell, Thing(0xFFFF), destinationMapX, destinationMapY);
+ _vm->_dungeonMan->linkThingToList(projectileThingNewCell, Thing(0xFFFF), destinationMapX, destinationMapY);
}
// This code is from CSB20. The projectiles move at the same speed on all maps instead of moving slower on maps other than the party map */
@@ -562,7 +562,7 @@ void ProjExpl::processEvent25(TimelineEvent *event) {
newEvent._mapTime++;
_vm->_timeline->addEventGetEventIndex(&newEvent);
} else {
- _vm->_dungeonMan->unlinkThingFromList(Thing(event->_Cu._slot), Thing(0), mapX, mapY);
+ _vm->_dungeonMan->unlinkThingFromList(Thing(event->_Cu._slot), Thing(0xFFFF), mapX, mapY);
explosion->setNextThing(_vm->_thingNone);
}
}
diff --git a/engines/dm/timeline.cpp b/engines/dm/timeline.cpp
index 055d289652f..0342343930b 100644
--- a/engines/dm/timeline.cpp
+++ b/engines/dm/timeline.cpp
@@ -307,7 +307,7 @@ void Timeline::processTimeline() {
break;
case kDMEventTypeRemoveFluxcage:
if (!_vm->_gameWon) {
- _vm->_dungeonMan->unlinkThingFromList(Thing(newEvent._Cu._slot), Thing(0), newEvent._Bu._location._mapX, newEvent._Bu._location._mapY);
+ _vm->_dungeonMan->unlinkThingFromList(Thing(newEvent._Cu._slot), Thing(0xFFFF), newEvent._Bu._location._mapX, newEvent._Bu._location._mapY);
Explosion *explosion = _vm->_dungeonMan->getExplosion(Thing(newEvent._Cu._slot));
explosion->setNextThing(_vm->_thingNone);
}
@@ -679,7 +679,7 @@ void Timeline::triggerProjectileLauncher(Sensor *sensor, TimelineEvent *event) {
if (firstProjectileAssociatedThing == _vm->_thingNone) /* BUG0_19 The game crashes when an object launcher sensor is triggered. _vm->_none should be _vm->_endOfList */
return;
- _vm->_dungeonMan->unlinkThingFromList(firstProjectileAssociatedThing, Thing(0), mapX, mapY); /* The object is removed without triggering any sensor effects */
+ _vm->_dungeonMan->unlinkThingFromList(firstProjectileAssociatedThing, Thing(0xFFFF), mapX, mapY); /* The object is removed without triggering any sensor effects */
if (!launchSingleProjectile) {
secondProjectileAssociatedThing = _vm->_dungeonMan->getSquareFirstThing(mapX, mapY);
while (secondProjectileAssociatedThing != _vm->_thingNone) { /* BUG0_19 The game crashes when an object launcher sensor is triggered. _vm->_none should be _vm->_endOfList. If there are no more objects on the square then this loop may return an undefined value, this can crash the game */
@@ -952,7 +952,7 @@ T0255002:
if (iconIndex == kDMIconIndiceJunkChampionBones) {
Junk *junkData = _vm->_dungeonMan->getJunk(curThing);
if (junkData->getChargeCount() == championIndex) {
- _vm->_dungeonMan->unlinkThingFromList(curThing, Thing(0), mapX, mapY); /* BUG0_25 When a champion dies, no bones object is created so it is not possible to bring the champion back to life at an altar of Vi. Each time a champion is brought back to life, the bones object is removed from the dungeon but it is not marked as unused and thus becomes an orphan. After a large number of champion deaths, all JUNK things are exhausted and the game cannot create any more. This also affects the creation of JUNK things dropped by some creatures when they die (Screamer, Rockpile, Magenta Worm, Pain Rat, Red Dragon) */
+ _vm->_dungeonMan->unlinkThingFromList(curThing, Thing(0xFFFF), mapX, mapY); /* BUG0_25 When a champion dies, no bones object is created so it is not possible to bring the champion back to life at an altar of Vi. Each time a champion is brought back to life, the bones object is removed from the dungeon but it is not marked as unused and thus becomes an orphan. After a large number of champion deaths, all JUNK things are exhausted and the game cannot create any more. This also affects the creation of JUNK things dropped by some creatures when they die (Screamer, Rockpile, Magenta Worm, Pain Rat, Red Dragon) */
junkData->setNextThing(_vm->_thingNone);
event->_mapTime += 1;
goto T0255002;
Commit: f732a10688f9d9a6dfa2df24c43675b29c19a50d
https://github.com/scummvm/scummvm/commit/f732a10688f9d9a6dfa2df24c43675b29c19a50d
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
`DM: Fix crash when renaming champion by ignoring out-of-bounds clicks`
Changed paths:
engines/dm/champion.cpp
diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp
index f35d1feb9a2..4c67d03ec9c 100644
--- a/engines/dm/champion.cpp
+++ b/engines/dm/champion.cpp
@@ -2541,14 +2541,11 @@ void ChampionMan::renameChampion(Champion *champ) {
curCharacter = '\b';
break;
}
-#if 0
- if ((mousePos.x < 107) || (mousePos.x > 215) || (mousePos.y < 116) || (mousePos.y > 144)) {/* Coordinates of table of all other characters */
- //goto T0281023;
- }
- if (!((mousePos.x + 4) % 10) || (!((mousePos.y + 5) % 10) && ((mousePos.x < 207) || (mousePos.y != 135)))) {
- //goto T0281023;
- }
-#endif
+ if ((mousePos.x < 107) || (mousePos.x > 215) || (mousePos.y < 116) || (mousePos.y > 144))
+ /* Coordinates of table of all other characters */
+ continue; //goto T0281023;
+ if (!((mousePos.x + 4) % 10) || (!((mousePos.y + 5) % 10) && ((mousePos.x < 207) || (mousePos.y != 135))))
+ continue; //goto T0281023;
curCharacter = 'A' + (11 * ((mousePos.y - 116) / 10)) + ((mousePos.x - 107) / 10);
if ((curCharacter == 86) || (curCharacter == 97)) {
// The 'Return' button occupies two cells in the table
Commit: 7306244681051460c4ed1ef231da6e593a2aa7b7
https://github.com/scummvm/scummvm/commit/7306244681051460c4ed1ef231da6e593a2aa7b7
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Implement support for extended saves
Changed paths:
engines/dm/champion.cpp
engines/dm/champion.h
engines/dm/dm.cpp
engines/dm/dm.h
engines/dm/dungeonman.cpp
engines/dm/dungeonman.h
engines/dm/group.cpp
engines/dm/group.h
engines/dm/loadsave.cpp
engines/dm/metaengine.cpp
engines/dm/timeline.cpp
engines/dm/timeline.h
diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp
index 4c67d03ec9c..ed64a76032e 100644
--- a/engines/dm/champion.cpp
+++ b/engines/dm/champion.cpp
@@ -1736,7 +1736,7 @@ void ChampionMan::applyTimeEffects() {
drawAllChampionStates();
}
-void ChampionMan::savePartyPart2(Common::OutSaveFile *file) {
+void ChampionMan::savePartyPart2(Common::WriteStream *file) {
for (uint16 i = 0; i < 4; ++i) {
Champion *champ = &_champions[i];
file->writeUint16BE(champ->_attributes);
@@ -1798,7 +1798,7 @@ void ChampionMan::savePartyPart2(Common::OutSaveFile *file) {
file->writeByte(party._event71Count_Invisibility);
}
-void ChampionMan::loadPartyPart2(Common::InSaveFile *file) {
+void ChampionMan::loadPartyPart2(Common::SeekableReadStream *file) {
for (uint16 i = 0; i < 4; ++i) {
Champion *champ = &_champions[i];
champ->_attributes = file->readUint16BE();
diff --git a/engines/dm/champion.h b/engines/dm/champion.h
index 18a798b572f..00eaee597a4 100644
--- a/engines/dm/champion.h
+++ b/engines/dm/champion.h
@@ -566,8 +566,8 @@ public:
void dropAllObjects(uint16 champIndex); // @ F0318_CHAMPION_DropAllObjects
void unpoison(int16 champIndex); // @ F0323_CHAMPION_Unpoison
void applyTimeEffects(); // @ F0331_CHAMPION_ApplyTimeEffects_CPSF
- void savePartyPart2(Common::OutSaveFile *file);
- void loadPartyPart2(Common::InSaveFile *file);
+ void savePartyPart2(Common::WriteStream *file);
+ void loadPartyPart2(Common::SeekableReadStream *file);
Box _boxChampionIcons[4];
Color _championColor[4];
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index d10bdde19f3..8ababf66ef1 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -230,6 +230,14 @@ bool DMEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return _canLoadFromGMM;
}
+bool DMEngine::canSaveGameStateCurrently(Common::U32String *msg) {
+ return true;
+}
+
+Common::String DMEngine::getSaveStateName(int slot) const {
+ return getMetaEngine()->getSavegameFile(slot, _targetName.c_str());
+}
+
void DMEngine::delay(uint16 verticalBlank) {
for (uint16 i = 0; i < verticalBlank * 2; ++i) {
_eventMan->processInput();
diff --git a/engines/dm/dm.h b/engines/dm/dm.h
index d4a141d1c25..de874d2de87 100644
--- a/engines/dm/dm.h
+++ b/engines/dm/dm.h
@@ -165,10 +165,6 @@ public:
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
-struct SaveGameHeader {
- byte _version;
- SaveStateDescriptor _descr;
-};
class DMEngine : public Engine {
private:
@@ -179,8 +175,9 @@ private:
void gameloop(); // @ F0002_MAIN_GameLoop_CPSDF
void initConstants();
Common::String getSavefileName(uint16 slot);
- void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName);
- bool writeCompleteSaveFile(int16 slot, Common::String &desc, int16 saveAndPlayChoice);
+ Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
+ Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
+ Common::Error writeCompleteSaveFile(Common::WriteStream *file);
void drawEntrance(); // @ F0439_STARTEND_DrawEntrance
void fuseSequenceUpdate(); // @ F0445_STARTEND_FuseSequenceUpdate
void processEntrance(); // @ F0441_STARTEND_ProcessEntrance
@@ -194,6 +191,8 @@ public:
Common::Error loadGameState(int slot) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
+ bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+ Common::String getSaveStateName(int slot) const override;
bool isDemo() const;
@@ -297,7 +296,6 @@ public:
Thing _thingParty; // @ C0xFFFF_THING_PARTY
};
-WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail = true);
} // End of namespace DM
diff --git a/engines/dm/dungeonman.cpp b/engines/dm/dungeonman.cpp
index 4695d2ca418..baccc88c882 100644
--- a/engines/dm/dungeonman.cpp
+++ b/engines/dm/dungeonman.cpp
@@ -537,7 +537,7 @@ void DungeonMan::decompressDungeonFile() {
f.close();
}
-void DungeonMan::loadDungeonFile(Common::InSaveFile *file) {
+void DungeonMan::loadDungeonFile(Common::SeekableReadStream *file) {
static const byte additionalThingCounts[16] = { // @ G0236_auc_Graphic559_AdditionalThingCounts{
0, /* Door */
0, /* Teleporter */
diff --git a/engines/dm/dungeonman.h b/engines/dm/dungeonman.h
index 2b25cf15f85..7c659404831 100644
--- a/engines/dm/dungeonman.h
+++ b/engines/dm/dungeonman.h
@@ -663,7 +663,7 @@ public:
void resetThing(Thing thing);
// TODO: this does stuff other than load the file!
- void loadDungeonFile(Common::InSaveFile *file); // @ F0434_STARTEND_IsLoadDungeonSuccessful_CPSC
+ void loadDungeonFile(Common::SeekableReadStream *file); // @ F0434_STARTEND_IsLoadDungeonSuccessful_CPSC
void setCurrentMapAndPartyMap(uint16 mapIndex); // @ F0174_DUNGEON_SetCurrentMapAndPartyMap
bool isWallOrnAnAlcove(int16 wallOrnIndex); // @ F0149_DUNGEON_IsWallOrnamentAnAlcove
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index c82be1b7363..24b7970f87b 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -2108,7 +2108,7 @@ void GroupMan::fuseAction(uint16 mapX, uint16 mapY) {
}
}
-void GroupMan::saveActiveGroupPart(Common::OutSaveFile *file) {
+void GroupMan::saveActiveGroupPart(Common::WriteStream *file) {
for (uint16 i = 0; i < _maxActiveGroupCount; ++i) {
ActiveGroup *group = &_activeGroups[i];
file->writeUint16BE(group->_groupThingIndex);
@@ -2127,7 +2127,7 @@ void GroupMan::saveActiveGroupPart(Common::OutSaveFile *file) {
}
}
-void GroupMan::loadActiveGroupPart(Common::InSaveFile *file) {
+void GroupMan::loadActiveGroupPart(Common::SeekableReadStream *file) {
for (uint16 i = 0; i < _maxActiveGroupCount; ++i) {
ActiveGroup *group = &_activeGroups[i];
group->_groupThingIndex = file->readUint16BE();
diff --git a/engines/dm/group.h b/engines/dm/group.h
index a50756c7ecb..860151335a1 100644
--- a/engines/dm/group.h
+++ b/engines/dm/group.h
@@ -242,8 +242,8 @@ public:
uint16 isLordChaosOnSquare(int16 mapX, int16 mapY); // @ F0222_GROUP_IsLordChaosOnSquare
bool isFluxcageOnSquare(int16 mapX, int16 mapY); // @ F0221_GROUP_IsFluxcageOnSquare
void fuseAction(uint16 mapX, uint16 mapY); // @ F0225_GROUP_FuseAction
- void saveActiveGroupPart(Common::OutSaveFile *file);
- void loadActiveGroupPart(Common::InSaveFile *file);
+ void saveActiveGroupPart(Common::WriteStream *file);
+ void loadActiveGroupPart(Common::SeekableReadStream *file);
};
}
diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp
index 1a9aca722ac..03abd13abc0 100644
--- a/engines/dm/loadsave.cpp
+++ b/engines/dm/loadsave.cpp
@@ -41,6 +41,71 @@
namespace DM {
+Common::Error DMEngine::loadGameStream(Common::SeekableReadStream *file) {
+
+ struct {
+ SaveTarget _saveTarget;
+ int32 _saveVersion;
+ OriginalSaveFormat _saveFormat;
+ OriginalSavePlatform _savePlatform;
+ uint16 _dungeonId;
+ } dmSaveHeader;
+
+ dmSaveHeader._saveTarget = (SaveTarget)file->readSint32BE();
+ dmSaveHeader._saveVersion = file->readSint32BE();
+ dmSaveHeader._saveFormat = (OriginalSaveFormat)file->readSint32BE();
+ dmSaveHeader._savePlatform = (OriginalSavePlatform)file->readSint32BE();
+
+ // Skip _gameId, which was useless
+ file->readSint32BE();
+ dmSaveHeader._dungeonId = file->readUint16BE();
+
+ _gameTime = file->readSint32BE();
+ // G0349_ul_LastRandomNumber = L1371_s_GlobalData.LastRandomNumber;
+ _championMan->_partyChampionCount = file->readUint16BE();
+ _dungeonMan->_partyMapX = file->readSint16BE();
+ _dungeonMan->_partyMapY = file->readSint16BE();
+ _dungeonMan->_partyDir = (Direction)file->readUint16BE();
+ _dungeonMan->_partyMapIndex = file->readByte();
+ _championMan->_leaderIndex = (ChampionIndex)file->readSint16BE();
+ _championMan->_magicCasterChampionIndex = (ChampionIndex)file->readSint16BE();
+ _timeline->_eventCount = file->readUint16BE();
+ _timeline->_firstUnusedEventIndex = file->readUint16BE();
+ _timeline->_eventMaxCount = file->readUint16BE();
+ _groupMan->_currActiveGroupCount = file->readUint16BE();
+ _projexpl->_lastCreatureAttackTime = file->readSint32BE();
+ _projexpl->_lastPartyMovementTime = file->readSint32BE();
+ _disabledMovementTicks = file->readSint16BE();
+ _projectileDisableMovementTicks = file->readSint16BE();
+ _lastProjectileDisabledMovementDirection = file->readSint16BE();
+ uint16 handVal = file->readUint16BE();
+ _championMan->_leaderHandObject = (handVal == 0) ? _thingNone : Thing(handVal);
+ _groupMan->_maxActiveGroupCount = file->readUint16BE();
+ if (!_restartGameRequest) {
+ _timeline->initTimeline();
+ _groupMan->initActiveGroups();
+ }
+
+ _groupMan->loadActiveGroupPart(file);
+ _championMan->loadPartyPart2(file);
+ _timeline->loadEventsPart(file);
+ _timeline->loadTimelinePart(file);
+
+ // read sentinel
+ uint32 sentinel = file->readUint32BE();
+ if (sentinel != 0x6f85e3d3) {
+ warning("Savegame is corrupted (sentinel mismatch)");
+ return Common::kReadingFailed;
+ }
+
+ _dungeonId = dmSaveHeader._dungeonId;
+
+ if (file->err())
+ return Common::kReadingFailed;
+
+ return Common::kNoError;
+}
+
LoadgameResult DMEngine::loadgame(int16 slot) {
if (slot >= 0)
_gameMode = kDMModeLoadSavedGame;
@@ -49,81 +114,23 @@ LoadgameResult DMEngine::loadgame(int16 slot) {
return kDMLoadgameFailure;
bool fadePalette = true;
- Common::String fileName;
- Common::SaveFileManager *saveFileManager = nullptr;
Common::InSaveFile *file = nullptr;
- struct {
- SaveTarget _saveTarget;
- int32 _saveVersion;
- OriginalSaveFormat _saveFormat;
- OriginalSavePlatform _savePlatform;
- uint16 _dungeonId;
- } dmSaveHeader;
-
if (_gameMode != kDMModeLoadSavedGame) {
//L1366_B_FadePalette = !F0428_DIALOG_RequireGameDiskInDrive_NoDialogDrawn(C0_DO_NOT_FORCE_DIALOG_DM_CSB, true);
_restartGameAllowed = false;
_championMan->_partyChampionCount = 0;
_championMan->_leaderHandObject = _thingNone;
} else {
- fileName = getSavefileName(slot);
- saveFileManager = _system->getSavefileManager();
- file = saveFileManager->openForLoading(fileName);
+ file = _system->getSavefileManager()->openForLoading(getSaveStateName(slot));
+ if (!file)
+ return kDMLoadgameFailure;
- SaveGameHeader header;
- if (!readSaveGameHeader(file, &header)) {
+ Common::Error err = loadGameStream(file);
+ if (err.getCode() != Common::kNoError) {
delete file;
return kDMLoadgameFailure;
}
-
- warning("MISSING CODE: missing check for matching format and platform in save in f435_loadgame");
-
- dmSaveHeader._saveTarget = (SaveTarget)file->readSint32BE();
- dmSaveHeader._saveVersion = file->readSint32BE();
- dmSaveHeader._saveFormat = (OriginalSaveFormat)file->readSint32BE();
- dmSaveHeader._savePlatform = (OriginalSavePlatform)file->readSint32BE();
-
- // Skip _gameId, which was useless
- file->readSint32BE();
- dmSaveHeader._dungeonId = file->readUint16BE();
-
- _gameTime = file->readSint32BE();
- // G0349_ul_LastRandomNumber = L1371_s_GlobalData.LastRandomNumber;
- _championMan->_partyChampionCount = file->readUint16BE();
- _dungeonMan->_partyMapX = file->readSint16BE();
- _dungeonMan->_partyMapY = file->readSint16BE();
- _dungeonMan->_partyDir = (Direction)file->readUint16BE();
- _dungeonMan->_partyMapIndex = file->readByte();
- _championMan->_leaderIndex = (ChampionIndex)file->readSint16BE();
- _championMan->_magicCasterChampionIndex = (ChampionIndex)file->readSint16BE();
- _timeline->_eventCount = file->readUint16BE();
- _timeline->_firstUnusedEventIndex = file->readUint16BE();
- _timeline->_eventMaxCount = file->readUint16BE();
- _groupMan->_currActiveGroupCount = file->readUint16BE();
- _projexpl->_lastCreatureAttackTime = file->readSint32BE();
- _projexpl->_lastPartyMovementTime = file->readSint32BE();
- _disabledMovementTicks = file->readSint16BE();
- _projectileDisableMovementTicks = file->readSint16BE();
- _lastProjectileDisabledMovementDirection = file->readSint16BE();
- uint16 handVal = file->readUint16BE();
- _championMan->_leaderHandObject = (handVal == 0) ? _thingNone : Thing(handVal);
- _groupMan->_maxActiveGroupCount = file->readUint16BE();
- if (!_restartGameRequest) {
- _timeline->initTimeline();
- _groupMan->initActiveGroups();
- }
-
- _groupMan->loadActiveGroupPart(file);
- _championMan->loadPartyPart2(file);
- _timeline->loadEventsPart(file);
- _timeline->loadTimelinePart(file);
-
- // read sentinel
- uint32 sentinel = file->readUint32BE();
- assert(sentinel == 0x6f85e3d3);
-
- _dungeonId = dmSaveHeader._dungeonId;
}
_dungeonMan->loadDungeonFile(file);
@@ -226,7 +233,8 @@ void DMEngine::saveGame() {
_championMan->_champions[_championMan->_leaderIndex]._load -= champHandObjWeight;
}
- if (!writeCompleteSaveFile(saveSlot, saveDescription, saveAndPlayChoice)) {
+ Common::Error saveErr = saveGameState(saveSlot, saveDescription);
+ if (saveErr.getCode() != Common::kNoError) {
_dialog->dialogDraw(nullptr, "Unable to open file for saving", "OK", nullptr, nullptr, nullptr, false, false, false);
_dialog->getChoice(1, kDMDialogCommandSetViewport, 0, kDMDialogChoiceNone);
}
@@ -256,44 +264,11 @@ Common::String DMEngine::getSavefileName(uint16 slot) {
#define SAVEGAME_ID MKTAG('D', 'M', '2', '1')
#define SAVEGAME_VERSION 1
-void DMEngine::writeSaveGameHeader(Common::OutSaveFile *out, const Common::String& saveName) {
- out->writeUint32BE(SAVEGAME_ID);
-
- // Write version
- out->writeByte(SAVEGAME_VERSION);
-
- // Write savegame name
- out->writeString(saveName);
- out->writeByte(0);
-
- // Save the game thumbnail
- if (_saveThumbnail)
- out->write(_saveThumbnail->getData(), _saveThumbnail->size());
- else
- Graphics::saveThumbnail(*out);
-
- // Creation date/time
- TimeDate curTime;
- _system->getTimeAndDate(curTime);
-
- uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
- uint16 saveTime = ((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF);
- uint32 playTime = getTotalPlayTime() / 1000;
-
- out->writeUint32BE(saveDate);
- out->writeUint16BE(saveTime);
- out->writeUint32BE(playTime);
+Common::Error DMEngine::saveGameStream(Common::WriteStream *file, bool isAutosave) {
+ return writeCompleteSaveFile(file);
}
-bool DMEngine::writeCompleteSaveFile(int16 saveSlot, Common::String& saveDescription, int16 saveAndPlayChoice) {
- Common::String savefileName = getSavefileName(saveSlot);
- Common::SaveFileManager *saveFileManager = _system->getSavefileManager();
- Common::OutSaveFile *file = saveFileManager->openForSaving(savefileName);
-
- if (!file)
- return false;
-
- writeSaveGameHeader(file, saveDescription);
+Common::Error DMEngine::writeCompleteSaveFile(Common::WriteStream *file) {
file->writeSint32BE(_gameVersion->_saveTargetToWrite);
file->writeSint32BE(1); // save version
@@ -493,59 +468,10 @@ bool DMEngine::writeCompleteSaveFile(int16 saveSlot, Common::String& saveDescrip
for (uint32 i = 0; i < _dungeonMan->_dungeonFileHeader._rawMapDataSize; ++i)
file->writeByte(_dungeonMan->_dungeonRawMapData[i]);
- file->flush();
- file->finalize();
- delete file;
-
- return true;
-}
-
-WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail) {
- uint32 id = in->readUint32BE();
-
- // Check if it's a valid ScummVM savegame
- if (id != SAVEGAME_ID)
- return false;
-
- // Read in the version
- header->_version = in->readByte();
-
- // Check that the save version isn't newer than this binary
- if (header->_version > SAVEGAME_VERSION)
- return false;
-
- // Read in the save name
- Common::String saveName;
- char ch;
- while ((ch = (char)in->readByte()) != '\0')
- saveName += ch;
- header->_descr.setDescription(saveName);
-
- // Get the thumbnail
- Graphics::Surface *thumbnail;
- if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) {
- return false;
- }
- header->_descr.setThumbnail(thumbnail);
-
- uint32 saveDate = in->readUint32BE();
- uint16 saveTime = in->readUint16BE();
- uint32 playTime = in->readUint32BE();
-
- int day = (saveDate >> 24) & 0xFF;
- int month = (saveDate >> 16) & 0xFF;
- int year = saveDate & 0xFFFF;
- header->_descr.setSaveDate(year, month, day);
-
- int hour = (saveTime >> 8) & 0xFF;
- int minutes = saveTime & 0xFF;
- header->_descr.setSaveTime(hour, minutes);
-
- header->_descr.setPlayTime(playTime * 1000);
- if (g_engine)
- g_engine->setTotalPlayTime(playTime * 1000);
+ if (file->err())
+ return Common::kWritingFailed;
- return true;
+ return Common::kNoError;
}
}
diff --git a/engines/dm/metaengine.cpp b/engines/dm/metaengine.cpp
index af47d8b0060..a6f54cf6964 100644
--- a/engines/dm/metaengine.cpp
+++ b/engines/dm/metaengine.cpp
@@ -53,66 +53,12 @@ public:
bool hasFeature(MetaEngineFeature f) const override {
return
- (f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
- (f == kSavesSupportThumbnail) ||
- (f == kSavesSupportMetaInfo) ||
- (f == kSimpleSavesNames) ||
- (f == kSavesSupportCreationDate);
+ (checkExtendedSaves(f) && f != kSimpleSavesNames);
}
int getMaximumSaveSlot() const override { return 99; }
- SaveStateList listSaves(const char *target) const override {
- Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
- SaveGameHeader header;
- Common::String pattern = target;
- pattern += ".###";
-
- Common::StringArray filenames = saveFileMan->listSavefiles(pattern.c_str());
-
- SaveStateList saveList;
-
- for (const auto &filename : filenames) {
- // Obtain the last 3 digits of the filename, since they correspond to the save slot
- int slotNum = atoi(filename.c_str() + filename.size() - 3);
-
- if ((slotNum >= 0) && (slotNum <= 999)) {
- Common::InSaveFile *in = saveFileMan->openForLoading(filename.c_str());
- if (in) {
- if (DM::readSaveGameHeader(in, &header))
- saveList.push_back(SaveStateDescriptor(this, slotNum, header._descr.getDescription()));
- delete in;
- }
- }
- }
-
- // Sort saves based on slot number.
- Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
- return saveList;
- }
-
- SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override {
- Common::String filename = Common::String::format("%s.%03u", target, slot);
- Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
-
- if (in) {
- DM::SaveGameHeader header;
-
- bool successfulRead = DM::readSaveGameHeader(in, &header);
- delete in;
-
- if (successfulRead) {
- SaveStateDescriptor desc(this, slot, header._descr.getDescription());
-
- return header._descr;
- }
- }
-
- return SaveStateDescriptor();
- }
-
- bool removeSaveState(const char *target, int slot) const override { return false; }
Common::KeymapArray initKeymaps(const char *target) const override;
};
diff --git a/engines/dm/timeline.cpp b/engines/dm/timeline.cpp
index 0342343930b..388b5b62131 100644
--- a/engines/dm/timeline.cpp
+++ b/engines/dm/timeline.cpp
@@ -971,7 +971,7 @@ T0255002:
}
}
-void Timeline::saveEventsPart(Common::OutSaveFile *file) {
+void Timeline::saveEventsPart(Common::WriteStream *file) {
for (uint16 i = 0; i < _eventMaxCount; ++i) {
TimelineEvent *event = &_events[i];
file->writeSint32BE(event->_mapTime);
@@ -984,12 +984,12 @@ void Timeline::saveEventsPart(Common::OutSaveFile *file) {
}
}
-void Timeline::saveTimelinePart(Common::OutSaveFile *file) {
+void Timeline::saveTimelinePart(Common::WriteStream *file) {
for (uint16 i = 0; i < _eventMaxCount; ++i)
file->writeUint16BE(_timeline[i]);
}
-void Timeline::loadEventsPart(Common::InSaveFile *file) {
+void Timeline::loadEventsPart(Common::SeekableReadStream *file) {
for (uint16 i = 0; i < _eventMaxCount; ++i) {
TimelineEvent *event = &_events[i];
event->_mapTime = file->readSint32BE();
@@ -1002,7 +1002,7 @@ void Timeline::loadEventsPart(Common::InSaveFile *file) {
}
}
-void Timeline::loadTimelinePart(Common::InSaveFile *file) {
+void Timeline::loadTimelinePart(Common::SeekableReadStream *file) {
for (uint16 i = 0; i < _eventMaxCount; ++i)
_timeline[i] = file->readUint16BE();
}
diff --git a/engines/dm/timeline.h b/engines/dm/timeline.h
index 3709d27726a..d87cc5af890 100644
--- a/engines/dm/timeline.h
+++ b/engines/dm/timeline.h
@@ -188,10 +188,10 @@ public:
void processEventLight(TimelineEvent *event); // @ F0257_TIMELINE_ProcessEvent70_Light
void refreshAllChampionStatusBoxes(); // @ F0260_TIMELINE_RefreshAllChampionStatusBoxes
void processEventViAltarRebirth(TimelineEvent *event); // @ F0255_TIMELINE_ProcessEvent13_ViAltarRebirth
- void saveEventsPart(Common::OutSaveFile *file);
- void saveTimelinePart(Common::OutSaveFile *file);
- void loadEventsPart(Common::InSaveFile *file);
- void loadTimelinePart(Common::InSaveFile *file);
+ void saveEventsPart(Common::WriteStream *file);
+ void saveTimelinePart(Common::WriteStream *file);
+ void loadEventsPart(Common::SeekableReadStream *file);
+ void loadTimelinePart(Common::SeekableReadStream *file);
signed char _actionDefense[44]; // @ G0495_ac_Graphic560_ActionDefense
Commit: c049b6ca9916a6dd1b1a708f24f87df1579bbcab
https://github.com/scummvm/scummvm/commit/c049b6ca9916a6dd1b1a708f24f87df1579bbcab
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Show load save dialog on game restart instead of loading slot 1
Changed paths:
engines/dm/dm.cpp
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 8ababf66ef1..5f2bcf7e8fd 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -720,13 +720,18 @@ T0444017:
_displayMan->fillScreen(kDMColorBlack);
_displayMan->startEndFadeToPalette(_displayMan->_palDungeonView[0]);
_gameMode = kDMModeLoadSavedGame;
- if (loadgame(1) != kDMLoadgameFailure) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(false);
+ int16 saveSlot = dialog->runModalWithCurrentTarget();
+ delete dialog;
+
+ if (saveSlot >= 0 && loadgame(saveSlot) != kDMLoadgameFailure) {
startGame();
_restartGameRequest = false;
_eventMan->hideMouse();
_eventMan->discardAllInput();
return;
}
+ _restartGameRequest = false;
}
}
Commit: 7cc77e1185a29088b0bdf35794fa48f9933caf96
https://github.com/scummvm/scummvm/commit/7cc77e1185a29088b0bdf35794fa48f9933caf96
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T20:20:09+02:00
Commit Message:
DM: Update TODO
Changed paths:
engines/dm/TODOs/todo.txt
diff --git a/engines/dm/TODOs/todo.txt b/engines/dm/TODOs/todo.txt
index 074ccf05996..29ca314d161 100644
--- a/engines/dm/TODOs/todo.txt
+++ b/engines/dm/TODOs/todo.txt
@@ -1,21 +1,2 @@
-Bugs:
- Display:
- Spellcasting tabs are displayed inproperly, switching between them is possible tho
- Cursor icons are drawn twice
- DisplayMan::blitBoxFilledWithMaskedBitmap does not produce the same effect as the original
-
- Logic:
- Items thrown on the right side end up on the left side
- Restarting the game after the party is dead segfaults
-
Todo:
Add wiki entry for DM
-
- Double check enums with hex literals
- Double check strcat, strstr usages
- I forgot to add a bunch of warning for show/hide mouse pointer and other mouse functions
-
-Code stuff todo:
- Complete stub methods(blitShrink)
- Add proper save header, add error handling to it
- Add translations to f433_processCommand140_saveGame 'LOAD'
More information about the Scummvm-git-logs
mailing list