[Scummvm-git-logs] scummvm master -> 17a9234e345d97032ec5460646c1e78e59922ba5

athrxx noreply at scummvm.org
Sun Aug 30 19:22:42 UTC 2026


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

Summary:
b735acaf57 KYRA: (EOBII/PC98) - fix text glitch
17a9234e34 KYRA: (EOB automap feature) - improved drawing


Commit: b735acaf57ff1ddf9d4b7ead5ad340865d906485
    https://github.com/scummvm/scummvm/commit/b735acaf57ff1ddf9d4b7ead5ad340865d906485
Author: athrxx (athrxx at scummvm.org)
Date: 2026-08-30T21:19:53+02:00

Commit Message:
KYRA: (EOBII/PC98) - fix text glitch

Changed paths:
    engines/kyra/text/text_rpg.cpp


diff --git a/engines/kyra/text/text_rpg.cpp b/engines/kyra/text/text_rpg.cpp
index 86c4f0daf0a..317236966c4 100644
--- a/engines/kyra/text/text_rpg.cpp
+++ b/engines/kyra/text/text_rpg.cpp
@@ -594,8 +594,13 @@ void TextDisplayer_rpg::printMessage(const char *str, int textColor, ...) {
 	vsnprintf(_dialogueBuffer, kEoBTextBufferSize - 1, str, args);
 	va_end(args);
 
+	int cs = (_vm->gameFlags().platform == Common::kPlatformPC98 && !_vm->gameFlags().use16ColorMode && _screen->curDimIndex() == 9) ? _screen->setFontStyles(_screen->_currentFont, Font::kStyleFat) : -1;
+
 	displayText(_dialogueBuffer, textColor);
 
+	if (cs != -1)
+		_screen->setFontStyles(_screen->_currentFont, cs);
+
 	if (_vm->game() != GI_EOB1)
 		_textDimData[_screen->curDimIndex()].color1= tc;
 


Commit: 17a9234e345d97032ec5460646c1e78e59922ba5
    https://github.com/scummvm/scummvm/commit/17a9234e345d97032ec5460646c1e78e59922ba5
Author: athrxx (athrxx at scummvm.org)
Date: 2026-08-30T21:21:39+02:00

Commit Message:
KYRA: (EOB automap feature) - improved drawing

- greatly improved logic for detecting and drawing barriers
   (glass walls, crumbling walls, spider webs, etc.)
- draw legend items only if needed for the current map
- improved drawing for centered/floor switches
- minor fixes

Changed paths:
    engines/kyra/gui/automap_eob.cpp
    engines/kyra/gui/automap_eob.h


diff --git a/engines/kyra/gui/automap_eob.cpp b/engines/kyra/gui/automap_eob.cpp
index 698f3df9795..7759a7ef8f0 100644
--- a/engines/kyra/gui/automap_eob.cpp
+++ b/engines/kyra/gui/automap_eob.cpp
@@ -163,6 +163,7 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 			"Pit",
 			"Plate",
 			"Door",
+			"Barrier",
 			"Illusionary Wall",
 			"Wall of Force",
 			"Switch",
@@ -242,8 +243,7 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 
 Automap_EoB::Automap_EoB(OSystem *system, LevelBlockProperty **blockData, const uint8 *wllFlags, const uint8 *specialWallTypes, int gameID, int lang, bool featureEnabled) : _system(system),
 	_blockData(*blockData), _wllWallFlags(wllFlags), _specialWallTypes(specialWallTypes), _enabled(featureEnabled), _visible(false), _automapBg(nullptr), _automapFrame(nullptr), _specialBlockIDs(nullptr), _levelNames(nullptr),
-		_colors(nullptr), _legendStrings(nullptr), _controlStrings(nullptr), _numLevelNames(gameID == GI_EOB1 ? 12 : (gameID == GI_EOB2 ? 16 : 0)),	_gameSupportsBreakables(gameID == GI_EOB2), _wallOfForceID(gameID == GI_EOB1 ? 0xFF : 74),
-			_portalParamsLen(0), _portalParams(nullptr){
+		_colors(nullptr), _legendStrings(nullptr), _controlStrings(nullptr), _numLevelNames(gameID == GI_EOB1 ? 12 : (gameID == GI_EOB2 ? 16 : 0)), _wallOfForceID(gameID == GI_EOB1 ? 0xFF : 74), _portalParamsLen(0), _portalParams(nullptr){
 	_automapBg = new Graphics::Surface();
 	_automapFrame = new Graphics::Surface();
 
@@ -300,13 +300,12 @@ void Automap_EoB::markVisited(uint16 block) {
 
 void Automap_EoB::markSeen(uint16 block, int8 dir) {
 	assert(block < 1024);
-
 	// Mark the cells in the line of sight ahead up to the first wall, door or enemy (but include the block with the enemy).
 	// Also 1 block diagonal to the left/right of the line of sight, to have a bit more realistic view (and not make
 	// players walk around pointlessly just to complete the map). 
 	// First value is the relative direction to move, next is whether to reveal the block or not. We don't reveal the
 	// blocks directly to the left/right of the party (behind line of sight), even if our route passes through them.
-	// We also don't reveal behind doors or destructable block objects.
+	// We also don't reveal behind doors or breakable block objects.
 	static const int8 traceRoutes[5][4] = {
 		{ -1,  0,  0,  1 },
 		{  0,  0, -1,  1 },
@@ -324,31 +323,28 @@ void Automap_EoB::markSeen(uint16 block, int8 dir) {
 			bool reveal = *r++;
 			uint8 wn = _blockData[nb].walls[d ^ 2];
 
-			bool blockDestructable = false;
-			if (_gameSupportsBreakables && (_blockData[nb].flags & 0x800)) {
-				// Check if it is destructable from multiple sides to determine if we should treat it as
-				// a wall object (like the breakable windows on the temple ground floor in EOBII) or a
-				// block object (like the barrels in the catacombs).
-				int cn = 0;
-				for (int iii = 0; iii < 4; ++iii) {
-					uint8 s = _specialWallTypes[_blockData[nb].walls[iii]];
-					if (s == 8 || s == 9)
-						++cn;
-				}
-				blockDestructable = cn >= 2;
-			}
-			bool blockHasDestructable = (_gameSupportsBreakables && (_specialWallTypes[wn] == 8 || _specialWallTypes[wn] == 9) );
-
+			int breakAbleObject = checkForBreakableObjectType(nb);
+			bool breakableFromHere = ((breakAbleObject == kBreakableBlockObject && (_specialWallTypes[wn] == 8 || _specialWallTypes[wn] == 9)) ||
+				(!(d & 1) && breakAbleObject == kBreakableBarrierNS) || ((d & 1) && breakAbleObject == kBreakableBarrierEW));
 
-			if ((!(_wllWallFlags[wn] & 9) && !blockDestructable) || _blockData[b].flags & 7)
+			if ((!(_wllWallFlags[wn] & 9) && breakAbleObject == kNoBreakableObject) || _blockData[b].flags & 7)
 				break;
 			b = nb;
 			if (reveal)
 				_blockData[b].direction |= 1;
-			if (_wllWallFlags[wn] & 8 || blockHasDestructable)
+			if (_wllWallFlags[wn] & 8 || breakableFromHere)
 				break;
 		}
 	}
+
+	// If there is a stairs behind the party, we reveal that, too. When entering a level from stairs, the party will
+	// often be placed on the block next to the block with the stairs, facing away from it. It will then not be marked
+	// on the map, unless the player turns around and looks at it. This is a bit annoying and we avoid it like this...
+	LevelBlockProperty &bp = _blockData[calcNewBlockPosition(block, dir ^ 2)];
+	for (int i = 0; i < 4; ++i) {
+		if (bp.walls[i] == _specialBlockIDs[3] || bp.walls[i] == _specialBlockIDs[4])
+			bp.direction |= 1;
+	}
 }
 
 void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
@@ -368,6 +364,8 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 	const int offY = l.offY;
 	const int wt = MAX(2, cell / 5);
 
+	uint legendFlags = (partyBlock != 0xFFFF) ? 1 : 0;
+
 	for (int by = 0; by < 32; ++by) {
 		for (int bx = 0; bx < 32; ++bx) {
 			const uint16 block = (by << 5) | bx;
@@ -382,15 +380,27 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 			bool wall[4];
 			for (int d = 0; d < 4; ++d) {
 				const uint16 nb = calcNewBlockPosition(block, d);
-				uint8 w = _blockData[nb].walls[d ^ 2];
+				uint8 wn = _blockData[nb].walls[d ^ 2];
 				// Check for doors or breakable block objects (like the barrels in the EOB II catacombs) which shouldn't be drawn as walls.
-				wall[d] = (!(_wllWallFlags[w] & 9) && w != _wallOfForceID && !isBreakableBlockObject(nb));
+				wall[d] = (!(_wllWallFlags[wn] & 9) && wn != _wallOfForceID && checkForBreakableObjectType(nb) == kNoBreakableObject);
 			}
 
 			const LevelBlockProperty *bp = &_blockData[block];
-			const bool doorNS = ((_wllWallFlags[bp->walls[0]] | _wllWallFlags[bp->walls[2]]) & 8);
-			const bool doorEW = ((_wllWallFlags[bp->walls[1]] | _wllWallFlags[bp->walls[3]]) & 8);
-			const bool wof = (bp->walls[0] == _wallOfForceID || bp->walls[1] == _wallOfForceID || bp->walls[2] == _wallOfForceID || bp->walls[3] == _wallOfForceID);
+			bool doorNS = ((_wllWallFlags[bp->walls[0]] | _wllWallFlags[bp->walls[2]]) & 8);
+			bool doorEW = ((_wllWallFlags[bp->walls[1]] | _wllWallFlags[bp->walls[3]]) & 8);
+			bool wof = (bp->walls[0] == _wallOfForceID || bp->walls[1] == _wallOfForceID || bp->walls[2] == _wallOfForceID || bp->walls[3] == _wallOfForceID);
+			int br = checkForBreakableObjectType(block);
+			int bcolor = kColorDoor;
+
+			if (br == kBreakableBarrierNS) {
+				doorNS = true;
+				bcolor = kColorInteractive;
+			}
+
+			if (br == kBreakableBarrierEW) {
+				doorEW = true;
+				bcolor = kColorInteractive;
+			}
 
 			if (doorNS)
 				wall[0] = wall[2] = false;
@@ -412,7 +422,7 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 			if (wall[3])
 				surf.fillRect(Common::Rect(sx, sy, sx + wt, sy + cell), wc);
 
-			auto drawButton = [&surf, cell](int x, int y, int alignment, int len, int wdth, uint32 color) {
+			auto drawButton = [&surf, &legendFlags, cell](int x, int y, int alignment, int len, int wdth, uint32 color, uint addFlag) {
 				switch (alignment) {
 				case 0:
 					x = x + cell / 2 - len / 2;
@@ -432,6 +442,7 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 					break;
 				}
 				surf.fillRect(Common::Rect(x, y, x + len, y + wdth), color);
+				legendFlags |= addFlag;
 			};
 
 
@@ -440,21 +451,24 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 				const int dt = MAX(2, wt + 1);
 				const int dm = MAX(1, cell / 5);
 				const int dcx = sx + cell / 2, dcy = sy + cell / 2;
+
+				legendFlags |= (br != kNoBreakableObject ? 0x80 : 0x40);
+
 				// Draw the door and also the door button if the door has one.
 				if (doorNS) {
-					surf.fillRect(Common::Rect(sx + dm, dcy - dt / 2, sx + cell - dm, dcy - dt / 2 + dt), _colors[kColorDoor]);
+					surf.fillRect(Common::Rect(sx + dm, dcy - dt / 2, sx + cell - dm, dcy - dt / 2 + dt), _colors[bcolor]);
 					if (_specialWallTypes[bp->walls[0]] == 1)
-						drawButton(sx - dm, sy + dt, 0, dm, dm, _colors[kColorLever]);	
+						drawButton(sx - dm, sy + dt, 0, dm, dm, _colors[kColorLever], 0x400);	
 					if (_specialWallTypes[bp->walls[2]] == 1)
-						drawButton(sx + dm, sy - dt, 2, dm, dm, _colors[kColorLever]);
+						drawButton(sx + dm, sy - dt, 2, dm, dm, _colors[kColorLever], 0x400);
 					
 				}
 				if (doorEW) {
-					surf.fillRect(Common::Rect(dcx - dt / 2, sy + dm, dcx - dt / 2 + dt, sy + cell - dm), _colors[kColorDoor]);
+					surf.fillRect(Common::Rect(dcx - dt / 2, sy + dm, dcx - dt / 2 + dt, sy + cell - dm), _colors[bcolor]);
 					if (_specialWallTypes[bp->walls[1]] == 1)
-						drawButton(sx - dt, sy - dm, 1, dm, dm, _colors[kColorLever]);	
+						drawButton(sx - dt, sy - dm, 1, dm, dm, _colors[kColorLever], 0x400);
 					if (_specialWallTypes[bp->walls[3]] == 1)
-						drawButton(sx + dt, sy + dm, 3, dm, dm, _colors[kColorLever]);
+						drawButton(sx + dt, sy + dm, 3, dm, dm, _colors[kColorLever], 0x400);
 					
 				}
 			}
@@ -464,7 +478,8 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 				uint16 nb = calcNewBlockPosition(block, d);
 				uint8 wn = _blockData[nb].walls[d ^ 2];
 				uint8 st = _specialWallTypes[wn];
-				if (st == 0 || st == 5 || st == 6)
+
+				if (st == 0 || st == 5 || st == 6 || st == 0xFF)
 					continue;
 
 				// At least for EOBI, there are cases where a wall has a clickable type, but there is no
@@ -481,7 +496,11 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 				// but it makes more sense to not to draw them here, but in the middle of the block if they're
 				// block objects (like the barrels in the EOB II catacombs). But if it is a wall object (like
 				// the breakable windows on the temple ground floor in EOBII) we should draw it here.
-				if (isBreakableBlockObject(nb))
+				if (checkForBreakableObjectType(nb) != kNoBreakableObject)
+					continue;
+
+				// Same for levers: There are center/floor switches which also shouldn't be drawn on the walls.
+				if (isCenteredSwitch(nb))
 					continue;
 
 				// Check if it is a stone portal.
@@ -493,14 +512,15 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 				}
 
 				uint32 pcol = _colors[(st == 10) ? kColorNiche : (st == 1 || st == 3 || st == 4) ? kColorLever : (st == 20 ? kColorTele : kColorInteractive)];
+				uint flag = (st == 10) ? 0x1000 : (st == 1 || st == 3 || st == 4) ? 0x400 : (st == 20 ? 0x2000 : 0x800);
 				int plen = MAX(2, cell * 2 / (st < 10 ? 8 : st == 10 ? 6 : 3));
 				int pwdth = MAX(2, cell / 4);
 
-				drawButton(sx, sy, d, plen, pwdth, pcol);				
+				drawButton(sx, sy, d, plen, pwdth, pcol, flag);				
 			}
 
 			// TODO: The icons could all be pregenerated instead of individually rendering them each time.
-			auto drawIcon = [&surf, cell](int ix, int iy, uint8 icon, const uint32 *colTable) {
+			auto drawIcon = [&surf, &legendFlags, cell](int ix, int iy, uint8 icon, const uint32 *colTable, uint addFlag) {
 				const int cx = ix + cell / 2;
 				const int cy = iy + cell / 2;
 				const int r = MAX(2, cell / 3);
@@ -528,14 +548,13 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 					automapFillTri(surf, cx - r, cy - r, cx + r, cy - r, cx, cy + r, colTable[kColorStair]);
 					break;
 				case 5:
-					surf.drawEllipse(cx - margin, cy - margin, cx + margin, cy + margin, colTable[kColorPit], true);
-					break;
 				case 6:
 				case 7:
-					surf.drawEllipse(cx - margin, cy - margin, cx + margin, cy + margin, colTable[kColorPlate], true);
+					surf.drawEllipse(cx - margin, cy - margin, cx + margin, cy + margin, colTable[icon == 5 ? kColorPit : kColorPlate], true);
 					break;
 				case 9:
-					surf.fillRect(Common::Rect(cx - margin, cy - margin, cx + margin, cy + margin), colTable[kColorInteractive]);
+				case 11:
+					surf.fillRect(Common::Rect(cx - margin, cy - margin, cx + margin, cy + margin), colTable[icon == 9 ?kColorInteractive : kColorLever]);
 					break;
 				case 10:
 					for (int posX = 0, g = 0; g < 3; ++g, posX += (step2 * 2)) {
@@ -549,23 +568,29 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 				default:
 					break;
 				}
+				legendFlags |= addFlag;
 			};
 
-			if (wof) {
-				drawIcon(sx, sy, 10, _colors);
-			} else if (isBreakableBlockObject(block)) {
-				drawIcon(sx, sy, 9, _colors);
+			if (br == kBreakableBlockObject) {
+				drawIcon(sx, sy, 9, _colors, 0x800);
+			} else if (wof) {
+				drawIcon(sx, sy, 10, _colors, 0x200);
+			} else if (isCenteredSwitch(block)) {
+				drawIcon(sx, sy, 11, _colors, 0x400);
 			} else {
-				// Special blocks: teleporter, illusionary wall, pressure plate, pit, stairs up/down
+				// Special blocks
+				const uint16 flags[] = { 0x08, 0x100, 0x100, 0x02, 0x04, 0x10, 0x20, 0x20 };
 				for (int i = 0; i < _numSpecialBlockIDs; ++i) {
 					uint8 s = _specialBlockIDs[i]; // order: teleporter, illusion1, illusion2, stairsUp, stairsDown, pit, plate1, plate2
 					if (bp->walls[0] == s || bp->walls[1] == s || bp->walls[2] == s || bp->walls[3] == s)
-						drawIcon(sx, sy, i, _colors);
+						drawIcon(sx, sy, i, _colors, flags[i]);
 				}
 			}
 		}
 	}
 
+	drawLegend(l, legendFlags);
+
 	const int mx = offX + (partyBlock & 0x1F) * cell;
 	const int my = offY + (partyBlock >> 5) * cell;
 	const int cx = mx + cell / 2;
@@ -753,117 +778,131 @@ void Automap_EoB::redrawBackground(const AutomapLayout &l, int width, int height
 
 	bg.fillRect(Common::Rect(0, 0, width, height), _colors[kColorStone]);
 	automapNoise(bg, 0, 0, width, height, _colors[kColorStoneHi], _colors[kColorStoneEdge], 0x9e3779b9u);
-		automapBevel(bg, Common::Rect(0, 0, width, height), _colors[kColorStoneHi], _colors[kColorStoneEdge]);
-		automapBevel(bg, Common::Rect(2, 2, width - 2, height - 2), _colors[kColorStone], _colors[kColorStoneEdge]);
-		const int rv = MAX(2, l.frame / 4);
-		const int ri = l.frame / 2;
-		automapRivet(bg, ri, ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
-		automapRivet(bg, width - ri, ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
-		automapRivet(bg, ri, height - ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
-		automapRivet(bg, width - ri, height - ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
-
-		const Common::Rect mr(l.mapX, l.mapY, l.mapX + l.mapW, l.mapY + l.mapH);
-		bg.fillRect(mr, _colors[kColorPaperEdge]);
-		bg.fillRect(Common::Rect(mr.left + 2, mr.top + 2, mr.right - 2, mr.bottom - 2), _colors[kColorPaper]);
-		automapNoise(bg, mr.left + 2, mr.top + 2, l.mapW - 4, l.mapH - 4, _colors[kColorPaperHi], _colors[kColorPaperLo], 0x85ebca6bu);
-		bg.frameRect(Common::Rect(mr.left + 2, mr.top + 2, mr.right - 2, mr.bottom - 2), _colors[kColorInkSoft]);
-		bg.frameRect(Common::Rect(mr.left + 5, mr.top + 5, mr.right - 5, mr.bottom - 5), _colors[kColorInk]);
-		bg.hLine(l.mapX + mpad, l.footY, l.mapX + l.mapW - mpad, _colors[kColorInkSoft]);
-
-		const Common::Rect sr(l.sideX, l.sideY, l.sideX + l.sideW, l.sideY + l.sideH);
-		bg.fillRect(sr, _colors[kColorStoneDark]);
-		automapNoise(bg, sr.left, sr.top, l.sideW, l.sideH, _colors[kColorStoneHi], _colors[kColorStoneEdge], 0xc2b2ae35u);
-		automapBevel(bg, sr, _colors[kColorStoneEdge], _colors[kColorStoneHi]);
-
-		// Plaque face
-		bg.fillRect(Common::Rect(l.plX, l.plY, l.plX + l.plW, l.plY + l.plH), _colors[kColorPlaqueEd]);
-		bg.fillRect(Common::Rect(l.plX + 2, l.plY + 2, l.plX + l.plW - 2, l.plY + l.plH - 2), _colors[kColorPlaqueBg]);
-
-		const int lx = l.plX, colW = l.plW;
-		const int rowH = fh * sc + MAX(4, sc * 4);
-		int cyy = l.plY + l.plH + MAX(8, sc * 6);
-
-		automapDrawBigString(bg, bigFont, _legendStrings[0], lx, cyy, colW, _colors[kColorGoldDim], sc);
-		cyy += fh * sc + MAX(4, sc * 3);
-		bg.hLine(lx, cyy, lx + colW - 1, _colors[kColorStoneHi]);
-		bg.hLine(lx, cyy + 1, lx + colW - 1, _colors[kColorStoneEdge]);
-		cyy += MAX(6, sc * 4);
-
-		// TODO: Move legend out of here and redraw it with only the icons that are actually
-		// needed for the current level map (to make it less crowded, the same way it is done for LOL).
-		const int isz = MAX(6, fh * sc);
-		for (int i = 0; i < 13; ++i) {
-			const int ix = lx, iy = cyy;
-			switch (i) {
-			case 0: // party (up)
-				automapFillTri(bg, ix + isz / 2, iy, ix + isz, iy + isz, ix, iy + isz, _colors[kColorParty]);
-				break;
-			case 1: // stairs up
-				automapFillTri(bg, ix, iy + isz, ix + isz, iy + isz, ix + isz / 2, iy, _colors[kColorStair]);
-				break;
-			case 2: // stairs down
-				automapFillTri(bg, ix, iy, ix + isz, iy, ix + isz / 2, iy + isz, _colors[kColorStair]);
-				break;
-			case 3: // teleporter
-				for (int ii = 0; ii < isz / 2 - sc; ++ii) {
-					bg.drawLine(ix + sc + ii, iy + isz / 2 - ii, ix + isz - sc - ii, iy + isz / 2 - ii, _colors[kColorTele]);
-					bg.drawLine(ix + sc + ii, iy + isz / 2 + ii, ix + isz - sc - ii, iy + isz / 2 + ii, _colors[kColorTele]);
-				}
-				break;
-			case 4: // pit
-				bg.drawEllipse(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc, _colors[kColorPit], true);
-				break;
-			case 5: // plate
-				bg.drawEllipse(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc, _colors[kColorPlate], true);
-				break;
-			case 6: // door
-				bg.fillRect(Common::Rect(ix, iy + isz / 3, ix + isz, iy + isz - isz / 3), _colors[kColorDoor]);
-				break;
-			case 7: { // illusionary wall
-				bg.fillRect(Common::Rect(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc), _colors[kColorFloor]);
-				int step = ((isz - 2 * sc) << 8) / 5;
-				for (int g = 0; g < 5; ++g) {
-					bg.drawLine(ix + sc + (step * g >> 8), iy + sc, ix + sc + (step * g >> 8), iy + isz - sc, _colors[kColorWall]);
-					bg.drawLine(ix + sc, iy + sc + (step * g >> 8), ix + isz - sc, iy + sc + (step * g >> 8), _colors[kColorWall]);
-				}
-			} break;
-			case 8: // wall of force
-				bg.fillRect(Common::Rect(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc), _colors[kColorWoF]);
-				break;
-			case 9:
-				bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorLever]);
-				break;
-			case 10:
-				bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorInteractive]);
-				break;
-			case 11: // niche
-				bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorNiche]);
-				break;
-			case 12: // stone portal
-				bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorTele]);
-			default:
-				break;
+	automapBevel(bg, Common::Rect(0, 0, width, height), _colors[kColorStoneHi], _colors[kColorStoneEdge]);
+	automapBevel(bg, Common::Rect(2, 2, width - 2, height - 2), _colors[kColorStone], _colors[kColorStoneEdge]);
+	const int rv = MAX(2, l.frame / 4);
+	const int ri = l.frame / 2;
+	automapRivet(bg, ri, ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
+	automapRivet(bg, width - ri, ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
+	automapRivet(bg, ri, height - ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
+	automapRivet(bg, width - ri, height - ri, rv, _colors[kColorStoneEdge], _colors[kColorStoneHi], _colors[kColorRivet]);
+
+	const Common::Rect mr(l.mapX, l.mapY, l.mapX + l.mapW, l.mapY + l.mapH);
+	bg.fillRect(mr, _colors[kColorPaperEdge]);
+	bg.fillRect(Common::Rect(mr.left + 2, mr.top + 2, mr.right - 2, mr.bottom - 2), _colors[kColorPaper]);
+	automapNoise(bg, mr.left + 2, mr.top + 2, l.mapW - 4, l.mapH - 4, _colors[kColorPaperHi], _colors[kColorPaperLo], 0x85ebca6bu);
+	bg.frameRect(Common::Rect(mr.left + 2, mr.top + 2, mr.right - 2, mr.bottom - 2), _colors[kColorInkSoft]);
+	bg.frameRect(Common::Rect(mr.left + 5, mr.top + 5, mr.right - 5, mr.bottom - 5), _colors[kColorInk]);
+	bg.hLine(l.mapX + mpad, l.footY, l.mapX + l.mapW - mpad, _colors[kColorInkSoft]);
+
+	const Common::Rect sr(l.sideX, l.sideY, l.sideX + l.sideW, l.sideY + l.sideH);
+	bg.fillRect(sr, _colors[kColorStoneDark]);
+	automapNoise(bg, sr.left, sr.top, l.sideW, l.sideH, _colors[kColorStoneHi], _colors[kColorStoneEdge], 0xc2b2ae35u);
+	automapBevel(bg, sr, _colors[kColorStoneEdge], _colors[kColorStoneHi]);
+
+	bg.fillRect(Common::Rect(l.plX, l.plY, l.plX + l.plW, l.plY + l.plH), _colors[kColorPlaqueEd]);
+	bg.fillRect(Common::Rect(l.plX + 2, l.plY + 2, l.plX + l.plW - 2, l.plY + l.plH - 2), _colors[kColorPlaqueBg]);
+
+	int lx = l.plX, colW = l.plW;
+	int cyy = l.plY + l.plH + MAX(8, sc * 6);
+
+	automapDrawBigString(bg, bigFont, _legendStrings[0], lx, cyy, colW, _colors[kColorGoldDim], sc);
+	cyy += fh * sc + MAX(4, sc * 3);
+	bg.hLine(lx, cyy, lx + colW - 1, _colors[kColorStoneHi]);
+	bg.hLine(lx, cyy + 1, lx + colW - 1, _colors[kColorStoneEdge]);
+}
+
+void Automap_EoB::drawLegend(const AutomapLayout &l, uint flags) {
+	Graphics::Surface &bg = *_automapFrame;
+	const Graphics::Font *bigFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+	int fh = bigFont ? bigFont->getFontHeight() : 8;
+	int sc = CLIP<int>(_automapBg->w / 320, 1, 3);
+	int isz = MAX(6, fh * sc);
+	int rowH = fh * sc + MAX(4, sc * 4);
+	int lx = l.plX;
+	int colW = l.plW;
+	int cyy = l.plY + l.plH + MAX(8, sc * 6) + fh * sc + MAX(4, sc * 3) + MAX(6, sc * 4);
+
+	for (int i = 0; i < ARRAYSIZE(_stringTable[0].legendStrings) - 1; ++i) {
+		if (!(flags & (1 << i)))
+			continue;
+
+		int ix = lx;
+		int iy = cyy;
+
+		switch (i) {
+		case 0: // party (up)
+			automapFillTri(bg, ix + isz / 2, iy, ix + isz, iy + isz, ix, iy + isz, _colors[kColorParty]);
+			break;
+		case 1: // stairs up
+			automapFillTri(bg, ix, iy + isz, ix + isz, iy + isz, ix + isz / 2, iy, _colors[kColorStair]);
+			break;
+		case 2: // stairs down
+			automapFillTri(bg, ix, iy, ix + isz, iy, ix + isz / 2, iy + isz, _colors[kColorStair]);
+			break;
+		case 3: // teleporter
+			for (int ii = 0; ii < isz / 2 - sc; ++ii) {
+				bg.drawLine(ix + sc + ii, iy + isz / 2 - ii, ix + isz - sc - ii, iy + isz / 2 - ii, _colors[kColorTele]);
+				bg.drawLine(ix + sc + ii, iy + isz / 2 + ii, ix + isz - sc - ii, iy + isz / 2 + ii, _colors[kColorTele]);
+			}
+			break;
+		case 4: // pit
+			bg.drawEllipse(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc, _colors[kColorPit], true);
+			break;
+		case 5: // plate
+			bg.drawEllipse(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc, _colors[kColorPlate], true);
+			break;
+		case 6: // door
+			bg.fillRect(Common::Rect(ix, iy + isz / 3, ix + isz, iy + isz - isz / 3), _colors[kColorDoor]);
+			break;
+		case 7: // barrier
+			bg.fillRect(Common::Rect(ix, iy + isz / 3, ix + isz, iy + isz - isz / 3), _colors[kColorInteractive]);
+			break;
+		case 8: { // illusionary wall
+			bg.fillRect(Common::Rect(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc), _colors[kColorFloor]);
+			int step = ((isz - 2 * sc) << 8) / 5;
+			for (int g = 0; g < 5; ++g) {
+				bg.drawLine(ix + sc + (step * g >> 8), iy + sc, ix + sc + (step * g >> 8), iy + isz - sc, _colors[kColorWall]);
+				bg.drawLine(ix + sc, iy + sc + (step * g >> 8), ix + isz - sc, iy + sc + (step * g >> 8), _colors[kColorWall]);
 			}
-			const int tx = lx + isz + MAX(4, sc * 2);
-			const int tw = colW - isz - MAX(4, sc * 2);
-			const int lsc = automapFit(bigFont, _legendStrings[i + 1], tw, sc);
-			automapDrawBigString(bg, bigFont, _legendStrings[i + 1], tx, iy + (isz - fh * lsc) / 2, tw, _colors[kColorPanelTxt], lsc, Graphics::kTextAlignLeft);
-			cyy += rowH;
+		} break;
+		case 9: // wall of force
+			bg.fillRect(Common::Rect(ix + sc, iy + sc, ix + isz - sc, iy + isz - sc), _colors[kColorWoF]);
+			break;
+		case 10:
+			bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorLever]);
+			break;
+		case 11:
+			bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorInteractive]);
+			break;
+		case 12: // niche
+			bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorNiche]);
+			break;
+		case 13: // stone portal
+			bg.fillRect(Common::Rect(ix + isz / 3, iy, ix + isz - isz / 3, iy + isz), _colors[kColorTele]);
+		default:
+			break;
 		}
+		const int tx = lx + isz + MAX(4, sc * 2);
+		const int tw = colW - isz - MAX(4, sc * 2);
+		const int lsc = automapFit(bigFont, _legendStrings[i + 1], tw, sc);
+		automapDrawBigString(bg, bigFont, _legendStrings[i + 1], tx, iy + (isz - fh * lsc) / 2, tw, _colors[kColorPanelTxt], lsc, Graphics::kTextAlignLeft);
+		cyy += rowH;
+	}
 
-		cyy += MAX(6, sc * 5);
-		automapDrawBigString(bg, bigFont, _controlStrings[0], lx, cyy, colW, _colors[kColorGoldDim], sc);
-		cyy += fh * sc + MAX(4, sc * 3);
-		bg.hLine(lx, cyy, lx + colW - 1, _colors[kColorStoneHi]);
-		bg.hLine(lx, cyy + 1, lx + colW - 1, _colors[kColorStoneEdge]);
-		cyy += MAX(6, sc * 4);
-		const int chipPad = MAX(2, sc * 2);
-		const int chipW = (bigFont ? bigFont->getStringWidth("Up/Down") * sc : 6 * sc) + chipPad * 2; // TODO: Use actual up/down arrow symbols. Our font doesn't have these.
-		const int chipH = fh * sc + chipPad;
-		bg.fillRect(Common::Rect(lx, cyy, lx + chipW, cyy + chipH), _colors[kColorPlaqueEd]);
-		bg.fillRect(Common::Rect(lx + 1, cyy + 1, lx + chipW - 1, cyy + chipH - 1), _colors[kColorPlaqueBg]);
-		automapDrawBigString(bg, bigFont, "Up/Down", lx, cyy + chipPad / 2, chipW, _colors[kColorGold], sc); // TODO: see above
-		automapDrawBigString(bg, bigFont, _controlStrings[1], lx + chipW + MAX(4, sc * 3), cyy + (chipH - fh * sc) / 2, colW - chipW - MAX(4, sc * 3), _colors[kColorPanelTxt], sc, Graphics::kTextAlignLeft);
+	cyy += MAX(6, sc * 5);
+	automapDrawBigString(bg, bigFont, _controlStrings[0], lx, cyy, colW, _colors[kColorGoldDim], sc);
+	cyy += fh * sc + MAX(4, sc * 3);
+	bg.hLine(lx, cyy, lx + colW - 1, _colors[kColorStoneHi]);
+	bg.hLine(lx, cyy + 1, lx + colW - 1, _colors[kColorStoneEdge]);
+	cyy += MAX(6, sc * 4);
+	const int chipPad = MAX(2, sc * 2);
+	const int chipW = (bigFont ? bigFont->getStringWidth("Up/Down") * sc : 6 * sc) + chipPad * 2; // TODO: Use actual up/down arrow symbols. Our font doesn't have these.
+	const int chipH = fh * sc + chipPad;
+	bg.fillRect(Common::Rect(lx, cyy, lx + chipW, cyy + chipH), _colors[kColorPlaqueEd]);
+	bg.fillRect(Common::Rect(lx + 1, cyy + 1, lx + chipW - 1, cyy + chipH - 1), _colors[kColorPlaqueBg]);
+	automapDrawBigString(bg, bigFont, "Up/Down", lx, cyy + chipPad / 2, chipW, _colors[kColorGold], sc); // TODO: see above
+	automapDrawBigString(bg, bigFont, _controlStrings[1], lx + chipW + MAX(4, sc * 3), cyy + (chipH - fh * sc) / 2, colW - chipW - MAX(4, sc * 3), _colors[kColorPanelTxt], sc, Graphics::kTextAlignLeft);
 }
 
 uint16 Automap_EoB::calcNewBlockPosition(uint16 block, int8 dir) const {
@@ -881,19 +920,68 @@ bool Automap_EoB::isSeen(uint16 block) const {
 	return (_blockData[block].direction & 1) != 0;
 }
 
-bool Automap_EoB::isBreakableBlockObject(uint16 block) const {
+int Automap_EoB::checkForBreakableObjectType(uint16 block) const {
+	LevelBlockProperty &bp = _blockData[block];
+
+	// Scripted types: most things in EOBII, like the barrels in the catacombs, the glass walls, the sealed 4 horns door, etc.
+	// The scripts may require specific items to be used, like the green hammer, the 4 horns, etc. 
+	bool breakableType = (bp.flags & 0x800);
+
+	if (!breakableType) {
+		// Non-scripted types: walls that can just be destroyed by a weapon, like the spider webs in the EOBII catacombs. Any
+		// close-combat weapon can be used.
+		for (int i = 0; i < 4 && !breakableType; ++i) {
+			if (_specialWallTypes[bp.walls[i]] == 0xFF)
+				breakableType = true;
+		}
+	}
+
+	if (!breakableType)
+		return kNoBreakableObject;
+
+	// Determine from the room layout whether it is a door-like barrier.
+	for (int i = 0; i < 2; ++i) {
+		if (!(_wllWallFlags[bp.walls[i]] & 1) && !(_wllWallFlags[bp.walls[i ^ 2]] & 1) &&
+			(_wllWallFlags[_blockData[calcNewBlockPosition(block, i)].walls[i ^ 2]] & 1) && (_wllWallFlags[_blockData[calcNewBlockPosition(block, i ^ 2)].walls[i]] & 1) &&
+				!(_wllWallFlags[_blockData[calcNewBlockPosition(block, i ^ 1)].walls[i ^ 3]] & 1) && !(_wllWallFlags[_blockData[calcNewBlockPosition(block, i ^ 3)].walls[i ^ 1]] & 1))
+					return kBreakableBarrierNS + i;
+	}
+
+	if (!(bp.flags & 0x800))
+		return kNoBreakableObject;
+
+	// Breakable objects (like the barrels in the EOBII catacombsvor the mantis eggs in the silver tower). Check if it is accessible/interactive from multiple sides.
+	int cn = 0;	
+	for (int i = 0; i < 4; ++i) {
+		if (!(_wllWallFlags[bp.walls[i]] & 1) && _specialWallTypes[bp.walls[i]] == 8)
+			++cn;
+	}
+	if (cn >= 2)
+		return kBreakableBlockObject;
+
+	// Unfortunately, some breakable objects don't get processed completely by the scripts after being broken. This can lead to glitchy drawing. So we try to figure out
+	// here if it is a broken barrier and report that...
+	cn = 0;
+	for (int i = 0; i < 4; ++i) {
+		if (!(_wllWallFlags[bp.walls[i]] & 1))
+			++cn;
+	}
+	if (cn < 4)
+		return kBrokenBarrier;
+
+	return kNoBreakableObject;
+}
+
+bool Automap_EoB::isCenteredSwitch(uint16 block) const {
 	LevelBlockProperty &bp = _blockData[block];
-	if (!_gameSupportsBreakables || !(bp.flags & 0x800))
-		return false;
-	// Breakable objects (like the barrels or the crumbling wall in the EOBII catacombs)
-	// Check if it is accessible/interactive from multiple sides.
+
 	int cn = 0;
-	for (int iii = 0; iii < 4; ++iii) {
-		uint8 s = _specialWallTypes[bp.walls[iii]];
-		if (s == 8 || s == 9)
+	for (int i = 0; i < 4; ++i) {
+		uint8 ww = bp.walls[i];
+		if ((_wllWallFlags[ww] & 1) && _specialWallTypes[ww] == 3)
 			++cn;
 	}
-	return (cn >= 2);
+	return (cn > 1);
 }
 
 int EoBCoreEngine::clickedAutomap(Button *button) {
diff --git a/engines/kyra/gui/automap_eob.h b/engines/kyra/gui/automap_eob.h
index 91bb8587ffc..7b095396a15 100644
--- a/engines/kyra/gui/automap_eob.h
+++ b/engines/kyra/gui/automap_eob.h
@@ -49,6 +49,7 @@ public:
 
 	void markVisited(uint16 block);
 	void markSeen(uint16 block, int8 dir);
+
 	void draw(int level, uint16 partyBlock, int8 partyDirection);
 
 private:
@@ -64,7 +65,7 @@ private:
 	};
 
 	struct TranslateableStrings {
-		const char *const legendStrings[14];
+		const char *const legendStrings[15];
 		const char *const controlStrings[3];
 		const char *const levelNames[2][16];
 	};
@@ -72,10 +73,21 @@ private:
 	AutomapLayout createLayout() const;
 	void createColors();
 	void redrawBackground(const AutomapLayout &l, int width, int height);
+	void drawLegend(const AutomapLayout &l, uint flags);
 	uint16 calcNewBlockPosition(uint16 block, int8 dir) const;
 	bool isVisited(uint16 block) const;
 	bool isSeen(uint16 block) const;
-	bool isBreakableBlockObject(uint16 block) const;
+
+	enum BreakableObjectType {
+		kNoBreakableObject = 0,
+		kBreakableBlockObject,
+		kBreakableBarrierNS,
+		kBreakableBarrierEW,
+		kBrokenBarrier
+	};
+
+	int checkForBreakableObjectType(uint16 block) const;
+	bool isCenteredSwitch(uint16 block) const;
 
 	bool _visible;
 
@@ -88,7 +100,6 @@ private:
 	const uint8 *_portalParams;
 	int _portalParamsLen;
 	const bool _enabled;
-	const bool _gameSupportsBreakables;
 
 	static const TranslateableStrings _stringTable[];
 	const char *const *_legendStrings;




More information about the Scummvm-git-logs mailing list