changeset 8258:6017c5ebeb7e draft

(svn r11822) -Codechange: Replaced fixed size custom name array. Names are now attached to their object directly and there is no limit to the amount of names. -Fix: NewGRF engines could not be renamed.
author peter1138 <peter1138@openttd.org>
date Sat, 12 Jan 2008 19:58:06 +0000
parents 38d56fa7b6f7
children 184c94f920a6
files src/aircraft_cmd.cpp src/autoreplace_cmd.cpp src/engine.cpp src/engine.h src/functions.h src/group.h src/group_cmd.cpp src/misc.cpp src/misc_cmd.cpp src/newgrf.cpp src/newgrf_engine.cpp src/newgrf_engine.h src/oldloader.cpp src/openttd.cpp src/order.h src/order_cmd.cpp src/player_base.h src/players.cpp src/roadveh_cmd.cpp src/saveload.cpp src/saveload.h src/ship_cmd.cpp src/signs.cpp src/signs.h src/signs_gui.cpp src/station.cpp src/station.h src/station_cmd.cpp src/strings.cpp src/table/engines.h src/town.h src/town_cmd.cpp src/train_cmd.cpp src/vehicle.cpp src/vehicle_base.h src/vehicle_gui.cpp src/waypoint.cpp src/waypoint.h
diffstat 38 files changed, 251 insertions(+), 299 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -335,7 +335,7 @@
 
 		v->cargo_subtype = 0;
 
-		v->string_id = STR_SV_AIRCRAFT_NAME;
+		v->name = NULL;
 //		v->next_order_param = v->next_order = 0;
 
 //		v->load_unload_time_rem = 0;
--- a/src/autoreplace_cmd.cpp
+++ b/src/autoreplace_cmd.cpp
@@ -134,7 +134,7 @@
 	const UnitID cached_unitnumber = old_v->unitnumber;
 	bool new_front = false;
 	Vehicle *new_v = NULL;
-	char vehicle_name[32];
+	char *vehicle_name = NULL;
 	CargoID replacement_cargo_type;
 
 	/* If the vehicle belongs to a group, check if the group is protected from the global autoreplace.
@@ -240,12 +240,7 @@
 		MoveVehicleCargo(new_v->type == VEH_TRAIN ? new_v->First() : new_v, old_v);
 
 		// Get the name of the old vehicle if it has a custom name.
-		if (!IsCustomName(old_v->string_id)) {
-			vehicle_name[0] = '\0';
-		} else {
-			SetDParam(0, old_v->index);
-			GetString(vehicle_name, STR_VEHICLE_NAME, lastof(vehicle_name));
-		}
+		if (old_v->name != NULL) vehicle_name = strdup(old_v->name);
 	} else { // flags & DC_EXEC not set
 		CommandCost tmp_move;
 
@@ -285,9 +280,10 @@
 	}
 
 	/* Transfer the name of the old vehicle */
-	if ((flags & DC_EXEC) && vehicle_name[0] != '\0') {
+	if ((flags & DC_EXEC) && vehicle_name != NULL) {
 		_cmd_text = vehicle_name;
 		DoCommand(0, new_v->index, 0, DC_EXEC, CMD_NAME_VEHICLE);
+		free(vehicle_name);
 	}
 
 	return cost;
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -54,6 +54,12 @@
 	do e->type = VEH_ROAD;     while (++e < &_engines[SHIP_ENGINES_INDEX]);
 	do e->type = VEH_SHIP;     while (++e < &_engines[AIRCRAFT_ENGINES_INDEX]);
 	do e->type = VEH_AIRCRAFT; while (++e < &_engines[TOTAL_NUM_ENGINES]);
+
+	/* Set up default engine names */
+	for (EngineID engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
+		EngineInfo *ei = &_engine_info[engine];
+		ei->string_id = STR_8000_KIRBY_PAUL_TANK_STEAM + engine;
+	}
 }
 
 
@@ -61,13 +67,10 @@
 
 void DeleteCustomEngineNames()
 {
-	uint i;
-	StringID old;
-
-	for (i = 0; i != TOTAL_NUM_ENGINES; i++) {
-		old = _engine_name_strings[i];
-		_engine_name_strings[i] = i + STR_8000_KIRBY_PAUL_TANK_STEAM;
-		DeleteName(old);
+	Engine *e;
+	FOR_ALL_ENGINES(e) {
+		free(e->name);
+		e->name = NULL;
 	}
 
 	_vehicle_design_names &= ~1;
@@ -79,18 +82,6 @@
 	DEBUG(misc, 1, "LoadCustomEngineNames: not done");
 }
 
-static void SetupEngineNames()
-{
-	StringID *name;
-
-	for (name = _engine_name_strings; name != endof(_engine_name_strings); name++)
-		*name = STR_SV_EMPTY;
-
-	DeleteCustomEngineNames();
-	LoadCustomEngineNames();
-}
-
-
 static void CalcEngineReliability(Engine *e)
 {
 	uint age = e->age;
@@ -134,8 +125,6 @@
 	/* Aging of vehicles stops, so account for that when starting late */
 	const Date aging_date = min(_date, ConvertYMDToDate(YEAR_ENGINE_AGING_STOPS, 0, 1));
 
-	SetupEngineNames();
-
 	for (e = _engines, ei = _engine_info; e != endof(_engines); e++, ei++) {
 		uint32 r;
 
@@ -402,23 +391,16 @@
  */
 CommandCost CmdRenameEngine(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	StringID str;
-
 	if (!IsEngineIndex(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
 
 	if (!IsUniqueEngineName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	str = AllocateName(_cmd_text, 0);
-	if (str == 0) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
-		StringID old_str = _engine_name_strings[p1];
-		_engine_name_strings[p1] = str;
-		DeleteName(old_str);
+		Engine *e = GetEngine(p1);
+		free(e->name);
+		e->name = strdup(_cmd_text);
 		_vehicle_design_names |= 3;
 		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
 	}
 
 	return CommandCost();
@@ -637,6 +619,7 @@
 	    SLE_VAR(Engine, preview_wait,        SLE_UINT8),
 	SLE_CONDNULL(1, 0, 44),
 	    SLE_VAR(Engine, player_avail,        SLE_UINT8),
+	SLE_CONDSTR(Engine, name,                SLE_STR, 0,                 84, SL_MAX_VERSION),
 
 	/* reserve extra space in savegame here. (currently 16 bytes) */
 	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
@@ -662,14 +645,21 @@
 	}
 }
 
-static void LoadSave_ENGS()
+static void Load_ENGS()
 {
-	SlArray(_engine_name_strings, lengthof(_engine_name_strings), SLE_STRINGID);
+	StringID names[TOTAL_NUM_ENGINES];
+
+	SlArray(names, lengthof(names), SLE_STRINGID);
+
+	for (EngineID engine = 0; engine < lengthof(names); engine++) {
+		Engine *e = GetEngine(engine);
+		e->name = CopyFromOldName(names[engine]);
+	}
 }
 
 extern const ChunkHandler _engine_chunk_handlers[] = {
 	{ 'ENGN', Save_ENGN,     Load_ENGN,     CH_ARRAY          },
-	{ 'ENGS', LoadSave_ENGS, LoadSave_ENGS, CH_RIFF           },
+	{ 'ENGS', NULL,          Load_ENGS,     CH_RIFF           },
 	{ 'ERNW', Save_ERNW,     Load_ERNW,     CH_ARRAY | CH_LAST},
 };
 
@@ -678,4 +668,10 @@
 	/* Clean the engine renew pool and create 1 block in it */
 	_EngineRenew_pool.CleanPool();
 	_EngineRenew_pool.AddBlockToPool();
+
+	Engine *e;
+	FOR_ALL_ENGINES(e) {
+		free(e->name);
+		e->name = NULL;
+	}
 }
--- a/src/engine.h
+++ b/src/engine.h
@@ -109,9 +109,11 @@
 	byte misc_flags;
 	byte callbackmask;
 	byte retire_early; ///< Number of years early to retire vehicle
+	StringID string_id; ///< Default name of engine
 };
 
 struct Engine {
+	char *name;         ///< Custom name of engine
 	Date intro_date;
 	Date age;
 	uint16 reliability;
--- a/src/functions.h
+++ b/src/functions.h
@@ -35,12 +35,7 @@
 
 /* misc.cpp */
 bool IsCustomName(StringID id);
-void DeleteName(StringID id);
-char *GetName(char *buff, StringID id, const char *last);
-
-#define AllocateName(name, skip) RealAllocateName(name, skip, false)
-StringID RealAllocateName(const char *name, byte skip, bool check_double);
-void ConvertNameArray();
+char *CopyFromOldName(StringID id);
 
 /* misc functions */
 /**
--- a/src/group.h
+++ b/src/group.h
@@ -20,7 +20,7 @@
 DECLARE_OLD_POOL(Group, Group, 5, 2047)
 
 struct Group : PoolItem<Group, GroupID, &_Group_pool> {
-	StringID string_id;                     ///< Group Name
+	char *name;                             ///< Group Name
 
 	uint16 num_vehicle;                     ///< Number of vehicles wich belong to the group
 	PlayerID owner;                         ///< Group Owner
--- a/src/group_cmd.cpp
+++ b/src/group_cmd.cpp
@@ -52,7 +52,7 @@
 
 Group::~Group()
 {
-	DeleteName(this->string_id);
+	free(this->name);
 	this->owner = INVALID_PLAYER;
 }
 
@@ -186,19 +186,13 @@
 
 	if (!IsUniqueGroupName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	/* Create the name */
-	StringID str = AllocateName(_cmd_text, 0);
-	if (str == STR_NULL) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
 		/* Delete the old name */
-		DeleteName(g->string_id);
+		free(g->name);
 		/* Assign the new one */
-		g->string_id = str;
+		g->name = strdup(_cmd_text);
 
 		InvalidateWindowData(GetWCForVT(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_player);
-	} else {
-		DeleteName(str);
 	}
 
 	return CommandCost();
@@ -433,7 +427,8 @@
 
 
 static const SaveLoad _group_desc[] = {
-  SLE_VAR(Group, string_id,          SLE_UINT16),
+  SLE_CONDVAR(Group, name,           SLE_NAME,    0, 83),
+  SLE_CONDSTR(Group, name,           SLE_STR, 0, 84, SL_MAX_VERSION),
   SLE_VAR(Group, num_vehicle,        SLE_UINT16),
   SLE_VAR(Group, owner,              SLE_UINT8),
   SLE_VAR(Group, vehicle_type,       SLE_UINT8),
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -116,18 +116,6 @@
 	return GB(id, 11, 5) == 15;
 }
 
-void DeleteName(StringID id)
-{
-	if (IsCustomName(id)) {
-		memset(_name_array[id & 0x1FF], 0, sizeof(_name_array[id & 0x1FF]));
-	}
-}
-
-char *GetName(char *buff, StringID id, const char* last)
-{
-	return strecpy(buff, _name_array[id & ~0x600], last);
-}
-
 
 static void InitializeCheats()
 {
@@ -140,40 +128,22 @@
 	memset(_name_array, 0, sizeof(_name_array));
 }
 
-StringID RealAllocateName(const char *name, byte skip, bool check_double)
+/* Copy and convert old custom names to UTF-8 */
+char *CopyFromOldName(StringID id)
 {
-	char (*free_item)[lengthof(*_name_array)] = NULL;
-	char (*i)[lengthof(*_name_array)];
-
-	for (i = _name_array; i != endof(_name_array); ++i) {
-		if ((*i)[0] == '\0') {
-			if (free_item == NULL) free_item = i;
-		} else if (check_double && strncmp(*i, name, lengthof(*i) - 1) == 0) {
-			_error_message = STR_0132_CHOSEN_NAME_IN_USE_ALREADY;
-			return 0;
-		}
-	}
+	if (!IsCustomName(id)) return NULL;
 
-	if (free_item != NULL) {
-		ttd_strlcpy(*free_item, name, lengthof(*free_item));
-		return (free_item - _name_array) | 0x7800 | (skip << 8);
-	} else {
-		_error_message = STR_0131_TOO_MANY_NAMES_DEFINED;
-		return 0;
-	}
-}
-
-void ConvertNameArray()
-{
-	uint i;
-
-	for (i = 0; i < lengthof(_name_array); i++) {
-		const char *strfrom = _name_array[i];
-		char tmp[sizeof(*_name_array)];
+	if (CheckSavegameVersion(37)) {
+		/* Old names were 32 characters long, so 128 characters should be
+		 * plenty to allow for expansion when converted to UTF-8. */
+		char tmp[128];
+		const char *strfrom = _name_array[GB(id, 0, 9)];
 		char *strto = tmp;
 
 		for (; *strfrom != '\0'; strfrom++) {
 			WChar c = (byte)*strfrom;
+
+			/* Map from non-ISO8859-15 characters to UTF-8. */
 			switch (c) {
 				case 0xA4: c = 0x20AC; break; // Euro
 				case 0xA6: c = 0x0160; break; // S with caron
@@ -185,13 +155,20 @@
 				case 0xBE: c = 0x0178; break; // Y with diaresis
 				default: break;
 			}
+
+			/* Check character will fit into our buffer. */
 			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
+
 			strto += Utf8Encode(strto, c);
 		}
 
 		/* Terminate the new string and copy it back to the name array */
 		*strto = '\0';
-		memcpy(_name_array[i], tmp, sizeof(*_name_array));
+
+		return strdup(tmp);
+	} else {
+		/* Name will already be in UTF-8. */
+		return strdup(_name_array[GB(id, 0, 9)]);
 	}
 }
 
@@ -206,19 +183,6 @@
 	}
 }
 
-
-static void Save_NAME()
-{
-	int i;
-
-	for (i = 0; i != lengthof(_name_array); ++i) {
-		if (_name_array[i][0] != '\0') {
-			SlSetArrayIndex(i);
-			SlArray(_name_array[i], (uint)strlen(_name_array[i]), SLE_UINT8);
-		}
-	}
-}
-
 static void Load_NAME()
 {
 	int index;
@@ -584,7 +548,7 @@
 	{ 'MAPE', Save_MAP6,     Load_MAP6,     CH_RIFF },
 	{ 'MAP7', Save_MAP7,     Load_MAP7,     CH_RIFF },
 
-	{ 'NAME', Save_NAME,     Load_NAME,     CH_ARRAY},
+	{ 'NAME', NULL,          Load_NAME,     CH_ARRAY},
 	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
 	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF},
 	{ 'CHTS', Save_CHTS,     Load_CHTS,     CH_RIFF | CH_LAST}
--- a/src/misc_cmd.cpp
+++ b/src/misc_cmd.cpp
@@ -223,23 +223,17 @@
  */
 CommandCost CmdChangeCompanyName(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	StringID str;
 	Player *p;
 
 	if (StrEmpty(_cmd_text)) return CMD_ERROR;
 
 	if (!IsUniqueCompanyName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	str = AllocateName(_cmd_text, 4);
-	if (str == 0) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
 		p = GetPlayer(_current_player);
-		DeleteName(p->name_1);
-		p->name_1 = str;
+		free(p->name);
+		p->name = strdup(_cmd_text);
 		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
 	}
 
 	return CommandCost();
@@ -268,20 +262,16 @@
  */
 CommandCost CmdChangePresidentName(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	StringID str;
 	Player *p;
 
 	if (StrEmpty(_cmd_text)) return CMD_ERROR;
 
 	if (!IsUniquePresidentName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	str = AllocateName(_cmd_text, 4);
-	if (str == 0) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
 		p = GetPlayer(_current_player);
-		DeleteName(p->president_name_1);
-		p->president_name_1 = str;
+		free(p->president_name);
+		p->president_name = strdup(_cmd_text);
 
 		if (p->name_1 == STR_SV_UNNAMED) {
 			char buf[80];
@@ -291,8 +281,6 @@
 			DoCommand(0, 0, 0, DC_EXEC, CMD_CHANGE_COMPANY_NAME);
 		}
 		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
 	}
 
 	return CommandCost();
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -3170,7 +3170,8 @@
 			case GSF_AIRCRAFT:
 				if (id < TOTAL_NUM_ENGINES) {
 					StringID string = AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, STR_8000_KIRBY_PAUL_TANK_STEAM + id);
-					SetCustomEngineName(id, string);
+					EngineInfo *ei = &_engine_info[id];
+					ei->string_id = string;
 				} else {
 					AddGRFString(_cur_grffile->grfid, id, lang, new_scheme, name, id);
 				}
@@ -5014,7 +5015,6 @@
 	/* Unload sprite group data */
 	UnloadWagonOverrides();
 	UnloadCustomEngineSprites();
-	UnloadCustomEngineNames();
 	ResetEngineListOrder();
 
 	/* Reset price base data */
--- a/src/newgrf_engine.cpp
+++ b/src/newgrf_engine.cpp
@@ -707,8 +707,6 @@
 		case 0x5D: return GB(ClampToI32(v->value),  8, 24);
 		case 0x5E: return GB(ClampToI32(v->value), 16, 16);
 		case 0x5F: return GB(ClampToI32(v->value), 24,  8);
-		case 0x60: return v->string_id;
-		case 0x61: return GB(v->string_id, 8, 8);
 		case 0x72: return v->cargo_subtype;
 		case 0x7A: return v->random_bits;
 		case 0x7B: return v->waiting_triggers;
@@ -1041,27 +1039,6 @@
 	DoTriggerVehicle(v, trigger, 0, true);
 }
 
-StringID _engine_custom_names[TOTAL_NUM_ENGINES];
-
-void SetCustomEngineName(EngineID engine, StringID name)
-{
-	assert(engine < lengthof(_engine_custom_names));
-	_engine_custom_names[engine] = name;
-}
-
-void UnloadCustomEngineNames()
-{
-	EngineID i;
-	for (i = 0; i < TOTAL_NUM_ENGINES; i++) {
-		_engine_custom_names[i] = 0;
-	}
-}
-
-StringID GetCustomEngineName(EngineID engine)
-{
-	return _engine_custom_names[engine] == 0 ? _engine_name_strings[engine] : _engine_custom_names[engine];
-}
-
 /* Functions for changing the order of vehicle purchase lists
  * This is currently only implemented for rail vehicles. */
 static EngineID _engine_list_order[NUM_TRAIN_ENGINES];
--- a/src/newgrf_engine.h
+++ b/src/newgrf_engine.h
@@ -53,12 +53,8 @@
 };
 void TriggerVehicle(Vehicle *veh, VehicleTrigger trigger);
 
-void SetCustomEngineName(EngineID engine, StringID name);
-StringID GetCustomEngineName(EngineID engine);
-
 void UnloadWagonOverrides();
 void UnloadCustomEngineSprites();
-void UnloadCustomEngineNames();
 
 void ResetEngineListOrder();
 EngineID GetRailVehAtPosition(EngineID pos);
--- a/src/oldloader.cpp
+++ b/src/oldloader.cpp
@@ -1235,7 +1235,8 @@
 
 		if (_old_next_ptr != 0xFFFF) v->next = GetVehiclePoolSize() <= _old_next_ptr ? new (_old_next_ptr) InvalidVehicle() : GetVehicle(_old_next_ptr);
 
-		v->string_id = RemapOldStringID(_old_string_id);
+		_old_string_id = RemapOldStringID(_old_string_id);
+		v->name = CopyFromOldName(_old_string_id);
 
 		/* Vehicle-subtype is different in TTD(Patch) */
 		if (v->type == VEH_SPECIAL) v->subtype = v->subtype >> 1;
@@ -1251,7 +1252,7 @@
 }
 
 static const OldChunks sign_chunk[] = {
-	OCL_SVAR( OC_UINT16, Sign, str ),
+	OCL_VAR ( OC_UINT16, 1, &_old_string_id ),
 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, x ),
 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, y ),
 	OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ),
@@ -1263,7 +1264,12 @@
 
 static bool LoadOldSign(LoadgameState *ls, int num)
 {
-	return LoadChunk(ls, new (num) Sign(), sign_chunk);
+	if (!LoadChunk(ls, new (num) Sign(), sign_chunk)) return false;
+
+	_old_string_id = RemapOldStringID(_old_string_id);
+	// XXX copy if custom name$$$
+
+	return true;
 }
 
 static const OldChunks engine_chunk[] = {
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -1343,6 +1343,34 @@
 		}
 	}
 
+	if (CheckSavegameVersion(84)) {
+		Player *p;
+		FOR_ALL_PLAYERS(p) {
+			p->name = CopyFromOldName(p->name_1);
+			if (p->name != NULL) p->name_1 = STR_SV_UNNAMED;
+			p->president_name = CopyFromOldName(p->president_name_1);
+			if (p->president_name != NULL) p->president_name_1 = SPECSTR_PRESIDENT_NAME;
+		}
+
+		Station *st;
+		FOR_ALL_STATIONS(st) {
+			st->name = CopyFromOldName(st->string_id);
+			if (st->name != NULL) st->string_id = STR_EMPTY;
+		}
+
+		Town *t;
+		FOR_ALL_TOWNS(t) {
+			t->name = CopyFromOldName(t->townnametype);
+			if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
+		}
+
+		Waypoint *wp;
+		FOR_ALL_WAYPOINTS(wp) {
+			wp->name = CopyFromOldName(wp->string);
+			wp->string = STR_EMPTY;
+		}
+	}
+
 	/* convert road side to my format. */
 	if (_opt.road_side) _opt.road_side = 1;
 
@@ -1936,10 +1964,6 @@
 		}
 	}
 
-	if (CheckSavegameVersion(37)) {
-		ConvertNameArray();
-	}
-
 	/* from version 38 we have optional elrails, since we cannot know the
 	 * preference of a user, let elrails enabled; it can be disabled manually */
 	if (CheckSavegameVersion(38)) _patches.disable_elrails = false;
--- a/src/order.h
+++ b/src/order.h
@@ -127,7 +127,7 @@
 	VehicleOrderID orderindex;
 	Order *order;
 	uint16 service_interval;
-	char name[32];
+	char *name;
 };
 
 VARDEF TileIndex _backup_orders_tile;
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -926,18 +926,13 @@
 	/* Make sure we always have freed the stuff */
 	free(bak->order);
 	bak->order = NULL;
+	free(bak->name);
+	bak->name = NULL;
 
 	/* Save general info */
 	bak->orderindex       = v->cur_order_index;
 	bak->service_interval = v->service_interval;
-
-	/* Safe custom string, if any */
-	if (!IsCustomName(v->string_id)) {
-		bak->name[0] = '\0';
-	} else {
-		SetDParam(0, v->index);
-		GetString(bak->name, STR_VEHICLE_NAME, lastof(bak->name));
-	}
+	if (v->name != NULL) bak->name = strdup(v->name);
 
 	/* If we have shared orders, store it on a special way */
 	if (IsOrderListShared(v)) {
@@ -979,7 +974,7 @@
 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
 {
 	/* If we have a custom name, process that */
-	if (!StrEmpty(bak->name)) {
+	if (bak->name != NULL) {
 		_cmd_text = bak->name;
 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
 	}
--- a/src/player_base.h
+++ b/src/player_base.h
@@ -25,9 +25,11 @@
 struct Player {
 	uint32 name_2;
 	uint16 name_1;
+	char *name;
 
 	uint16 president_name_1;
 	uint32 president_name_2;
+	char *president_name;
 
 	PlayerFace face;
 
--- a/src/players.cpp
+++ b/src/players.cpp
@@ -612,10 +612,12 @@
 
 	DeletePlayerWindows(pi);
 	p = GetPlayer(pi);
-	DeleteName(p->name_1);
-	DeleteName(p->president_name_1);
-	p->name_1 = 0;
-	p->president_name_1 = 0;
+	p->name_1 = STR_NULL;
+	p->president_name_1 = STR_NULL;
+	free(p->name);
+	free(p->president_name);
+	p->name = NULL;
+	p->president_name = NULL;
 }
 
 /** Change engine renewal parameters
@@ -1096,9 +1098,11 @@
 static const SaveLoad _player_desc[] = {
 	    SLE_VAR(Player, name_2,          SLE_UINT32),
 	    SLE_VAR(Player, name_1,          SLE_STRINGID),
+	SLE_CONDSTR(Player, name,            SLE_STR, 0,                       84, SL_MAX_VERSION),
 
 	    SLE_VAR(Player, president_name_1,SLE_UINT16),
 	    SLE_VAR(Player, president_name_2,SLE_UINT32),
+	SLE_CONDSTR(Player, president_name,  SLE_STR, 0,                       84, SL_MAX_VERSION),
 
 	    SLE_VAR(Player, face,            SLE_UINT32),
 
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -245,7 +245,7 @@
 		v->max_age = e->lifelength * 366;
 		_new_vehicle_id = v->index;
 
-		v->string_id = STR_SV_ROADVEH_NAME;
+		v->name = NULL;
 
 		v->service_interval = _patches.servint_roadveh;
 
--- a/src/saveload.cpp
+++ b/src/saveload.cpp
@@ -33,7 +33,7 @@
 #include "autoreplace_base.h"
 #include <list>
 
-extern const uint16 SAVEGAME_VERSION = 83;
+extern const uint16 SAVEGAME_VERSION = 84;
 uint16 _sl_version;       ///< the major savegame version identifier
 byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 
@@ -434,6 +434,7 @@
 	case SLE_VAR_U32: *(uint32*)ptr = val; break;
 	case SLE_VAR_I64: *(int64 *)ptr = val; break;
 	case SLE_VAR_U64: *(uint64*)ptr = val; break;
+	case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
 	case SLE_VAR_NULL: break;
 	default: NOT_REACHED();
 	}
@@ -922,6 +923,9 @@
 {
 	ChunkSaveLoadProc *proc = ch->save_proc;
 
+	/* Don't save any chunk information if there is no save handler. */
+	if (proc == NULL) return;
+
 	SlWriteUint32(ch->id);
 	DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
 
--- a/src/saveload.h
+++ b/src/saveload.h
@@ -117,6 +117,7 @@
 	SLE_VAR_STRBQ = 11 << 4, ///< string enclosed in quotes (with pre-allocated buffer)
 	SLE_VAR_STR   = 12 << 4, ///< string pointer
 	SLE_VAR_STRQ  = 13 << 4, ///< string pointer enclosed in quotes
+	SLE_VAR_NAME  = 14 << 4, ///< old custom name to be converted to a char pointer
 	/* 2 more possible memory-primitives */
 
 	/* Shortcut values */
@@ -140,6 +141,7 @@
 	SLE_STRINGBQUOTE = SLE_FILE_STRING   | SLE_VAR_STRBQ,
 	SLE_STRING       = SLE_FILE_STRING   | SLE_VAR_STR,
 	SLE_STRINGQUOTE  = SLE_FILE_STRING   | SLE_VAR_STRQ,
+	SLE_NAME         = SLE_FILE_STRINGID | SLE_VAR_NAME,
 
 	/* Shortcut values */
 	SLE_UINT  = SLE_UINT32,
--- a/src/ship_cmd.cpp
+++ b/src/ship_cmd.cpp
@@ -864,7 +864,7 @@
 		v->max_age = e->lifelength * 366;
 		_new_vehicle_id = v->index;
 
-		v->string_id = STR_SV_SHIP_NAME;
+		v->name = NULL;
 		v->u.ship.state = TRACK_BIT_DEPOT;
 
 		v->service_interval = _patches.servint_ships;
--- a/src/signs.cpp
+++ b/src/signs.cpp
@@ -26,15 +26,15 @@
 /* Initialize the sign-pool */
 DEFINE_OLD_POOL_GENERIC(Sign, Sign)
 
-Sign::Sign(StringID string)
+Sign::Sign(PlayerID owner)
 {
-	this->str = string;
+	this->owner = owner;
 }
 
 Sign::~Sign()
 {
-	DeleteName(this->str);
-	this->str = STR_NULL;
+	free(this->name);
+	this->owner = INVALID_PLAYER;
 }
 
 /**
@@ -95,7 +95,7 @@
 CommandCost CmdPlaceSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	/* Try to locate a new sign */
-	Sign *si = new Sign(STR_280A_SIGN);
+	Sign *si = new Sign(_current_player);
 	if (si == NULL) return_cmd_error(STR_2808_TOO_MANY_SIGNS);
 	AutoPtrT<Sign> s_auto_delete = si;
 
@@ -106,7 +106,6 @@
 
 		si->x = x;
 		si->y = y;
-		si->owner = _current_player; // owner of the sign; just eyecandy
 		si->z = GetSlopeZ(x, y);
 		UpdateSignVirtCoords(si);
 		MarkSignDirty(si);
@@ -136,17 +135,13 @@
 	/* If _cmd_text 0 means the new text for the sign is non-empty.
 	 * So rename the sign. If it is empty, it has no name, so delete it */
 	if (!StrEmpty(_cmd_text)) {
-		/* Create the name */
-		StringID str = AllocateName(_cmd_text, 0);
-		if (str == 0) return CMD_ERROR;
-
 		if (flags & DC_EXEC) {
 			Sign *si = GetSign(p1);
 
 			/* Delete the old name */
-			DeleteName(si->str);
+			free(si->name);
 			/* Assign the new one */
-			si->str = str;
+			si->name = strdup(_cmd_text);
 			si->owner = _current_player;
 
 			/* Update; mark sign dirty twice, because it can either becom longer, or shorter */
@@ -155,9 +150,6 @@
 			MarkSignDirty(si);
 			InvalidateWindow(WC_SIGN_LIST, 0);
 			_sign_sort_dirty = true;
-		} else {
-			/* Free the name, because we did not assign it yet */
-			DeleteName(str);
 		}
 	} else { // Delete sign
 		if (flags & DC_EXEC) {
@@ -214,7 +206,8 @@
 }
 
 static const SaveLoad _sign_desc[] = {
-      SLE_VAR(Sign, str,   SLE_UINT16),
+  SLE_CONDVAR(Sign, name,  SLE_NAME,                   0, 83),
+  SLE_CONDSTR(Sign, name,  SLE_STR, 0,                84, SL_MAX_VERSION),
   SLE_CONDVAR(Sign, x,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
   SLE_CONDVAR(Sign, y,     SLE_FILE_I16 | SLE_VAR_I32, 0, 4),
   SLE_CONDVAR(Sign, x,     SLE_INT32,                  5, SL_MAX_VERSION),
--- a/src/signs.h
+++ b/src/signs.h
@@ -11,7 +11,7 @@
 DECLARE_OLD_POOL(Sign, Sign, 2, 16000)
 
 struct Sign : PoolItem<Sign, SignID, &_Sign_pool> {
-	StringID     str;
+	char *name;
 	ViewportSign sign;
 	int32        x;
 	int32        y;
@@ -21,12 +21,12 @@
 	/**
 	 * Creates a new sign
 	 */
-	Sign(StringID string = STR_NULL);
+	Sign(PlayerID owner = INVALID_PLAYER);
 
 	/** Destroy the sign */
 	~Sign();
 
-	inline bool IsValid() const { return this->str != STR_NULL; }
+	inline bool IsValid() const { return this->owner != INVALID_PLAYER; }
 };
 
 enum {
--- a/src/signs_gui.cpp
+++ b/src/signs_gui.cpp
@@ -33,11 +33,13 @@
 	const Sign *sign1 = *(const Sign**)b;
 	char buf1[64];
 
-	GetString(buf1, sign0->str, lastof(buf1));
+	SetDParam(0, sign0->index);
+	GetString(buf1, STR_SIGN_NAME, lastof(buf1));
 
 	if (sign1 != _last_sign) {
 		_last_sign = sign1;
-		GetString(_bufcache, sign1->str, lastof(_bufcache));
+		SetDParam(0, sign1->index);
+		GetString(_bufcache, STR_SIGN_NAME, lastof(_bufcache));
 	}
 
 	return strcmp(buf1, _bufcache); // sort by name
@@ -175,7 +177,7 @@
 static void UpdateSignEditWindow(Window *w, const Sign *si)
 {
 	/* Display an empty string when the sign hasnt been edited yet */
-	if (si->str != STR_280A_SIGN) {
+	if (si->name != NULL) {
 		SetDParam(0, si->index);
 		GetString(_edit_str_buf, STR_SIGN_NAME, lastof(_edit_str_buf));
 	} else {
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -61,7 +61,7 @@
 {
 	DEBUG(station, cDebugCtorLevel, "I-%3d", index);
 
-	DeleteName(this->string_id);
+	free(this->name);
 	free(this->speclist);
 
 	if (CleaningPool()) return;
--- a/src/station.h
+++ b/src/station.h
@@ -136,7 +136,8 @@
 	TileIndex airport_tile;
 	TileIndex dock_tile;
 	Town *town;
-	uint16 string_id;
+	StringID string_id;     ///< Default name (town area) of station
+	char *name;             ///< Custom name
 
 	ViewportSign sign;
 
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -2625,19 +2625,13 @@
 
 	if (!IsUniqueStationName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	StringID str = AllocateName(_cmd_text, 6);
-	if (str == 0) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
-		StringID old_str = st->string_id;
-
-		st->string_id = str;
+		free(st->name);
+		st->name = strdup(_cmd_text);
+
 		UpdateStationVirtCoord(st);
-		DeleteName(old_str);
 		ResortStationLists();
 		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
 	}
 
 	return CommandCost();
@@ -3046,6 +3040,7 @@
 	SLE_CONDNULL(1, 0, 3),
 
 	    SLE_VAR(Station, string_id,                  SLE_STRINGID),
+	SLE_CONDSTR(Station, name,                       SLE_STR, 0,                 84, SL_MAX_VERSION),
 	    SLE_VAR(Station, had_vehicle_of_type,        SLE_UINT16),
 
 	    SLE_VAR(Station, time_since_load,            SLE_UINT8),
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -138,8 +138,7 @@
 			break;
 
 		case 15:
-			/* User defined name */
-			return GetName(buffr, index, last);
+			error("Boo!");
 
 		case 26:
 			/* Include string within newgrf text (format code 81) */
@@ -821,17 +820,20 @@
 				break;
 
 			case SCC_WAYPOINT_NAME: { // {WAYPOINT}
-				int64 temp[2];
 				Waypoint *wp = GetWaypoint(GetInt32(&argv));
-				StringID str;
-				if (wp->string != STR_NULL) {
-					str = wp->string;
+
+				if (!wp->IsValid()) { // waypoint doesn't exist anymore
+					buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
+				} else if (wp->name != NULL) {
+					buff = strecpy(buff, wp->name, last);
 				} else {
+					int64 temp[2];
 					temp[0] = wp->town_index;
 					temp[1] = wp->town_cn + 1;
-					str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
+					StringID str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
+
+					buff = GetStringWithArgs(buff, str, temp, last);
 				}
-				buff = GetStringWithArgs(buff, str, temp, last);
 				break;
 			}
 
@@ -840,6 +842,8 @@
 
 				if (!st->IsValid()) { // station doesn't exist anymore
 					buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
+				} else if (st->name != NULL) {
+					buff = strecpy(buff, st->name, last);
 				} else {
 					int64 temp[3];
 					temp[0] = STR_TOWN;
@@ -859,7 +863,9 @@
 				temp[0] = t->townnameparts;
 				uint32 grfid = t->townnamegrfid;
 
-				if (grfid == 0) {
+				if (t->name != NULL) {
+					buff = strecpy(buff, t->name, last);
+				} else if (grfid == 0) {
 					/* Original town name */
 					buff = GetStringWithArgs(buff, t->townnametype, temp, last);
 				} else {
@@ -877,44 +883,75 @@
 
 			case SCC_GROUP_NAME: { // {GROUP}
 				const Group *g = GetGroup(GetInt32(&argv));
-				int64 args[1];
 
 				assert(g->IsValid());
 
-				args[0] = g->index;
-				buff = GetStringWithArgs(buff, IsCustomName(g->string_id) ? g->string_id : STR_GROUP_NAME_FORMAT, args, last);
+				if (g->name != NULL) {
+					buff = strecpy(buff, g->name, last);
+				} else {
+					int64 args[1];
 
+					args[0] = g->index;
+					buff = GetStringWithArgs(buff, STR_GROUP_NAME_FORMAT, args, last);
+				}
 				break;
 			}
 
 			case SCC_ENGINE_NAME: { // {ENGINE}
 				EngineID engine = (EngineID)GetInt32(&argv);
+				const Engine *e = GetEngine(engine);
 
-				buff = GetString(buff, GetCustomEngineName(engine), last);
+				if (e->name != NULL) {
+					buff = strecpy(buff, e->name, last);
+				} else {
+					buff = GetStringWithArgs(buff, EngInfo(engine)->string_id, NULL, last);
+				}
 				break;
 			}
 
 			case SCC_VEHICLE_NAME: { // {VEHICLE}
 				const Vehicle *v = GetVehicle(GetInt32(&argv));
 
-				int64 args[1];
-				args[0] = v->unitnumber;
+				if (v->name != NULL) {
+					buff = strecpy(buff, v->name, last);
+				} else {
+					int64 args[1];
+					args[0] = v->unitnumber;
 
-				buff = GetStringWithArgs(buff, v->string_id, args, last);
+					StringID str;
+					switch (v->type) {
+						default: NOT_REACHED();
+						case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
+						case VEH_ROAD:     str = STR_SV_ROADVEH_NAME; break;
+						case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
+						case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
+					}
+
+					buff = GetStringWithArgs(buff, str, args, last);
+				}
 				break;
 			}
 
 			case SCC_SIGN_NAME: { // {SIGN}
 				const Sign *si = GetSign(GetInt32(&argv));
-				buff = GetString(buff, si->str, last);
+				if (si->name != NULL) {
+					buff = strecpy(buff, si->name, last);
+				} else {
+					buff = GetStringWithArgs(buff, STR_280A_SIGN, NULL, last);
+				}
 				break;
 			}
 
 			case SCC_COMPANY_NAME: { // {COMPANY}
 				const Player *p = GetPlayer((PlayerID)GetInt32(&argv));
-				int64 args[1];
-				args[0] = p->name_2;
-				buff = GetStringWithArgs(buff, p->name_1, args, last);
+
+				if (p->name != NULL) {
+					buff = strecpy(buff, p->name, last);
+				} else {
+					int64 args[1];
+					args[0] = p->name_2;
+					buff = GetStringWithArgs(buff, p->name_1, args, last);
+				}
 				break;
 			}
 
@@ -932,9 +969,14 @@
 
 			case SCC_PLAYER_NAME: { // {PLAYERNAME}
 				const Player *p = GetPlayer((PlayerID)GetInt32(&argv));
-				int64 args[1];
-				args[0] = p->president_name_2;
-				buff = GetStringWithArgs(buff, p->president_name_1, args, last);
+
+				if (p->president_name != NULL) {
+					buff = strecpy(buff, p->president_name, last);
+				} else {
+					int64 args[1];
+					args[0] = p->president_name_2;
+					buff = GetStringWithArgs(buff, p->president_name_1, args, last);
+				}
 				break;
 			}
 
--- a/src/table/engines.h
+++ b/src/table/engines.h
@@ -17,7 +17,7 @@
  * @note the 0x80 in parameter b sets the "is carriage bit"
  * @note the 5 between d and e is the load amount
  */
-#define MK(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, e, 0, 8, 0, 0, 0 }
+#define MK(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, e, 0, 8, 0, 0, 0, STR_EMPTY }
 
 /** Writes the properties of a train carriage into the EngineInfo struct.
  * @param a Introduction date
@@ -28,7 +28,7 @@
  * @see MK
  * @note the 5 between d and e is the load amount
  */
-#define MW(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b | 0x80, 5, e, 0, 8, 0, 0, 0 }
+#define MW(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b | 0x80, 5, e, 0, 8, 0, 0, 0, STR_EMPTY }
 
 /** Writes the properties of a ship into the EngineInfo struct.
  * @param a Introduction date
@@ -39,7 +39,7 @@
  * @see MK
  * @note the 10 between d and e is the load amount
  */
-#define MS(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, e, 0, 8, 0, 0, 0 }
+#define MS(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, e, 0, 8, 0, 0, 0, STR_EMPTY }
 
 /** Writes the properties of an aeroplane into the EngineInfo struct.
  * @param a Introduction date
@@ -50,7 +50,7 @@
  * @see MK
  * @note the 20 between d and e is the load amount
  */
-#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, 0, 8, 0, 0, 0 }
+#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, 0, 8, 0, 0, 0, STR_EMPTY }
 
 // Climates
 // T = Temperate
--- a/src/town.h
+++ b/src/town.h
@@ -88,6 +88,7 @@
 	uint32 townnamegrfid;
 	uint16 townnametype;
 	uint32 townnameparts;
+	char *name;
 
 	/* NOSAVE: Location of name sign, UpdateTownVirtCoord updates this. */
 	ViewportSign sign;
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -55,7 +55,7 @@
 
 Town::~Town()
 {
-	DeleteName(this->townnametype);
+	free(this->name);
 
 	if (CleaningPool()) return;
 
@@ -1888,7 +1888,6 @@
  */
 CommandCost CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	StringID str;
 	Town *t;
 
 	if (!IsValidTownID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
@@ -1897,21 +1896,15 @@
 
 	if (!IsUniqueTownName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	str = AllocateName(_cmd_text, 4);
-	if (str == 0) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
-		DeleteName(t->townnametype);
-		t->townnametype = str;
-		t->townnamegrfid = 0;
+		free(t->name);
+		t->name = strdup(_cmd_text);
 
 		UpdateTownVirtCoord(t);
 		_town_sort_dirty = true;
 		UpdateAllStationVirtCoord();
 		UpdateAllWaypointSigns();
 		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
 	}
 	return CommandCost();
 }
@@ -2417,6 +2410,7 @@
 	SLE_CONDVAR(Town, townnamegrfid,         SLE_UINT32, 66, SL_MAX_VERSION),
 	    SLE_VAR(Town, townnametype,          SLE_UINT16),
 	    SLE_VAR(Town, townnameparts,         SLE_UINT32),
+	SLE_CONDSTR(Town, name,                  SLE_STR, 0, 84, SL_MAX_VERSION),
 
 	    SLE_VAR(Town, flags12,               SLE_UINT8),
 	    SLE_VAR(Town, statues,               SLE_UINT8),
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -751,7 +751,7 @@
 			v->reliability_spd_dec = e->reliability_spd_dec;
 			v->max_age = e->lifelength * 366;
 
-			v->string_id = STR_SV_TRAIN_NAME;
+			v->name = NULL;
 			v->u.rail.railtype = rvi->railtype;
 			_new_vehicle_id = v->index;
 
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -570,7 +570,7 @@
 
 Vehicle::~Vehicle()
 {
-	DeleteName(this->string_id);
+	free(this->name);
 
 	if (CleaningPool()) return;
 
@@ -2308,7 +2308,6 @@
 CommandCost CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	Vehicle *v;
-	StringID str;
 
 	if (!IsValidVehicleID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
 
@@ -2318,17 +2317,11 @@
 
 	if (!IsUniqueVehicleName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-	str = AllocateName(_cmd_text, 2);
-	if (str == 0) return CMD_ERROR;
-
 	if (flags & DC_EXEC) {
-		StringID old_str = v->string_id;
-		v->string_id = str;
-		DeleteName(old_str);
+		free(v->name);
+		v->name = strdup(_cmd_text);
 		ResortVehicleLists();
 		MarkWholeScreenDirty();
-	} else {
-		DeleteName(str);
 	}
 
 	return CommandCost();
@@ -2741,7 +2734,8 @@
 	    SLE_VAR(Vehicle, subtype,              SLE_UINT8),
 
 	    SLE_REF(Vehicle, next,                 REF_VEHICLE_OLD),
-	    SLE_VAR(Vehicle, string_id,            SLE_STRINGID),
+	SLE_CONDVAR(Vehicle, name,                 SLE_NAME,                    0, 83),
+	SLE_CONDSTR(Vehicle, name,                 SLE_STR, 0,                 84, SL_MAX_VERSION),
 	SLE_CONDVAR(Vehicle, unitnumber,           SLE_FILE_U8  | SLE_VAR_U16,  0, 7),
 	SLE_CONDVAR(Vehicle, unitnumber,           SLE_UINT16,                  8, SL_MAX_VERSION),
 	    SLE_VAR(Vehicle, owner,                SLE_UINT8),
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -201,7 +201,7 @@
 
 	Vehicle *depot_list;     // NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace
 
-	StringID string_id;      // Displayed string
+	char *name;              ///< Name of vehicle
 
 	UnitID unitnumber;       // unit number, for display purposes only
 	PlayerByte owner;        // which player owns the vehicle?
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -552,20 +552,14 @@
 
 	if (va != last_vehicle[0]) {
 		last_vehicle[0] = va;
-		if (IsCustomName(va->string_id)) {
-			GetString(last_name[0], va->string_id, lastof(last_name[0]));
-		} else {
-			last_name[0][0] = '\0';
-		}
+		SetDParam(0, va->index);
+		GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0]));
 	}
 
 	if (vb != last_vehicle[1]) {
 		last_vehicle[1] = vb;
-		if (IsCustomName(vb->string_id)) {
-			GetString(last_name[1], vb->string_id, lastof(last_name[1]));
-		} else {
-			last_name[1][0] = '\0';
-		}
+		SetDParam(1, vb->index);
+		GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1]));
 	}
 
 	r = strcmp(last_name[0], last_name[1]); // sort by name
@@ -1010,11 +1004,7 @@
 		DrawVehicleImage(v, x + 19, y + 6, INVALID_VEHICLE, w->widget[VLW_WIDGET_LIST].right - w->widget[VLW_WIDGET_LIST].left - 20, 0);
 		DrawString(x + 19, y + w->resize.step_height - 8, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, TC_FROMSTRING);
 
-		if ((v->type == VEH_TRAIN    && v->string_id != STR_SV_TRAIN_NAME)   ||
-			(v->type == VEH_ROAD     && v->string_id != STR_SV_ROADVEH_NAME) ||
-			(v->type == VEH_SHIP     && v->string_id != STR_SV_SHIP_NAME)    ||
-			(v->type == VEH_AIRCRAFT && v->string_id != STR_SV_AIRCRAFT_NAME)) {
-
+		if (v->name != NULL) {
 			/* The vehicle got a name so we will print it */
 			SetDParam(0, v->index);
 			DrawString(x + 19, y, STR_01AB, TC_FROMSTRING);
--- a/src/waypoint.cpp
+++ b/src/waypoint.cpp
@@ -92,14 +92,14 @@
 	FOR_ALL_WAYPOINTS(local_wp) {
 		if (wp == local_wp) continue;
 
-		if (local_wp->xy && local_wp->string == STR_NULL && local_wp->town_index == wp->town_index)
+		if (local_wp->xy && local_wp->name == NULL && local_wp->town_index == wp->town_index)
 			used_waypoint[local_wp->town_cn] = true;
 	}
 
 	/* Find an empty spot */
 	for (i = 0; used_waypoint[i] && i < MAX_WAYPOINTS_PER_TOWN; i++) {}
 
-	wp->string = STR_NULL;
+	wp->name = NULL;
 	wp->town_cn = i;
 }
 
@@ -197,7 +197,7 @@
 		wp_auto_delete = wp;
 
 		wp->town_index = 0;
-		wp->string = STR_NULL;
+		wp->name = NULL;
 		wp->town_cn = 0;
 	} else if (flags & DC_EXEC) {
 		/* Move existing (recently deleted) waypoint to the new location */
@@ -350,24 +350,17 @@
 	if (!StrEmpty(_cmd_text)) {
 		if (!IsUniqueWaypointName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
-		StringID str = AllocateName(_cmd_text, 0);
-
-		if (str == 0) return CMD_ERROR;
-
 		if (flags & DC_EXEC) {
-			if (wp->string != STR_NULL) DeleteName(wp->string);
-
-			wp->string = str;
+			free(wp->name);
+			wp->name = strdup(_cmd_text);
 			wp->town_cn = 0;
 
 			UpdateWaypointSign(wp);
 			MarkWholeScreenDirty();
-		} else {
-			DeleteName(str);
 		}
 	} else {
 		if (flags & DC_EXEC) {
-			if (wp->string != STR_NULL) DeleteName(wp->string);
+			free(wp->name);
 
 			MakeDefaultWaypointName(wp);
 			UpdateWaypointSign(wp);
@@ -393,7 +386,6 @@
 
 	stat.train_tile = stat.xy = wp->xy;
 	stat.town = GetTown(wp->town_index);
-	stat.string_id = wp->string;
 	stat.build_date = wp->build_date;
 
 	return &stat;
@@ -423,7 +415,7 @@
 
 Waypoint::~Waypoint()
 {
-	if (this->string != STR_NULL) DeleteName(this->string);
+	free(this->name);
 
 	if (CleaningPool()) return;
 
@@ -462,7 +454,8 @@
 	SLE_CONDVAR(Waypoint, xy,         SLE_UINT32,                  6, SL_MAX_VERSION),
 	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16,                 12, SL_MAX_VERSION),
 	SLE_CONDVAR(Waypoint, town_cn,    SLE_UINT8,                  12, SL_MAX_VERSION),
-	    SLE_VAR(Waypoint, string,     SLE_UINT16),
+	SLE_CONDVAR(Waypoint, string,     SLE_STRINGID,                0, 83),
+	SLE_CONDSTR(Waypoint, name,       SLE_STR, 0,                 84, SL_MAX_VERSION),
 	    SLE_VAR(Waypoint, deleted,    SLE_UINT8),
 
 	SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
--- a/src/waypoint.h
+++ b/src/waypoint.h
@@ -17,7 +17,8 @@
 
 	TownID town_index; ///< Town associated with the waypoint
 	byte town_cn;      ///< The Nth waypoint for this town (consecutive number)
-	StringID string;   ///< If this is zero (i.e. no custom name), town + town_cn is used for naming
+	StringID string;   ///< C000-C03F have special meaning in old games
+	char *name;        ///< Custom name. If not set, town + town_cn is used for naming
 
 	ViewportSign sign; ///< Dimensions of sign (not saved)
 	Date build_date;   ///< Date of construction