changeset 13756:9f062af2f34a draft

(svn r18281) -Feature: founding towns in-game (based on work by Belugas, TheJosh, GeekToo, Terkhen and others)
author smatz <smatz@openttd.org>
date Tue, 24 Nov 2009 21:18:11 +0000
parents bf8a4ced15fe
children 509215d7f09a
files src/command.cpp src/command_type.h src/lang/english.txt src/saveload/saveload.cpp src/settings.cpp src/settings_gui.cpp src/settings_type.h src/table/settings.h src/toolbar_gui.cpp src/town_cmd.cpp src/town_gui.cpp src/town_type.h
diffstat 12 files changed, 107 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -295,7 +295,7 @@
 	{CmdSellShareInCompany,                         0}, // CMD_SELL_SHARE_IN_COMPANY
 	{CmdBuyCompany,                                 0}, // CMD_BUY_COMANY
 
-	{CmdFoundTown,          CMD_NO_TEST | CMD_OFFLINE}, // CMD_FOUND_TOWN
+	{CmdFoundTown,                        CMD_NO_TEST}, // CMD_FOUND_TOWN; founding random town can fail only in exec run
 	{CmdRenameTown,                        CMD_SERVER}, // CMD_RENAME_TOWN
 	{CmdDoTownAction,                               0}, // CMD_DO_TOWN_ACTION
 
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -243,7 +243,6 @@
 	CMD_BUY_COMPANY,                  ///< buy a company which is bankrupt
 
 	CMD_FOUND_TOWN,                   ///< found a town
-
 	CMD_RENAME_TOWN,                  ///< rename a town
 	CMD_DO_TOWN_ACTION,               ///< do a action from the town detail window (like advertises or bribe)
 
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -368,7 +368,9 @@
 STR_MAP_MENU_SIGN_LIST                                          :Sign list
 ############ range for town menu starts, yet the town directory is shown in the map menu in the scenario editor
 STR_TOWN_MENU_TOWN_DIRECTORY                                    :Town directory
-############ both ranges ends here
+############ end of the 'Display map' dropdown
+STR_TOWN_MENU_FOUND_TOWN                                        :Found town
+############ end of the 'Town' dropdown
 
 ############ range for subsidies menu starts
 STR_SUBSIDIES_MENU_SUBSIDIES                                    :Subsidies
@@ -760,6 +762,8 @@
 STR_NEWS_MERGER_TAKEOVER_TITLE                                  :{BIGFONT}{BLACK}{RAW_STRING} has been taken over by {RAW_STRING}!
 STR_PRESIDENT_NAME_MANAGER                                      :{BLACK}{PRESIDENTNAME}{}(Manager)
 
+STR_NEWS_NEW_TOWN                                               :{BLACK}{BIGFONT}{RAW_STRING} sponsored construction of new town {TOWN}!
+
 STR_NEWS_INDUSTRY_CONSTRUCTION                                  :{BIGFONT}{BLACK}New {STRING} under construction near {TOWN}!
 STR_NEWS_INDUSTRY_PLANTED                                       :{BIGFONT}{BLACK}New {STRING} being planted near {TOWN}!
 
@@ -1237,6 +1241,10 @@
 STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM                           :random
 STR_CONFIG_SETTING_ALLOW_TOWN_ROADS                             :{LTBLUE}Towns are allowed to build roads: {ORANGE}{STRING1}
 STR_CONFIG_SETTING_NOISE_LEVEL                                  :{LTBLUE}Allow town controlled noise level for airports: {ORANGE}{STRING}
+STR_CONFIG_SETTING_TOWN_FOUNDING                                :{LTBLUE}Founding towns in game: {ORANGE}{STRING1}
+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_TOOLBAR_POS                                  :{LTBLUE}Position of main toolbar: {ORANGE}{STRING1}
 STR_CONFIG_SETTING_TOOLBAR_POS_LEFT                             :Left
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -47,7 +47,7 @@
 
 #include "saveload_internal.h"
 
-extern const uint16 SAVEGAME_VERSION = 127;
+extern const uint16 SAVEGAME_VERSION = 128;
 
 SavegameType _savegame_type; ///< type of savegame we are loading
 
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -753,6 +753,17 @@
 	return true;
 }
 
+static bool TownFoundingChanged(int32 p1)
+{
+	if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) {
+		DeleteWindowById(WC_FOUND_TOWN, 0);
+		return true;
+	}
+	InvalidateWindowData(WC_FOUND_TOWN, 0);
+	return true;
+}
+
+
 /*
  * A: competitors
  * B: competitor start time. Deprecated since savegame version 110.
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1298,6 +1298,7 @@
 	SettingEntry("economy.exclusive_rights"),
 	SettingEntry("economy.town_layout"),
 	SettingEntry("economy.allow_town_roads"),
+	SettingEntry("economy.found_town"),
 	SettingEntry("economy.mod_road_rebuild"),
 	SettingEntry("economy.town_growth_rate"),
 	SettingEntry("economy.larger_towns"),
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -327,8 +327,9 @@
 	uint8  town_growth_rate;                 ///< town growth rate
 	uint8  larger_towns;                     ///< the number of cities to build. These start off larger and grow twice as fast
 	uint8  initial_city_size;                ///< multiplier for the initial size of the cities compared to towns
-	TownLayoutByte town_layout;              ///< select town layout
+	TownLayoutByte town_layout;              ///< select town layout, @see TownLayout
 	bool   allow_town_roads;                 ///< towns are allowed to build roads (always allowed when generating world / in SE)
+	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)
 };
--- a/src/table/settings.h
+++ b/src/table/settings.h
@@ -23,6 +23,7 @@
 static bool CheckInterval(int32 p1);
 static bool TrainAccelerationModelChanged(int32 p1);
 static bool DragSignalsDensityChanged(int32);
+static bool TownFoundingChanged(int32 p1);
 static bool DifficultyReset(int32 level);
 static bool DifficultyChange(int32);
 static bool DifficultyNoiseChange(int32 i);
@@ -364,8 +365,9 @@
 	    SDT_BOOL(GameSettings, construction.longbridges,                                            0,NN,  true,                    STR_CONFIG_SETTING_LONGBRIDGES,            NULL),
 	    SDT_BOOL(GameSettings, construction.signal_side,                                            N,NN,  true,                    STR_CONFIG_SETTING_SIGNALSIDE,             RedrawScreen),
 	    SDT_BOOL(GameSettings, station.never_expire_airports,                                       0,NN, false,                    STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS,  NULL),
-	 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,     NULL),
+	 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_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),
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -405,12 +405,17 @@
 
 static void ToolbarTownClick(Window *w)
 {
-	PopupMainToolbMenu(w, TBN_TOWNDIRECTORY, STR_TOWN_MENU_TOWN_DIRECTORY, 1);
+	PopupMainToolbMenu(w, TBN_TOWNDIRECTORY, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
 }
 
 static void MenuClickTown(int index)
 {
-	ShowTownDirectory();
+	switch (index) {
+		case 0: ShowTownDirectory(); break;
+		case 1: // setting could be changed when the dropdown was open
+			if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
+			break;
+	}
 }
 
 /* --- Subidies button menu --- */
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -1458,7 +1458,7 @@
 
 	int x = (int)size * 16 + 3;
 	if (size == TS_RANDOM) x = (Random() & 0xF) + 8;
-	if (city) x *= _settings_game.economy.initial_city_size;
+	if (city && _game_mode == GM_EDITOR) x *= _settings_game.economy.initial_city_size;
 
 	t->num_houses += x;
 	UpdateTownRadius(t);
@@ -1515,9 +1515,8 @@
 	return true;
 }
 
-/** Create a new town.
- * This obviously only works in the scenario editor. Function not removed
- * as it might be possible in the future to fund your own town :)
+/**
+ * Create a new town.
  * @param tile coordinates where town is built
  * @param flags type of operation
  * @param p1  0..1 size of the town (@see TownSize)
@@ -1530,9 +1529,6 @@
  */
 CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	/* Only in the scenario editor */
-	if (_game_mode != GM_EDITOR) return CMD_ERROR;
-
 	TownSize size = (TownSize)GB(p1, 0, 2);
 	bool city = HasBit(p1, 2);
 	TownLayout layout = (TownLayout)GB(p1, 3, 3);
@@ -1543,6 +1539,16 @@
 	if (size > TS_RANDOM) return CMD_ERROR;
 	if (layout > TL_RANDOM) return CMD_ERROR;
 
+	/* Some things are allowed only in the scenario editor */
+	if (_game_mode != GM_EDITOR) {
+		if (_settings_game.economy.found_town == TF_FORBIDDEN) return CMD_ERROR;
+		if (size == TS_LARGE) return CMD_ERROR;
+		if (random) return CMD_ERROR;
+		if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT && layout != _settings_game.economy.town_layout) {
+			return CMD_ERROR;
+		}
+	}
+
 	if (StrEmpty(text)) {
 		/* If supplied name is empty, townnameparts has to generate unique automatic name */
 		if (!VerifyTownName(townnameparts, &par)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
@@ -1555,10 +1561,23 @@
 	/* Allocate town struct */
 	if (!Town::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_TOWNS);
 
-	CommandCost cost(EXPENSES_OTHER);
 	if (!random) {
-		cost = TownCanBePlacedHere(tile);
-		if (CmdFailed(cost)) return cost;
+		CommandCost ret = TownCanBePlacedHere(tile);
+		if (CmdFailed(ret)) return ret;
+	}
+
+	static const byte price_mult[][TS_RANDOM + 1] = {{ 15, 25, 40, 25 }, { 20, 35, 55, 35 }};
+	/* multidimensional arrays have to have defined length of non-first dimension */
+	assert_compile(lengthof(price_mult[0]) == 4);
+
+	CommandCost cost(EXPENSES_OTHER, _price[PR_BUILD_INDUSTRY]);
+	byte mult = price_mult[city][size];
+
+	cost.MultiplyCost(mult);
+
+	if (cost.GetCost() > GetAvailableMoneyForCommand()) {
+		_additional_cash_required = cost.GetCost();
+		return CommandCost(EXPENSES_OTHER);
 	}
 
 	/* Create the town */
@@ -1579,10 +1598,25 @@
 		}
 		UpdateNearestTownForRoadTiles(false);
 		_generating_world = false;
+
 		if (t != NULL && !StrEmpty(text)) {
 			t->name = strdup(text);
 			t->UpdateVirtCoord();
 		}
+
+		if (_game_mode != GM_EDITOR) {
+			/* 't' can't be NULL since 'random' is false outside scenedit */
+			assert(!random);
+			char company_name[MAX_LENGTH_COMPANY_NAME_BYTES];
+			SetDParam(0, _current_company);
+			GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
+
+			char *cn = strdup(company_name);
+			SetDParamStr(0, cn);
+			SetDParam(1, t->index);
+
+			AddNewsItem(STR_NEWS_NEW_TOWN, NS_INDUSTRY_OPEN, NR_TILE, tile, NR_NONE, UINT32_MAX, cn);
+		}
 	}
 	return cost;
 }
--- a/src/town_gui.cpp
+++ b/src/town_gui.cpp
@@ -991,7 +991,7 @@
 		this->InitNested(desc, window_number);
 		InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, MAX_LENGTH_TOWN_NAME_PIXELS);
 		this->RandomTownName();
-		this->UpdateButtons();
+		this->UpdateButtons(true);
 	}
 
 	void RandomTownName()
@@ -1010,8 +1010,15 @@
 		this->SetWidgetDirty(TSEW_TOWNNAME_EDITBOX);
 	}
 
-	void UpdateButtons()
+	void UpdateButtons(bool check_availability)
 	{
+		if (check_availability && _game_mode != GM_EDITOR) {
+			this->SetWidgetsDisabledState(true, TSEW_RANDOMTOWN, TSEW_MANYRANDOMTOWNS, TSEW_SIZE_LARGE, WIDGET_LIST_END);
+			this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT,
+					TSEW_LAYOUT_ORIGINAL, TSEW_LAYOUT_BETTER, TSEW_LAYOUT_GRID2, TSEW_LAYOUT_GRID3, TSEW_LAYOUT_RANDOM, WIDGET_LIST_END);
+			if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout;
+		}
+
 		for (int i = TSEW_SIZE_SMALL; i <= TSEW_SIZE_RANDOM; i++) {
 			this->SetWidgetLoweredState(i, i == TSEW_SIZE_SMALL + this->town_size);
 		}
@@ -1080,7 +1087,7 @@
 
 			case TSEW_SIZE_SMALL: case TSEW_SIZE_MEDIUM: case TSEW_SIZE_LARGE: case TSEW_SIZE_RANDOM:
 				this->town_size = (TownSize)(widget - TSEW_SIZE_SMALL);
-				this->UpdateButtons();
+				this->UpdateButtons(false);
 				break;
 
 			case TSEW_CITY:
@@ -1092,7 +1099,7 @@
 			case TSEW_LAYOUT_ORIGINAL: case TSEW_LAYOUT_BETTER: case TSEW_LAYOUT_GRID2:
 			case TSEW_LAYOUT_GRID3: case TSEW_LAYOUT_RANDOM:
 				this->town_layout = (TownLayout)(widget - TSEW_LAYOUT_ORIGINAL);
-				this->UpdateButtons();
+				this->UpdateButtons(false);
 				break;
 		}
 	}
@@ -1124,7 +1131,12 @@
 	virtual void OnPlaceObjectAbort()
 	{
 		this->RaiseButtons();
-		this->UpdateButtons();
+		this->UpdateButtons(false);
+	}
+
+	virtual void OnInvalidateData(int)
+	{
+		this->UpdateButtons(true);
 	}
 };
 
--- a/src/town_type.h
+++ b/src/town_type.h
@@ -87,10 +87,20 @@
 
 	NUM_TLS,             ///< Number of town layouts
 };
-
 /** It needs to be 8bits, because we save and load it as such */
 typedef SimpleTinyEnumT<TownLayout, byte> TownLayoutByte; // typedefing-enumification of TownLayout
 
+/** Town founding setting values */
+enum TownFounding {
+	TF_BEGIN = 0,     ///< Used for iterations and limit testing
+	TF_FORBIDDEN = 0, ///< Forbidden
+	TF_ALLOWED,       ///< Allowed
+	TF_CUSTOM_LAYOUT, ///< Allowed, with custom town layout
+	TF_END,           ///< Used for iterations and limit testing
+};
+/** It needs to be 8bits, because we save and load it as such */
+typedef SimpleTinyEnumT<TownFounding, byte> TownFoundingByte;
+
 enum {
 	MAX_LENGTH_TOWN_NAME_BYTES  =  31, ///< The maximum length of a town name in bytes including '\0'
 	MAX_LENGTH_TOWN_NAME_PIXELS = 130, ///< The maximum length of a town name in pixels