changeset 12010:d0bf08a7c260 draft

(svn r16416) -Fix [FS#2912]: Rework deleting of news when referenced vehicles/stations/industries are deleted.
author frosch <frosch@openttd.org>
date Sun, 24 May 2009 16:52:42 +0000
parents 5ac019d48a1b
children 69744e567407
files src/aircraft_cmd.cpp src/company_cmd.cpp src/currency.cpp src/disaster_cmd.cpp src/economy.cpp src/engine.cpp src/engine_gui.cpp src/industry_cmd.cpp src/news_func.h src/news_gui.cpp src/news_type.h src/order_cmd.cpp src/roadveh_cmd.cpp src/ship_cmd.cpp src/station_cmd.cpp src/subsidy.cpp src/town_cmd.cpp src/train_cmd.cpp src/vehicle.cpp src/water_cmd.cpp
diffstat 20 files changed, 216 insertions(+), 162 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -1320,10 +1320,10 @@
 
 	AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, crash_reason));
 
-	AddNewsItem(newsitem,
-		NS_ACCIDENT_VEHICLE,
+	AddVehicleNewsItem(newsitem,
+		NS_ACCIDENT,
 		v->index,
-		0);
+		st != NULL ? st->index : INVALID_STATION);
 
 	SndPlayVehicleFx(SND_12_EXPLOSION, v);
 }
@@ -1364,7 +1364,7 @@
 		st->had_vehicle_of_type |= HVOT_AIRCRAFT;
 		SetDParam(0, st->index);
 		/* show newsitem of celebrating citizens */
-		AddNewsItem(
+		AddVehicleNewsItem(
 			STR_NEWS_FIRST_AIRCRAFT_ARRIVAL,
 			(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 			v->index,
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -289,7 +289,7 @@
 			SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION);
 			SetDParamStr(2, cni->company_name);
 			SetDParam(3, t->index);
-			AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_NEW, c->last_build_coordinate, 0, cni);
+			AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_NEW, NR_TILE, c->last_build_coordinate, NR_NONE, UINT32_MAX, cni);
 		}
 		AI::BroadcastNewEvent(new AIEventCompanyNew(c->index), c->index);
 		return;
@@ -827,7 +827,7 @@
 			SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE);
 			SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION);
 			SetDParamStr(2, cni->company_name);
-			AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_BANKRUPT, 0, 0, cni);
+			AddCompanyNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_BANKRUPT, cni);
 
 			/* Remove the company */
 			ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
--- a/src/currency.cpp
+++ b/src/currency.cpp
@@ -157,7 +157,7 @@
 			_currency_specs[_settings_game.locale.currency].to_euro != CF_ISEURO &&
 			_cur_year >= _currency_specs[_settings_game.locale.currency].to_euro) {
 		_settings_game.locale.currency = 2; // this is the index of euro above.
-		AddNewsItem(STR_EURO_INTRODUCE, NS_ECONOMY, 0, 0);
+		AddNewsItem(STR_EURO_INTRODUCE, NS_ECONOMY);
 	}
 }
 
--- a/src/disaster_cmd.cpp
+++ b/src/disaster_cmd.cpp
@@ -207,10 +207,9 @@
 				v->age = 0;
 
 				SetDParam(0, GetStationIndex(v->tile));
-				AddNewsItem(STR_NEWS_DISASTER_ZEPPELIN,
-					NS_ACCIDENT_VEHICLE,
-					v->index,
-					0);
+				AddVehicleNewsItem(STR_NEWS_DISASTER_ZEPPELIN,
+					NS_ACCIDENT,
+					v->index); // Delete the news, when the zeppelin is gone
 				AI::NewEvent(GetTileOwner(v->tile), new AIEventDisasterZeppelinerCrashed(GetStationIndex(v->tile)));
 			}
 		}
@@ -340,10 +339,9 @@
 			if (u->crashed_ctr == 0) {
 				u->crashed_ctr++;
 
-				AddNewsItem(STR_NEWS_DISASTER_SMALL_UFO,
-					NS_ACCIDENT_VEHICLE,
-					u->index,
-					0);
+				AddVehicleNewsItem(STR_NEWS_DISASTER_SMALL_UFO,
+					NS_ACCIDENT,
+					u->index); // delete the news, when the roadvehicle is gone
 
 				AI::NewEvent(u->owner, new AIEventVehicleCrashed(u->index, u->tile, AIEventVehicleCrashed::CRASH_RV_UFO));
 
@@ -426,7 +424,7 @@
 			DestructIndustry(i);
 
 			SetDParam(0, i->town->index);
-			AddNewsItem(news_message, NS_ACCIDENT_TILE, i->xy, 0);
+			AddIndustryNewsItem(news_message, NS_ACCIDENT, i->index); // delete the news, when the industry closes
 			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
 		}
 	} else if (v->current_order.GetDestination() == 0) {
@@ -523,9 +521,9 @@
 		Town *t = ClosestTownFromTile(v->dest_tile, UINT_MAX);
 		SetDParam(0, t->index);
 		AddNewsItem(STR_NEWS_DISASTER_BIG_UFO,
-			NS_ACCIDENT_TILE,
-			v->tile,
-			0);
+			NS_ACCIDENT,
+			NR_TILE,
+			v->tile);
 
 		if (!Vehicle::CanAllocateItem(2)) {
 			delete v;
@@ -865,7 +863,7 @@
 			if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_CAN_SUBSIDENCE) && --index < 0) {
 				SetDParam(0, i->town->index);
 				AddNewsItem(STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE,
-					NS_ACCIDENT_TILE, i->xy + TileDiffXY(1, 1), 0);
+					NS_ACCIDENT, NR_TILE, i->xy + TileDiffXY(1, 1)); // keep the news, even when the mine closes
 
 				{
 					TileIndex tile = i->xy;
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -481,7 +481,7 @@
 			SetDParam(0, STR_NEWS_COMPANY_IN_TROUBLE_TITLE);
 			SetDParam(1, STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION);
 			SetDParamStr(2, cni->company_name);
-			AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_TROUBLE, 0, 0, cni);
+			AddCompanyNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_TROUBLE, cni);
 			AI::BroadcastNewEvent(new AIEventCompanyInTrouble(c->index));
 			break;
 		case 3: {
@@ -491,7 +491,7 @@
 				SetDParam(0, STR_NEWS_COMPANY_IN_TROUBLE_TITLE);
 				SetDParam(1, STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION);
 				SetDParamStr(2, cni->company_name);
-				AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_TROUBLE, 0, 0, cni);
+				AddCompanyNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_TROUBLE, cni);
 				break;
 			}
 
@@ -526,7 +526,7 @@
 			SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE);
 			SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION);
 			SetDParamStr(2, cni->company_name);
-			AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_BANKRUPT, 0, 0, cni);
+			AddCompanyNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_BANKRUPT, cni);
 
 			/* Remove the company */
 			ChangeNetworkOwner(c->index, COMPANY_SPECTATOR);
@@ -668,10 +668,10 @@
 
 	if (--_economy.fluct == 0) {
 		_economy.fluct = -(int)GB(Random(), 0, 2);
-		AddNewsItem(STR_NEWS_BEGIN_OF_RECESSION, NS_ECONOMY, 0, 0);
+		AddNewsItem(STR_NEWS_BEGIN_OF_RECESSION, NS_ECONOMY);
 	} else if (_economy.fluct == -12) {
 		_economy.fluct = GB(Random(), 0, 8) + 312;
-		AddNewsItem(STR_NEWS_END_OF_RECESSION, NS_ECONOMY, 0, 0);
+		AddNewsItem(STR_NEWS_END_OF_RECESSION, NS_ECONOMY);
 	}
 }
 
@@ -1507,7 +1507,7 @@
 	SetDParamStr(2, cni->company_name);
 	SetDParamStr(3, cni->other_company_name);
 	SetDParam(4, c->bankrupt_value);
-	AddNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_MERGER, 0, 0, cni);
+	AddCompanyNewsItem(STR_NEWS_MESSAGE, NS_COMPANY_MERGER, cni);
 	AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company));
 
 	/* original code does this a little bit differently */
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -683,7 +683,7 @@
 
 	SetDParam(0, GetEngineCategoryName(index));
 	SetDParam(1, index);
-	AddNewsItem(STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, index, 0);
+	AddNewsItem(STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, NR_ENGINE, index);
 }
 
 void EnginesMonthlyLoop()
--- a/src/engine_gui.cpp
+++ b/src/engine_gui.cpp
@@ -224,7 +224,8 @@
 
 void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni)
 {
-	EngineID engine = ni->data_a;
+	assert(ni->reftype1 == NR_ENGINE);
+	EngineID engine = ni->ref1;
 	const DrawEngineInfo *dei = &_draw_engine_list[Engine::Get(engine)->type];
 
 	SetDParam(0, GetEngineCategoryName(engine));
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -164,6 +164,7 @@
 	DecIndustryTypeCount(this->type);
 
 	DeleteSubsidyWithIndustry(this->index);
+	DeleteIndustryNews(this->index);
 	DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
 	InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
 }
@@ -1693,7 +1694,7 @@
 		} else {
 			SetDParam(1, ind->town->index);
 		}
-		AddNewsItem(indspec->new_industry_text, NS_INDUSTRY_OPEN, ind->xy, 0);
+		AddIndustryNewsItem(indspec->new_industry_text, NS_INDUSTRY_OPEN, ind->index);
 		AI::BroadcastNewEvent(new AIEventIndustryOpen(ind->index));
 	}
 
@@ -1898,7 +1899,7 @@
 	} else {
 		SetDParam(1, ind->town->index);
 	}
-	AddNewsItem(ind_spc->new_industry_text, NS_INDUSTRY_OPEN, ind->xy, 0);
+	AddIndustryNewsItem(ind_spc->new_industry_text, NS_INDUSTRY_OPEN, ind->index);
 	AI::BroadcastNewEvent(new AIEventIndustryOpen(ind->index));
 }
 
@@ -2042,10 +2043,10 @@
 	SetDParam(2, abs(percent));
 	SetDParam(0, GetCargo(type)->name);
 	SetDParam(1, ind->index);
-	AddNewsItem(
+	AddIndustryNewsItem(
 		percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
 		ns,
-		ind->xy + TileDiffXY(1, 1), 0
+		ind->index
 	);
 }
 
@@ -2250,7 +2251,8 @@
 		/* and report the news to the user */
 		AddNewsItem(str,
 			ns,
-			i->xy + TileDiffXY(1, 1), 0);
+			closeit ? NR_TILE : NR_INDUSTRY,
+			closeit ? i->xy + TileDiffXY(1, 1) : i->index);
 	}
 }
 
--- a/src/news_func.h
+++ b/src/news_func.h
@@ -8,8 +8,25 @@
 #include "news_type.h"
 #include "vehicle_type.h"
 #include "station_type.h"
+#include "industry_type.h"
 
-void AddNewsItem(StringID string, NewsSubtype subtype, uint data_a, uint data_b, void *free_data = NULL);
+void AddNewsItem(StringID string, NewsSubtype subtype, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, void *free_data = NULL);
+
+static inline void AddCompanyNewsItem(StringID string, NewsSubtype subtype, CompanyNewsInformation *cni)
+{
+	AddNewsItem(string, subtype, NR_NONE, UINT32_MAX, NR_NONE, UINT32_MAX, cni);
+}
+
+static inline void AddVehicleNewsItem(StringID string, NewsSubtype subtype, VehicleID vehicle, StationID station = INVALID_STATION)
+{
+	AddNewsItem(string, subtype, NR_VEHICLE, vehicle, station == INVALID_STATION ? NR_NONE : NR_STATION, station);
+}
+
+static inline void AddIndustryNewsItem(StringID string, NewsSubtype subtype, IndustryID industry)
+{
+	AddNewsItem(string, subtype, NR_INDUSTRY, industry);
+}
+
 void NewsLoop();
 void InitNewsItemStructs();
 
@@ -23,9 +40,12 @@
  * if the news item type is INVALID_STRING_ID all news about the vehicle get
  * deleted
  */
-void DeleteVehicleNews(VehicleID, StringID news);
+void DeleteVehicleNews(VehicleID vid, StringID news);
 
 /** Delete news associated with given station */
-void DeleteStationNews(StationID);
+void DeleteStationNews(StationID sid);
+
+/** Delete news associated with given station */
+void DeleteIndustryNews(IndustryID iid);
 
 #endif /* NEWS_FUNC_H */
--- a/src/news_gui.cpp
+++ b/src/news_gui.cpp
@@ -14,11 +14,15 @@
 #include "window_func.h"
 #include "date_func.h"
 #include "vehicle_base.h"
+#include "station_base.h"
+#include "industry.h"
+#include "town.h"
 #include "sound_func.h"
 #include "string_func.h"
 #include "widgets/dropdown_func.h"
 #include "statusbar_gui.h"
 #include "company_manager_face.h"
+#include "map_func.h"
 
 #include "table/strings.h"
 
@@ -90,6 +94,22 @@
 	}
 }
 
+/**
+ * Get the position a news-reference is referencing.
+ * @param reftype The type of reference.
+ * @param ref     The reference.
+ * @return A tile for the referenced object, or INVALID_TILE if none.
+ */
+static TileIndex GetReferenceTile(NewsReferenceType reftype, uint32 ref)
+{
+	switch (reftype) {
+		case NR_TILE:     return (TileIndex)ref;
+		case NR_STATION:  return Station::Get((StationID)ref)->xy;
+		case NR_INDUSTRY: return Industry::Get((IndustryID)ref)->xy + TileDiffXY(1, 1);
+		case NR_TOWN:     return Town::Get((TownID)ref)->xy;
+		default:          return INVALID_TILE;
+	}
+}
 
 /**
  * Data common to all news items of a given subtype (structure)
@@ -106,25 +126,24 @@
  */
 static const NewsSubtypeData _news_subtype_data[] = {
 	/* type,               display_mode, flags,                  callback */
-	{ NT_ARRIVAL_COMPANY,  NM_THIN,     NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ARRIVAL_COMPANY
-	{ NT_ARRIVAL_OTHER,    NM_THIN,     NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ARRIVAL_OTHER
-	{ NT_ACCIDENT,         NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_ACCIDENT_TILE
-	{ NT_ACCIDENT,         NM_THIN,     NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ACCIDENT_VEHICLE
-	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_TROUBLE
-	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_MERGER
-	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_BANKRUPT
-	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_TILE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_NEW
-	{ NT_INDUSTRY_OPEN,    NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_OPEN
-	{ NT_INDUSTRY_CLOSE,   NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_CLOSE
-	{ NT_ECONOMY,          NM_NORMAL,   NF_NONE,                NULL                    }, ///< NS_ECONOMY
-	{ NT_INDUSTRY_COMPANY, NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_COMPANY
-	{ NT_INDUSTRY_OTHER,   NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_OTHER
-	{ NT_INDUSTRY_NOBODY,  NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_NOBODY
-	{ NT_ADVICE,           NM_SMALL,    NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ADVICE
-	{ NT_NEW_VEHICLES,     NM_NORMAL,   NF_NONE,                DrawNewsNewVehicleAvail }, ///< NS_NEW_VEHICLES
-	{ NT_ACCEPTANCE,       NM_SMALL,    NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_ACCEPTANCE
-	{ NT_SUBSIDIES,        NM_NORMAL,   NF_TILE|NF_TILE2,       NULL                    }, ///< NS_SUBSIDIES
-	{ NT_GENERAL,          NM_NORMAL,   NF_TILE,                NULL                    }, ///< NS_GENERAL
+	{ NT_ARRIVAL_COMPANY,  NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_ARRIVAL_COMPANY
+	{ NT_ARRIVAL_OTHER,    NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_ARRIVAL_OTHER
+	{ NT_ACCIDENT,         NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_ACCIDENT
+	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,     DrawNewsBankrupcy       }, ///< NS_COMPANY_TROUBLE
+	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,     DrawNewsBankrupcy       }, ///< NS_COMPANY_MERGER
+	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,     DrawNewsBankrupcy       }, ///< NS_COMPANY_BANKRUPT
+	{ NT_COMPANY_INFO,     NM_NORMAL,   NF_NONE,     DrawNewsBankrupcy       }, ///< NS_COMPANY_NEW
+	{ NT_INDUSTRY_OPEN,    NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_INDUSTRY_OPEN
+	{ NT_INDUSTRY_CLOSE,   NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_INDUSTRY_CLOSE
+	{ NT_ECONOMY,          NM_NORMAL,   NF_NONE,     NULL                    }, ///< NS_ECONOMY
+	{ NT_INDUSTRY_COMPANY, NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_INDUSTRY_COMPANY
+	{ NT_INDUSTRY_OTHER,   NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_INDUSTRY_OTHER
+	{ NT_INDUSTRY_NOBODY,  NM_THIN,     NF_VIEWPORT, NULL                    }, ///< NS_INDUSTRY_NOBODY
+	{ NT_ADVICE,           NM_SMALL,    NF_VIEWPORT, NULL                    }, ///< NS_ADVICE
+	{ NT_NEW_VEHICLES,     NM_NORMAL,   NF_NONE,     DrawNewsNewVehicleAvail }, ///< NS_NEW_VEHICLES
+	{ NT_ACCEPTANCE,       NM_SMALL,    NF_VIEWPORT, NULL                    }, ///< NS_ACCEPTANCE
+	{ NT_SUBSIDIES,        NM_NORMAL,   NF_NONE,     NULL                    }, ///< NS_SUBSIDIES
+	{ NT_GENERAL,          NM_NORMAL,   NF_NONE,     NULL                    }, ///< NS_GENERAL
 };
 
 assert_compile(lengthof(_news_subtype_data) == NS_END);
@@ -253,18 +272,18 @@
 				break;
 
 			case 0:
-				if (this->ni->flags & NF_VEHICLE) {
-					const Vehicle *v = Vehicle::Get(this->ni->data_a);
+				if (this->ni->reftype1 == NR_VEHICLE) {
+					const Vehicle *v = Vehicle::Get(this->ni->ref1);
 					ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos);
-				} else if (this->ni->flags & NF_TILE) {
+				} else {
+					TileIndex tile1 = GetReferenceTile(this->ni->reftype1, this->ni->ref1);
+					TileIndex tile2 = GetReferenceTile(this->ni->reftype2, this->ni->ref2);
 					if (_ctrl_pressed) {
-						ShowExtraViewPortWindow(this->ni->data_a);
-						if (this->ni->flags & NF_TILE2) {
-							ShowExtraViewPortWindow(this->ni->data_b);
-						}
+						if (tile1 != INVALID_TILE) ShowExtraViewPortWindow(tile1);
+						if (tile2 != INVALID_TILE) ShowExtraViewPortWindow(tile2);
 					} else {
-						if (!ScrollMainWindowToTile(this->ni->data_a) && this->ni->flags & NF_TILE2) {
-							ScrollMainWindowToTile(this->ni->data_b);
+						if (((tile1 == INVALID_TILE) || !ScrollMainWindowToTile(tile1)) && (tile2 != INVALID_TILE)) {
+							ScrollMainWindowToTile(tile2);
 						}
 					}
 				}
@@ -405,7 +424,7 @@
 			w = new NewsWindow(&_news_type13_desc, ni);
 			if (ni->flags & NF_VIEWPORT) {
 				InitializeWindowViewport(w, 2, 58, 426, 110,
-					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
+					ni->reftype1 == NR_VEHICLE ? 0x80000000 | ni->ref1 : GetReferenceTile(ni->reftype1, ni->ref1), ZOOM_LVL_NEWS);
 			}
 			break;
 
@@ -414,7 +433,7 @@
 			w = new NewsWindow(&_news_type2_desc, ni);
 			if (ni->flags & NF_VIEWPORT) {
 				InitializeWindowViewport(w, 2, 58, 426, 70,
-					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
+					ni->reftype1 == NR_VEHICLE ? 0x80000000 | ni->ref1 : GetReferenceTile(ni->reftype1, ni->ref1), ZOOM_LVL_NEWS);
 			}
 			break;
 
@@ -423,7 +442,7 @@
 			w = new NewsWindow(&_news_type0_desc, ni);
 			if (ni->flags & NF_VIEWPORT) {
 				InitializeWindowViewport(w, 3, 17, 274, 47,
-					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
+					ni->reftype1 == NR_VEHICLE ? 0x80000000 | ni->ref1 : GetReferenceTile(ni->reftype1, ni->ref1), ZOOM_LVL_NEWS);
 			}
 			break;
 	}
@@ -511,12 +530,14 @@
  * Add a new newsitem to be shown.
  * @param string String to display
  * @param subtype news category, any of the NewsSubtype enums (NS_)
- * @param data_a news-specific value based on news type
- * @param data_b news-specific value based on news type
+ * @param reftype1 Type of ref1
+ * @param ref1     Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleteing the news when the object is deleted.
+ * @param reftype2 Type of ref2
+ * @param ref2     Reference 2 to some object: Used for scrolling after clicking on the news, and for deleteing the news when the object is deleted.
  *
  * @see NewsSubype
  */
-void AddNewsItem(StringID string, NewsSubtype subtype, uint data_a, uint data_b, void *free_data)
+void AddNewsItem(StringID string, NewsSubtype subtype, NewsReferenceType reftype1, uint32 ref1, NewsReferenceType reftype2, uint32 ref2, void *free_data)
 {
 	if (_game_mode == GM_MENU) return;
 
@@ -530,8 +551,10 @@
 	/* show this news message in colour? */
 	if (_cur_year >= _settings_client.gui.coloured_news_year) ni->flags |= NF_INCOLOUR;
 
-	ni->data_a = data_a;
-	ni->data_b = data_b;
+	ni->reftype1 = reftype1;
+	ni->reftype2 = reftype2;
+	ni->ref1 = ref1;
+	ni->ref2 = ref2;
 	ni->free_data = free_data;
 	ni->date = _date;
 	CopyOutDParam(ni->params, 0, lengthof(ni->params));
@@ -591,16 +614,12 @@
 	NewsItem *ni = _oldest_news;
 
 	while (ni != NULL) {
-		if (ni->flags & NF_VEHICLE &&
-				ni->data_a == vid &&
+		NewsItem *next = ni->next;
+		if (((ni->reftype1 == NR_VEHICLE && ni->ref1 == vid) || (ni->reftype2 == NR_VEHICLE && ni->ref2 == vid)) &&
 				(news == INVALID_STRING_ID || ni->string_id == news)) {
-			/* grab a pointer to the next item before ni is freed */
-			NewsItem *p = ni->next;
 			DeleteNewsItem(ni);
-			ni = p;
-		} else {
-			ni = ni->next;
 		}
+		ni = next;
 	}
 }
 
@@ -614,14 +633,24 @@
 
 	while (ni != NULL) {
 		NewsItem *next = ni->next;
-		switch (ni->subtype) {
-			case NS_ARRIVAL_COMPANY:
-			case NS_ARRIVAL_OTHER:
-			case NS_ACCEPTANCE:
-				if (ni->data_b == sid) DeleteNewsItem(ni);
-				break;
-			default:
-				break;
+		if ((ni->reftype1 == NR_STATION && ni->ref1 == sid) || (ni->reftype2 == NR_STATION && ni->ref2 == sid)) {
+			DeleteNewsItem(ni);
+		}
+		ni = next;
+	}
+}
+
+/** Remove news regarding given industry
+ * @param iid industry to remove news about
+ */
+void DeleteIndustryNews(IndustryID iid)
+{
+	NewsItem *ni = _oldest_news;
+
+	while (ni != NULL) {
+		NewsItem *next = ni->next;
+		if ((ni->reftype1 == NR_INDUSTRY && ni->ref1 == iid) || (ni->reftype2 == NR_INDUSTRY && ni->ref2 == iid)) {
+			DeleteNewsItem(ni);
 		}
 		ni = next;
 	}
--- a/src/news_type.h
+++ b/src/news_type.h
@@ -38,8 +38,7 @@
 enum NewsSubtype {
 	NS_ARRIVAL_COMPANY,  ///< NT_ARRIVAL_COMPANY
 	NS_ARRIVAL_OTHER,    ///< NT_ARRIVAL_OTHER
-	NS_ACCIDENT_TILE,    ///< NT_ACCIDENT (tile)
-	NS_ACCIDENT_VEHICLE, ///< NT_ACCIDENT (vehicle)
+	NS_ACCIDENT,         ///< NT_ACCIDENT
 	NS_COMPANY_TROUBLE,  ///< NT_COMPANY_INFO (trouble)
 	NS_COMPANY_MERGER,   ///< NT_COMPANY_INFO (merger)
 	NS_COMPANY_BANKRUPT, ///< NT_COMPANY_INFO (bankrupt)
@@ -68,16 +67,26 @@
 };
 
 /**
+ * References to objects in news.
+ */
+enum NewsReferenceType {
+	NR_NONE,      ///< Empty reference
+	NR_TILE,      ///< Reference tile.     Scroll to tile when clicking on the news.
+	NR_VEHICLE,   ///< Reference vehicle.  Scroll to vehicle when clicking on the news. Delete news when vehicle is deleted.
+	NR_STATION,   ///< Reference station.  Scroll to station when clicking on the news. Delete news when station is deleted.
+	NR_INDUSTRY,  ///< Reference industry. Scroll to industry when clicking on the news. Delete news when industry is deleted.
+	NR_TOWN,      ///< Reference town.     Scroll to town when clicking on the news.
+	NR_ENGINE     ///< Reference engine.
+};
+
+/**
  * Various OR-able news-item flags.
  * note: NF_INCOLOUR is set automatically if needed
  */
 enum NewsFlag {
-	NF_NONE      = 0,        ///< No flag is set.
-	NF_VIEWPORT  = (1 << 1), ///< Does the news message have a viewport? (ingame picture of happening)
-	NF_TILE      = (1 << 2), ///< When clicked on the news message scroll to a given tile? Tile is in data_a
-	NF_VEHICLE   = (1 << 3), ///< When clicked on the message scroll to the vehicle? VehicleID is in data_a
-	NF_INCOLOUR  = (1 << 5), ///< Show the newsmessage in colour, otherwise it defaults to black & white
-	NF_TILE2     = (1 << 6), ///< There is a second tile to scroll to; tile is in data_b
+	NF_NONE      = 0,      ///< No flag is set.
+	NF_VIEWPORT  = 1 << 1, ///< Does the news message have a viewport? (ingame picture of happening)
+	NF_INCOLOUR  = 1 << 2, ///< Show the newsmessage in colour, otherwise it defaults to black & white
 };
 DECLARE_ENUM_AS_BIT_SET(NewsFlag);
 
@@ -112,17 +121,19 @@
 };
 
 struct NewsItem {
-	NewsItem *prev;        ///< Previous news item
-	NewsItem *next;        ///< Next news item
-	StringID string_id;    ///< Message text
-	Date date;             ///< Date of the news
-	NewsSubtype subtype;   ///< News subtype @see NewsSubtype
-	NewsFlag flags;        ///< NewsFlags bits @see NewsFlag
+	NewsItem *prev;              ///< Previous news item
+	NewsItem *next;              ///< Next news item
+	StringID string_id;          ///< Message text
+	Date date;                   ///< Date of the news
+	NewsSubtype subtype;         ///< News subtype @see NewsSubtype
+	NewsFlag flags;              ///< NewsFlags bits @see NewsFlag
 
-	uint data_a;           ///< Custom data 1 (usually tile or vehicle)
-	uint data_b;           ///< Custom data 2
+	NewsReferenceType reftype1;  ///< Type of ref1
+	NewsReferenceType reftype2;  ///< Type of ref2
+	uint32 ref1;                 ///< Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleteing the news when the object is deleted.
+	uint32 ref2;                 ///< Reference 2 to some object: Used for scrolling after clicking on the news, and for deleteing the news when the object is deleted.
 
-	void *free_data;       ///< Data to be freed when the news item has reached its end.
+	void *free_data;             ///< Data to be freed when the news item has reached its end.
 
 	uint64 params[10];
 };
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -1433,11 +1433,10 @@
 		//DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
 
 		SetDParam(0, v->index);
-		AddNewsItem(
+		AddVehicleNewsItem(
 			message,
 			NS_ADVICE,
-			v->index,
-			0
+			v->index
 		);
 	}
 }
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -591,12 +591,11 @@
 	AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
 
 	SetDParam(0, pass);
-	AddNewsItem(
+	AddVehicleNewsItem(
 		(pass == 1) ?
 			STR_NEWS_ROAD_CRASH_DRIVER : STR_NEWS_ROAD_CRASH,
-		NS_ACCIDENT_VEHICLE,
-		v->index,
-		0
+		NS_ACCIDENT,
+		v->index
 	);
 
 	ModifyStationRatingAround(v->tile, v->owner, -160, 22);
@@ -770,7 +769,7 @@
 		if (!(st->had_vehicle_of_type & HVOT_BUS)) {
 			st->had_vehicle_of_type |= HVOT_BUS;
 			SetDParam(0, st->index);
-			AddNewsItem(
+			AddVehicleNewsItem(
 				v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_ROAD_BUS_ARRIVAL : STR_NEWS_FIRST_ROAD_PASSENGER_TRAM_ARRIVAL,
 				(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 				v->index,
@@ -783,7 +782,7 @@
 		if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
 			st->had_vehicle_of_type |= HVOT_TRUCK;
 			SetDParam(0, st->index);
-			AddNewsItem(
+			AddVehicleNewsItem(
 				v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_ROAD_TRUCK_ARRIVAL : STR_NEWS_FIRST_ROAD_CARGO_TRAM_ARRIVAL,
 				(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 				v->index,
--- a/src/ship_cmd.cpp
+++ b/src/ship_cmd.cpp
@@ -354,7 +354,7 @@
 		st->had_vehicle_of_type |= HVOT_SHIP;
 
 		SetDParam(0, st->index);
-		AddNewsItem(
+		AddVehicleNewsItem(
 			STR_NEWS_FIRST_SHIP_ARRIVAL,
 			(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 			v->index,
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -439,7 +439,7 @@
 	}
 
 	SetDParam(0, st->index);
-	AddNewsItem(msg, NS_ACCEPTANCE, st->xy, st->index);
+	AddNewsItem(msg, NS_ACCEPTANCE, NR_STATION, st->index);
 }
 
 /**
--- a/src/subsidy.cpp
+++ b/src/subsidy.cpp
@@ -21,9 +21,8 @@
 
 Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
 {
-	TileIndex tile;
-	TileIndex tile2;
-	Pair tp;
+	NewsReferenceType reftype1 = NR_NONE;
+	NewsReferenceType reftype2 = NR_NONE;
 
 	/* if mode is false, use the singular form */
 	const CargoSpec *cs = GetCargo(s->cargo_type);
@@ -33,38 +32,38 @@
 		if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL) {
 			SetDParam(1, STR_INDUSTRY);
 			SetDParam(2, s->from);
-			tile = Industry::Get(s->from)->xy;
+			reftype1 = NR_INDUSTRY;
 
 			if (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD) {
 				SetDParam(4, STR_INDUSTRY);
 				SetDParam(5, s->to);
-				tile2 = Industry::Get(s->to)->xy;
+				reftype2 = NR_INDUSTRY;
 			} else {
 				SetDParam(4, STR_TOWN);
 				SetDParam(5, s->to);
-				tile2 = Town::Get(s->to)->xy;
+				reftype2 = NR_TOWN;
 			}
 		} else {
 			SetDParam(1, STR_TOWN);
 			SetDParam(2, s->from);
-			tile = Town::Get(s->from)->xy;
+			reftype1 = NR_TOWN;
 
 			SetDParam(4, STR_TOWN);
 			SetDParam(5, s->to);
-			tile2 = Town::Get(s->to)->xy;
+			reftype2 = NR_TOWN;
 		}
 	} else {
 		SetDParam(1, s->from);
-		tile = Station::Get(s->from)->xy;
+		reftype1 = NR_STATION;
 
 		SetDParam(2, s->to);
-		tile2 = Station::Get(s->to)->xy;
+		reftype2 = NR_STATION;
 	}
 
-	tp.a = tile;
-	tp.b = tile2;
-
-	return tp;
+	Pair p;
+	p.a = reftype1;
+	p.b = reftype2;
+	return p;
 }
 
 void DeleteSubsidyWithTown(TownID index)
@@ -214,7 +213,6 @@
 void SubsidyMonthlyLoop()
 {
 	Subsidy *s;
-	Pair pair;
 	Station *st;
 	uint n;
 	FoundRoute fr;
@@ -224,16 +222,16 @@
 		if (s->cargo_type == CT_INVALID) continue;
 
 		if (s->age == 12 - 1) {
-			pair = SetupSubsidyDecodeParam(s, 1);
-			AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
+			Pair reftype = SetupSubsidyDecodeParam(s, 1);
+			AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->from, (NewsReferenceType)reftype.b, s->to);
 			s->cargo_type = CT_INVALID;
 			modified = true;
 			AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s - _subsidies));
 		} else if (s->age == 2 * 12 - 1) {
 			st = Station::Get(s->to);
 			if (st->owner == _local_company) {
-				pair = SetupSubsidyDecodeParam(s, 1);
-				AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
+				Pair reftype = SetupSubsidyDecodeParam(s, 1);
+				AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->from, (NewsReferenceType)reftype.b, s->to);
 			}
 			s->cargo_type = CT_INVALID;
 			modified = true;
@@ -272,8 +270,8 @@
 	add_subsidy:
 				if (!CheckSubsidyDuplicate(s)) {
 					s->age = 0;
-					pair = SetupSubsidyDecodeParam(s, 0);
-					AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
+					Pair reftype = SetupSubsidyDecodeParam(s, 0);
+					AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, (NewsReferenceType)reftype.a, s->from, (NewsReferenceType)reftype.b, s->to);
 					AI::BroadcastNewEvent(new AIEventSubsidyOffer(s - _subsidies));
 					modified = true;
 					break;
@@ -290,7 +288,6 @@
 {
 	Subsidy *s;
 	TileIndex xy;
-	Pair pair;
 
 	/* check if there is an already existing subsidy that applies to us */
 	for (s = _subsidies; s != endof(_subsidies); s++) {
@@ -335,14 +332,14 @@
 			s->to = to->index;
 
 			/* Add a news item */
-			pair = SetupSubsidyDecodeParam(s, 0);
+			Pair reftype = SetupSubsidyDecodeParam(s, 0);
 			InjectDParam(1);
 
 			SetDParam(0, _current_company);
 			AddNewsItem(
 				STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
 				NS_SUBSIDIES,
-				pair.a, pair.b
+				(NewsReferenceType)reftype.a, s->from, (NewsReferenceType)reftype.b, s->to
 			);
 			AI::BroadcastNewEvent(new AIEventSubsidyAwarded(s - _subsidies));
 
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -2344,7 +2344,7 @@
 	SetDParam(0, t->index);
 	SetDParamStr(1, cn);
 
-	AddNewsItem(STR_NEWS_ROAD_REBUILDING, NS_GENERAL, t->xy, 0, cn);
+	AddNewsItem(STR_NEWS_ROAD_REBUILDING, NS_GENERAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cn);
 }
 
 static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id)
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -2987,11 +2987,11 @@
 				AI::NewEvent(v->owner, new AIEventVehicleLost(v->index));
 				if (_settings_client.gui.lost_train_warn && v->owner == _local_company) {
 					SetDParam(0, v->index);
-					AddNewsItem(
+					AddVehicleNewsItem(
 						STR_TRAIN_IS_LOST,
 						NS_ADVICE,
-						v->index,
-						0);
+						v->index
+					);
 				}
 			}
 		} else {
@@ -3357,7 +3357,7 @@
 	if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
 		st->had_vehicle_of_type |= HVOT_TRAIN;
 		SetDParam(0, st->index);
-		AddNewsItem(
+		AddVehicleNewsItem(
 			STR_NEWS_FIRST_TRAIN_ARRIVAL,
 			v->owner == _local_company ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 			v->index,
@@ -3615,10 +3615,9 @@
 	if (tcc.num == 0) return false;
 
 	SetDParam(0, tcc.num);
-	AddNewsItem(STR_NEWS_TRAIN_CRASH,
-		NS_ACCIDENT_VEHICLE,
-		v->index,
-		0
+	AddVehicleNewsItem(STR_NEWS_TRAIN_CRASH,
+		NS_ACCIDENT,
+		v->index
 	);
 
 	ModifyStationRatingAround(v->tile, v->owner, -160, 30);
@@ -4328,11 +4327,11 @@
 				/* Show message to player. */
 				if (_settings_client.gui.lost_train_warn && v->owner == _local_company) {
 					SetDParam(0, v->index);
-					AddNewsItem(
+					AddVehicleNewsItem(
 						STR_TRAIN_IS_STUCK,
 						NS_ADVICE,
-						v->index,
-						0);
+						v->index
+					);
 				}
 				v->load_unload_time_rem = 0;
 			}
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -669,7 +669,7 @@
 
 		SetDParam(0, v->index);
 		SetDParam(1, error_message);
-		AddNewsItem(message, NS_ADVICE, v->index, 0);
+		AddVehicleNewsItem(message, NS_ADVICE, v->index);
 	}
 
 	_current_company = OWNER_NONE;
@@ -922,7 +922,7 @@
 	}
 
 	SetDParam(0, v->index);
-	AddNewsItem(str, NS_ADVICE, v->index, 0);
+	AddVehicleNewsItem(str, NS_ADVICE, v->index);
 }
 
 /**
@@ -1043,7 +1043,7 @@
 				if (v->owner == _local_company) {
 					/* Notify the user that we stopped the vehicle */
 					SetDParam(0, v->index);
-					AddNewsItem(STR_ORDER_REFIT_FAILED, NS_ADVICE, v->index, 0);
+					AddVehicleNewsItem(STR_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
 				}
 			} else if (v->owner == _local_company && cost.GetCost() != 0) {
 				ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
@@ -1070,7 +1070,7 @@
 				}
 
 				SetDParam(0, v->index);
-				AddNewsItem(string, NS_ADVICE, v->index, 0);
+				AddVehicleNewsItem(string, NS_ADVICE, v->index);
 			}
 			AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
 		}
@@ -1681,11 +1681,11 @@
 				if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
 					SetDParam(0, v->index);
 					SetDParam(1, profit);
-					AddNewsItem(
+					AddVehicleNewsItem(
 						STR_VEHICLE_IS_UNPROFITABLE,
 						NS_ADVICE,
-						v->index,
-						0);
+						v->index
+					);
 				}
 				AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
 			}
--- a/src/water_cmd.cpp
+++ b/src/water_cmd.cpp
@@ -841,10 +841,9 @@
 
 		AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
 		SetDParam(0, pass);
-		AddNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
-			NS_ACCIDENT_VEHICLE,
-			v->index,
-			0);
+		AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
+			NS_ACCIDENT,
+			v->index);
 		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
 		SndPlayVehicleFx(SND_12_EXPLOSION, v);
 	}