[Scummvm-git-logs] scummvm master -> 4dc20b7f941dfa87fff9e74e19f71fba1d702644

athrxx noreply at scummvm.org
Sun Oct 4 14:24:51 UTC 2026


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

Summary:
4dc20b7f94 KYRA: (EOB automap feature) - add special hard-coded map spots


Commit: 4dc20b7f941dfa87fff9e74e19f71fba1d702644
    https://github.com/scummvm/scummvm/commit/4dc20b7f941dfa87fff9e74e19f71fba1d702644
Author: athrxx (athrxx at scummvm.org)
Date: 2026-10-04T16:11:48+02:00

Commit Message:
KYRA: (EOB automap feature) - add special hard-coded map spots

Added some hardcoded locations on the map, mainly
for level exits that don't have a stairway, teleporter, etc.
(e. g. Temple Darkmoon in the EOBII forest).
Also improved text spacing a bit for lower resolutions.

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 b8c170146a8..046db0c5bb7 100644
--- a/engines/kyra/gui/automap_eob.cpp
+++ b/engines/kyra/gui/automap_eob.cpp
@@ -30,10 +30,10 @@
 
 namespace Kyra {
 
-// Automap strings that should be translated to the game's language. Currently, only English is available.
+// Automap strings that should be translated to the game's language.
 // TODO: Probably move to KYRA.DAT eventually.
 const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
-	{
+	{	// English
 		{
 			"- LEGEND -",
 			"Party",
@@ -65,7 +65,7 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 		// The FM-Towns version of EOBII has level names for its autogenerated savegame names
 		// which are similar to what we do (names based on the graphics/sound files).
 		{
-			{
+			{	// EOB I level names
 				"Upper Sewers",
 				"Middle Sewers",
 				"Lower Sewers",
@@ -83,7 +83,7 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 				"",
 				""
 			},
-			{
+			{	// EOB II level names
 				"Catacombs I",
 				"Catacombs II",
 				"Catacombs III",
@@ -101,9 +101,20 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 				"Crimson Tower I",
 				"Crimson Tower II"
 			}
+		},
+		{
+			{	// EOB I special markers
+				"",
+				""
+			},
+			{	// EOB II special markers
+				"Temple Darkmoon",
+				"Hidden Stairway",
+				"Forest Exit"
+			}
 		}
 	},
-	{
+	{	// German
 		{
 			"- LEGENDE -",
 			"Gruppe",
@@ -117,7 +128,7 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 			"Illusionswand",
 			"Kraftfeld",
 			"Schalter",
-			"Interaktives Objekt",
+			"Interaktionsobjekt",
 			"Nische",
 			"Steinportal"
 		},
@@ -128,14 +139,8 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 			"Esc/Tab",		"Beenden"
 		},
 
-		// Area names for the plaque. The games have no level names in their data and the file
-		// names of the graphics and sound data files provide only vague hints. So we hardcode
-		// the level names here. The Sega CD version of EOBI has an automap, but it doesn't use
-		// level names. The maps are just called "L%d" or "Floor %d" (%d being the level number).
-		// The FM-Towns version of EOBII has level names for its autogenerated savegame names
-		// which are similar to what we do (names based on the graphics/sound files).
-		{
-			{	
+		{	
+			{	// EOB I level names
 				"Kanalisation I",
 				"Kanalisation II",
 				"Kanalisation III",
@@ -153,7 +158,7 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 				"",
 				""
 			},
-			{
+			{	// EOB II level names
 				"Katakomben I",
 				"Katakomben II",
 				"Katakomben III",
@@ -171,15 +176,34 @@ const Automap_EoB::TranslateableStrings Automap_EoB::_stringTable[] = {
 				"Purpurturm I",
 				"Purpurturm II"
 			}
+		},
+		{
+			{	// EOB I special markers
+				"",
+				""
+			},
+			{	// EOB II special markers
+				"Tempel Darkmoon",
+				"Versteckte Treppe",
+				"Ausgang zum Wald"	
+			}
 		}
 	}
 };
 
+// These are manual map entries for certain location that deserve a marker.
+// Currently, we use them for level exits that would otherwise have no map entry.
+const Automap_EoB::SpecialMarkers Automap_EoB::_specialMarkersEOB2[] = {
+	{	04,		0x14F,		kColorSpecial7 },	//  Temple Darkmoon
+	{	04,		0x211,		kColorSpecial2 },	//  Hidden Stairway
+	{	05,		0x12F,		kColorSpecial1 }	//  Forest Exit
+};
+
 Automap_EoB::Automap_EoB(OSystem *system, LevelBlockProperty **blockData, const uint8 *wllFlags, const uint8 *specialWallTypes, const int8 *wllShapeMap, /* const uint8 *wllVmpMap,*/ int gameID, int lang, bool featureEnabled) :
 	_system(system), _blockData(*blockData), _wllWallFlags(wllFlags), _specialWallTypes(specialWallTypes), _wllShapeMap(wllShapeMap), /*_wllVmpMap(wllVmpMap),*/ _enabled(featureEnabled), _visible(false), _background(nullptr),
 		_frame(nullptr), _specialBlockIDs(nullptr), _levelNames(nullptr), _colors(nullptr), _legendStrings(nullptr), _controlStrings(nullptr), _numLevelNames(gameID == GI_EOB1 ? 12 : (gameID == GI_EOB2 ? 16 : 0)), _l(),
 			_wallOfForceID(gameID == GI_EOB1 ? 0xFF : 74), _portalParamsLen(0), _portalParams(nullptr), _drawIcon(nullptr), _legendHeadScl(1), _legendBodyScl(1), _levelStrScl(1), _coordStrScl(1), _levelStrY(0), _coordStrY(0),
-				_partyIconColor(kColorPartyFrame0), _partyIconColorStep(1) {
+				_partyIconColor(kColorPartyFrame0), _partyIconColorStep(1), _specialMarkers(nullptr), _numSpecialMarkers(0), _specialMarkerStrings(nullptr), _reduceSpace(0) {
 	_background = new Graphics::Surface();
 	_frame = new Graphics::Surface();
 
@@ -202,6 +226,12 @@ Automap_EoB::Automap_EoB(OSystem *system, LevelBlockProperty **blockData, const
 	_legendStrings = _stringTable[langIndex].legendStrings;
 	_controlStrings = _stringTable[langIndex].controlStrings;
 	_levelNames = _stringTable[langIndex].levelNames[gameIndex];
+	_specialMarkerStrings = _stringTable[langIndex].specialMarkerStrings[gameIndex];
+
+	if (gameID == GI_EOB2) {
+		_specialMarkers = _specialMarkersEOB2;
+		_numSpecialMarkers = ARRAYSIZE(_specialMarkersEOB2);
+	}
 
 	const uint8 teleporter = gameID == GI_EOB1 ? 52 : 44;
 	const uint8 illusion1 = gameID == GI_EOB1 ? 67 : 46;
@@ -510,8 +540,17 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 				(this->*_drawIcon)(surf, 0, kIconBigObject, sx, sy, _l.cell, kAlignCenter, 0, 0, -1);
 				legendFlags |= 0x2000;
 			} else {
-				// Special blocks
-				
+				// Hard coded special blocks. Mostly used for level exits that are neither stairs nor teleporters (e. g. Temple Darkmoon in the EOBII forest).
+				for (int i = 0, flc = 0; i < _numSpecialMarkers; ++i) {
+					if (level != _specialMarkers[i].level)
+						continue;
+					if (block == _specialMarkers[i].block) {
+						(this->*_drawIcon)(surf, 0, kIconSpecial, sx, sy, _l.cell, kAlignCenter, 0, 0, _specialMarkers[i].iconColor);
+						legendFlags |= (0x20000 << flc);
+						break;
+					}
+					++flc;
+				}
 
 				/* for (int ii = 0; ii < 4; ++ii) {
 					if (_wllVmpMap[bp->walls[ii]] != 1)
@@ -523,6 +562,7 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 					}
 				}*/
 
+				// stairs, teleporters, pits, plates, etc.
 				for (int i = 0; i < _numSpecialBlockIDs; ++i) {
 					uint8 s = _specialBlockIDs[i].wall;
 					// This is a bit tricky due to glitchy game data. EOBII puts the special wall type on all four walls of a block, but EOBI does not, so we can't
@@ -555,7 +595,7 @@ void Automap_EoB::draw(int level, uint16 partyBlock, int8 partyDirection) {
 		legendFlags |= (1 << partyDirection);
 	}
 
-	drawLegend(legendFlags);
+	drawLegend(level, legendFlags);
 
 	const Graphics::Font *bigFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
 	if (bigFont) {
@@ -640,17 +680,35 @@ void Automap_EoB::recalcScaling(int width, int height) {
 	int fh = bigFont ? bigFont->getFontHeight() : 8;
 
 	int scl = CLIP<int>(MIN<int>(width / 320, height / 200), 1, 12);
-	_legendHeadScl = fitString(bigFont, _legendStrings[0], _l.plW * 4 / 5, scl);
+	_legendHeadScl = MAX<int>(fitString(bigFont, _legendStrings[0], _l.plW * 4 / 5, scl), 1);
 
-	int isz = 2 * _l.cell + MAX(2, _legendHeadScl * 2);
-	int tw = _l.plW - isz;
 	_legendBodyScl = 12;
-	for (int i = 1; i < kNumLegendStrings; ++i)
+	int isz = 2 * fh + MAX(2, _legendHeadScl * 2);
+	int tw = _l.plW - isz;
+
+	for (int i = 1; i < kNumLegendStrings; ++i) {
 		_legendBodyScl = MIN<int>(_legendBodyScl, fitString(bigFont, _legendStrings[i], tw, _legendBodyScl));
+		if (_legendBodyScl > 1)
+			_legendBodyScl = MIN<int>(_legendBodyScl, fitString(bigFont, _legendStrings[i], tw + (_legendBodyScl - 1) * 2 * fh, _legendBodyScl));
+
+		if (_legendBodyScl == 0) {
+			_legendBodyScl = MIN<int>(_legendBodyScl, fitString(bigFont, _legendStrings[i], tw - MAX(2, _legendHeadScl * 2), _legendBodyScl));
+			_reduceSpace = 1;
+		}
+	}
+	if (_legendBodyScl == 0) {
+		_legendBodyScl = 1;
+		++_reduceSpace;
+	}
+	
 	for (int i = 2; i < kNumControlStrings; i += 2) {
 		Common::String str = Common::String::format("%s %s", _controlStrings[i], _controlStrings[i + 1]);
 		_legendBodyScl = MIN<int>(_legendBodyScl, fitString(bigFont, str, _l.plW, _legendBodyScl));
 	}
+	if (_legendBodyScl == 0) {
+		_legendBodyScl = 1;
+		++_reduceSpace;
+	}
 
 	int pm = MAX<int>(3, scl * 2);
 	int innerW = _l.plW - 2 * pm;
@@ -701,6 +759,13 @@ void Automap_EoB::createColorTable() {
 		{ 0xf0, 0xc8, 0x50 },	// gold
 		{ 0xb8, 0x92, 0x3a },	// gold dim
 		{ 0xd8, 0xc8, 0xa8 },	// panel text
+		{ 0x33, 0x88, 0x99 },	// special location 1
+		{ 0x99, 0x44, 0x44 },	// special location 2
+		{ 0x66, 0x66, 0x66 },	// special location 3
+		{ 0xff, 0xaa, 0x44 },	// special location 4
+		{ 0x33, 0xff, 0xaa },	// special location 5
+		{ 0xff, 0x44, 0x44 },	// special location 6
+		{ 0x55, 0x55, 0xff },	// special location 7
 		{ 0xfe, 0x12, 0xfe },	// transparency key
 		{ 0xa8, 0x28, 0x1c },	// party frame 0
 		{ 0xff, 0xff, 0xff },	// party frame 1 (placeholder, correct values will be calculated)
@@ -723,7 +788,7 @@ void Automap_EoB::createColorTable() {
 	// Create color gradient for the party icon frames (we let it blink for better visibility).
 	float algoBase = 1.25f; // It looks much better with a non-linear gradient.
 	int div = 0;
-	for (int i = 0; i < 10; ++i)
+	for (int i = 0; i < (kNumColors - kColorPartyFrame0); ++i)
 		div += powf(algoBase, i);
 
 	int stepR = (rgbTable[kColorPartyFrame9][0] - rgbTable[kColorPartyFrame0][0]) * 0x10000 / div;
@@ -734,7 +799,7 @@ void Automap_EoB::createColorTable() {
 	uint32 curG = rgbTable[kColorPartyFrame0][1] * 0x10000;
 	uint32 curB = rgbTable[kColorPartyFrame0][2] * 0x10000;
 
-	for (int i = 0; i < 10; ++i) {
+	for (int i = 0; i < (kNumColors - kColorPartyFrame0); ++i) {
 		colors[kColorPartyFrame0 + i] = fmt.RGBToColor(curR >> 16, curG >> 16, curB >> 16);
 		curR += stepR * powf(algoBase, i);
 		curG += stepG * powf(algoBase, i);
@@ -895,6 +960,13 @@ void Automap_EoB::createIcons(bool lowResTarget) {
 			surf.fillRect(Common::Rect(doorWdth, doorLen), colTable[kColorDoor]);
 			break;
 		case kIconSpecial:
+			prepSurface(size2full, size2full, -1);
+			for (int i = 0; i < 360; i += 45) {
+				for (int ii = -10; ii < 10; ++ii) {
+					float a = (float)((360 + i + ii) % 360) * M_PI / 180.0f;
+					surf.drawLine(size2half + size2half * cosf(a), size2half + size2half * sinf(a), size2half + (size2half / 3) * cosf(a), size2half + (size2half / 3) * sinf(a), colTable[kColorPartyFrame0]);
+				}
+			}
 			break;
 		default:
 			break;
@@ -1027,7 +1099,7 @@ void Automap_EoB::drawBackground(int width, int height) {
 	bg.hLine(_l.plX, cyy + 1, _l.plX + _l.plW - 1, _colors[kColorStoneEdge]);
 }
 
-void Automap_EoB::drawLegend(uint flags) {
+void Automap_EoB::drawLegend(int level,	uint flags) {
 	Graphics::Surface &bg = *_frame;
 	const Graphics::Font *bigFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
 	int fh = bigFont ? bigFont->getFontHeight() : 8;
@@ -1055,7 +1127,7 @@ void Automap_EoB::drawLegend(uint flags) {
 	assert(ARRAYSIZE(legendIcons) == kNumLegendStrings + 2); // ignore first string (title), but there is also only one string for the party (regardless of direction)
 
 	int lh = fh * _legendBodyScl;
-	int isz = 2 * lh + MAX(2, _legendHeadScl * 2);
+	int isz = 2 * lh + (1 - _reduceSpace) * MAX(2, _legendHeadScl * 2);
 	int tw = _l.plW - isz;
 	int rowH = lh + MAX(4, _legendBodyScl * 4);
 
@@ -1080,6 +1152,28 @@ void Automap_EoB::drawLegend(uint flags) {
 		cyy += rowH;
 	}
 
+	// Now, the special locations, if we have any...
+	flags &= ~0x1ffff;
+	for (int i = 0; i < 7; ++i) {
+		if (!(flags & (0x20000 << i)))
+			continue;
+
+		int id = i;
+		for (int ii = 0; ii < _numSpecialMarkers && id >= 0; ++ii) {
+			if (_specialMarkers[ii].level != level)
+				continue;
+			if (id-- == 0) {
+				id = ii;
+				break;
+			}
+		}
+
+		(this->*_drawIcon)(bg, 1, kIconSpecial, _l.plX, cyy, lh, kAlignCenter, 0, 0, _specialMarkers[id].iconColor);
+
+		drawString(bg, bigFont, _specialMarkerStrings[id], tx, cyy, tw, _colors[kColorPanelTxt], _legendBodyScl, Graphics::kTextAlignLeft);
+		cyy += rowH;
+	}
+
 	cyy += MAX(4, _legendHeadScl * 4);
 	drawString(bg, bigFont, _controlStrings[0], _l.plX, cyy, _l.plW, _colors[kColorGoldDim], _legendHeadScl);
 	cyy += fh * _legendHeadScl + MAX(4, _legendHeadScl * 3);
@@ -1091,7 +1185,7 @@ void Automap_EoB::drawLegend(uint flags) {
 
 	int maxW = 0;
 	for (int i = 2; i < kNumControlStrings; i += 2)
-		maxW = MAX<int>(maxW, (bigFont ? bigFont->getStringWidth(_controlStrings[i]) * _legendBodyScl : 6 * _legendBodyScl) + chipPad * 2);
+		maxW = MAX<int>(maxW, (bigFont ? bigFont->getStringWidth(_controlStrings[i]) * _legendBodyScl : 6 * _legendBodyScl) + chipPad * 2 - _reduceSpace);
 
 	for (int i = 2; i < kNumControlStrings; i += 2) {
 		int chipW = (bigFont ? bigFont->getStringWidth(_controlStrings[i]) * _legendBodyScl : 6 * _legendBodyScl) + chipPad * 2;
@@ -1163,7 +1257,7 @@ template void Automap_EoB::drawIconImpl<uint32>(Graphics::Surface&, int, int, in
 int Automap_EoB::fitString(const Graphics::Font *f, const Common::String &str, int maxW, int maxSc) const {
 	Common::U32String u32str(str.c_str(), Common::CodePage::kUtf8);
 	int wdth = f ? f->getStringWidth(u32str) : 0;
-	return (wdth == 0) ? 1 : CLIP<int>(maxW / wdth, 1, maxSc);
+	return (wdth == 0) ? 0 : CLIP<int>(maxW / wdth, 0, maxSc);
 }
 
 uint16 Automap_EoB::calcNewBlockPosition(uint16 block, int8 dir) const {
diff --git a/engines/kyra/gui/automap_eob.h b/engines/kyra/gui/automap_eob.h
index c79fe3bbf3f..475c8d3508b 100644
--- a/engines/kyra/gui/automap_eob.h
+++ b/engines/kyra/gui/automap_eob.h
@@ -76,6 +76,13 @@ private:
 		const char *const legendStrings[kNumLegendStrings];
 		const char *const controlStrings[kNumControlStrings];
 		const char *const levelNames[2][16];
+		const char *const specialMarkerStrings[2][3];
+	};
+
+	struct SpecialMarkers {
+		int8 level;
+		uint16 block;
+		int8 iconColor;
 	};
 
 	enum IconID : int {
@@ -110,7 +117,7 @@ private:
 	void createIcons(bool lowResSurface);
 	void releaseIcons();
 	void drawBackground(int width, int height);
-	void drawLegend(uint flags);
+	void drawLegend(int level, uint flags);
 
 	enum IconAlignment : int {
 		kAlignTopLeft = -1,
@@ -167,11 +174,17 @@ private:
 	const char *const *_levelNames;
 	const int _numLevelNames;
 
+	static const SpecialMarkers _specialMarkersEOB2[];
+	const SpecialMarkers *_specialMarkers;
+	const char *const *_specialMarkerStrings;
+	int _numSpecialMarkers;
+
 	AutomapLayout _l;
 	int _levelStrScl;
 	int _coordStrScl;
 	int _legendHeadScl;
 	int _legendBodyScl;
+	int _reduceSpace;
 	int _levelStrY;
 	int _coordStrY;
 
@@ -214,6 +227,13 @@ private:
 		kColorGold,
 		kColorGoldDim,
 		kColorPanelTxt,
+		kColorSpecial1,
+		kColorSpecial2,
+		kColorSpecial3,
+		kColorSpecial4,
+		kColorSpecial5,
+		kColorSpecial6,
+		kColorSpecial7,
 		kColorTransp,
 		kColorPartyFrame0,
 		kColorPartyFrame1,
@@ -228,7 +248,7 @@ private:
 		kNumColors
 	};
 
-	const uint32 *_colors;
+	/* const */uint32 *_colors;
 	int _partyIconColor;
 	int _partyIconColorStep;
 };




More information about the Scummvm-git-logs mailing list