namegen.c
author darkvater
Tue, 04 Jan 2005 00:07:58 +0000
changeset 880 f3d9b97fff06
parent 852 5ad549960d8b
child 948 02a654572ceb
permissions -rw-r--r--
(svn r1365) -Fix: very, very nasty buffer overflow bug introduced with replace vehicles. You CANNOT access the i[255] of an array that only has 255 elements! I will kick the next person that does that so hard...goddammit (I only noticed it because it screwed up my console in the debug build and took me at least an hour to fix)
#include "stdafx.h"
#include "ttd.h"

#include "table/namegen.h"

inline static uint32 GetNumberBasedOnSeed(int x, int y, uint32 seed)
{
	return (((uint16)(seed >> x) * (y))>>16);
}

static void ReplaceWords(byte a, byte b, byte c, byte d, byte e, byte f, byte g, byte h, byte *buf)
{
	if (buf[0] == a && buf[1] == b && buf[2] == c && buf[3] == d)
	{
		buf[0] = e;
		buf[1] = f;
		buf[2] = g;
		buf[3] = h;
	}
}

static byte MakeEnglishOriginalTownName(byte *buf, uint32 seed)
{
	int i;

	//null terminates the string for strcat
	strcpy(buf, "");

	// optional first segment
	if ((i = GetNumberBasedOnSeed(0, lengthof(name_original_english_1) + 50, seed) - 50) >= 0)
	{
		strcat(buf,name_original_english_1[i]);
	}

	//mandatory middle segments
	strcat(buf, name_original_english_2[GetNumberBasedOnSeed(4,  lengthof(name_original_english_2), seed)]);
	strcat(buf, name_original_english_3[GetNumberBasedOnSeed(7,  lengthof(name_original_english_3), seed)]);
	strcat(buf, name_original_english_4[GetNumberBasedOnSeed(10, lengthof(name_original_english_4), seed)]);
	strcat(buf, name_original_english_5[GetNumberBasedOnSeed(13, lengthof(name_original_english_5), seed)]);

	//optional last segment
	if ((i = GetNumberBasedOnSeed(15, lengthof(name_original_english_6) + 60, seed) - 60) >= 0)
	{
		strcat(buf, name_original_english_6[i]);
	}

	if (buf[0] == 'C' && (buf[1] == 'e' || buf[1] == 'i'))
		buf[0] = 'K';

	ReplaceWords('C','u','n','t',  'E','a','s','t', buf);
	ReplaceWords('S','l','a','g',  'P','i','t','s', buf);
	ReplaceWords('S','l','u','t',  'E','d','i','n', buf);
//	ReplaceWords('F','a','r','t',  'B','o','o','t', buf);
	ReplaceWords('D','r','a','r',  'Q','u','a','r', buf);
	ReplaceWords('D','r','e','h',  'B','a','s','h', buf);
	ReplaceWords('F','r','a','r',  'S','h','o','r', buf);
	ReplaceWords('G','r','a','r',  'A','b','e','r', buf);
	ReplaceWords('B','r','a','r',  'O','v','e','r', buf);
	ReplaceWords('W','r','a','r',  'I','n','v','e', buf);

	return 0;
}


static byte MakeEnglishAdditionalTownName(byte *buf, uint32 seed)
{
	int i;

	//null terminates the string for strcat
	strcpy(buf, "");

	// optional first segment
	if ((i = GetNumberBasedOnSeed(0, lengthof(name_additional_english_prefix) + 50, seed) - 50) >= 0)
	{
		strcat(buf,name_additional_english_prefix[i]);
	}

	if (GetNumberBasedOnSeed(3, 20, seed) >= 14)
	{
		strcat(buf, name_additional_english_1a[GetNumberBasedOnSeed(6, lengthof(name_additional_english_1a), seed)]);
	}
	else
	{
		strcat(buf, name_additional_english_1b1[GetNumberBasedOnSeed(6, lengthof(name_additional_english_1b1), seed)]);
		strcat(buf, name_additional_english_1b2[GetNumberBasedOnSeed(9, lengthof(name_additional_english_1b2), seed)]);
		if (GetNumberBasedOnSeed(11, 20, seed) >= 4)
		{
			strcat(buf, name_additional_english_1b3a[GetNumberBasedOnSeed(12, lengthof(name_additional_english_1b3a), seed)]);
		}
		else
		{
			strcat(buf, name_additional_english_1b3b[GetNumberBasedOnSeed(12, lengthof(name_additional_english_1b3b), seed)]);
		}
	}

	strcat(buf, name_additional_english_2[GetNumberBasedOnSeed(14, lengthof(name_additional_english_2), seed)]);

	//optional last segment
	if ((i = GetNumberBasedOnSeed(15, lengthof(name_additional_english_3) + 60, seed) - 60) >= 0)
	{
		strcat(buf, name_additional_english_3[i]);
	}

	ReplaceWords('C','u','n','t',  'E','a','s','t', buf);
	ReplaceWords('S','l','a','g',  'P','i','t','s', buf);
	ReplaceWords('S','l','u','t',  'E','d','i','n', buf);
	ReplaceWords('F','a','r','t',  'B','o','o','t', buf);
	ReplaceWords('D','r','a','r',  'Q','u','a','r', buf);
	ReplaceWords('D','r','e','h',  'B','a','s','h', buf);
	ReplaceWords('F','r','a','r',  'S','h','o','r', buf);
	ReplaceWords('G','r','a','r',  'A','b','e','r', buf);
	ReplaceWords('B','r','a','r',  'O','v','e','r', buf);
	ReplaceWords('W','r','a','r',  'S','t','a','n', buf);

	return 0;


}

static byte MakeAustrianTownName(byte *buf, uint32 seed)
{
	int i, j = 0;
	strcpy(buf, "");

	// Bad, Maria, Gross, ...
	i = GetNumberBasedOnSeed(0, lengthof(name_austrian_a1) + 15,seed) - 15;

	if (i >= 0) strcat(buf, name_austrian_a1[i]);

	i = GetNumberBasedOnSeed(4, 6, seed);
	if (i >= 4)
	{
		// Kaisers-kirchen
		strcat(buf, name_austrian_a2[GetNumberBasedOnSeed( 7, lengthof(name_austrian_a2), seed)]);
		strcat(buf, name_austrian_a3[GetNumberBasedOnSeed(13, lengthof(name_austrian_a3), seed)]);
	}
	else if (i >= 2)
	{
		// St. Johann
		strcat(buf, name_austrian_a5[GetNumberBasedOnSeed( 7, lengthof(name_austrian_a5), seed)]);
		strcat(buf, name_austrian_a6[GetNumberBasedOnSeed( 9, lengthof(name_austrian_a6), seed)]);
		j = 1; // More likely to have a " an der " or " am "
	}
	else
	{
		// Zell
		strcat(buf, name_austrian_a4[GetNumberBasedOnSeed( 7, lengthof(name_austrian_a4), seed)]);
	}

	i = GetNumberBasedOnSeed(1, 6, seed);
	if (i >= 4 - j)
	{
		// an der Donau (rivers)
		strcat(buf, name_austrian_f1[GetNumberBasedOnSeed(4, lengthof(name_austrian_f1), seed)]);
		strcat(buf, name_austrian_f2[GetNumberBasedOnSeed(5, lengthof(name_austrian_f2), seed)]);
	}
	else if (i >= 2 - j)
	{
		// am Dachstein (mountains)
		strcat(buf, name_austrian_b1[GetNumberBasedOnSeed(4, lengthof(name_austrian_b1), seed)]);
		strcat(buf, name_austrian_b2[GetNumberBasedOnSeed(5, lengthof(name_austrian_b2), seed)]);
	}

	return 0;
}

static byte MakeGermanTownName(byte *buf, uint32 seed)
{
	int i;

	//null terminates the string for strcat
	strcpy(buf, "");

	// optional first segment
	if ((i = GetNumberBasedOnSeed(0, lengthof(name_german_pre) + 50, seed) - 50) >= 0)
	{
		strcat(buf,name_german_pre[i]);
	}

	// mandatory middle segments including option of hardcoded name
	if ((i = GetNumberBasedOnSeed(4, lengthof(name_german_hardcoded) + 50, seed) - 50) >= 0)
	{
		strcat(buf,name_german_hardcoded[i]);
	}
	else
	{
		strcat(buf, name_german_1[GetNumberBasedOnSeed( 7, lengthof(name_german_1), seed)]);
		strcat(buf, name_german_2[GetNumberBasedOnSeed(10, lengthof(name_german_2), seed)]);
	}

	//optional last segment
	if ((i = GetNumberBasedOnSeed(12, 50 + 10, seed) - 50) >= 0)
	{
		if (i > 2)
		{
			strcat(buf, name_german_3_an_der[GetNumberBasedOnSeed(14, lengthof(name_german_3_an_der), seed)]);
			strcat(buf, name_german_4_an_der[GetNumberBasedOnSeed(15, lengthof(name_german_4_an_der), seed)]);
		} else {
			strcat(buf, name_german_3_am[GetNumberBasedOnSeed(14, lengthof(name_german_3_am), seed)]);
			strcat(buf, name_german_4_am[GetNumberBasedOnSeed(15, lengthof(name_german_4_am), seed)]);
		}


	}
	return 0;
}

static byte MakeSpanishTownName(byte *buf, uint32 seed)
{
	strcpy(buf, "");
	strcat(buf, name_spanish_1[GetNumberBasedOnSeed(0, lengthof(name_spanish_1), seed)]);
	return 0;
}

static byte MakeFrenchTownName(byte *buf, uint32 seed)
{
	strcpy(buf, "");
	strcat(buf, name_french_1[GetNumberBasedOnSeed(0, lengthof(name_french_1), seed)]);
	return 0;
}

static byte MakeSillyTownName(byte *buf, uint32 seed)
{
	strcpy(buf, "");
	strcat(buf, name_silly_1[GetNumberBasedOnSeed( 0, lengthof(name_silly_1), seed)]);
	strcat(buf, name_silly_2[GetNumberBasedOnSeed(16, lengthof(name_silly_2), seed)]);
	return 0;
}

static byte MakeSwedishTownName(byte *buf, uint32 seed)
{
	int i;

	//null terminates the string for strcat
	strcpy(buf, "");

	// optional first segment
	if ((i = GetNumberBasedOnSeed(0, lengthof(name_swedish_1) + 50, seed) - 50) >= 0)
	{
		strcat(buf, name_swedish_1[i]);
	}

	// mandatory middle segments including option of hardcoded name
	if (GetNumberBasedOnSeed(4, 5, seed) >= 3)
	{
		strcat(buf, name_swedish_2[GetNumberBasedOnSeed( 7, lengthof(name_swedish_2), seed)]);
	}
	else
	{
		strcat(buf, name_swedish_2a[GetNumberBasedOnSeed( 7, lengthof(name_swedish_2a), seed)]);
		strcat(buf, name_swedish_2b[GetNumberBasedOnSeed(10, lengthof(name_swedish_2b), seed)]);
		strcat(buf, name_swedish_2c[GetNumberBasedOnSeed(13, lengthof(name_swedish_2c), seed)]);
	}

	strcat(buf, name_swedish_3[GetNumberBasedOnSeed(16, lengthof(name_swedish_3), seed)]);

	return 0;
}

static byte MakeDutchTownName(byte *buf, uint32 seed)
{
	int i;

	//null terminates the string for strcat
	strcpy(buf, "");

	// optional first segment
	if ((i = GetNumberBasedOnSeed(0, lengthof(name_dutch_1) + 50, seed) - 50) >= 0)
	{
		strcat(buf, name_dutch_1[i]);
	}

	// mandatory middle segments including option of hardcoded name
	if (GetNumberBasedOnSeed(6, 9, seed) > 4)
	{
		strcat(buf, name_dutch_2[GetNumberBasedOnSeed( 9, lengthof(name_dutch_2), seed)]);
	}
	else
	{
		strcat(buf, name_dutch_3[GetNumberBasedOnSeed( 9, lengthof(name_dutch_3), seed)]);
		strcat(buf, name_dutch_4[GetNumberBasedOnSeed(12, lengthof(name_dutch_4), seed)]);
	}
	strcat(buf, name_dutch_5[GetNumberBasedOnSeed(15, lengthof(name_dutch_5), seed)]);

	return 0;
}

static byte MakeFinnishTownName(byte *buf, uint32 seed)
{
	//null terminates the string for strcat
	strcpy(buf, "");

	// Select randomly if town name should consists of one or two parts.
	if (GetNumberBasedOnSeed(0, 15, seed) >= 10)
	{
		strcat(buf, name_finnish_1[GetNumberBasedOnSeed( 2, lengthof(name_finnish_1), seed)]);
	}
	else
	{
		strcat(buf, name_finnish_2a[GetNumberBasedOnSeed( 2, lengthof(name_finnish_2a), seed)]);
		strcat(buf, name_finnish_2b[GetNumberBasedOnSeed(10, lengthof(name_finnish_2b), seed)]);
	}

	return 0;
}

static byte MakePolishTownName(byte *buf, uint32 seed)
{
	int i, j;

	//null terminates the string for strcat
	strcpy(buf, "");

	// optional first segment
	i = GetNumberBasedOnSeed(0,
					lengthof(name_polish_2_o) +
					lengthof(name_polish_2_m) +
					lengthof(name_polish_2_f) +
					lengthof(name_polish_2_n), seed);
	j = GetNumberBasedOnSeed(2, 20, seed);


	if (i < lengthof(name_polish_2_o))
	{
		strcat(buf, name_polish_2_o[GetNumberBasedOnSeed(3, lengthof(name_polish_2_o), seed)]);
	}
	else if (i < lengthof(name_polish_2_m) + lengthof(name_polish_2_o))
	{
		if (j < 4)
			strcat(buf, name_polish_1_m[GetNumberBasedOnSeed(5, lengthof(name_polish_1_m), seed)]);

		strcat(buf, name_polish_2_m[GetNumberBasedOnSeed(7, lengthof(name_polish_2_m), seed)]);

		if (j >= 4 && j < 16)
			strcat(buf, name_polish_3_m[GetNumberBasedOnSeed(10, lengthof(name_polish_3_m), seed)]);
	}
	else if (i < lengthof(name_polish_2_f) + lengthof(name_polish_2_m) + lengthof(name_polish_2_o))
	{
		if (j < 4)
			strcat(buf, name_polish_1_f[GetNumberBasedOnSeed(5, lengthof(name_polish_1_f), seed)]);

		strcat(buf, name_polish_2_f[GetNumberBasedOnSeed(7, lengthof(name_polish_2_f), seed)]);

		if (j >= 4 && j < 16)
			strcat(buf, name_polish_3_f[GetNumberBasedOnSeed(10, lengthof(name_polish_3_f), seed)]);
	}
	else
	{
		if (j < 4)
			strcat(buf, name_polish_1_n[GetNumberBasedOnSeed(5, lengthof(name_polish_1_n), seed)]);

		strcat(buf, name_polish_2_n[GetNumberBasedOnSeed(7, lengthof(name_polish_2_n), seed)]);

		if (j >= 4 && j < 16)
			strcat(buf, name_polish_3_n[GetNumberBasedOnSeed(10, lengthof(name_polish_3_n), seed)]);
	}
	return 0;
}

static byte MakeCzechTownName(byte *buf, uint32 seed)
{
	strcpy(buf, "");
	strcat(buf, name_czech_1[GetNumberBasedOnSeed(0, lengthof(name_czech_1), seed)]);
	return 0;
}

static byte MakeRomanianTownName(byte *buf, uint32 seed)
{
	strcpy(buf, "");
	strcat(buf, name_romanian_1[GetNumberBasedOnSeed(0, lengthof(name_romanian_1), seed)]);
	return 0;
}

static byte MakeSlovakTownName(byte *buf, uint32 seed)
{
	strcpy(buf, "");
	strcat(buf, name_slovakish_1[GetNumberBasedOnSeed(0, lengthof(name_slovakish_1), seed)]);
	return 0;
}

static byte MakeHungarianTownName(byte *buf, uint32 seed)
{
	int i;

	//null terminates the string for strcat
	strcpy(buf, "");

	if (GetNumberBasedOnSeed(12, 15, seed) < 3)
	{
		strcat(buf, name_hungarian_real[GetNumberBasedOnSeed(0, lengthof(name_hungarian_real), seed)]);
	}
	else
	{
		// optional first segment
		if ((i = GetNumberBasedOnSeed(0, lengthof(name_hungarian_1) * 3, seed)) < lengthof(name_hungarian_1))
		{
			strcat(buf, name_hungarian_1[i]);
		}

		// mandatory middle segments
		strcat(buf, name_hungarian_2[GetNumberBasedOnSeed(3, lengthof(name_hungarian_2), seed)]);
		strcat(buf, name_hungarian_3[GetNumberBasedOnSeed(6, lengthof(name_hungarian_3), seed)]);

		// optional last segment
		if ((i = GetNumberBasedOnSeed(10, lengthof(name_hungarian_4) * 3, seed)) < lengthof(name_hungarian_4)) {
			strcat(buf, name_hungarian_4[i]);
		}
	}

	return 0;
}

TownNameGenerator * const _town_name_generators[] = {
	MakeEnglishOriginalTownName,
	MakeFrenchTownName,
	MakeGermanTownName,
	MakeEnglishAdditionalTownName,
	MakeSpanishTownName,
	MakeSillyTownName,
	MakeSwedishTownName,
	MakeDutchTownName,
	MakeFinnishTownName,
	MakePolishTownName,
	MakeSlovakTownName,
	MakeHungarianTownName,
	MakeAustrianTownName,
	MakeRomanianTownName,
	MakeCzechTownName,
};

// DO WE NEED THIS ANY MORE?
#define FIXNUM(x, y, z) (((((x) << 16) / (y)) + 1) << z)

uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type)
{
	switch (old_town_name_type) {
		case 0: case 3: /* English, American */
			/*	Already OK */
			return townnameparts;
		case 1: /* French */
			/*	For some reason 86 needs to be subtracted from townnameparts
			*	0000 0000 0000 0000 0000 0000 1111 1111 */
			return FIXNUM(townnameparts - 86, lengthof(name_french_1), 0);
		case 2: /* German */
			DEBUG(misc, 0) ("German Townnames are buggy... (%d)", townnameparts);
			return townnameparts;
		case 4: /* Latin-American */
			/*	0000 0000 0000 0000 0000 0000 1111 1111 */
			return FIXNUM(townnameparts, lengthof(name_spanish_1), 0);
		case 5: /* Silly */
			/*	NUM_SILLY_1	-	lower 16 bits
			*	NUM_SILLY_2	-	upper 16 bits without leading 1 (first 8 bytes)
			*	1000 0000 2222 2222 0000 0000 1111 1111 */
			return FIXNUM(townnameparts, lengthof(name_silly_1), 0) | FIXNUM(((townnameparts >> 16)&0xFF), lengthof(name_silly_2), 16);
	}
	return 0;
}