diff --git a/src/lang/english.txt b/src/lang/english.txt
index eaec72c..8be3d3e 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1268,6 +1268,7 @@ STR_CONFIG_SETTING_TOWN_FOUNDING                                :{LTBLUE}Foundin
 STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN                      :forbidden
 STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED                        :allowed
 STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT          :allowed, custom town layout
+STR_CONFIG_SETTING_TOWN_CARGO_FACTOR                            :{LTBLUE}Town cargo generation factor (less < 0 < more): {ORANGE}{STRING1}
 
 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT                         :{LTBLUE}In game placement of trees: {ORANGE}{STRING1}
 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE                    :none {RED}(breaks lumber mill)
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index a1d8a64..9e68ca5 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1306,6 +1306,7 @@ static SettingEntry _settings_economy_towns[] = {
 	SettingEntry("economy.town_growth_rate"),
 	SettingEntry("economy.larger_towns"),
 	SettingEntry("economy.initial_city_size"),
+	SettingEntry("economy.town_cargo_factor"),
 };
 /** Towns sub-page */
 static SettingsPage _settings_economy_towns_page = {_settings_economy_towns, lengthof(_settings_economy_towns)};
diff --git a/src/settings_type.h b/src/settings_type.h
index 429548a..ac5361e 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -345,6 +345,7 @@ struct EconomySettings {
 	TownFoundingByte found_town;             ///< town founding, @see TownFounding
 	bool   station_noise_level;              ///< build new airports when the town noise level is still within accepted limits
 	uint16 town_noise_population[3];         ///< population to base decision on noise evaluation (@see town_council_tolerance)
+	int8   town_cargo_factor;                ///< power-of-two multiplier for town (passenger, mail) generation. May be negative.
 	uint16 moving_average_unit;              ///< unit of time to use for calculating the moving average of capacities and usage of links
 	uint16 moving_average_length;            ///< length of the moving average for capacities and usage of links
 };
diff --git a/src/table/settings.h b/src/table/settings.h
index 5b7d990..6ca1a4d 100644
--- a/src/table/settings.h
+++ b/src/table/settings.h
@@ -369,6 +369,7 @@ const SettingDesc _settings[] = {
 	 SDT_CONDVAR(GameSettings, economy.town_layout,                  SLE_UINT8, 59, SL_MAX_VERSION, 0,MS,TL_ORIGINAL,TL_BEGIN,NUM_TLS - 1, 1, STR_CONFIG_SETTING_TOWN_LAYOUT,  TownFoundingChanged),
 	SDT_CONDBOOL(GameSettings, economy.allow_town_roads,                       113, SL_MAX_VERSION, 0, 0,  true,                    STR_CONFIG_SETTING_ALLOW_TOWN_ROADS,       NULL),
 	 SDT_CONDVAR(GameSettings, economy.found_town,                   SLE_UINT8,128, SL_MAX_VERSION, 0,MS,TF_FORBIDDEN,TF_BEGIN,TF_END - 1, 1, STR_CONFIG_SETTING_TOWN_FOUNDING, TownFoundingChanged),
+	 SDT_CONDVAR(GameSettings, economy.town_cargo_factor,            SLE_INT8, 132, SL_MAX_VERSION, 0, 0,     0,   -16,      +8, 1,       STR_CONFIG_SETTING_TOWN_CARGO_FACTOR,      NULL),
 
 	     SDT_VAR(GameSettings, vehicle.train_acceleration_model,     SLE_UINT8,                     0,MS,     0,     0,       1, 1, STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL, TrainAccelerationModelChanged),
 	    SDT_BOOL(GameSettings, pf.forbid_90_deg,                                                    0, 0, false,                    STR_CONFIG_SETTING_FORBID_90_DEG,          NULL),
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 18a4b36..de4e7e6 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -433,6 +433,61 @@ static void MakeTownHouseBigger(TileIndex tile)
 }
 
 /**
+ * Generate cargo for a town (house).
+ *
+ * The amount of cargo should be and will be greater than zero.
+ *
+ * @param t current town
+ * @param ct type of cargo to generate, usually CT_PASSENGERS or CT_MAIL
+ * @param amount how many units of cargo
+ * @param stations available stations for this house
+ */
+static void TownGenerateCargo (Town *t, CargoID ct, uint amount, StationFinder &stations)
+{
+	// custom cargo generation factor
+	int cf = _settings_game.economy.town_cargo_factor;
+
+	// when the economy flunctuates, everyone wants to stay at home
+	if (_economy.fluct <= 0)
+		amount = (amount + 1) >> 1; 
+	
+	// apply custom factor?
+	if (cf < 0)
+		// approx (amount / 2^cf)
+		// adjust with a constant offset of {(2 ^ cf) - 1} (i.e. add cf * 1-bits) before dividing to ensure that it doesn't become zero
+		// this skews the curve a little so that isn't entirely exponential, but will still decrease
+		amount = (amount + ((1 << -cf) - 1)) >> -cf;
+
+	else if (cf > 0)
+		// approx (amount * 2^cf)
+		// XXX: overflow?
+		amount = amount << cf;
+	
+	// with the adjustments above, this should never happen
+	assert(amount > 0);
+	
+	// send cargo to station
+	uint moved = MoveGoodsToStation(ct, amount, ST_TOWN, t->index, stations.GetStations());
+	
+	// calculate for town stats
+	const CargoSpec *cs = CargoSpec::Get(ct);
+	switch (cs->town_effect) {
+		case TE_PASSENGERS:
+			t->new_max_pass += amount;
+			t->new_act_pass += moved;
+			break;
+
+		case TE_MAIL:
+			t->new_max_mail += amount;
+			t->new_act_mail += moved;
+			break;
+
+		default:
+			break;
+	}
+}
+
+/**
  * Tile callback function.
  *
  * Periodic tic handler for houses and town
@@ -479,39 +534,20 @@ static void TileLoop_Town(TileIndex tile)
 			uint amt = GB(callback, 0, 8);
 			if (amt == 0) continue;
 
-			uint moved = MoveGoodsToStation(cargo, amt, ST_TOWN, t->index, stations.GetStations());
-
-			const CargoSpec *cs = CargoSpec::Get(cargo);
-			switch (cs->town_effect) {
-				case TE_PASSENGERS:
-					t->new_max_pass += amt;
-					t->new_act_pass += moved;
-					break;
-
-				case TE_MAIL:
-					t->new_max_mail += amt;
-					t->new_act_mail += moved;
-					break;
-
-				default:
-					break;
-			}
+			// XXX: no economy flunctuation for GRF cargos?
+			TownGenerateCargo(t, cargo, amt, stations);
 		}
 	} else {
 		if (GB(r, 0, 8) < hs->population) {
 			uint amt = GB(r, 0, 8) / 8 + 1;
-
-			if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
-			t->new_max_pass += amt;
-			t->new_act_pass += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations());
+			
+			TownGenerateCargo(t, CT_PASSENGERS, amt, stations);
 		}
 
 		if (GB(r, 8, 8) < hs->mail_generation) {
 			uint amt = GB(r, 8, 8) / 8 + 1;
-
-			if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
-			t->new_max_mail += amt;
-			t->new_act_mail += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations());
+			
+			TownGenerateCargo(t, CT_MAIL, amt, stations);
 		}
 	}
 
