Howto apply a patch/diff file

Forum for technical discussions regarding development. If you have a general suggestion, problem or comment, please use one of the other forums.

Moderator: OpenTTD Developers

ProphetSe7en
Engineer
Engineer
Posts: 14
Joined: 10 Mar 2017 15:31

Re: Howto apply a patch/diff file

Post by ProphetSe7en »

Not sure if I am doing this correctly.

After compiling openttd using

Code: Select all

./configure
make
I try to add a patch using

Code: Select all

patch -p0 <
Do I use p0 or p1?

I am not sure what the next step is. Is that the final step and I can run the openttd.exe in the bin folder with my patches included, or do I have to do something else before I can start the game?
Alberth
OpenTTD Developer
OpenTTD Developer
Posts: 4763
Joined: 09 Sep 2007 05:03
Location: home

Re: Howto apply a patch/diff file

Post by Alberth »

"Compiling" converts a set of source code to a binary executable. If you run that executable, you get the behaviour as specified in the source code.

"Patching" changes (some of the) source code. To get the changes in an executable, you must again "compile" the (modified) source code.

There are several different ways to create a patch file, and these differences cause that you sometimes must use p0 and sometimes you must use p1 when applying the file to the source code (ie, "patching" above).
To see, open the patch file (it's a plain text file, wordpad, notepad++, or any other plain texteditor will work), and look for likes like

Code: Select all

--- src/...
+++ src/...
These must be applied with '-p0'

Other files may have

Code: Select all

--- a/src/...
+++ b/src/...
(there is an additional "a/" and "b/" there) These must be applied with "-p1"

The digit is the number of directory levels to discard, In the first example the number of directory levels is correct, so you don't want to throw anything away, in the second example, you want to throw the "a/" and "b/" levels out, so it's -p1.

The generally recommended order to do things
1. Get unmodified source code of OpenTTD
2. Setup Compiler
3. Compile source code to OpenTTD program, and check if it works
# Here you established that the compiler setup is sane, and can produce working programs
4. Patch the source code
5. Compile modified source code to get modified OpenTTD program, and check if it works.
6. ???
7. Profit!
Being a retired OpenTTD developer does not mean I know what I am doing.
ProphetSe7en
Engineer
Engineer
Posts: 14
Joined: 10 Mar 2017 15:31

Re: Howto apply a patch/diff file

Post by ProphetSe7en »

Thank you so much :D

After compiling the game seems to work.

I then add this patch using -p1, everything still works.

viewtopic.php?t=64762

Then I want to add the advanced buy window used in Spring 2013 Patch Pack. I have tried with -p1 and -p0, but i seems to mess up my game either way. Keep getting an error message about language pack. This patch only work for older trunk, but then I cant get the first one to work.

http://forums.ttdrussia.net/viewtopic.php?f=17&t=3975
ProphetSe7en
Engineer
Engineer
Posts: 14
Joined: 10 Mar 2017 15:31

Re: Howto apply a patch/diff file

Post by ProphetSe7en »

Is it possible to add one patch to r24945, then update the trunk and add a new patch to r27728 and that way add all the patches I want to add?

It is really complicated when all the patches are made for different trunks.
Alberth
OpenTTD Developer
OpenTTD Developer
Posts: 4763
Joined: 09 Sep 2007 05:03
Location: home

Re: Howto apply a patch/diff file

Post by Alberth »

ProphetSe7en wrote:Is it possible to add one patch to r24945, then update the trunk and add a new patch to r27728 and that way add all the patches I want to add?
Theoretically, yes.

It does need knowledge of what changes are being performed, and whether they are in conflict with each other. (To increase fun, there are also conflicts that cannot be detected by comparing modified lines, what all computer tools do, so lack of merge conflicts does not mean it will work correctly.)
Unfortunately, this gets very complicated very quickly, not something you can do without knowing how the program works.

Another way is to move all patches to the same revision separately, and then merge them. For each patch separately, this should be simpler (but still not as simple as letting a computer do it without knowledge about the software).

The merge of multiple patches together is going to be a nightmare anyway. No patch is designed to work together with any other patch, even if they were made with the same trunk revision. To merge patches, you need to understand how each patch works, how the program works, and then figure out how to make all three agree on what to do. You need a lot of knowledge for doing that.
ProphetSe7en wrote:It is really complicated when all the patches are made for different trunks.
Trunk pretty much changes daily, although quite often it is only translations that change, not actual code. Since patches stick around for years and get abandoned after some time, yes, lots of history to catch up with.
At some point it is actually easier to rewrite the patch in the current version, if only to get a better understanding of how it works.
Being a retired OpenTTD developer does not mean I know what I am doing.
ProphetSe7en
Engineer
Engineer
Posts: 14
Joined: 10 Mar 2017 15:31

Re: Howto apply a patch/diff file

Post by ProphetSe7en »

To bad it is not an easier way to implement patches. Some of them really makes the game better and should be in there from the start.

For now I just have to choose one of the patch pack available and hopefully someone else will add the patches I want to the pack.

I have tried a lot to implement several patches I want on different versions of the game, but only a few of them are possible to add at the same time. I was hoping it would be possible to add some of them to one of the patch packs, but it only gave me an error along the way.

So for now I am giving up. Maybe I will look into how the patches are coded later on, but for now I am giving up trying to add several patches at the same time.
User avatar
kamnet
Moderator
Moderator
Posts: 8548
Joined: 28 Sep 2009 17:15
Location: Eastern KY
Contact:

Re: Howto apply a patch/diff file

Post by kamnet »

If anything, OpenTTD always needs more people who are willing to look at the code, learn how it works, and get their hands dirty with testing things and failing, then learning from how things failed. If you have a passion for this, OpenTTD is a great project to learn with!

It's certainly something I wish I had more patience and time to learn myself. So much I'd like to see accomplished.
ProphetSe7en
Engineer
Engineer
Posts: 14
Joined: 10 Mar 2017 15:31

Re: Howto apply a patch/diff file

Post by ProphetSe7en »

Maybe someone can help here so I can understand how this works.

Just to take an example.

I am trying to add this patch.
[+] Spoiler

Code: Select all

diff --git a/src/command.cpp b/src/command.cpp
index 959610c..de74e22 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -183,11 +183,13 @@ CommandProc CmdDepotSellAllVehicles;
 CommandProc CmdDepotMassAutoReplace;
 
 CommandProc CmdCreateGroup;
+CommandProc CmdCreateGroupSpecificName;
 CommandProc CmdAlterGroup;
 CommandProc CmdDeleteGroup;
 CommandProc CmdAddVehicleGroup;
 CommandProc CmdAddSharedVehicleGroup;
 CommandProc CmdRemoveAllVehiclesGroup;
+CommandProc CmdAutoGroupVehiclesGroup;
 CommandProc CmdSetGroupReplaceProtection;
 
 CommandProc CmdMoveOrder;
@@ -341,11 +343,13 @@ static const Command _command_proc_table[] = {
 	DEF_CMD(CmdDepotSellAllVehicles,                           0, CMDT_VEHICLE_CONSTRUCTION  ), // CMD_DEPOT_SELL_ALL_VEHICLES
 	DEF_CMD(CmdDepotMassAutoReplace,                           0, CMDT_VEHICLE_CONSTRUCTION  ), // CMD_DEPOT_MASS_AUTOREPLACE
 	DEF_CMD(CmdCreateGroup,                                    0, CMDT_ROUTE_MANAGEMENT      ), // CMD_CREATE_GROUP
+	DEF_CMD(CmdCreateGroupSpecificName,                        0, CMDT_ROUTE_MANAGEMENT      ), // CMD_CREATE_GROUP_SPECIFIC_NAME
 	DEF_CMD(CmdDeleteGroup,                                    0, CMDT_ROUTE_MANAGEMENT      ), // CMD_DELETE_GROUP
 	DEF_CMD(CmdAlterGroup,                                     0, CMDT_OTHER_MANAGEMENT      ), // CMD_ALTER_GROUP
 	DEF_CMD(CmdAddVehicleGroup,                                0, CMDT_ROUTE_MANAGEMENT      ), // CMD_ADD_VEHICLE_GROUP
 	DEF_CMD(CmdAddSharedVehicleGroup,                          0, CMDT_ROUTE_MANAGEMENT      ), // CMD_ADD_SHARE_VEHICLE_GROUP
 	DEF_CMD(CmdRemoveAllVehiclesGroup,                         0, CMDT_ROUTE_MANAGEMENT      ), // CMD_REMOVE_ALL_VEHICLES_GROUP
+	DEF_CMD(CmdAutoGroupVehiclesGroup,                         0, CMDT_ROUTE_MANAGEMENT      ), // CMD_AUTO_GROUP_VEHICLES_GROUP
 	DEF_CMD(CmdSetGroupReplaceProtection,                      0, CMDT_ROUTE_MANAGEMENT      ), // CMD_SET_GROUP_REPLACE_PROTECTION
 	DEF_CMD(CmdMoveOrder,                                      0, CMDT_ROUTE_MANAGEMENT      ), // CMD_MOVE_ORDER
 	DEF_CMD(CmdChangeTimetable,                                0, CMDT_ROUTE_MANAGEMENT      ), // CMD_CHANGE_TIMETABLE
diff --git a/src/command_type.h b/src/command_type.h
index f318216..e0cd11b 100644
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -314,11 +314,13 @@ enum Commands {
 	CMD_DEPOT_MASS_AUTOREPLACE,       ///< force the autoreplace to take action in a given depot
 
 	CMD_CREATE_GROUP,                 ///< create a new group
+	CMD_CREATE_GROUP_SPECIFIC_NAME,   ///< create a new group
 	CMD_DELETE_GROUP,                 ///< delete a group
 	CMD_ALTER_GROUP,                  ///< alter a group
 	CMD_ADD_VEHICLE_GROUP,            ///< add a vehicle to a group
 	CMD_ADD_SHARED_VEHICLE_GROUP,     ///< add all other shared vehicles to a group which are missing
 	CMD_REMOVE_ALL_VEHICLES_GROUP,    ///< remove all vehicles from a group
+	CMD_AUTO_GROUP_VEHICLES_GROUP,    ///< group all vehicles
 	CMD_SET_GROUP_REPLACE_PROTECTION, ///< set the autoreplace-protection for a group
 
 	CMD_MOVE_ORDER,                   ///< move an order
diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp
index 12cce41..7d5f6a7 100644
--- a/src/group_cmd.cpp
+++ b/src/group_cmd.cpp
@@ -15,9 +15,12 @@
 #include "train.h"
 #include "vehiclelist.h"
 #include "vehicle_func.h"
+#include "station_base.h"
+#include "town.h"
 #include "autoreplace_base.h"
 #include "autoreplace_func.h"
 #include "string_func.h"
+#include "strings_func.h"
 #include "company_func.h"
 #include "core/pool_func.hpp"
 #include "order_backup.h"
@@ -33,12 +36,12 @@ INSTANTIATE_POOL_METHODS(Group)
 
 GroupStatistics::GroupStatistics()
 {
-	this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
+    this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
 }
 
 GroupStatistics::~GroupStatistics()
 {
-	free(this->num_engines);
+    free(this->num_engines);
 }
 
 /**
@@ -46,13 +49,13 @@ GroupStatistics::~GroupStatistics()
  */
 void GroupStatistics::Clear()
 {
-	this->num_vehicle = 0;
-	this->num_profit_vehicle = 0;
-	this->profit_last_year = 0;
+    this->num_vehicle = 0;
+    this->num_profit_vehicle = 0;
+    this->profit_last_year = 0;
 
-	/* This is also called when NewGRF change. So the number of engines might have changed. Reallocate. */
-	free(this->num_engines);
-	this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
+    /* This is also called when NewGRF change. So the number of engines might have changed. Reallocate. */
+    free(this->num_engines);
+    this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
 }
 
 /**
@@ -64,17 +67,17 @@ void GroupStatistics::Clear()
  */
 /* static */ GroupStatistics &GroupStatistics::Get(CompanyID company, GroupID id_g, VehicleType type)
 {
-	if (Group::IsValidID(id_g)) {
-		Group *g = Group::Get(id_g);
-		assert(g->owner == company);
-		assert(g->vehicle_type == type);
-		return g->statistics;
-	}
+    if (Group::IsValidID(id_g)) {
+        Group *g = Group::Get(id_g);
+        assert(g->owner == company);
+        assert(g->vehicle_type == type);
+        return g->statistics;
+    }
 
-	if (IsDefaultGroupID(id_g)) return Company::Get(company)->group_default[type];
-	if (IsAllGroupID(id_g)) return Company::Get(company)->group_all[type];
+    if (IsDefaultGroupID(id_g)) return Company::Get(company)->group_default[type];
+    if (IsAllGroupID(id_g)) return Company::Get(company)->group_all[type];
 
-	NOT_REACHED();
+    NOT_REACHED();
 }
 
 /**
@@ -84,7 +87,7 @@ void GroupStatistics::Clear()
  */
 /* static */ GroupStatistics &GroupStatistics::Get(const Vehicle *v)
 {
-	return GroupStatistics::Get(v->owner, v->group_id, v->type);
+    return GroupStatistics::Get(v->owner, v->group_id, v->type);
 }
 
 /**
@@ -94,7 +97,7 @@ void GroupStatistics::Clear()
  */
 /* static */ GroupStatistics &GroupStatistics::GetAllGroup(const Vehicle *v)
 {
-	return GroupStatistics::Get(v->owner, ALL_GROUP, v->type);
+    return GroupStatistics::Get(v->owner, ALL_GROUP, v->type);
 }
 
 /**
@@ -102,32 +105,32 @@ void GroupStatistics::Clear()
  */
 /* static */ void GroupStatistics::UpdateAfterLoad()
 {
-	/* Set up the engine count for all companies */
-	Company *c;
-	FOR_ALL_COMPANIES(c) {
-		for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
-			c->group_all[type].Clear();
-			c->group_default[type].Clear();
-		}
-	}
-
-	/* Recalculate */
-	Group *g;
-	FOR_ALL_GROUPS(g) {
-		g->statistics.Clear();
-	}
-
-	const Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
-		if (!v->IsEngineCountable()) continue;
-
-		GroupStatistics::CountEngine(v, 1);
-		if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, 1);
-	}
-
-	FOR_ALL_COMPANIES(c) {
-		GroupStatistics::UpdateAutoreplace(c->index);
-	}
+    /* Set up the engine count for all companies */
+    Company *c;
+    FOR_ALL_COMPANIES(c) {
+            for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
+                c->group_all[type].Clear();
+                c->group_default[type].Clear();
+            }
+        }
+
+    /* Recalculate */
+    Group *g;
+    FOR_ALL_GROUPS(g) {
+            g->statistics.Clear();
+        }
+
+    const Vehicle *v;
+    FOR_ALL_VEHICLES(v) {
+            if (!v->IsEngineCountable()) continue;
+
+            GroupStatistics::CountEngine(v, 1);
+            if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, 1);
+        }
+
+    FOR_ALL_COMPANIES(c) {
+            GroupStatistics::UpdateAutoreplace(c->index);
+        }
 }
 
 /**
@@ -137,20 +140,20 @@ void GroupStatistics::Clear()
  */
 /* static */ void GroupStatistics::CountVehicle(const Vehicle *v, int delta)
 {
-	assert(delta == 1 || delta == -1);
+    assert(delta == 1 || delta == -1);
 
-	GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v);
-	GroupStatistics &stats = GroupStatistics::Get(v);
+    GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v);
+    GroupStatistics &stats = GroupStatistics::Get(v);
 
-	stats_all.num_vehicle += delta;
-	stats.num_vehicle += delta;
+    stats_all.num_vehicle += delta;
+    stats.num_vehicle += delta;
 
-	if (v->age > VEHICLE_PROFIT_MIN_AGE) {
-		stats_all.num_profit_vehicle += delta;
-		stats_all.profit_last_year += v->GetDisplayProfitLastYear() * delta;
-		stats.num_profit_vehicle += delta;
-		stats.profit_last_year += v->GetDisplayProfitLastYear() * delta;
-	}
+    if (v->age > VEHICLE_PROFIT_MIN_AGE) {
+        stats_all.num_profit_vehicle += delta;
+        stats_all.profit_last_year += v->GetDisplayProfitLastYear() * delta;
+        stats.num_profit_vehicle += delta;
+        stats.profit_last_year += v->GetDisplayProfitLastYear() * delta;
+    }
 }
 
 /**
@@ -160,9 +163,9 @@ void GroupStatistics::Clear()
  */
 /* static */ void GroupStatistics::CountEngine(const Vehicle *v, int delta)
 {
-	assert(delta == 1 || delta == -1);
-	GroupStatistics::GetAllGroup(v).num_engines[v->engine_type] += delta;
-	GroupStatistics::Get(v).num_engines[v->engine_type] += delta;
+    assert(delta == 1 || delta == -1);
+    GroupStatistics::GetAllGroup(v).num_engines[v->engine_type] += delta;
+    GroupStatistics::Get(v).num_engines[v->engine_type] += delta;
 }
 
 /**
@@ -170,13 +173,13 @@ void GroupStatistics::Clear()
  */
 /* static */ void GroupStatistics::VehicleReachedProfitAge(const Vehicle *v)
 {
-	GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v);
-	GroupStatistics &stats = GroupStatistics::Get(v);
+    GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v);
+    GroupStatistics &stats = GroupStatistics::Get(v);
 
-	stats_all.num_profit_vehicle++;
-	stats_all.profit_last_year += v->GetDisplayProfitLastYear();
-	stats.num_profit_vehicle++;
-	stats.profit_last_year += v->GetDisplayProfitLastYear();
+    stats_all.num_profit_vehicle++;
+    stats_all.profit_last_year += v->GetDisplayProfitLastYear();
+    stats.num_profit_vehicle++;
+    stats.profit_last_year += v->GetDisplayProfitLastYear();
 }
 
 /**
@@ -184,25 +187,25 @@ void GroupStatistics::Clear()
  */
 /* static */ void GroupStatistics::UpdateProfits()
 {
-	/* Set up the engine count for all companies */
-	Company *c;
-	FOR_ALL_COMPANIES(c) {
-		for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
-			c->group_all[type].ClearProfits();
-			c->group_default[type].ClearProfits();
-		}
-	}
-
-	/* Recalculate */
-	Group *g;
-	FOR_ALL_GROUPS(g) {
-		g->statistics.ClearProfits();
-	}
-
-	const Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
-		if (v->IsPrimaryVehicle() && v->age > VEHICLE_PROFIT_MIN_AGE) GroupStatistics::VehicleReachedProfitAge(v);
-	}
+    /* Set up the engine count for all companies */
+    Company *c;
+    FOR_ALL_COMPANIES(c) {
+            for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
+                c->group_all[type].ClearProfits();
+                c->group_default[type].ClearProfits();
+            }
+        }
+
+    /* Recalculate */
+    Group *g;
+    FOR_ALL_GROUPS(g) {
+            g->statistics.ClearProfits();
+        }
+
+    const Vehicle *v;
+    FOR_ALL_VEHICLES(v) {
+            if (v->IsPrimaryVehicle() && v->age > VEHICLE_PROFIT_MIN_AGE) GroupStatistics::VehicleReachedProfitAge(v);
+        }
 }
 
 /**
@@ -211,29 +214,29 @@ void GroupStatistics::Clear()
  */
 /* static */ void GroupStatistics::UpdateAutoreplace(CompanyID company)
 {
-	/* Set up the engine count for all companies */
-	Company *c = Company::Get(company);
-	for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
-		c->group_all[type].ClearAutoreplace();
-		c->group_default[type].ClearAutoreplace();
-	}
-
-	/* Recalculate */
-	Group *g;
-	FOR_ALL_GROUPS(g) {
-		if (g->owner != company) continue;
-		g->statistics.ClearAutoreplace();
-	}
-
-	for (EngineRenewList erl = c->engine_renew_list; erl != NULL; erl = erl->next) {
-		const Engine *e = Engine::Get(erl->from);
-		GroupStatistics &stats = GroupStatistics::Get(company, erl->group_id, e->type);
-		if (!stats.autoreplace_defined) {
-			stats.autoreplace_defined = true;
-			stats.autoreplace_finished = true;
-		}
-		if (stats.num_engines[erl->from] > 0) stats.autoreplace_finished = false;
-	}
+    /* Set up the engine count for all companies */
+    Company *c = Company::Get(company);
+    for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
+        c->group_all[type].ClearAutoreplace();
+        c->group_default[type].ClearAutoreplace();
+    }
+
+    /* Recalculate */
+    Group *g;
+    FOR_ALL_GROUPS(g) {
+            if (g->owner != company) continue;
+            g->statistics.ClearAutoreplace();
+        }
+
+    for (EngineRenewList erl = c->engine_renew_list; erl != NULL; erl = erl->next) {
+        const Engine *e = Engine::Get(erl->from);
+        GroupStatistics &stats = GroupStatistics::Get(company, erl->group_id, e->type);
+        if (!stats.autoreplace_defined) {
+            stats.autoreplace_defined = true;
+            stats.autoreplace_finished = true;
+        }
+        if (stats.num_engines[erl->from] > 0) stats.autoreplace_finished = false;
+    }
 }
 
 /**
@@ -245,25 +248,25 @@ void GroupStatistics::Clear()
  */
 static inline void UpdateNumEngineGroup(const Vehicle *v, GroupID old_g, GroupID new_g)
 {
-	if (old_g != new_g) {
-		/* Decrease the num engines in the old group */
-		GroupStatistics::Get(v->owner, old_g, v->type).num_engines[v->engine_type]--;
+    if (old_g != new_g) {
+        /* Decrease the num engines in the old group */
+        GroupStatistics::Get(v->owner, old_g, v->type).num_engines[v->engine_type]--;
 
-		/* Increase the num engines in the new group */
-		GroupStatistics::Get(v->owner, new_g, v->type).num_engines[v->engine_type]++;
-	}
+        /* Increase the num engines in the new group */
+        GroupStatistics::Get(v->owner, new_g, v->type).num_engines[v->engine_type]++;
+    }
 }
 
 
 
 Group::Group(Owner owner)
 {
-	this->owner = owner;
+    this->owner = owner;
 }
 
 Group::~Group()
 {
-	free(this->name);
+    free(this->name);
 }
 
 
@@ -278,23 +281,23 @@ Group::~Group()
  */
 CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	VehicleType vt = Extract<VehicleType, 0, 3>(p1);
-	if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
+    VehicleType vt = Extract<VehicleType, 0, 3>(p1);
+    if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
 
-	if (!Group::CanAllocateItem()) return CMD_ERROR;
+    if (!Group::CanAllocateItem()) return CMD_ERROR;
 
-	if (flags & DC_EXEC) {
-		Group *g = new Group(_current_company);
-		g->replace_protection = false;
-		g->vehicle_type = vt;
-		g->parent = INVALID_GROUP;
+    if (flags & DC_EXEC) {
+        Group *g = new Group(_current_company);
+        g->replace_protection = false;
+        g->vehicle_type = vt;
+        g->parent = INVALID_GROUP;
 
-		_new_group_id = g->index;
+        _new_group_id = g->index;
 
-		InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
-	}
+        InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
+    }
 
-	return CommandCost();
+    return CommandCost();
 }
 
 
@@ -310,56 +313,61 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
  */
 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Group *g = Group::GetIfValid(p1);
-	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
+    Group *g = Group::GetIfValid(p1);
+    if (g == NULL || g->owner != _current_company) return CMD_ERROR;
 
-	/* Remove all vehicles from the group */
-	DoCommand(0, p1, 0, flags, CMD_REMOVE_ALL_VEHICLES_GROUP);
+    /* Remove all vehicles from the group */
+    DoCommand(0, p1, 0, flags, CMD_REMOVE_ALL_VEHICLES_GROUP);
 
-	/* Delete sub-groups */
-	Group *gp;
-	FOR_ALL_GROUPS(gp) {
-		if (gp->parent == g->index) {
-			DoCommand(0, gp->index, 0, flags, CMD_DELETE_GROUP);
-		}
-	}
+    /* Delete sub-groups */
+    Group *gp;
+    FOR_ALL_GROUPS(gp) {
+            if (gp->parent == g->index) {
+                DoCommand(0, gp->index, 0, flags, CMD_DELETE_GROUP);
+            }
+        }
 
-	if (flags & DC_EXEC) {
-		/* Update backupped orders if needed */
-		OrderBackup::ClearGroup(g->index);
+    if (flags & DC_EXEC) {
+        /* Update backupped orders if needed */
+        OrderBackup::ClearGroup(g->index);
 
-		/* If we set an autoreplace for the group we delete, remove it. */
-		if (_current_company < MAX_COMPANIES) {
-			Company *c;
-			EngineRenew *er;
+        /* If we set an autoreplace for the group we delete, remove it. */
+        if (_current_company < MAX_COMPANIES) {
+            Company *c;
+            EngineRenew *er;
 
-			c = Company::Get(_current_company);
-			FOR_ALL_ENGINE_RENEWS(er) {
-				if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
-			}
-		}
+            c = Company::Get(_current_company);
+            FOR_ALL_ENGINE_RENEWS(er) {
+                    if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
+                }
+        }
 
-		VehicleType vt = g->vehicle_type;
+        VehicleType vt = g->vehicle_type;
 
-		/* Delete the Replace Vehicle Windows */
-		DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
-		delete g;
+        /* Delete the Replace Vehicle Windows */
+        DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
+        delete g;
 
-		InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
-	}
+        InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
+    }
 
-	return CommandCost();
+    return CommandCost();
 }
 
-static bool IsUniqueGroupNameForVehicleType(const char *name, VehicleType type)
+static const Group *GetGroup(const char *name, VehicleType type)
 {
-	const Group *g;
-
-	FOR_ALL_GROUPS(g) {
-		if (g->name != NULL && g->vehicle_type == type && strcmp(g->name, name) == 0) return false;
-	}
+    const Group *g = NULL;
+    FOR_ALL_GROUPS(g) {
+            if (g->name != NULL && g->vehicle_type == type && strcmp(g->name, name) == 0) break;
+        }
+    return g;
+}
 
-	return true;
+static bool IsUniqueGroupNameForVehicleType(const char *name, VehicleType type)
+{
+    const Group *g = GetGroup(name, type);
+    if (g) return false;
+    return true;
 }
 
 /**
@@ -376,48 +384,48 @@ static bool IsUniqueGroupNameForVehicleType(const char *name, VehicleType type)
  */
 CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Group *g = Group::GetIfValid(GB(p1, 0, 16));
-	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
-
-	if (!HasBit(p1, 16)) {
-		/* Rename group */
-		bool reset = StrEmpty(text);
-
-		if (!reset) {
-			if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
-			if (!IsUniqueGroupNameForVehicleType(text, g->vehicle_type)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
-		}
-
-		if (flags & DC_EXEC) {
-			/* Delete the old name */
-			free(g->name);
-			/* Assign the new one */
-			g->name = reset ? NULL : stredup(text);
-		}
-	} else {
-		/* Set group parent */
-		const Group *pg = Group::GetIfValid(GB(p2, 0, 16));
-
-		if (pg != NULL) {
-			if (pg->owner != _current_company) return CMD_ERROR;
-			if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR;
-
-			/* Ensure request parent isn't child of group.
-			 * This is the only place that infinite loops are prevented. */
-			if (GroupIsInGroup(pg->index, g->index)) return CMD_ERROR;
-		}
-
-		if (flags & DC_EXEC) {
-			g->parent = (pg == NULL) ? INVALID_GROUP : pg->index;
-		}
-	}
-
-	if (flags & DC_EXEC) {
-		SetWindowDirty(WC_REPLACE_VEHICLE, g->vehicle_type);
-		InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
-	}
-
-	return CommandCost();
+    Group *g = Group::GetIfValid(GB(p1, 0, 16));
+    if (g == NULL || g->owner != _current_company) return CMD_ERROR;
+
+    if (!HasBit(p1, 16)) {
+        /* Rename group */
+        bool reset = StrEmpty(text);
+
+        if (!reset) {
+            if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
+            if (!IsUniqueGroupNameForVehicleType(text, g->vehicle_type)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
+        }
+
+        if (flags & DC_EXEC) {
+            /* Delete the old name */
+            free(g->name);
+            /* Assign the new one */
+            g->name = reset ? NULL : stredup(text);
+        }
+    } else {
+        /* Set group parent */
+        const Group *pg = Group::GetIfValid(GB(p2, 0, 16));
+
+        if (pg != NULL) {
+            if (pg->owner != _current_company) return CMD_ERROR;
+            if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR;
+
+            /* Ensure request parent isn't child of group.
+             * This is the only place that infinite loops are prevented. */
+            if (GroupIsInGroup(pg->index, g->index)) return CMD_ERROR;
+        }
+
+        if (flags & DC_EXEC) {
+            g->parent = (pg == NULL) ? INVALID_GROUP : pg->index;
+        }
+    }
+
+    if (flags & DC_EXEC) {
+        SetWindowDirty(WC_REPLACE_VEHICLE, g->vehicle_type);
+        InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
+    }
+
+    return CommandCost();
 }
 
 
@@ -428,23 +436,23 @@ CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
  */
 static void AddVehicleToGroup(Vehicle *v, GroupID new_g)
 {
-	GroupStatistics::CountVehicle(v, -1);
-
-	switch (v->type) {
-		default: NOT_REACHED();
-		case VEH_TRAIN:
-			SetTrainGroupID(Train::From(v), new_g);
-			break;
-
-		case VEH_ROAD:
-		case VEH_SHIP:
-		case VEH_AIRCRAFT:
-			if (v->IsEngineCountable()) UpdateNumEngineGroup(v, v->group_id, new_g);
-			v->group_id = new_g;
-			break;
-	}
-
-	GroupStatistics::CountVehicle(v, 1);
+    GroupStatistics::CountVehicle(v, -1);
+
+    switch (v->type) {
+        default: NOT_REACHED();
+        case VEH_TRAIN:
+            SetTrainGroupID(Train::From(v), new_g);
+            break;
+
+        case VEH_ROAD:
+        case VEH_SHIP:
+        case VEH_AIRCRAFT:
+            if (v->IsEngineCountable()) UpdateNumEngineGroup(v, v->group_id, new_g);
+            v->group_id = new_g;
+            break;
+    }
+
+    GroupStatistics::CountVehicle(v, 1);
 }
 
 /**
@@ -461,82 +469,299 @@ static void AddVehicleToGroup(Vehicle *v, GroupID new_g)
  */
 CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Vehicle *v = Vehicle::GetIfValid(GB(p2, 0, 20));
-	GroupID new_g = p1;
+    Vehicle *v = Vehicle::GetIfValid(GB(p2, 0, 20));
+    GroupID new_g = p1;
+
+    if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP)) return CMD_ERROR;
 
-	if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP)) return CMD_ERROR;
+    if (Group::IsValidID(new_g)) {
+        Group *g = Group::Get(new_g);
+        if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
+    }
 
-	if (Group::IsValidID(new_g)) {
-		Group *g = Group::Get(new_g);
-		if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
-	}
+    if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
 
-	if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
+    if (new_g == NEW_GROUP) {
+        /* Create new group. */
+        CommandCost ret = CmdCreateGroup(0, flags, v->type, 0, NULL);
+        if (ret.Failed()) return ret;
 
-	if (new_g == NEW_GROUP) {
-		/* Create new group. */
-		CommandCost ret = CmdCreateGroup(0, flags, v->type, 0, NULL);
-		if (ret.Failed()) return ret;
+        new_g = _new_group_id;
+    }
 
-		new_g = _new_group_id;
-	}
+    if (flags & DC_EXEC) {
+        AddVehicleToGroup(v, new_g);
 
-	if (flags & DC_EXEC) {
-		AddVehicleToGroup(v, new_g);
+        if (HasBit(p2, 31)) {
+            /* Add vehicles in the shared order list as well. */
+            for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
+                if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g);
+            }
+        }
 
-		if (HasBit(p2, 31)) {
-			/* Add vehicles in the shared order list as well. */
-			for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
-				if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g);
-			}
-		}
+        GroupStatistics::UpdateAutoreplace(v->owner);
 
-		GroupStatistics::UpdateAutoreplace(v->owner);
+        /* Update the Replace Vehicle Windows */
+        SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
+        InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack());
+    }
 
-		/* Update the Replace Vehicle Windows */
-		SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
-		InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack());
-	}
+    return CommandCost();
+}
 
-	return CommandCost();
+static uint8 GroupSpecificName(Vehicle *v, char *str, char *str_last)
+{
+    /* Find first and last order */
+    Order *first = NULL;
+    Order *last = NULL;
+    {
+        typedef SmallVector<DestinationID,8> DestVec;
+        struct Data {
+            DestVec dests;
+            Order *order;
+            size_t count;
+        };
+        typedef SmallMap<DestinationID,Data> StationMap;
+
+        VehicleOrderID start = 0;
+        Order *order, *next;
+        DestinationID dest, ndest;
+        StationMap map = StationMap();
+        StationMap::iterator iter;
+        Data *f = NULL, *l = NULL, *d;
+        char looped = 0;
+
+        // Construct map of stations
+        for (order = v->GetOrder(start); order != NULL; order = order->next) {
+            if (order->IsType(OT_GOTO_STATION)) {
+                dest = order->GetDestination();
+                if (!map.Contains(dest)) {
+                    DestVec ds = DestVec();
+                    Data dat = { ds, order, 0};
+                    memcpy(&map[dest], &dat, sizeof(Data));
+                }
+
+                for (next = order->next; !looped || next != NULL; next = next->next) {
+                    if (next == NULL) next = v->GetOrder(start);
+
+                    if (next->IsType(OT_GOTO_STATION)) {
+                        ndest = next->GetDestination();
+                        if (dest != ndest && !map[dest].dests.Contains(ndest)) {
+                            map[dest].dests.Include(ndest);
+                            map[dest].count++;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Find first / last
+        for (iter = map.Begin(); iter != map.End(); iter++) {
+            d = &iter->second;
+            if (f == NULL) f = d;
+            else if (d->count < f->count) { l = f; f = d; }
+            else if (l == NULL) l = d;
+            else if (d->count < l->count) l = d;
+        }
+        if (f != NULL) first = f->order;
+        if (l != NULL) last = l->order;
+    }
+    if(last == NULL || first == NULL) return 1;
+
+    /* Find max lengths */
+    size_t str_len, sep_len;
+    {
+        static char sep_str[MAX_LENGTH_GROUP_NAME_CHARS] = { "" };
+        static char empty[1] = "";
+        SetDParamStr(0, empty);
+        SetDParamStr(1, empty);
+        GetString(sep_str, STR_GROUP_SPECIFIC_NAME_STATION, lastof(sep_str));
+        sep_len = strlen(sep_str);
+        str_len = max(MAX_LENGTH_STATION_NAME_CHARS,MAX_LENGTH_TOWN_NAME_CHARS) * 2 + sep_len;
+    }
+
+    /* Create group name */
+    if(_settings_client.gui.specific_group_name == 1) { // Use station names
+        static char stationname_first[MAX_LENGTH_STATION_NAME_CHARS+2] = { "" };
+        static char stationname_last[MAX_LENGTH_STATION_NAME_CHARS+2] = { "" };
+
+        /* Get station names */
+        SetDParam(0, first->GetDestination());
+        GetString(stationname_first, STR_STATION_NAME, lastof(stationname_first));
+        SetDParam(0, last->GetDestination());
+        GetString(stationname_last, STR_STATION_NAME, lastof(stationname_last));
+
+        /* Find greatest common prefix (that ends with a space) */
+        size_t prefix;
+        {
+            for (prefix = 0; stationname_first[prefix] != '\0' && stationname_last[prefix] != '\0' && stationname_first[prefix] == stationname_last[prefix]; prefix++);
+            if (stationname_first[prefix] == '\0' && stationname_last[prefix] == ' ') {
+                stationname_first[prefix] = ' ';
+                prefix++;
+                stationname_first[prefix] = '\0';
+            }
+            else if (stationname_last[prefix] == '\0' && stationname_first[prefix] == ' ') {
+                stationname_last[prefix] = ' ';
+                prefix++;
+                stationname_last[prefix] = '\0';
+            }
+            while (prefix > 0 && stationname_first[prefix-1] != ' ') prefix--;
+        }
+
+        /* Truncate */
+        {
+            int diff = Utf8StringLength(stationname_first) + sep_len + Utf8StringLength(stationname_last) - prefix - MAX_LENGTH_GROUP_NAME_CHARS + 1;
+            if ( diff > 0 ) {
+                diff = (diff+1)/2;
+                Utf8TrimString(stationname_first, Utf8StringLength(stationname_first)-diff);
+                Utf8TrimString(stationname_last, Utf8StringLength(stationname_last)-diff);
+            }
+
+            /* Remove white endings */
+            int i;
+            for (i = 0; stationname_first[i] != '\0'; i++); i--;
+            while (stationname_first[i] == ' ') { stationname_first[i] = '\0'; i--; }
+            for (i = 0; stationname_last[i] != '\0'; i++); i--;
+            while (stationname_last[i] == ' ') { stationname_last[i] = '\0'; i--; }
+        }
+
+        /* Create name (Sorted) */
+        if(strnatcmp(stationname_first, stationname_last) > 0) {
+            SetDParamStr(0, stationname_last);
+            SetDParamStr(1, &stationname_first[prefix]);
+        } else {
+            SetDParamStr(0, stationname_first);
+            SetDParamStr(1, &stationname_last[prefix]);
+        }
+        GetString(str, STR_GROUP_SPECIFIC_NAME_STATION, str_last);
+
+    } else { // Use town names
+
+        Station *station_first = Station::GetIfValid(first->GetDestination());
+        Station *station_last = Station::GetIfValid(last->GetDestination());
+
+        if(station_last->IsValidID == false || station_first->IsValidID == false) return 1;
+
+        Town *town_first = station_first->town;
+        Town *town_last = station_last->town;
+
+        if(town_first->index == town_last->index) { // First and last station belong to the same town
+            SetDParam(0, town_first->index);
+            GetString(str, STR_GROUP_SPECIFIC_NAME_TOWN_LOCAL, str_last);
+        } else {
+            static char townname_first[64] = { "" };
+            static char townname_last[64] = { "" };
+
+            SetDParam(0, town_first->index);
+            GetString(townname_first, STR_TOWN_NAME, lastof(townname_first));
+
+            SetDParam(0, town_last->index);
+            GetString(townname_last, STR_TOWN_NAME, lastof(townname_last));
+
+            if(strnatcmp(townname_first, townname_last) > 0) { // Sort by name
+                Town *town_temp = town_first;
+                town_first = town_last;
+                town_last = town_temp;
+            }
+
+            SetDParam(0, town_first->index);
+            SetDParam(1, town_last->index );
+            GetString(str, STR_GROUP_SPECIFIC_NAME_TOWN, str_last);
+        }
+    }
+
+    return 0;
 }
 
 /**
- * Add all shared vehicles of all vehicles from a group
+ * Create a new group, rename it with specific name and add vehicle to this group
  * @param tile unused
  * @param flags type of operation
- * @param p1   index of group array
- *  - p1 bit 0-15 : GroupID
- * @param p2   type of vehicles
+ * @param p1   vehicle to add to a group
+ *   - p1 bit 0-19 : VehicleID
+ *   - p1 bit   31 : Add shared vehicles as well.
+ * @param p2   unused
  * @param text unused
  * @return the cost of this operation or an error
  */
-CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+CommandCost CmdCreateGroupSpecificName(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	VehicleType type = Extract<VehicleType, 0, 3>(p2);
-	GroupID id_g = p1;
-	if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
+    Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
+
+    /* Preconditions */
+    if (v == NULL) return CMD_ERROR;
+    if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
+
+    char str[MAX_LENGTH_GROUP_NAME_CHARS+1] = { "" };
+    if (GroupSpecificName(v, str, lastof(str))) return_cmd_error(STR_ERROR_GROUP_CAN_T_CREATE_NAME);
 
-	if (flags & DC_EXEC) {
-		Vehicle *v;
+    /* Check group name */
+    if (!IsUniqueGroupNameForVehicleType(str, v->type)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
+    if (Utf8StringLength(str) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
 
-		/* Find the first front engine which belong to the group id_g
-		 * then add all shared vehicles of this front engine to the group id_g */
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == type && v->IsPrimaryVehicle()) {
-				if (v->group_id != id_g) continue;
+    /* Create group and set name */
+    CommandCost ret = CmdCreateGroup(0, flags, v->type, 0, NULL);
+    if (ret.Failed()) return ret;
+    GroupID new_g = _new_group_id;
+    CmdAlterGroup(0, flags, new_g, 0, str);
 
-				/* For each shared vehicles add it to the group */
-				for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
-					if (v2->group_id != id_g) DoCommand(tile, id_g, v2->index, flags, CMD_ADD_VEHICLE_GROUP, text);
-				}
-			}
-		}
+    /* If execute flag is set, add vehicles to groups */
+    if (flags & DC_EXEC) {
+        AddVehicleToGroup(v, new_g);
 
-		InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
-	}
+        if (HasBit(p1, 31)) { // Add vehicles in the shared order list as well.
+            for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
+                if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g);
+            }
+        }
 
-	return CommandCost();
+        GroupStatistics::UpdateAutoreplace(v->owner);
+
+        /* Update the Replace Vehicle Windows */
+        SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
+        InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack());
+    }
+
+    return CommandCost();
+}
+
+/**
+ * Add all shared vehicles of all vehicles from a group
+ * @param tile unused
+ * @param flags type of operation
+ * @param p1   index of group array
+ *  - p1 bit 0-15 : GroupID
+ * @param p2   type of vehicles
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+    VehicleType type = Extract<VehicleType, 0, 3>(p2);
+    GroupID id_g = p1;
+    if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
+
+    if (flags & DC_EXEC) {
+        Vehicle *v;
+
+        /* Find the first front engine which belong to the group id_g
+         * then add all shared vehicles of this front engine to the group id_g */
+        FOR_ALL_VEHICLES(v) {
+                if (v->type == type && v->IsPrimaryVehicle()) {
+                    if (v->group_id != id_g) continue;
+
+                    /* For each shared vehicles add it to the group */
+                    for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
+                        if (v2->group_id != id_g) DoCommand(tile, id_g, v2->index, flags, CMD_ADD_VEHICLE_GROUP, text);
+                    }
+                }
+            }
+
+        InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
+    }
+
+    return CommandCost();
 }
 
 
@@ -552,28 +777,82 @@ CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32
  */
 CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	GroupID old_g = p1;
-	Group *g = Group::GetIfValid(old_g);
+    GroupID old_g = p1;
+    Group *g = Group::GetIfValid(old_g);
 
-	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
+    if (g == NULL || g->owner != _current_company) return CMD_ERROR;
 
-	if (flags & DC_EXEC) {
-		Vehicle *v;
+    if (flags & DC_EXEC) {
+        Vehicle *v;
 
-		/* Find each Vehicle that belongs to the group old_g and add it to the default group */
-		FOR_ALL_VEHICLES(v) {
-			if (v->IsPrimaryVehicle()) {
-				if (v->group_id != old_g) continue;
+        /* Find each Vehicle that belongs to the group old_g and add it to the default group */
+        FOR_ALL_VEHICLES(v) {
+                if (v->IsPrimaryVehicle()) {
+                    if (v->group_id != old_g) continue;
 
-				/* Add The Vehicle to the default group */
-				DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP, text);
-			}
-		}
+                    /* Add The Vehicle to the default group */
+                    DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP, text);
+                }
+            }
 
-		InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
-	}
+        InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
+    }
 
-	return CommandCost();
+    return CommandCost();
+}
+
+CommandCost CmdAutoGroupVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+    VehicleType type = Extract<VehicleType, 0, 3>(p2);
+    GroupID old_g_id = p1;
+    Group *old_g = Group::GetIfValid(old_g_id);
+
+    if (old_g_id != ALL_GROUP  && old_g_id != DEFAULT_GROUP && (old_g == NULL || old_g->owner != _current_company)) return CMD_ERROR;
+
+    if (flags & DC_EXEC) {
+        Vehicle *v;
+
+        /* Find each Vehicle that belongs to the group old_g and add it to the default group */
+        FOR_ALL_VEHICLES(v) {
+                if (v->type == type && v->IsPrimaryVehicle()) {
+                    if (old_g_id != ALL_GROUP && v->group_id != old_g_id) continue;
+
+                    /* Create name */
+                    char str[MAX_LENGTH_GROUP_NAME_CHARS+1] = { "" };
+                    if (!GroupSpecificName(v, str, lastof(str))) {
+                        /* Get group */
+                        const Group *new_g = GetGroup(str, v->type);
+
+                        /* Check group name */
+                        GroupID new_g_id;
+                        if (new_g == NULL) {
+                            if (Utf8StringLength(str) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
+
+                            /* Create group and set name */
+                            CommandCost ret = CmdCreateGroup(0, flags, v->type, 0, NULL);
+                            if (ret.Failed()) return ret;
+                            new_g_id = _new_group_id;
+                            CmdAlterGroup(0, flags, new_g_id, 0, str);
+                        } else {
+                            new_g_id = new_g->index;
+                        }
+
+                        /* Add vehicle to group */
+                        AddVehicleToGroup(v, new_g_id);
+
+                        GroupStatistics::UpdateAutoreplace(v->owner);
+                    } else {
+                        // TODO How to handle errors ?
+                    }
+                }
+            }
+
+        /* Update the Replace Vehicle Windows */
+        SetWindowDirty(WC_REPLACE_VEHICLE, type);
+        InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
+    }
+
+    return CommandCost();
 }
 
 /**
@@ -583,12 +862,12 @@ CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint3
  */
 static void SetGroupReplaceProtection(Group *g, bool protect)
 {
-	g->replace_protection = protect;
+    g->replace_protection = protect;
 
-	Group *pg;
-	FOR_ALL_GROUPS(pg) {
-		if (pg->parent == g->index) SetGroupReplaceProtection(pg, protect);
-	}
+    Group *pg;
+    FOR_ALL_GROUPS(pg) {
+            if (pg->parent == g->index) SetGroupReplaceProtection(pg, protect);
+        }
 }
 
 /**
@@ -605,21 +884,21 @@ static void SetGroupReplaceProtection(Group *g, bool protect)
  */
 CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Group *g = Group::GetIfValid(p1);
-	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
+    Group *g = Group::GetIfValid(p1);
+    if (g == NULL || g->owner != _current_company) return CMD_ERROR;
 
-	if (flags & DC_EXEC) {
-		if (HasBit(p2, 1)) {
-			SetGroupReplaceProtection(g, HasBit(p2, 0));
-		} else {
-			g->replace_protection = HasBit(p2, 0);
-		}
+    if (flags & DC_EXEC) {
+        if (HasBit(p2, 1)) {
+            SetGroupReplaceProtection(g, HasBit(p2, 0));
+        } else {
+            g->replace_protection = HasBit(p2, 0);
+        }
 
-		SetWindowDirty(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
-		InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
-	}
+        SetWindowDirty(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
+        InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
+    }
 
-	return CommandCost();
+    return CommandCost();
 }
 
 /**
@@ -629,9 +908,9 @@ CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, ui
  */
 void RemoveVehicleFromGroup(const Vehicle *v)
 {
-	if (!v->IsPrimaryVehicle()) return;
+    if (!v->IsPrimaryVehicle()) return;
 
-	if (!IsDefaultGroupID(v->group_id)) GroupStatistics::CountVehicle(v, -1);
+    if (!IsDefaultGroupID(v->group_id)) GroupStatistics::CountVehicle(v, -1);
 }
 
 
@@ -643,19 +922,19 @@ void RemoveVehicleFromGroup(const Vehicle *v)
  */
 void SetTrainGroupID(Train *v, GroupID new_g)
 {
-	if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
+    if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
 
-	assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
+    assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
 
-	for (Vehicle *u = v; u != NULL; u = u->Next()) {
-		if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
+    for (Vehicle *u = v; u != NULL; u = u->Next()) {
+        if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
 
-		u->group_id = new_g;
-	}
+        u->group_id = new_g;
+    }
 
-	/* Update the Replace Vehicle Windows */
-	GroupStatistics::UpdateAutoreplace(v->owner);
-	SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
+    /* Update the Replace Vehicle Windows */
+    GroupStatistics::UpdateAutoreplace(v->owner);
+    SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
 }
 
 
@@ -668,18 +947,18 @@ void SetTrainGroupID(Train *v, GroupID new_g)
  */
 void UpdateTrainGroupID(Train *v)
 {
-	assert(v->IsFrontEngine() || v->IsFreeWagon());
+    assert(v->IsFrontEngine() || v->IsFreeWagon());
 
-	GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP;
-	for (Vehicle *u = v; u != NULL; u = u->Next()) {
-		if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
+    GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP;
+    for (Vehicle *u = v; u != NULL; u = u->Next()) {
+        if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g);
 
-		u->group_id = new_g;
-	}
+        u->group_id = new_g;
+    }
 
-	/* Update the Replace Vehicle Windows */
-	GroupStatistics::UpdateAutoreplace(v->owner);
-	SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
+    /* Update the Replace Vehicle Windows */
+    GroupStatistics::UpdateAutoreplace(v->owner);
+    SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
 }
 
 /**
@@ -692,22 +971,22 @@ void UpdateTrainGroupID(Train *v)
  */
 uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
 {
-	uint count = 0;
-	const Engine *e = Engine::Get(id_e);
-	const Group *g;
-	FOR_ALL_GROUPS(g) {
-		if (g->parent == id_g) count += GetGroupNumEngines(company, g->index, id_e);
-	}
-	return count + GroupStatistics::Get(company, id_g, e->type).num_engines[id_e];
+    uint count = 0;
+    const Engine *e = Engine::Get(id_e);
+    const Group *g;
+    FOR_ALL_GROUPS(g) {
+            if (g->parent == id_g) count += GetGroupNumEngines(company, g->index, id_e);
+        }
+    return count + GroupStatistics::Get(company, id_g, e->type).num_engines[id_e];
 }
 
 void RemoveAllGroupsForCompany(const CompanyID company)
 {
-	Group *g;
+    Group *g;
 
-	FOR_ALL_GROUPS(g) {
-		if (company == g->owner) delete g;
-	}
+    FOR_ALL_GROUPS(g) {
+            if (company == g->owner) delete g;
+        }
 }
 
 
@@ -719,12 +998,12 @@ void RemoveAllGroupsForCompany(const CompanyID company)
  */
 bool GroupIsInGroup(GroupID search, GroupID group)
 {
-	if (!Group::IsValidID(search)) return search == group;
+    if (!Group::IsValidID(search)) return search == group;
 
-	do {
-		if (search == group) return true;
-		search = Group::Get(search)->parent;
-	} while (search != INVALID_GROUP);
+    do {
+        if (search == group) return true;
+        search = Group::Get(search)->parent;
+    } while (search != INVALID_GROUP);
 
-	return false;
+    return false;
 }
diff --git a/src/group_gui.cpp b/src/group_gui.cpp
index 361ab53..b1a9a9e 100644
--- a/src/group_gui.cpp
+++ b/src/group_gui.cpp
@@ -748,8 +748,18 @@ public:
 				}
 				break;
 			}
+			case WID_GL_CREATE_GROUP: { // make new group with vehicle specific name and add vehicle
+				const VehicleID vindex = this->vehicle_sel;
+				this->vehicle_sel = INVALID_VEHICLE;
+				this->group_over = INVALID_GROUP;
+				this->SetDirty();
+
+				DoCommandP(0, vindex | (_ctrl_pressed ? 1 << 31 : 0),0 , CMD_CREATE_GROUP_SPECIFIC_NAME | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE_SPECIFIC_NAME),  NULL);
+				
+				break;
 		}
 	}
+	}
 
 	virtual void OnDragDrop(Point pt, int widget)
 	{
@@ -801,6 +811,9 @@ public:
 
 						DoCommandP(0, this->vli.index, 0, CMD_REMOVE_ALL_VEHICLES_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES));
 						break;
+					case ADI_AUTO_GROUP: // Automatically group all vehicles
+						DoCommandP(0, this->vli.index, this->vli.vtype, CMD_AUTO_GROUP_VEHICLES_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_AUTO_GROUP_VEHICLES));
+						break;
 					default: NOT_REACHED();
 				}
 				break;
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 0b8406e..7dc0b2d 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1213,6 +1213,10 @@ STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE                      :On the driving
 STR_CONFIG_SETTING_SIGNALSIDE_RIGHT                             :On the right
 STR_CONFIG_SETTING_SHOWFINANCES                                 :Show finances window at the end of the year: {STRING2}
 STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT                        :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company
+STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME                          :Use {STRING2} names for specific group name
+STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME_HELPTEXT                 :Uses the selected name from the first and last order of a vehicle to create a specific group name
+STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME_TOWN                     :town
+STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME_STATION                  :station
 STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT                           :New orders are 'non-stop' by default: {STRING2}
 STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT                  :Normally, a vehicle will stop at every station it passes. By enabling this setting, it will drive through all station on the way to its final destination without stopping. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless
 STR_CONFIG_SETTING_STOP_LOCATION                                :New train orders stop by default at the {STRING2} of the platform
@@ -3361,8 +3365,12 @@ STR_GROUP_DELETE_QUERY_TEXT                                     :{WHITE}Are you
 
 STR_GROUP_ADD_SHARED_VEHICLE                                    :Add shared vehicles
 STR_GROUP_REMOVE_ALL_VEHICLES                                   :Remove all vehicles
+STR_GROUP_AUTO_GROUP_VEHICLES                                   :Auto group all vehicles
 
 STR_GROUP_RENAME_CAPTION                                        :{BLACK}Rename a group
+STR_GROUP_SPECIFIC_NAME_STATION                                 :{RAW_STRING} - {RAW_STRING}
+STR_GROUP_SPECIFIC_NAME_TOWN                                    :{TOWN} - {TOWN}
+STR_GROUP_SPECIFIC_NAME_TOWN_LOCAL                              :Local {TOWN}
 
 # Build vehicle window
 STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION                              :New Rail Vehicles
@@ -4365,6 +4373,9 @@ STR_ERROR_GROUP_CAN_T_SET_PARENT                                :{WHITE}Can't se
 STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES                       :{WHITE}Can't remove all vehicles from this group...
 STR_ERROR_GROUP_CAN_T_ADD_VEHICLE                               :{WHITE}Can't add the vehicle to this group...
 STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE                        :{WHITE}Can't add shared vehicles to group...
+STR_ERROR_GROUP_CAN_T_AUTO_GROUP_VEHICLES                       :{WHITE}Can't auto group all vehicles...
+STR_ERROR_GROUP_CAN_T_CREATE_SPECIFIC_NAME                      :{WHITE}Can't create group with specific name...
+STR_ERROR_GROUP_CAN_T_CREATE_NAME                               :{WHITE}Can't create group name...
 
 # Generic vehicle errors
 STR_ERROR_TRAIN_IN_THE_WAY                                      :{WHITE}Train in the way
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index 0652d1b..e4180c9 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1576,6 +1576,7 @@ static SettingsContainer &GetSettingsTree()
 			company->Add(new SettingEntry("gui.default_signal_type"));
 			company->Add(new SettingEntry("gui.cycle_signal_types"));
 			company->Add(new SettingEntry("gui.drag_signals_fixed_distance"));
+			company->Add(new SettingEntry("gui.specific_group_name"));
 			company->Add(new SettingEntry("gui.new_nonstop"));
 			company->Add(new SettingEntry("gui.stop_location"));
 			company->Add(new SettingEntry("company.engine_renew"));
diff --git a/src/settings_type.h b/src/settings_type.h
index 41366a7..91e49b1 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -78,6 +78,7 @@ struct GUISettings {
 	uint8  order_review_system;              ///< perform order reviews on vehicles
 	bool   vehicle_income_warn;              ///< if a vehicle isn't generating income, show a warning
 	bool   show_finances;                    ///< show finances at end of year
+	uint8  specific_group_name;              ///< use station or town names for specific group names
 	bool   sg_new_nonstop;                   ///< ttdpatch compatible nonstop handling read from pre v93 savegames
 	bool   new_nonstop;                      ///< ttdpatch compatible nonstop handling
 	uint8  stop_location;                    ///< what is the default stop location of trains?
diff --git a/src/table/settings.ini b/src/table/settings.ini
index f314f21..3f2fcc4 100644
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -2950,6 +2950,20 @@ strhelp  = STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT
 proc     = RedrawScreen
 cat      = SC_EXPERT
 
+[SDTC_VAR]
+var      = gui.specific_group_name
+type     = SLE_UINT8
+flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def      = 0
+min      = 0
+max      = 1
+interval = 1
+str      = STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME
+strhelp  = STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME_HELPTEXT
+strval   = STR_CONFIG_SETTING_SPECIFIC_GROUP_NAME_TOWN
+cat      = SC_BASIC
+
 [SDTC_BOOL]
 var      = gui.new_nonstop
 flags    = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp
index 8ea8cda..bc52e31 100644
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -177,6 +177,8 @@ DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autorepla
 		*list->Append() = new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false);
 	}
 
+    *list->Append() = new DropDownListStringItem(STR_GROUP_AUTO_GROUP_VEHICLES, ADI_AUTO_GROUP, false);
+
 	return list;
 }
 
diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h
index 5755c7f..cf267bd 100644
--- a/src/vehicle_gui_base.h
+++ b/src/vehicle_gui_base.h
@@ -32,6 +32,7 @@ struct BaseVehicleListWindow : public Window {
 		ADI_DEPOT,
 		ADI_ADD_SHARED,
 		ADI_REMOVE_ALL,
+		ADI_AUTO_GROUP,
 	};
 
 	static const StringID vehicle_depot_name[];
I then get these error when trying to do so.
[+] Spoiler

Code: Select all

$ patch -p1 < specific_group_names-r27728.diff
patching file src/command.cpp
Hunk #1 succeeded at 186 (offset 3 lines).
Hunk #2 succeeded at 380 (offset 37 lines).
patching file src/command_type.h
Hunk #1 succeeded at 331 (offset 17 lines).
patching file src/group_cmd.cpp
Hunk #14 succeeded at 281 with fuzz 2.
Hunk #15 succeeded at 313 with fuzz 2.
Hunk #16 succeeded at 384 with fuzz 2.
Hunk #18 FAILED at 469.
Hunk #19 succeeded at 560 with fuzz 2.
Hunk #21 succeeded at 667 with fuzz 2.
1 out of 26 hunks FAILED -- saving rejects to file src/group_cmd.cpp.rej
patching file src/group_gui.cpp
Hunk #1 succeeded at 983 (offset 235 lines).
Hunk #2 succeeded at 1051 (offset 240 lines).
patching file src/lang/english.txt
Hunk #1 succeeded at 1327 (offset 114 lines).
Hunk #2 succeeded at 4162 with fuzz 2 (offset 797 lines).
Hunk #3 succeeded at 5349 (offset 976 lines).
patching file src/settings_gui.cpp
Hunk #1 succeeded at 1641 (offset 65 lines).
patching file src/settings_type.h
Hunk #1 succeeded at 80 (offset 2 lines).
patching file src/table/settings.ini
Hunk #1 succeeded at 5930 (offset 2980 lines).
patching file src/vehicle_gui.cpp
Hunk #1 succeeded at 181 (offset 4 lines).
patching file src/vehicle_gui_base.h
I need so understand why I get these errors and how to fix them.

What does

- Hunk #18 FAILED at 469 and 1 out of 26 hunks FAILED -- saving rejects to file src/group_cmd.cpp.rej means.

As far as I can tell the error is when trying to alter the file src/group_cmd.cpp, but how can I figure out where the error is by this line "Hunk #18 FAILED at 469"? Is it line 469 in the diff file that is making problems, or is it the line 469 in group_cmd.cpp? And how do I fix this? I just need som help along the way to figure this out :)
Alberth
OpenTTD Developer
OpenTTD Developer
Posts: 4763
Joined: 09 Sep 2007 05:03
Location: home

Re: Howto apply a patch/diff file

Post by Alberth »

It's a very bad patch.

You have a lot of this kind of 'changes':

Code: Select all

 GroupStatistics::GroupStatistics()
 {
-   this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
+    this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
 }
As you can see, the actual text isn't changed, only the leading white-space was modified.

Someone used spaces for indenting, and 'fixed' a lot of lines to match with his preferred indenting.
This makes the patch pretty much useless; you have a lot of changed lines that are not really changes at all. It reduces the chance for a clean merge dramatically.
Any change in those 'changed' lines (eg from an unrelated patch you applied earlier, or unrelated fixes in the code that were done later) will trigger a failure to merge.


As for your error, if you open the patch file with an editor you see big blocks with

Code: Select all

--- old/file/name
+++ new/file/name
in it. Below it, and upto the next big block (almost), are the changes for this file.
Inside a block are hunks. They start with @@, and run until the next hunk, or the next big block

Hunks are numbered within each file, starting with hunk 1. By some counting you can find the hunk that failed.
The line number is the line number where the hunk started in the unpatched file (at least I hope so, else there is nothing you can do with the line number :p )

Since patch couldn't deposit the change into the file, you need to fix that manually. For your convenience, patch makes a ".rej" file with the rejected hunks (after some pre-processing, it shuffles the "+" and "-" around). It also makes a ".orig" file of the unpatched source file, in case you need it.

See also https://en.wikipedia.org/wiki/Unified_d ... ied_format
Being a retired OpenTTD developer does not mean I know what I am doing.
Eddi
Tycoon
Tycoon
Posts: 8257
Joined: 17 Jan 2007 00:14

Re: Howto apply a patch/diff file

Post by Eddi »

try applying the patch with "--ignore-whitespace" (or short "-l"). or try applying the patch to the original revision and re-create it without the whitespace changes (like "diff -b")
Post Reply

Return to “OpenTTD Development”

Who is online

Users browsing this forum: Argus and 16 guests