changeset 5352:396149d61d0d draft

(svn r7523) -Feature: Add the possibility to change the newgrf configuration of a running game. This is only possible in SP (or in the intro menu). During game play you will get a confirmation window when applying the changes as some actions can crash OpenTTD and/or make your current game unplayable.
author Darkvater <Darkvater@openttd.org>
date Thu, 21 Dec 2006 10:29:16 +0000
parents 6419e75ebeec
children cb2d6cb7dd89
files intro_gui.c lang/english.txt main_gui.c misc_gui.c network_gui.c newgrf.h newgrf_config.h newgrf_gui.c openttd.c vehicle.c vehicle.h
diffstat 11 files changed, 102 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/intro_gui.c
+++ b/intro_gui.c
@@ -84,7 +84,7 @@
 		case 12: ShowGameOptions(); break;
 		case 13: ShowGameDifficulty(); break;
 		case 14: ShowPatchesSelection(); break;
-		case 15: ShowNewGRFSettings(true, true, &_grfconfig_newgame); break;
+		case 15: ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
 		case 16: HandleExitGameRequest(); break;
 		}
 		break;
--- a/lang/english.txt
+++ b/lang/english.txt
@@ -154,6 +154,7 @@
 STR_00B1_GAME_OPTIONS                                           :{WHITE}Game Options
 STR_00B2_MESSAGE                                                :{YELLOW}Message
 STR_00B3_MESSAGE_FROM                                           :{YELLOW}Message from {STRING1}
+STR_POPUP_CAUTION_CAPTION                                       :{WHITE}Caution!
 STR_00B4_CAN_T_DO_THIS                                          :{WHITE}Can't do this....
 STR_00B5_CAN_T_CLEAR_THIS_AREA                                  :{WHITE}Can't clear this area....
 STR_00B6_ORIGINAL_COPYRIGHT                                     :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved
@@ -2889,6 +2890,7 @@
 STR_NEWGRF_FILENAME                                             :{BLACK}Filename: {SILVER}{STRING}
 STR_NEWGRF_GRF_ID                                               :{BLACK}GRF ID: {SILVER}{STRING}
 STR_NEWGRF_MD5SUM                                               :{BLACK}MD5sum: {SILVER}{STRING}
+STR_NEWGRF_CONFIRMATION_TEXT                                    :{YELLOW}You are about to make changes to a running game; this can crash OpenTTD.{}Are you absolutely sure about this?
 
 STR_NEWGRF_ADD                                                  :{BLACK}Add
 STR_NEWGRF_ADD_TIP                                              :{BLACK}Add a NewGRF file to the list
--- a/main_gui.c
+++ b/main_gui.c
@@ -153,7 +153,7 @@
 		case 0: ShowGameOptions();      return;
 		case 1: ShowGameDifficulty();   return;
 		case 2: ShowPatchesSelection(); return;
-		case 3: ShowNewGRFSettings(false, true, &_grfconfig);   return;
+		case 3: ShowNewGRFSettings(!_networking, true, true, &_grfconfig);   return;
 
 		case  5: _display_opt ^= DO_SHOW_TOWN_NAMES;    break;
 		case  6: _display_opt ^= DO_SHOW_STATION_NAMES; break;
--- a/misc_gui.c
+++ b/misc_gui.c
@@ -6,7 +6,7 @@
 #include "heightmap.h"
 #include "debug.h"
 #include "functions.h"
-#include "gfxinit.h"
+#include "newgrf.h"
 #include "saveload.h"
 #include "strings.h"
 #include "table/sprites.h"
@@ -1658,9 +1658,7 @@
 	if (p1 == -1) p1 = 3;
 	if (p1 ==  4) p1 = 0;
 	_opt.landscape = p1;
-	GfxLoadSprites();
-	LoadStringWidthTable();
-	MarkWholeScreenDirty();
+	ReloadNewGRFData();
 	return _opt.landscape;
 }
 
--- a/network_gui.c
+++ b/network_gui.c
@@ -442,7 +442,7 @@
 				NetworkQueryServer(nd->server->info.hostname, nd->server->port, true);
 			break;
 		case 18: // NewGRF Settings
-			if (nd->server != NULL) ShowNewGRFSettings(false, false, &nd->server->info.grfconfig);
+			if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig);
 			break;
 
 	}	break;
--- a/newgrf.h
+++ b/newgrf.h
@@ -66,5 +66,6 @@
 
 void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage);
 void LoadNewGRF(uint load_index, uint file_index);
+void ReloadNewGRFData(void); // in openttd.c
 
 #endif /* NEWGRF_H */
--- a/newgrf_config.h
+++ b/newgrf_config.h
@@ -52,7 +52,7 @@
 char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last);
 
 /* In newgrf_gui.c */
-void ShowNewGRFSettings(bool editable, bool show_params, GRFConfig **config);
+void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config);
 
 /* For communication about GRFs over the network */
 #define UNKNOWN_GRF_NAME_PLACEHOLDER "<Unknown>"
--- a/newgrf_gui.c
+++ b/newgrf_gui.c
@@ -9,6 +9,7 @@
 #include "window.h"
 #include "table/strings.h"
 #include "table/sprites.h"
+#include "newgrf.h"
 #include "newgrf_config.h"
 
 
@@ -219,13 +220,16 @@
 
 /* 'NewGRF Settings' dialogue */
 typedef struct newgrf_d {
-	GRFConfig **list;
-	GRFConfig *sel;
-	bool editable;
-	bool show_params;
+	GRFConfig **orig_list; ///< grf list the window is shown with
+	GRFConfig **list;      ///< temporary grf list to which changes are made
+	GRFConfig *sel;        ///< selected grf item
+	bool editable;         ///< is the window editable
+	bool show_params;      ///< are the grf-parameters shown in the info-panel
+	bool execute;          ///< on pressing 'apply changes' are grf changes applied immediately, or only list is updated
 } newgrf_d;
 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_d));
 
+
 enum ShowNewGRFStateWidgets {
 	SNGRFS_ADD = 3,
 	SNGRFS_REMOVE,
@@ -234,8 +238,10 @@
 	SNGRFS_FILE_LIST = 7,
 	SNGRFS_NEWGRF_INFO = 9,
 	SNGRFS_SET_PARAMETERS,
+	SNGRFS_APPLY_CHANGES,
 };
 
+
 static void SetupNewGRFState(Window *w)
 {
 	bool disable_all = WP(w, newgrf_d).sel == NULL || !WP(w, newgrf_d).editable;
@@ -266,6 +272,21 @@
 
 	w->vscroll.cap = (w->widget[SNGRFS_FILE_LIST].bottom - w->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
 	SetVScrollCount(w, i);
+	SetWindowWidgetDisabledState(w, SNGRFS_APPLY_CHANGES, !WP(w, newgrf_d).editable);
+}
+
+
+/** Callback function for the newgrf 'apply changes' confirmation window
+ * @param yes_clicked boolean value, true when yes was clicked, false otherwise */
+static void NewGRFConfirmationCallback(bool yes_clicked)
+{
+	if (yes_clicked) {
+		Window *w = FindWindowById(WC_GAME_OPTIONS, 0);
+		newgrf_d *nd = &WP(w, newgrf_d);
+
+		CopyGRFConfigList(nd->orig_list, *nd->list);
+		ReloadNewGRFData();
+	}
 }
 
 
@@ -398,6 +419,20 @@
 					break;
 				}
 
+				case SNGRFS_APPLY_CHANGES: /* Apply changes made to GRF list */
+					if (WP(w, newgrf_d).execute) {
+						ShowQuery(
+							STR_POPUP_CAUTION_CAPTION,
+							STR_NEWGRF_CONFIRMATION_TEXT,
+							NewGRFConfirmationCallback,
+							w->window_class,
+							w->window_number
+						);
+					} else {
+						CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list);
+					}
+					break;
+
 				case SNGRFS_SET_PARAMETERS: { /* Edit parameters */
 					char buff[512];
 					if (WP(w, newgrf_d).sel == NULL) break;
@@ -421,6 +456,11 @@
 			SetWindowDirty(w);
 			break;
 
+		case WE_DESTROY:
+			/* Remove the temporary copy of grf-list used in window */
+			ClearGRFConfigList(WP(w, newgrf_d).list);
+			break;
+
 		case WE_RESIZE:
 			w->vscroll.cap += e->we.sizing.diff.y / 14;
 			w->widget[SNGRFS_FILE_LIST].data = (w->vscroll.cap << 8) + 1;
@@ -447,8 +487,10 @@
 /* NewGRF file info */
 {      WWT_PANEL,   RESIZE_RTB, 10,   0, 299, 100, 199, STR_NULL,                    STR_NULL },
 
-/* Edit parameter button... */
-{ WWT_PUSHTXTBTN,   RESIZE_RTB, 10,   0, 287, 200, 211, STR_NEWGRF_SET_PARAMETERS,   STR_NULL },
+/* Edit parameter and apply changes button... */
+{ WWT_PUSHTXTBTN,    RESIZE_TB, 10,   0, 143, 200, 211, STR_NEWGRF_SET_PARAMETERS,   STR_NULL },
+{ WWT_PUSHTXTBTN,   RESIZE_RTB, 10, 144, 287, 200, 211, STR_NEWGRF_APPLY_CHANGES,    STR_NULL },
+
 {  WWT_RESIZEBOX,  RESIZE_LRTB, 10, 288, 299, 200, 211, 0x0,                         STR_RESIZE_BUTTON },
 
 { WIDGETS_END },
@@ -464,8 +506,15 @@
 };
 
 
-void ShowNewGRFSettings(bool editable, bool show_params, GRFConfig **config)
+/** Setup the NewGRF gui
+ * @param editable allow the user to make changes to the grfconfig in the window
+ * @param show_params show information about what parameters are set for the grf files
+ * @param exec_changes if changes are made to the list (editable is true), apply these
+ *        changes immediately or only update the list
+ * @param config pointer to a linked-list of grfconfig's that will be shown */
+void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
 {
+	static GRFConfig *local = NULL;
 	Window *w;
 
 	DeleteWindowByClass(WC_GAME_OPTIONS);
@@ -473,11 +522,14 @@
 	if (w == NULL) return;
 
 	w->resize.step_height = 14;
+	CopyGRFConfigList(&local, *config);
 
 	/* Clear selections */
 	WP(w, newgrf_d).sel         = NULL;
-	WP(w, newgrf_d).list        = config;
+	WP(w, newgrf_d).list        = &local;
+	WP(w, newgrf_d).orig_list   = config;
 	WP(w, newgrf_d).editable    = editable;
+	WP(w, newgrf_d).execute     = exec_changes;
 	WP(w, newgrf_d).show_params = show_params;
 
 	SetupNewGRFWindow(w);
--- a/openttd.c
+++ b/openttd.c
@@ -1559,3 +1559,24 @@
 
 	return true;
 }
+
+/** Reload all NewGRF files during a running game. This is a cut-down
+ * version of AfterLoadGame().
+ * XXX - We need to reset the vehicle position hash because with a non-empty
+ * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles()
+ * to recalculate vehicle data as some NewGRF vehicle sets could have been
+ * removed or added and changed statistics */
+void ReloadNewGRFData(void)
+{
+	/* reload grf data */
+	GfxLoadSprites();
+	LoadStringWidthTable();
+	/* reload vehicles */
+	ResetVehiclePosHash();
+	AfterLoadVehicles();
+	/* update station and waypoint graphics */
+	AfterLoadWaypoints();
+	AfterLoadStations();
+	/* redraw the whole screen */
+	MarkWholeScreenDirty();
+}
--- a/vehicle.c
+++ b/vehicle.c
@@ -440,6 +440,14 @@
 	}
 }
 
+void ResetVehiclePosHash(void)
+{
+	uint i;
+	for (i = 0; i < lengthof(_vehicle_position_hash); i++) {
+		_vehicle_position_hash[i] = INVALID_VEHICLE;
+	}
+}
+
 void InitializeVehicles(void)
 {
 	uint i;
@@ -449,12 +457,11 @@
 	 *  vehicles (which is increased on-the-fly) */
 	CleanPool(&_Vehicle_pool);
 	AddBlockToPool(&_Vehicle_pool);
-	for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++)
+	for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++) {
 		AddBlockToPool(&_Vehicle_pool);
-
-	for (i = 0; i < lengthof(_vehicle_position_hash); i++) {
-		_vehicle_position_hash[i] = INVALID_VEHICLE;
 	}
+
+	ResetVehiclePosHash();
 }
 
 Vehicle *GetLastVehicleInChain(Vehicle *v)
--- a/vehicle.h
+++ b/vehicle.h
@@ -277,6 +277,7 @@
 
 void InitializeTrains(void);
 byte VehicleRandomBits(void);
+void ResetVehiclePosHash(void);
 
 bool CanFillVehicle(Vehicle *v);
 bool CanRefitTo(EngineID engine_type, CargoID cid_to);