diff --git a/intro_gui.c b/intro_gui.c index b6bce05ad5..9d0198d446 100644 --- a/intro_gui.c +++ b/intro_gui.c @@ -84,7 +84,7 @@ static void SelectGameWndProc(Window *w, WindowEvent *e) 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; diff --git a/lang/english.txt b/lang/english.txt index 26360d36f9..3306dedc63 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -154,6 +154,7 @@ STR_00B0_MAP :{WHITE}Map - {S 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_NO_FILES_INSTALLED :{BLACK}There ar 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 diff --git a/main_gui.c b/main_gui.c index 37bfb5db03..774df16a99 100644 --- a/main_gui.c +++ b/main_gui.c @@ -153,7 +153,7 @@ static void MenuClickSettings(int index) 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; diff --git a/misc_gui.c b/misc_gui.c index 371f7fc120..b10073d542 100644 --- 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 @@ static int32 ClickChangeClimateCheat(int32 p1, int32 p2) if (p1 == -1) p1 = 3; if (p1 == 4) p1 = 0; _opt.landscape = p1; - GfxLoadSprites(); - LoadStringWidthTable(); - MarkWholeScreenDirty(); + ReloadNewGRFData(); return _opt.landscape; } diff --git a/network_gui.c b/network_gui.c index 99d8660551..207d93fbe0 100644 --- a/network_gui.c +++ b/network_gui.c @@ -442,7 +442,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e) 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; diff --git a/newgrf.h b/newgrf.h index 4d57ff4c9f..2cefa9c84e 100644 --- a/newgrf.h +++ b/newgrf.h @@ -66,5 +66,6 @@ extern bool _have_2cc; 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 */ diff --git a/newgrf_config.h b/newgrf_config.h index b0660e3a6a..24721a555d 100644 --- a/newgrf_config.h +++ b/newgrf_config.h @@ -52,7 +52,7 @@ bool FillGRFDetails(GRFConfig *config, bool is_static); 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 "" diff --git a/newgrf_gui.c b/newgrf_gui.c index 3fe0bdcd8f..6771174faa 100644 --- 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 @@ static const WindowDesc _newgrf_add_dlg_desc = { /* '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 @@ enum ShowNewGRFStateWidgets { 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 @@ static void SetupNewGRFWindow(Window *w) 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 @@ static void NewGRFWndProc(Window *w, WindowEvent *e) 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 @@ static void NewGRFWndProc(Window *w, WindowEvent *e) 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 @@ static const Widget _newgrf_widgets[] = { /* 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 @@ static const WindowDesc _newgrf_desc = { }; -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 @@ void ShowNewGRFSettings(bool editable, bool show_params, GRFConfig **config) 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); diff --git a/openttd.c b/openttd.c index c9d59c2f1a..8ed10a6b38 100644 --- a/openttd.c +++ b/openttd.c @@ -1559,3 +1559,24 @@ bool AfterLoadGame(void) 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(); +} diff --git a/vehicle.c b/vehicle.c index 89d2ed0a3e..9ef5918a00 100644 --- a/vehicle.c +++ b/vehicle.c @@ -440,6 +440,14 @@ static void UpdateVehiclePosHash(Vehicle* v, int x, int y) } } +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 @@ void InitializeVehicles(void) * 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) diff --git a/vehicle.h b/vehicle.h index a75b0bf6b6..20c1b70184 100644 --- a/vehicle.h +++ b/vehicle.h @@ -277,6 +277,7 @@ Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z); void InitializeTrains(void); byte VehicleRandomBits(void); +void ResetVehiclePosHash(void); bool CanFillVehicle(Vehicle *v); bool CanRefitTo(EngineID engine_type, CargoID cid_to);