changeset 9618:c3886802471d draft

(svn r13674) -Fix [FS#2127]: crash when drawing a non-real sprite. The drawing of the non-real sprite is caused when two NewGRFs replace the same sprite and the first replaces it with a real sprite (and thus assumes it remains a real sprite) and the second replaces it with a non-real sprite. OpenTTD already looked at whether the sprite to load should be seen as a real or non-real sprite, but it failed to replace non-real sprites with a substitute real sprite when getting the sprite from the cache.
author rubidium <rubidium@openttd.org>
date Fri, 04 Jul 2008 14:45:51 +0000
parents 67791dec09fd
children d287838c713c
files src/spritecache.cpp
diffstat 1 files changed, 10 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/spritecache.cpp
+++ b/src/spritecache.cpp
@@ -24,10 +24,11 @@
 
 struct SpriteCache {
 	void *ptr;
+	size_t file_pos;
 	uint32 id;
-	size_t file_pos;
 	uint16 file_slot;
 	int16 lru;
+	bool real_sprite; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as non-real sprite. If the non-real sprite gets into the cache it might be drawn as real sprite which causes enormous trouble.
 };
 
 
@@ -176,6 +177,7 @@
 		byte *dest = (byte *)AllocSprite(num);
 
 		sc->ptr = dest;
+		sc->real_sprite = false;
 		FioReadBlock(dest, num);
 
 		return sc->ptr;
@@ -217,9 +219,13 @@
 			}
 		}
 
+		sc->real_sprite = false;
+
 		return sc->ptr;
 	}
 
+	sc->real_sprite = true;
+
 	if (!real_sprite) {
 		static byte warning_level = 0;
 		DEBUG(sprite, warning_level, "Tried to load real sprite #%d as a non sprite. Probable cause: NewGRF interference", id);
@@ -255,6 +261,7 @@
 	sc->ptr = NULL;
 	sc->lru = 0;
 	sc->id = file_sprite_id;
+	sc->real_sprite = false;
 
 	return true;
 }
@@ -269,6 +276,7 @@
 	scnew->file_pos = scold->file_pos;
 	scnew->ptr = NULL;
 	scnew->id = scold->id;
+	scnew->real_sprite = scold->real_sprite;
 }
 
 
@@ -453,7 +461,7 @@
 	p = sc->ptr;
 
 	/* Load the sprite, if it is not loaded, yet */
-	if (p == NULL) p = ReadSprite(sc, sprite, real_sprite);
+	if (p == NULL || sc->real_sprite != real_sprite) p = ReadSprite(sc, sprite, real_sprite);
 
 	return p;
 }