(svn r1925) Fixed an infinite loop if the town generator runs out of town names. The number of generated towns is then limited by the number of available names.
authorpasky
Sat, 05 Mar 2005 13:49:43 +0000
changeset 1421 5a9eb1b81efb
parent 1420 5308b177b5b3
child 1422 c3bc75035658
(svn r1925) Fixed an infinite loop if the town generator runs out of town names. The number of generated towns is then limited by the number of available names.
town_cmd.c
--- a/town_cmd.c	Fri Mar 04 10:34:44 2005 +0000
+++ b/town_cmd.c	Sat Mar 05 13:49:43 2005 +0000
@@ -864,21 +864,28 @@
 	}
 }
 
-static void CreateTownName(Town *t1)
+static bool CreateTownName(uint32 *townnameparts)
 {
 	Town *t2;
 	char buf1[64];
 	char buf2[64];
 	uint32 r;
+	/* Do not set too low tries, since when we run out of names, we loop
+	 * for #tries only one time anyway - then we stop generating more
+	 * towns. Do not show it too high neither, since looping through all
+	 * the other towns may take considerable amount of time (10000 is
+	 * too much). */
+	int tries = 1000;
+	uint16 townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
 
-	t1->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
+	assert(townnameparts);
 
 	for(;;) {
 restart:
 		r = Random();
 
 		SetDParam(0, r);
-		GetString(buf1, t1->townnametype);
+		GetString(buf1, townnametype);
 
 		// Check size and width
 		if (strlen(buf1) >= 31 || GetStringWidth(buf1) > 130)
@@ -886,15 +893,19 @@
 
 		FOR_ALL_TOWNS(t2) {
 			if (t2->xy != 0) {
+				// We can't just compare the numbers since
+				// several numbers may map to a single name.
 				SetDParam(0, t2->townnameparts);
 				GetString(buf2, t2->townnametype);
-				if (strcmp(buf1, buf2) == 0)
+				if (strcmp(buf1, buf2) == 0) {
+					if (tries-- < 0)
+						return false;
 					goto restart;
+				}
 			}
 		}
-		t1->townnameparts = r;
-
-		return;
+		*townnameparts = r;
+		return true;
 	}
 }
 
@@ -904,7 +915,7 @@
 	t->max_mail = t->population >> 4;
 }
 
-static void DoCreateTown(Town *t, TileIndex tile)
+static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts)
 {
 	int x, i;
 
@@ -946,7 +957,8 @@
 	t->exclusive_counter = 0;
 	t->statues = 0;
 
-	CreateTownName(t);
+	t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
+	t->townnameparts = townnameparts;
 
 	UpdateTownVirtCoord(t);
 	_town_sort_dirty = true;
@@ -997,6 +1009,7 @@
 	uint tile = TILE_FROM_XY(x,y);
 	TileInfo ti;
 	Town *t;
+	uint32 townnameparts;
 
 	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 
@@ -1013,6 +1026,10 @@
 	if (IsCloseToTown(tile, 20))
 		return_cmd_error(STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN);
 
+	// Get a unique name for the town.
+	if (!CreateTownName(&townnameparts))
+		return_cmd_error(STR_023A_TOO_MANY_TOWNS);
+
 	// Allocate town struct
 	t = AllocateTown();
 	if (t == NULL)
@@ -1021,7 +1038,7 @@
 	// Create the town
 	if (flags & DC_EXEC) {
 		_generating_world = true;
-		DoCreateTown(t, tile);
+		DoCreateTown(t, tile, townnameparts);
 		_generating_world = false;
 	}
 	return 0;
@@ -1032,6 +1049,7 @@
 	uint tile;
 	TileInfo ti;
 	Town *t;
+	uint32 townnameparts;
 
 	do {
 		// Generate a tile index not too close from the edge
@@ -1048,12 +1066,16 @@
 		if (IsCloseToTown(tile, 20))
 			continue;
 
+		// Get a unique name for the town.
+		if (!CreateTownName(&townnameparts))
+			break;
+
 		// Allocate a town struct
 		t = AllocateTown();
 		if (t == NULL)
 			break;
 
-		DoCreateTown(t, tile);
+		DoCreateTown(t, tile, townnameparts);
 		return t;
 	} while (--attempts);
 	return NULL;