diff options
-rw-r--r-- | aircraft_cmd.c | 24 | ||||
-rw-r--r-- | aircraft_gui.c | 46 | ||||
-rw-r--r-- | command.c | 6 | ||||
-rw-r--r-- | command.h | 3 | ||||
-rw-r--r-- | engine.c | 38 | ||||
-rw-r--r-- | engine.h | 1 | ||||
-rw-r--r-- | gui.h | 1 | ||||
-rw-r--r-- | lang/english.txt | 22 | ||||
-rw-r--r-- | misc.c | 8 | ||||
-rw-r--r-- | misc_gui.c | 9 | ||||
-rw-r--r-- | network_gui.c | 8 | ||||
-rw-r--r-- | roadveh_cmd.c | 6 | ||||
-rw-r--r-- | roadveh_gui.c | 44 | ||||
-rw-r--r-- | settings_gui.c | 18 | ||||
-rw-r--r-- | ship_cmd.c | 24 | ||||
-rw-r--r-- | ship_gui.c | 45 | ||||
-rw-r--r-- | train_cmd.c | 24 | ||||
-rw-r--r-- | train_gui.c | 80 | ||||
-rw-r--r-- | ttd.h | 1 | ||||
-rw-r--r-- | variables.h | 3 | ||||
-rw-r--r-- | vehicle.c | 180 | ||||
-rw-r--r-- | vehicle.h | 2 | ||||
-rw-r--r-- | vehicle_gui.c | 644 | ||||
-rw-r--r-- | vehicle_gui.h | 12 | ||||
-rw-r--r-- | widget.c | 250 | ||||
-rw-r--r-- | window.c | 5 | ||||
-rw-r--r-- | window.h | 17 |
27 files changed, 1249 insertions, 272 deletions
diff --git a/aircraft_cmd.c b/aircraft_cmd.c index 8236e414a..37c4e56d3 100644 --- a/aircraft_cmd.c +++ b/aircraft_cmd.c @@ -406,29 +406,32 @@ int32 CmdChangeAircraftServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 } // p1 = vehicle -// p2 = new cargo type +// p2 = new cargo type(0xFF) +// p2 = skip check for stopped in hanger (0x0100) int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2) { Vehicle *v,*u; int pass, mail; int32 cost; + byte SkipStoppedInHangerCheck = (p2 & 0x100) >> 8; //excludes the cargo value + byte new_cargo_type = p2 & 0xFF; //gets the cargo number SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN); v = &_vehicles[p1]; - if (!CheckOwnership(v->owner) || !CheckStoppedInHangar(v)) + if (!CheckOwnership(v->owner) || (!CheckStoppedInHangar(v) && !(SkipStoppedInHangerCheck))) return CMD_ERROR; pass = AircraftVehInfo(v->engine_type)->passanger_capacity; - if (p2 != 0) { + if (new_cargo_type != CT_PASSENGERS) { pass >>= 1; - if (p2 != 5) + if (new_cargo_type != CT_GOODS) pass >>= 1; } _aircraft_refit_capacity = pass; cost = 0; - if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) { + if (IS_HUMAN_PLAYER(v->owner) && new_cargo_type != v->cargo_type) { cost = _price.aircraft_base >> 7; } @@ -437,12 +440,15 @@ int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2) u = v->next; mail = AircraftVehInfo(v->engine_type)->mail_capacity; - if (p2 != 0) { + if (new_cargo_type != CT_PASSENGERS) { mail = 0; } u->cargo_cap = mail; - v->cargo_count = u->cargo_count = 0; - v->cargo_type = (byte)p2; + //autorefitted planes wants to keep the cargo + //it will be checked if the cargo is valid in CmdReplaceVehicle + if (!(SkipStoppedInHangerCheck)) + v->cargo_count = u->cargo_count = 0; + v->cargo_type = new_cargo_type; InvalidateWindow(WC_VEHICLE_DETAILS, v->index); } @@ -1157,7 +1163,7 @@ static void AircraftEnterHangar(Vehicle *v) ServiceAircraft(v); - MaybeRenewVehicle(v); + MaybeReplaceVehicle(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); diff --git a/aircraft_gui.c b/aircraft_gui.c index 41e9767a5..2dd567724 100644 --- a/aircraft_gui.c +++ b/aircraft_gui.c @@ -13,6 +13,26 @@ #include "player.h" +void Set_DPARAM_Aircraft_Build_Window(uint16 engine_number) +{ + const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number); + Engine *e; + YearMonthDay ymd; + + SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5); + SetDParam(1, avi->max_speed * 8); + SetDParam(2, avi->passanger_capacity); + SetDParam(3, avi->mail_capacity); + SetDParam(4, avi->running_cost * _price.aircraft_running >> 8); + + e = &_engines[engine_number]; + SetDParam(6, e->lifelength); + SetDParam(7, e->reliability * 100 >> 16); + ConvertDayToYMD(&ymd, e->intro_date); + SetDParam(5, ymd.year + 1920); + +} + static void DrawAircraftImage(Vehicle *v, int x, int y, VehicleID selection) { int image = GetAircraftImage(v, 6); @@ -43,8 +63,6 @@ void CcBuildAircraft(bool success, uint tile, uint32 p1, uint32 p2) static void NewAircraftWndProc(Window *w, WindowEvent *e) { - YearMonthDay ymd; - switch(e->event) { case WE_PAINT: { @@ -89,20 +107,7 @@ static void NewAircraftWndProc(Window *w, WindowEvent *e) WP(w,buildtrain_d).sel_engine = selected_id; if (selected_id != -1) { - const AircraftVehicleInfo *avi = AircraftVehInfo(selected_id); - Engine *e; - - SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5); - SetDParam(1, avi->max_speed * 8); - SetDParam(2, avi->passanger_capacity); - SetDParam(3, avi->mail_capacity); - SetDParam(4, avi->running_cost * _price.aircraft_running >> 8); - - e = &_engines[selected_id]; - SetDParam(6, e->lifelength); - SetDParam(7, e->reliability * 100 >> 16); - ConvertDayToYMD(&ymd, e->intro_date); - SetDParam(5, ymd.year + 1920); + Set_DPARAM_Aircraft_Build_Window(selected_id); DrawString(2, 111, STR_A007_COST_SPEED_CAPACITY_PASSENGERS, 0); } @@ -899,7 +904,7 @@ static Widget _player_aircraft_widgets[] = { { WWT_MATRIX, 14, 0, 248, 26, 169, 0x401, STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT}, { WWT_SCROLLBAR, 14, 249, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, { WWT_PUSHTXTBTN, 14, 0, 129, 170, 181, STR_A003_NEW_AIRCRAFT, STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES}, -{ WWT_PANEL, 14, 130, 259, 170, 181, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 130, 259, 170, 181, STR_REPLACE_VEHICLES, STR_REPLACE_HELP}, { WIDGETS_END}, }; @@ -1005,7 +1010,7 @@ static void PlayerAircraftWndProc(Window *w, WindowEvent *e) break; case 4: case 5:/* Select sorting criteria dropdown menu */ - ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0); + ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0); return; case 7: { /* Matrix to show vehicles */ @@ -1044,6 +1049,11 @@ static void PlayerAircraftWndProc(Window *w, WindowEvent *e) ShowBuildAircraftWindow(0); } break; + + case 10: + ShowReplaceVehicleWindow(VEH_Aircraft); + break; + } } break; @@ -167,7 +167,7 @@ DEF_COMMAND(CmdStartScenario); DEF_COMMAND(CmdBuildManySignals); -DEF_COMMAND(CmdRenewVehicle); +DEF_COMMAND(CmdReplaceVehicle); /* The master command table */ static CommandProc * const _command_proc_table[] = { @@ -309,7 +309,7 @@ static CommandProc * const _command_proc_table[] = { CmdDestroyCompanyHQ, /* 111 */ CmdGiveMoney, /* 112 */ CmdChangePatchSetting, /* 113 */ - CmdRenewVehicle, /* 114 */ + CmdReplaceVehicle, /* 114 */ }; int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc) @@ -431,7 +431,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, _docommand_recursive = 1; // cost estimation only? - if (_shift_pressed && _current_player == _local_player && !(cmd & CMD_NETWORK_COMMAND)) { + if (_shift_pressed && _current_player == _local_player && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) { // estimate the cost. res = proc(x, y, flags, p1, p2); if ((uint32)res >> 16 == 0x8000) { @@ -149,7 +149,7 @@ enum { CMD_GIVE_MONEY = 112, CMD_CHANGE_PATCH_SETTING = 113, - CMD_RENEW_VEHICLE = 114, + CMD_REPLACE_VEHICLE = 114, }; enum { @@ -172,6 +172,7 @@ enum { CMD_NO_WATER = 0x400, CMD_NETWORK_COMMAND = 0x800, // execute the command without sending it on the network CMD_NO_TEST_IF_IN_NETWORK = 0x1000, // When enabled, the command will bypass the no-DC_EXEC round if in network + CMD_SHOW_NO_ERROR = 0x2000, }; //#define return_cmd_error(errcode) do { _error_message=(errcode); return CMD_ERROR; } while(0) @@ -115,6 +115,29 @@ static void CalcEngineReliability(Engine *e) } } +void AddTypeToEngines() +{ + Engine *e; + uint32 counter = 0; + + for(e=_engines; e != endof(_engines); e++, counter++) { + + e->type = VEH_Train; + if (counter >= ROAD_ENGINES_INDEX) { + e->type = VEH_Road; + if (counter >= SHIP_ENGINES_INDEX) { + e->type = VEH_Ship; + if (counter >= AIRCRAFT_ENGINES_INDEX) { + e->type = VEH_Aircraft; + if (counter >= TOTAL_NUM_ENGINES) { + e->type = VEH_Special; + } + } + } + } + } +} + void StartupEngines() { Engine *e; @@ -123,8 +146,8 @@ void StartupEngines() SetupEngineNames(); - for(e=_engines, ei=_engine_info; e != endof(_engines); e++, ei++, counter++) { + e->age = 0; e->railtype = ei->railtype_climates >> 4; e->flags = 0; @@ -170,19 +193,6 @@ void StartupEngines() It should hopefully be the same as when you ask a vehicle what it is but using this, you can ask what type an engine number is even if it is not a vehicle (yet)*/ - e->type = VEH_Train; - if (counter >= ROAD_ENGINES_INDEX) { - e->type = VEH_Road; - if (counter >= SHIP_ENGINES_INDEX) { - e->type = VEH_Ship; - if (counter >= AIRCRAFT_ENGINES_INDEX) { - e->type = VEH_Aircraft; - if (counter >= TOTAL_NUM_ENGINES) { - e->type = VEH_Special; - } - } - } - } } AdjustAvailAircraft(); @@ -80,6 +80,7 @@ enum { }; +void AddTypeToEngines(); void StartupEngines(); @@ -85,6 +85,7 @@ void CheckRedrawStationCoverage(Window *w); void ShowSmallMap(); void ShowExtraViewPortWindow(); void SetVScrollCount(Window *w, int num); +void SetVScroll2Count(Window *w, int num); void SetHScrollCount(Window *w, int num); int HandleEditBoxKey(Window *w, int wid, WindowEvent *we); diff --git a/lang/english.txt b/lang/english.txt index f12cb61ea..1a9167cef 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -2763,3 +2763,25 @@ STR_SCHEDULED_TRAINS_TIP :{BLACK}Show all trains which have this station on STR_SCHEDULED_ROAD_VEHICLES_TIP :{BLACK}Show all road vehicles which have this station on their schedule STR_SCHEDULED_AIRCRAFT_TIP :{BLACK}Show all aircraft which have this station on their schedule STR_SCHEDULED_SHIPS_TIP :{BLACK}Show all ships which have this station on their schedule + +STR_REPLACE_VEHICLES :{BLACK}Replace Vehicles +STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles +STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Replaing Vehicles +STR_NOT_REPLACING :{BLACK}Not replacing +STR_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}No vehicle selected +STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Select a type of engine to replace{}Select an engine on the right side to replace to +STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Select an engine to replace to{}It will replace the engines selected on the left side +STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Press this button if you don't want to replace the engine, you selected on the left +STR_REPLACE_HELP_START_BUTTON :{BLACK}Press this button if you want to replace the engine selected on the left with the one selected on the right +STR_REPLACE_HELP_RAILTYPE :{BLACK}Select a railtype you want to select engines for +STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}This displays what engine the selected engine on the left are being replaced to +STR_REPLACE_HELP :{BLACK}This feature allows you to select an enginetype and replace that one with another one. This will then be done automatically when the vehicles enters a depot anyway + +############ Lists rail types + +STR_RAIL_VEHICLES :{BLACK}Rail Vehicles +STR_MONORAIL_VEHICLES :{BLACK}Monorail Vehicles +STR_MAGLEV_VEHICLES :{BLACK}Maglev Vehicles + +############ End of list of rail types + @@ -9,6 +9,7 @@ #include "network.h" #include "network_data.h" #include "network_server.h" +#include "engine.h" extern void StartupEconomy(); extern void InitNewsItemStructs(); @@ -182,6 +183,13 @@ void ConvertGroundTilesIntoWaterTiles(); void InitializeGame() { + // Initialize the autoreplace array. Needs to be cleared between each game + int i; + for (i = 0; i < 256; i++) { + _autoreplace_array[i] = i; + } + AddTypeToEngines(); // make sure all engines have a type + SetObjectToPlace(1, 0, 0, 0); _pause = 0; diff --git a/misc_gui.c b/misc_gui.c index a5e7db7a0..1b17cc449 100644 --- a/misc_gui.c +++ b/misc_gui.c @@ -692,6 +692,14 @@ void SetVScrollCount(Window *w, int num) if (num < w->vscroll.pos) w->vscroll.pos = num; } +void SetVScroll2Count(Window *w, int num) +{ + w->vscroll2.count = num; + num -= w->vscroll2.cap; + if (num < 0) num = 0; + if (num < w->vscroll2.pos) w->vscroll2.pos = num; +} + void SetHScrollCount(Window *w, int num) { w->hscroll.count = num; @@ -700,7 +708,6 @@ void SetHScrollCount(Window *w, int num) if (num < w->hscroll.pos) w->hscroll.pos = num; } - int HandleEditBoxKey(Window *w, int wid, WindowEvent *we) { byte *p; diff --git a/network_gui.c b/network_gui.c index 5f62b29a5..172eea23a 100644 --- a/network_gui.c +++ b/network_gui.c @@ -231,7 +231,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e) DeleteWindowById(WC_NETWORK_WINDOW, 0); break; case 4: case 5: - ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0); // do it for widget 5 + ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0, 0); // do it for widget 5 break; case 10: { /* Matrix to show networkgames */ uint32 id_v = (e->click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW; @@ -540,13 +540,13 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e) SetWindowDirty(w); } break; case 7: case 8: /* Connection type */ - ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0); // do it for widget 8 + ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8 break; case 9: case 10: /* Number of Players */ - ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max - 2, 10, 0); // do it for widget 10 + ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max - 2, 10, 0, 0); // do it for widget 10 return; case 11: case 12: /* Language */ - ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 12, 0); // do it for widget 12 + ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 12, 0, 0); // do it for widget 12 return; case 13: /* Start game */ _is_network_server = true; diff --git a/roadveh_cmd.c b/roadveh_cmd.c index 72adbade1..37196cc86 100644 --- a/roadveh_cmd.c +++ b/roadveh_cmd.c @@ -105,6 +105,8 @@ int32 EstimateRoadVehCost(byte engine_type) return ((_price.roadveh_base >> 3) * RoadVehInfo(engine_type)->base_cost) >> 5; } +// p1 = engine_type +// p2 not used int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) { int32 cost; @@ -211,6 +213,8 @@ int32 CmdStartStopRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) return 0; } +// p1 = vehicle index in &_vehicles[] +// p2 not used int32 CmdSellRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) { Vehicle *v; @@ -1379,7 +1383,7 @@ void RoadVehEnterDepot(Vehicle *v) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); - MaybeRenewVehicle(v); + MaybeReplaceVehicle(v); VehicleServiceInDepot(v); diff --git a/roadveh_gui.c b/roadveh_gui.c index ed7f2201b..09e8b5a95 100644 --- a/roadveh_gui.c +++ b/roadveh_gui.c @@ -12,6 +12,25 @@ #include "player.h" #include "engine.h" +void Set_DPARAM_Road_Veh_Build_Window(uint16 engine_number) +{ + const RoadVehicleInfo *rvi = RoadVehInfo(engine_number); + Engine *e; + YearMonthDay ymd; + + SetDParam(0, rvi->base_cost * (_price.roadveh_base>>3)>>5); + SetDParam(1, rvi->max_speed * 10 >> 5); + SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8); + SetDParam(4, rvi->capacity); + SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]); + + e = &_engines[engine_number]; + SetDParam(6, e->lifelength); + SetDParam(7, e->reliability * 100 >> 16); + ConvertDayToYMD(&ymd, e->intro_date); + SetDParam(5, ymd.year + 1920); +} + static void DrawRoadVehImage(Vehicle *v, int x, int y, VehicleID selection) { int image = GetRoadVehImage(v, 6); @@ -307,8 +326,6 @@ void ShowRoadVehViewWindow(Vehicle *v) static void DrawNewRoadVehWindow(Window *w) { - YearMonthDay ymd; - if (w->window_number == 0) w->disabled_state = 1 << 5; @@ -350,20 +367,7 @@ static void DrawNewRoadVehWindow(Window *w) WP(w,buildtrain_d).sel_engine = selected_id; if (selected_id != -1) { - const RoadVehicleInfo *rvi = RoadVehInfo(selected_id); - Engine *e; - - SetDParam(0, rvi->base_cost * (_price.roadveh_base>>3)>>5); - SetDParam(1, rvi->max_speed * 10 >> 5); - SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8); - SetDParam(4, rvi->capacity); - SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]); - - e = &_engines[selected_id]; - SetDParam(6, e->lifelength); - SetDParam(7, e->reliability * 100 >> 16); - ConvertDayToYMD(&ymd, e->intro_date); - SetDParam(5, ymd.year + 1920); + Set_DPARAM_Road_Veh_Build_Window(selected_id); DrawString(2, 127, STR_9008_COST_SPEED_RUNNING_COST, 0); } @@ -714,7 +718,7 @@ static Widget _player_roadveh_widgets[] = { { WWT_SCROLLBAR, 14, 249, 259, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, /* only for our road list, a 'Build Vehicle' button that opens the depot of the last built depot */ { WWT_PUSHTXTBTN, 14, 0, 129, 208, 219, STR_8815_NEW_VEHICLES, STR_901B_BUILD_NEW_ROAD_VEHICLES}, -{ WWT_PANEL, 14, 130, 259, 208, 219, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 130, 259, 208, 219, STR_REPLACE_VEHICLES, STR_REPLACE_HELP}, { WIDGETS_END}, }; @@ -818,7 +822,7 @@ static void PlayerRoadVehWndProc(Window *w, WindowEvent *e) break; case 4: case 5:/* Select sorting criteria dropdown menu */ - ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0); + ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0); return; case 7: { /* Matrix to show vehicles */ uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_SMALL; @@ -856,6 +860,10 @@ static void PlayerRoadVehWndProc(Window *w, WindowEvent *e) ShowBuildRoadVehWindow(0); } break; + case 10: { + ShowReplaceVehicleWindow(VEH_Road); + break; + } } } break; diff --git a/settings_gui.c b/settings_gui.c index 253b3acf5..e6cf1f93c 100644 --- a/settings_gui.c +++ b/settings_gui.c @@ -92,35 +92,35 @@ static void GameOptionsWndProc(Window *w, WindowEvent *e) case WE_CLICK: switch(e->click.widget) { case 5: - ShowDropDownMenu(w, _currency_string_list, _opt_mod_ptr->currency, e->click.widget, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies()); + ShowDropDownMenu(w, _currency_string_list, _opt_mod_ptr->currency, e->click.widget, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0); return; case 8: - ShowDropDownMenu(w, _distances_dropdown, _opt_mod_ptr->kilometers, e->click.widget, 0); + ShowDropDownMenu(w, _distances_dropdown, _opt_mod_ptr->kilometers, e->click.widget, 0, 0); return; case 11: { int i = _opt_mod_ptr->road_side; - ShowDropDownMenu(w, _driveside_dropdown, i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i)); + ShowDropDownMenu(w, _driveside_dropdown, i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0); return; } case 14: { int i = _opt_mod_ptr->town_name; - ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i)); + ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0); return; } case 17: - ShowDropDownMenu(w, _autosave_dropdown, _opt_mod_ptr->autosave, e->click.widget, 0); + ShowDropDownMenu(w, _autosave_dropdown, _opt_mod_ptr->autosave, e->click.widget, 0, 0); return; case 20: - ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names&1)?1:0, e->click.widget, (_vehicle_design_names&2)?0:2); + ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names&1)?1:0, e->click.widget, (_vehicle_design_names&2)?0:2, 0); return; case 21: return; case 24: - ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, e->click.widget, 0); + ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, e->click.widget, 0, 0); return; case 27: // setup resolution dropdown - ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), e->click.widget, 0); + ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), e->click.widget, 0, 0); return; case 28: /* Click fullscreen on/off */ (_fullscreen) ? CLRBIT(w->click_state, 28) : SETBIT(w->click_state, 28); @@ -128,7 +128,7 @@ static void GameOptionsWndProc(Window *w, WindowEvent *e) SetWindowDirty(w); return; case 31: /* Setup screenshot format dropdown */ - ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, e->click.widget, 0); + ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, e->click.widget, 0, 0); return; } diff --git a/ship_cmd.c b/ship_cmd.c index 3c350d938..9d7a8553e 100644 --- a/ship_cmd.c +++ b/ship_cmd.c @@ -400,7 +400,7 @@ static void ShipEnterDepot(Vehicle *v) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); - MaybeRenewVehicle(v); + MaybeReplaceVehicle(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); @@ -975,30 +975,38 @@ int32 CmdChangeShipServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2) // p1 = vehicle -// p2 = new cargo +// p2 = new cargo (0xFF) +// p2 = skip check for stopped in hanger (0x0100) int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2) { Vehicle *v; int32 cost; + byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8; //excludes the cargo value + p2 = p2 & 0xFF; SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN); v = &_vehicles[p1]; if (!CheckOwnership(v->owner)) return CMD_ERROR; - if (!IsShipDepotTile(v->tile) || - !(v->vehstatus&VS_STOPPED) || - v->u.ship.state != 0x80) - return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN); - + if (!( SkipStoppedInDepotCheck )) { + if (!IsShipDepotTile(v->tile) || + !(v->vehstatus&VS_STOPPED) || + v->u.ship.state != 0x80) + return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN); + } + cost = 0; if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) { cost = _price.ship_base >> 7; } if (flags & DC_EXEC) { - v->cargo_count = 0; + //autorefitted ships wants to keep the cargo + //it will be checked if the cargo is valid in CmdRenewVehicle + if (!(SkipStoppedInDepotCheck)) + v->cargo_count = 0; v->cargo_type = (byte)p2; InvalidateWindow(WC_VEHICLE_DETAILS, v->index); } diff --git a/ship_gui.c b/ship_gui.c index 98e53f559..881fd47fd 100644 --- a/ship_gui.c +++ b/ship_gui.c @@ -12,6 +12,25 @@ #include "player.h" #include "engine.h" +void Set_DPARAM_Ship_Build_Window(uint16 engine_number) +{ + YearMonthDay ymd; + const ShipVehicleInfo *svi = ShipVehInfo(engine_number); + Engine *e; + + SetDParam(0, svi->base_cost * (_price.ship_base>>3)>>5); + SetDParam(1, svi->max_speed * 10 >> 5); + SetDParam(2, _cargoc.names_long_p[svi->cargo_type]); + SetDParam(3, svi->capacity); + SetDParam(4, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY); + SetDParam(5, svi->running_cost * _price.ship_running >> 8); + + e = &_engines[engine_number]; + SetDParam(7, e->lifelength); + SetDParam(8, e->reliability * 100 >> 16); + ConvertDayToYMD(&ymd, e->intro_date); + SetDParam(6, ymd.year + 1920); +} static void DrawShipImage(Vehicle *v, int x, int y, VehicleID selection); @@ -317,7 +336,6 @@ void CcBuildShip(bool success, uint tile, uint32 p1, uint32 p2) static void NewShipWndProc(Window *w, WindowEvent *e) { - YearMonthDay ymd; switch(e->event) { case WE_PAINT: if (w->window_number == 0) @@ -362,21 +380,7 @@ static void NewShipWndProc(Window *w, WindowEvent *e) WP(w,buildtrain_d).sel_engine = selected_id; if (selected_id != -1) { - const ShipVehicleInfo *svi = ShipVehInfo(selected_id); - Engine *e; - - SetDParam(0, svi->base_cost * (_price.ship_base>>3)>>5); - SetDParam(1, svi->max_speed * 10 >> 5); - SetDParam(2, _cargoc.names_long_p[svi->cargo_type]); - SetDParam(3, svi->capacity); - SetDParam(4, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY); - SetDParam(5, svi->running_cost * _price.ship_running >> 8); - - e = &_engines[selected_id]; - SetDParam(7, e->lifelength); - SetDParam(8, e->reliability * 100 >> 16); - ConvertDayToYMD(&ymd, e->intro_date); - SetDParam(6, ymd.year + 1920); + Set_DPARAM_Ship_Build_Window(selected_id); DrawString(2, 111, STR_980A_COST_SPEED_CAPACITY_RUNNING, 0); } @@ -881,7 +885,7 @@ static Widget _player_ships_widgets[] = { { WWT_MATRIX, 14, 0, 248, 26, 169, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR}, { WWT_SCROLLBAR, 14, 249, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, { WWT_PUSHTXTBTN, 14, 0, 129, 170, 181, STR_9804_NEW_SHIPS, STR_9824_BUILD_NEW_SHIPS_REQUIRES}, -{ WWT_PANEL, 14, 130, 259, 170, 181, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 130, 259, 170, 181, STR_REPLACE_VEHICLES, STR_REPLACE_HELP}, { WIDGETS_END}, }; @@ -986,7 +990,7 @@ static void PlayerShipsWndProc(Window *w, WindowEvent *e) SetWindowDirty(w); break; case 4: case 5:/* Select sorting criteria dropdown menu */ - ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0); + ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0); return; case 7: { /* Matrix to show vehicles */ uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_BIG; @@ -1024,7 +1028,12 @@ static void PlayerShipsWndProc(Window *w, WindowEvent *e) ShowBuildShipWindow(0); } break; + + case 10: { + ShowReplaceVehicleWindow(VEH_Ship); + break; } + } } break; case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ diff --git a/train_cmd.c b/train_cmd.c index 5386addf4..4700ab4d4 100644 --- a/train_cmd.c +++ b/train_cmd.c @@ -1057,23 +1057,27 @@ int32 CmdForceTrainProceed(int x, int y, uint32 flags, uint32 p1, uint32 p2) } // p1 = vehicle to refit -// p2 = new cargo - +// p2 = new cargo (0xFF) +// p2 = skip check for stopped in hanger (0x0100) int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) { Vehicle *v; int32 cost; uint num; - SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); + byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8; + + p2 = p2 & 0xFF; + SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); + v = &_vehicles[p1]; - if (!CheckOwnership(v->owner) || CheckStoppedInDepot(v) < 0) + if (!CheckOwnership(v->owner) || ((CheckStoppedInDepot(v) < 0) && !(SkipStoppedInDepotCheck))) return CMD_ERROR; cost = 0; num = 0; - + do { /* XXX: We also refit all the attached wagons en-masse if they * can be refitted. This is how TTDPatch does it. TODO: Have @@ -1084,12 +1088,16 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) cost += (_price.build_railvehicle >> 8); num += v->cargo_cap; if (flags & DC_EXEC) { - v->cargo_count = 0; + //autorefitted train cars wants to keep the cargo + //it will be checked if the cargo is valid in CmdReplaceVehicle + if (!(SkipStoppedInDepotCheck)) + v->cargo_count = 0; v->cargo_type = (byte)p2; InvalidateWindow(WC_VEHICLE_DETAILS, v->index); } } - } while ( (v=v->next) != NULL); + // SkipStoppedInDepotCheck is called by CmdReplace and it should only apply to the single car it is called for + } while ( (v=v->next) != NULL || SkipStoppedInDepotCheck ); _returned_refit_amount = num; @@ -2618,7 +2626,7 @@ void TrainEnterDepot(Vehicle *v, uint tile) v->load_unload_time_rem = 0; v->cur_speed = 0; - MaybeRenewVehicle(v); + MaybeReplaceVehicle(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); diff --git a/train_gui.c b/train_gui.c index 3e1de7bae..78095eb35 100644 --- a/train_gui.c +++ b/train_gui.c @@ -16,6 +16,44 @@ int _traininfo_vehicle_pitch = 0; +void Set_DPARAM_Train_Engine_Build_Window(uint16 engine_number) +{ + const RailVehicleInfo *rvi = RailVehInfo(engine_number); + Engine *e; + int multihead = (rvi->flags&RVI_MULTIHEAD?1:0); + YearMonthDay ymd; + + + SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5); + SetDParam(2, rvi->max_speed * 10 >> 4); + SetDParam(3, rvi->power << multihead); + SetDParam(1, rvi->weight << multihead); + SetDParam(4, (rvi->running_cost_base * _price.running_rail[rvi->engclass] >> 8) << multihead); + + SetDParam(5, STR_8838_N_A); + if (rvi->capacity != 0) { + SetDParam(6, rvi->capacity << multihead); + SetDParam(5, _cargoc.names_long_p[rvi->cargo_type]); + } + + e = &_engines[engine_number]; + + SetDParam(8, e->lifelength); + SetDParam(9, e->reliability * 100 >> 16); + ConvertDayToYMD(&ymd, e->intro_date); + SetDParam(7, ymd.year + 1920); +} + +void Set_DPARAM_Train_Car_Build_Window(Window *w, uint16 engine_number) +{ + const RailVehicleInfo *rvi = RailVehInfo(engine_number); + + SetDParam(0, DoCommandByTile(w->window_number, engine_number, 0, DC_QUERY_COST, CMD_BUILD_RAIL_VEHICLE) ); + SetDParam(4, rvi->capacity); + SetDParam(1, rvi->weight); + SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]); + SetDParam(2, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight); +} void CcBuildWagon(bool success, uint tile, uint32 p1, uint32 p2) { @@ -131,43 +169,16 @@ static void NewRailVehicleWndProc(Window *w, WindowEvent *e) if (selected_id != -1) { const RailVehicleInfo *rvi = RailVehInfo(selected_id); - Engine *e; - YearMonthDay ymd; if (!(rvi->flags & RVI_WAGON)) { /* it's an engine */ - int multihead = (rvi->flags&RVI_MULTIHEAD?1:0); - - SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5); - SetDParam(2, rvi->max_speed * 10 >> 4); - SetDParam(3, rvi->power << multihead); - SetDParam(1, rvi->weight << multihead); - SetDParam(4, (rvi->running_cost_base * _price.running_rail[rvi->engclass] >> 8) << multihead); - - SetDParam(5, STR_8838_N_A); - if (rvi->capacity != 0) { - SetDParam(6, rvi->capacity << multihead); - SetDParam(5, _cargoc.names_long_p[rvi->cargo_type]); - } - - e = &_engines[selected_id]; - - SetDParam(8, e->lifelength); - SetDParam(9, e->reliability * 100 >> 16); - ConvertDayToYMD(&ymd, e->intro_date); - SetDParam(7, ymd.year + 1920); + Set_DPARAM_Train_Engine_Build_Window(selected_id); DrawString(2, 0x7F, STR_8817_COST_WEIGHT_T_SPEED_POWER, 0); } else { /* it's a wagon */ - - SetDParam(0, - DoCommandByTile(w->window_number, selected_id, 0, DC_QUERY_COST, CMD_BUILD_RAIL_VEHICLE) - ); - SetDParam(4, rvi->capacity); - SetDParam(1, rvi->weight); - SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]); - SetDParam(2, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight); + Set_DPARAM_Train_Car_Build_Window(w, selected_id); + DrawString(2, 0x7F, STR_8821_COST_WEIGHT_T_T_CAPACITY, 0); } } @@ -1183,7 +1194,7 @@ static Widget _player_trains_widgets[] = { { WWT_MATRIX, 14, 0, 313, 26, 207, 0x701, STR_883D_TRAINS_CLICK_ON_TRAIN_FOR}, { WWT_SCROLLBAR, 14, 314, 324, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, { WWT_PUSHTXTBTN, 14, 0, 161, 208, 219, STR_8815_NEW_VEHICLES, STR_883E_BUILD_NEW_TRAINS_REQUIRES}, -{ WWT_PANEL, 14, 162, 324, 208, 219, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 162, 324, 208, 219, STR_REPLACE_VEHICLES, STR_REPLACE_HELP}, { WIDGETS_END}, }; @@ -1289,7 +1300,7 @@ static void PlayerTrainsWndProc(Window *w, WindowEvent *e) break; case 4: case 5:/* Select sorting criteria dropdown menu */ - ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0); + ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0); return; case 7: { /* Matrix to show vehicles */ @@ -1328,6 +1339,11 @@ static void PlayerTrainsWndProc(Window *w, WindowEvent *e) ShowBuildTrainWindow(0); } break; + case 10: { + ShowReplaceVehicleWindow(VEH_Train); + break; + } + } } break; @@ -439,6 +439,7 @@ enum { WC_CLIENT_LIST = 0x49, WC_NETWORK_STATUS_WINDOW = 0x4A, WC_CUSTOM_CURRENCY = 0x4B, + WC_REPLACE_VEHICLE = 0x4C, }; diff --git a/variables.h b/variables.h index c62cc78fa..3d6b7a5fd 100644 --- a/variables.h +++ b/variables.h @@ -431,6 +431,9 @@ VARDEF SignStruct *_new_sign_struct; /* tunnelbridge */ #define MAX_BRIDGES 13 +/* Autoreplace vehicle stuff*/ +VARDEF byte _autoreplace_array[255]; + /* Debugging levels */ VARDEF int _debug_spritecache_level; VARDEF int _debug_misc_level; @@ -4,7 +4,6 @@ #include "map.h" #include "vehicle.h" #include "gfx.h" -//#include "station.h" #include "viewport.h" #include "news.h" #include "command.h" @@ -1394,35 +1393,45 @@ extern int32 EstimateTrainCost(const RailVehicleInfo *rvi); extern int32 EstimateRoadVehCost(byte engine_type); extern int32 EstimateShipCost(uint16 engine_type); extern int32 EstimateAircraftCost(uint16 engine_type); +extern int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2); +extern int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2); +extern int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2); -/* Renews a vehicle +/* Replaces a vehicle (used to be called autorenew) p1 - Index of vehicle p2 - Type of new engine */ -int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) -{ - byte new_engine_type = p2; +int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) +{ + /* makesvariables to inform about how much money the player wants to have left after replacing + and which engine to replace with out of p2. + the first 16 bit is the money. The last 5 digits (all 0) were removed when sent, so we add them again. + This way the max is 6553 millions and it is more than the 32 bit that is stored in _patches + This is a nice way to send 32 bit and only use 16 bit + the last 8 bit is the engine. The 8 bits in front of the engine is free so it have room for 16 bit engine entries */ + uint16 new_engine_type = (uint16)(p2 & 0xFFFF); + uint32 autorefit_money = (p2 >> 16) * 100000; Vehicle *v = DEREF_VEHICLE(p1); int cost, build_cost; - - SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); + + if (v->type != _engines[new_engine_type].type) return CMD_ERROR; switch (v->type) { - case VEH_Train: build_cost = EstimateTrainCost(RailVehInfo(v->engine_type)); break; - case VEH_Road: build_cost = EstimateRoadVehCost(new_engine_type); break; - case VEH_Ship: build_cost = EstimateShipCost(v->engine_type); break; - case VEH_Aircraft: build_cost = EstimateAircraftCost(new_engine_type); break; + case VEH_Train: build_cost = EstimateTrainCost(RailVehInfo(new_engine_type)); break; + case VEH_Road: build_cost = EstimateRoadVehCost(new_engine_type); break; + case VEH_Ship: build_cost = EstimateShipCost(new_engine_type); break; + case VEH_Aircraft: build_cost = EstimateAircraftCost(new_engine_type); break; default: return CMD_ERROR; } /* In a rare situation, when 2 clients are connected to 1 company and have the same settings, a vehicle can be replaced twice.. check if this is the situation here */ - if (v->age == 0) + if (v->engine_type == new_engine_type && v->age == 0) return CMD_ERROR; /* Check if there is money for the upgrade.. if not, give a nice news-item (that is needed, because this CMD is called automaticly) */ - if (DEREF_PLAYER(v->owner)->money64 < _patches.autorenew_money + build_cost - v->value) { - if (_local_player == v->owner) { + if ( DEREF_PLAYER(v->owner)->money64 < (int32)(autorefit_money + build_cost - v->value)) { + if (( _local_player == v->owner ) && ( v->unitnumber != 0 )) { //v->unitnumber = 0 for train cars int message; SetDParam(0, v->unitnumber); switch (v->type) { @@ -1439,21 +1448,106 @@ int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) return CMD_ERROR; } - cost = build_cost - v->value; - if (flags & DC_QUERY_COST) - return cost; if (flags & DC_EXEC) { Engine *e; + e = &_engines[new_engine_type]; + + // TODO make it check if refit is possible before actually doing it /* We do not really buy a new vehicle, we upgrade the old one */ if (v->engine_type != new_engine_type) { - /* XXX - We need to do some more stuff here, when we are going to upgrade - to a new engine! */ + byte cargo_type = v->cargo_type; + v->engine_type = new_engine_type; + v->max_age = e->lifelength * 366; + + /* Update limits of the vehicle (for when upgraded) */ + switch (v->type) { + case VEH_Train: + // using if (true) to declare the const + { + const RailVehicleInfo *rvi = RailVehInfo(new_engine_type); + byte capacity = rvi->capacity; + + v->spritenum = rvi->image_index; + v->cargo_type = rvi->cargo_type; + v->cargo_cap = rvi->capacity; + v->max_speed = rvi->max_speed; + + v->u.rail.railtype = e->railtype; + + // 0x0100 means that we skip the check for being stopped inside the depot + // since we do not stop it for autorefitting + if (v->cargo_type != cargo_type && capacity) { + // BUG: somehow v->index is not transfered properly + //CmdRefitRailVehicle(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 ); + v->cargo_type = cargo_type; // workaround, but it do not check the refit table + } else { + v->cargo_type = rvi->cargo_type; + } + break; + } + case VEH_Road: + // using if (true) to declare the const + if (true) { + const RoadVehicleInfo *rvi = RoadVehInfo(new_engine_type); + + v->spritenum = rvi->image_index; + v->cargo_type = rvi->cargo_type; + v->cargo_cap = rvi->capacity; + v->max_speed = rvi->max_speed; + break; + } + case VEH_Ship: + // using if (true) to declare the const + if (true) { + const ShipVehicleInfo *svi = ShipVehInfo(new_engine_type); + + v->spritenum = svi->image_index; + v->cargo_type = svi->cargo_type; + v->cargo_cap = svi->capacity; + v->max_speed = svi->max_speed; + + // 0x0100 means that we skip the check for being stopped inside the depot + // since we do not stop it for autorefitting + if (v->cargo_type != cargo_type) + CmdRefitShip(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 ); + break; + } + case VEH_Aircraft: + // using if (true) to declare the const + if (true) { + const AircraftVehicleInfo *avi = AircraftVehInfo(new_engine_type); + Vehicle *u; + + v->max_speed = avi->max_speed; + v->acceleration = avi->acceleration; + v->spritenum = avi->image_index; + + if ( cargo_type == CT_PASSENGERS ) { + v->cargo_cap = avi->passanger_capacity; + u = v->next; + u->cargo_cap = avi->mail_capacity; + } else { + // 0x0100 means that we skip the check for being stopped inside the hangar + // since we do not stop it for autorefitting + CmdRefitAircraft(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 ); + } + break; + } + default: return CMD_ERROR; + } + // makes sure that the cargo is still valid compared to new capacity + if (v->cargo_count != 0) { + if ( v->cargo_type != cargo_type ) + v->cargo_count = 0; + else if ( v->cargo_count > v->cargo_cap ) + v->cargo_count = v->cargo_cap; + } } - e = &_engines[new_engine_type]; + v->reliability = e->reliability; v->reliability_spd_dec = e->reliability_spd_dec; v->age = 0; @@ -1465,26 +1559,58 @@ int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); } + //needs to be down here because refitting will change SET_EXPENSES_TYPE if called + SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); return cost; } -void MaybeRenewVehicle(Vehicle *v) +void MaybeReplaceVehicle(Vehicle *v) { + uint32 new_engine_and_autoreplace_money; + if (v->owner != _local_player) return; + // uncomment next line if you want to see what engine type just entered a depot + //printf("engine type: %d\n", v->engine_type); // A vehicle is autorenewed when it it gets the amount of months // give by _patches.autorenew_months away for his max age. // Standard is -6, meaning 6 months before his max age // It can be any value between -12 and 12. - if (!_patches.autorenew || v->age - v->max_age < (_patches.autorenew_months * 30)) - return; - + // Here it also checks if the vehicles is listed for replacement + if (!_patches.autorenew || v->age - v->max_age < (_patches.autorenew_months * 30)) { //replace if engine is too old + if (_autoreplace_array[v->engine_type] == v->engine_type && v->type != VEH_Train) //updates to a new model + return; + } + /* Now replace the vehicle */ _current_player = v->owner; - - /* Now renew the vehicle */ - DoCommandP(v->tile, v->index, v->engine_type, NULL, CMD_RENEW_VEHICLE); + + /* makes the variable to inform about how much money the player wants to have left after replacing + and which engine to replace with + the first 16 bit is the money. Since we know the last 5 digits is 0, they are thrown away. + This way the max is 6553 millions and it is more than the 32 bit that is stored in _patches + This is a nice way to send 32 bit and only use 16 bit + the last 8 bit is the engine. The 8 bits in front of the engine is free so it have room for 16 bit engine entries */ + new_engine_and_autoreplace_money = (((_patches.autorenew_money / 100000) & 0xFFFF) << 16) + + _autoreplace_array[v->engine_type]; + + assert(v->type == _engines[ _autoreplace_array[v->engine_type] ].type); + + if ( v->type != VEH_Train ) { + DoCommandP(v->tile, v->index, new_engine_and_autoreplace_money, NULL, CMD_REPLACE_VEHICLE | CMD_SHOW_NO_ERROR); + } else { + // checks if the front engine is outdated + if (v->engine_type != _autoreplace_array[v->engine_type] ) + DoCommandP(v->tile, v->index, new_engine_and_autoreplace_money, NULL, CMD_REPLACE_VEHICLE | CMD_SHOW_NO_ERROR); + //we will check all the cars and engines if they should be replaced + while (v->next != NULL){ + v = v->next; + if (v->engine_type != _autoreplace_array[v->engine_type] || v->age - v->max_age < (_patches.autorenew_months * 30)) + DoCommandP(v->tile, v->index, new_engine_and_autoreplace_money , NULL, CMD_REPLACE_VEHICLE | CMD_SHOW_NO_ERROR); + } + } + _current_player = OWNER_NONE; } @@ -361,7 +361,7 @@ Vehicle *CheckClickOnVehicle(ViewPort *vp, int x, int y); void DecreaseVehicleValue(Vehicle *v); void CheckVehicleBreakdown(Vehicle *v); void AgeVehicle(Vehicle *v); -void MaybeRenewVehicle(Vehicle *v); +void MaybeReplaceVehicle(Vehicle *v); void DeleteCommandFromVehicleSchedule(Order cmd); diff --git a/vehicle_gui.c b/vehicle_gui.c index 09dcb9e84..83c13c3c9 100644 --- a/vehicle_gui.c +++ b/vehicle_gui.c @@ -3,6 +3,10 @@ #include "table/strings.h" #include "vehicle.h" #include "window.h" +#include "engine.h" +#include "gui.h" +#include "command.h" +#include "gfx.h" VehicleSortListingTypeFunctions * const _vehicle_sorter[] = { &VehicleUnsortedSorter, @@ -29,6 +33,13 @@ const StringID _vehicle_sort_listing[] = { INVALID_STRING_ID }; +const StringID _rail_types_list[] = { + STR_RAIL_VEHICLES, + STR_MONORAIL_VEHICLES, + STR_MAGLEV_VEHICLES, + INVALID_STRING_ID +}; + void RebuildVehicleLists(void) { Window *w; @@ -294,3 +305,636 @@ int CDECL VehicleMaxSpeedSorter(const void *a, const void *b) return (_internal_sort_order & 1) ? -r : r; } + +// this define is to match engine.c, but engine.c keeps it to itself +// ENGINE_AVAILABLE is used in ReplaceVehicleWndProc +#define ENGINE_AVAILABLE ((e->flags & 1 && HASBIT(info->railtype_climates, _opt.landscape)) || HASBIT(e->player_avail, _local_player)) + +/* if show_outdated is selected, it do not sort psudo engines properly but it draws all engines + * if used compined with show_cars set to false, it will work as intended. Replace window do it like that + * this was a big hack even before show_outdated was added. Stupid newgrf :p */ +static void train_engine_drawing_loop(int *x, int *y, int *pos, int *sel, int *selected_id, byte railtype, + uint8 lines_drawn, bool is_engine, bool show_cars, bool show_outdated) +{ + int i; + byte colour; + + for (i = 0; i < NUM_TRAIN_ENGINES; i++) { + const Engine *e = DEREF_ENGINE(i); + const RailVehicleInfo *rvi = RailVehInfo(i); + const EngineInfo *info = &_engine_info[i]; + + if ( rvi->power == 0 && !(show_cars) ) // disables display of cars (works since they do not have power) + continue; + + if (*sel == 0) *selected_id = i; + + + colour = *sel == 0 ? 0xC : 0x10; + if (!(ENGINE_AVAILABLE && show_outdated && RailVehInfo(i)->power && e->railtype == railtype)) { + if (e->railtype != railtype || !(rvi->flags & RVI_WAGON) != is_engine || + !HASBIT(e->player_avail, _local_player)) + continue; + } /*else { + // TODO find a nice red colour for vehicles being replaced + if ( _autoreplace_array[i] != i ) + colour = *sel == 0 ? 0x44 : 0x45; + } */ + + if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) { + DrawString(*x + 59, *y + 2, GetCustomEngineName(i), + colour); + DrawTrainEngine(*x + 29, *y + 6, i, + SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + *y += 14; + } + --*sel; + } +} + + +static void SetupScrollStuffForReplaceWindow(Window *w) +{ + byte railtype; + int selected_id[2] = {-1,-1}; + int sel[2] = { WP(w,replaceveh_d).sel_index[0], WP(w,replaceveh_d).sel_index[1]}; + int count = 0; + int count2 = 0; + int engine_id; + + switch (WP(w,replaceveh_d).vehicletype) { + case VEH_Train: { + railtype = WP(w,replaceveh_d).railtype; + for (engine_id = 0; engine_id < NUM_TRAIN_ENGINES; engine_id++) { + const Engine *e = DEREF_ENGINE(engine_id); + const EngineInfo *info = &_engine_info[engine_id]; + + if (ENGINE_AVAILABLE && RailVehInfo(engine_id)->power && e->railtype == railtype) { + count++; + if (sel[0]==0) selected_id[0] = engine_id; + sel[0]--; + if (HASBIT(e->player_avail, _local_player)) { + if (sel[1]==0) selected_id[1] = engine_id; + count2++; + sel[1]--; + } + } + } + break; + } + case VEH_Road: { + int num = NUM_ROAD_ENGINES; + Engine *e = &_engines[ROAD_ENGINES_INDEX]; + byte cargo; + EngineInfo *info; + engine_id = ROAD_ENGINES_INDEX; + + do { + info = &_engine_info[engine_id]; + if (ENGINE_AVAILABLE) { + if (sel[0]==0) selected_id[0] = engine_id; + count++; + sel[0]--; + } + } while (++engine_id,++e,--num); + + if ( selected_id[0] != -1 ) { // only draw right array if we have anything in the left one + num = NUM_ROAD_ENGINES; + engine_id = ROAD_ENGINES_INDEX; + e = &_engines[ROAD_ENGINES_INDEX]; + cargo = RoadVehInfo(selected_id[0])->cargo_type; + + do { + if ( cargo == RoadVehInfo(engine_id)->cargo_type && HASBIT(e->player_avail, _local_player)) { + count2++; + if (sel[1]==0) selected_id[1] = engine_id; + sel[1]--; + } + } while (++engine_id,++e,--num); + } + break; + } + + case VEH_Ship: { + int num = NUM_SHIP_ENGINES; + Engine *e = &_engines[SHIP_ENGINES_INDEX]; + byte cargo; + EngineInfo *info; + engine_id = SHIP_ENGINES_INDEX; + byte refittable; + + do { + info = &_engine_info[engine_id]; + if (ENGINE_AVAILABLE) { + if ( sel[0] == 0 ) selected_id[0] = engine_id; + count++; + sel[0]--; + } + } while (++engine_id,++e,--num); + + if ( selected_id[0] != -1 ) { + num = NUM_SHIP_ENGINES; + e = &_engines[SHIP_ENGINES_INDEX]; + engine_id = SHIP_ENGINES_INDEX; + cargo = ShipVehInfo(selected_id[0])->cargo_type; + refittable = ShipVehInfo(selected_id[0])->refittable; + + do { + if (HASBIT(e->player_avail, _local_player) + && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) { + + if ( sel[1]==0) selected_id[1] = engine_id; + sel[1]--; + count2++; + } + } while (++engine_id,++e,--num); + } + break; + } //end of ship + + case VEH_Aircraft:{ + int num = NUM_AIRCRAFT_ENGINES; + Engine *e = &_engines[AIRCRAFT_ENGINES_INDEX]; + EngineInfo *info; + engine_id = AIRCRAFT_ENGINES_INDEX; + byte subtype; + + do { + info = &_engine_info[engine_id]; + if (ENGINE_AVAILABLE) { + count++; + if (sel[0]==0) selected_id[0] = engine_id; + sel[0]--; + } + } while (++engine_id,++e,--num); + + if ( selected_id[0] != -1 ) { + num = NUM_AIRCRAFT_ENGINES; + e = &_engines[AIRCRAFT_ENGINES_INDEX]; + subtype = AircraftVehInfo(selected_id[0])->subtype; + engine_id = AIRCRAFT_ENGINES_INDEX; + do { + if (HASBIT(e->player_avail, _local_player)) { + if ( (subtype && AircraftVehInfo(engine_id)->subtype) || (!(subtype) && !AircraftVehInfo(engine_id)->subtype) ) { + count2++; + if (sel[1]==0) selected_id[1] = engine_id; + sel[1]--; + } + } + } while (++engine_id,++e,--num); + } + break; + } + } + // sets up the number of items in each list + SetVScrollCount(w, count); + SetVScroll2Count(w, count2); + WP(w,replaceveh_d).sel_engine[0] = selected_id[0]; + WP(w,replaceveh_d).sel_engine[1] = selected_id[1]; + + WP(w,replaceveh_d).count[0] = count; + WP(w,replaceveh_d).count[1] = count2; + return; +} + + +static void DrawEngineArrayInReplaceWindow(Window *w, int x, int y, int x2, int y2, int pos, int pos2, + int sel1, int sel2, int selected_id1, int selected_id2) +{ + int sel[2] = {sel1, sel2}; + int selected_id[2] = {selected_id1, selected_id2}; + switch (WP(w,replaceveh_d).vehicletype) { + case VEH_Train: { + byte railtype = WP(w,replaceveh_d).railtype; + DrawString(157, 89 + (14 * w->vscroll.cap), _rail_types_list[railtype], 0x10); + /* draw sorting criteria string */ + + /* Ensure that custom engines which substituted wagons + * are sorted correctly. + * XXX - DO NOT EVER DO THIS EVER AGAIN! GRRR hacking in wagons as + * engines to get more types.. Stays here until we have our own format + * then it is exit!!! */ + train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, true, false, true); // True engines + train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, true, false, false); // True engines + train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, false, false); // Feeble wagons + break; + } + + case VEH_Road: { + int num = NUM_ROAD_ENGINES; + Engine *e = &_engines[ROAD_ENGINES_INDEX]; + int engine_id = ROAD_ENGINES_INDEX; + byte cargo; + EngineInfo *info; + + if ( selected_id[0] >= ROAD_ENGINES_INDEX && selected_id[0] <= SHIP_ENGINES_INDEX ) + cargo = RoadVehInfo(selected_id[0])->cargo_type; + + do { + info = &_engine_info[engine_id]; + if (ENGINE_AVAILABLE) { + if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { + DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); + DrawRoadVehEngine(x+29, y+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + y += 14; + } + + if ( RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player) ) { + if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) { + DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10); + DrawRoadVehEngine(x2+29, y2+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + y2 += 14; + } + sel[1]--; + } + sel[0]--; + } + } while (++engine_id, ++e,--num); + + break; + } + + case VEH_Ship: { + int num = NUM_SHIP_ENGINES; + Engine *e = &_engines[SHIP_ENGINES_INDEX]; + int engine_id = SHIP_ENGINES_INDEX; + byte cargo, refittable; + EngineInfo *info; + + if ( selected_id[0] != -1 ) { + cargo = ShipVehInfo(selected_id[0])->cargo_type; + refittable = ShipVehInfo(selected_id[0])->refittable; + } + + do { + info = &_engine_info[engine_id]; + if (ENGINE_AVAILABLE) { + if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { + DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); + DrawShipEngine(x+35, y+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + y += 24; + } + if ( selected_id[0] != -1 ) { + if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) { + if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) { + DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10); + DrawShipEngine(x2+35, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + y2 += 24; + } + sel[1]--; + } + } + sel[0]--; + } + } while (++engine_id, ++e,--num); + break; + } //end of ship + + case VEH_Aircraft: { + if ( selected_id[0] != -1 ) { + int num = NUM_AIRCRAFT_ENGINES; + Engine *e = &_engines[AIRCRAFT_ENGINES_INDEX]; + int engine_id = AIRCRAFT_ENGINES_INDEX; + byte subtype = AircraftVehInfo(selected_id[0])->subtype; + EngineInfo *info; + + do { + info = &_engine_info[engine_id]; + if (ENGINE_AVAILABLE) { + if (sel[0]==0) selected_id[0] = engine_id; + if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { + DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); + DrawAircraftEngine(x+29, y+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + y += 24; + } + if ( ((subtype && AircraftVehInfo(engine_id)->subtype) || (!(subtype) && !AircraftVehInfo(engine_id)->subtype)) + && HASBIT(e->player_avail, _local_player) ) { + if (sel[1]==0) selected_id[1] = engine_id; + if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) { + DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10); + DrawAircraftEngine(x2+29, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player))); + y2 += 24; + } + sel[1]--; + } + sel[0]--; + } + } while (++engine_id, ++e,--num); + } + break; + } // end of aircraft + } + +} +static void ReplaceVehicleWndProc(Window *w, WindowEvent *e) +{ + // these 3 variables is used if any of the lists is clicked + uint16 click_scroll_pos = w->vscroll2.pos; + uint16 click_scroll_cap = w->vscroll2.cap; + byte click_side = 1; + + switch(e->event) { + case WE_PAINT: + { + int pos = w->vscroll.pos; + int selected_id[2] = {-1,-1}; + int x = 1; + int y = 15; + int pos2 = w->vscroll2.pos; + int x2 = 1 + 228; + int y2 = 15; + int sel[2] = { WP(w,replaceveh_d).sel_index[0], WP(w,replaceveh_d).sel_index[1]}; + + SetupScrollStuffForReplaceWindow(w); + + selected_id[0] = WP(w,replaceveh_d).sel_engine[0]; + selected_id[1] = WP(w,replaceveh_d).sel_engine[1]; + + // sets the selected left item to the top one if it's greater than the number of vehicles in the left side + + if ( WP(w,replaceveh_d).count[0] <= sel[0] ) { + if (WP(w,replaceveh_d).count[0]) { + sel[0] = 0; + WP(w,replaceveh_d).sel_index[0] = 0; + w->vscroll.pos = 0; + // now we go back to set selected_id[1] properly + SetWindowDirty(w); + return; + } else { //there are no vehicles in the left window + selected_id[1] = -1; + } + } + + if ( WP(w,replaceveh_d).count[1] <= sel[1] ) { + if (WP(w,replaceveh_d).count[1]) { + sel[1] = 0; + WP(w,replaceveh_d).sel_index[1] = 0; + w->vscroll2.pos = 0; + // now we go back to set selected_id[1] properly + SetWindowDirty(w); + return; + } else { //there are no vehicles in the right window + selected_id[1] = -1; + } + } + + if ( selected_id[0] == selected_id[1] || _autoreplace_array[selected_id[0]] == selected_id[1] + || selected_id[0] == -1 || selected_id[1] == -1 ) + SETBIT(w->disabled_state, 4); + else + CLRBIT(w->disabled_state, 4); + + if ( _autoreplace_array[selected_id[0]] == selected_id[0] || selected_id[0] == -1 ) + SETBIT(w->disabled_state, 6); + else + CLRBIT(w->disabled_state, 6); + + // now the actual drawing of the window itself takes place + DrawWindowWidgets(w); + + + + // sets up the string for the vehicle that is being replaced to + if ( selected_id[0] != -1 ) { + if ( selected_id[0] == _autoreplace_array[selected_id[0]] ) + SetDParam(0, STR_NOT_REPLACING); + else + SetDParam(0, GetCustomEngineName(_autoreplace_array[selected_id[0]])); + } else { + SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED); + } + + + DrawString(145, (WP(w,replaceveh_d).line_height == 24 ? 67 : 77 ) + ( WP(w,replaceveh_d).line_height * w->vscroll.cap), STR_02BD, 0x10); + + + /* now we draw the two arrays according to what we just counted */ + DrawEngineArrayInReplaceWindow(w, x, y, x2, y2, pos, pos2, sel[0], sel[1], selected_id[0], selected_id[1]); + + WP(w,replaceveh_d).sel_engine[0] = selected_id[0]; + WP(w,replaceveh_d).sel_engine[1] = selected_id[1]; + /* now we draw the info about the vehicles we selected */ + switch (WP(w,replaceveh_d).vehicletype) { + case VEH_Train: { + byte i = 0; + int offset = 0; + + for ( i = 0 ; i < 2 ; i++) { + if ( i ) + offset = 228; + if (selected_id[i] != -1) { + if (!(RailVehInfo(selected_id[i])->flags & RVI_WAGON)) { + /* it's an engine */ + Set_DPARAM_Train_Engine_Build_Window(selected_id[i]); + DrawString(2 + offset, 15 + (14 * w->vscroll.cap), STR_8817_COST_WEIGHT_T_SPEED_POWER, 0); + } else { + /* it's a wagon. Train cars are not replaced with the current GUI, but this code is ready for newgrf if anybody adds that*/ + Set_DPARAM_Train_Car_Build_Window(w, selected_id[i]); + DrawString(2 + offset, 15 + (14 * w->vscroll.cap), STR_8821_COST_WEIGHT_T_T_CAPACITY, 0); + } + } + } + break; + } //end if case VEH_Train + + case VEH_Road: { + if (selected_id[0] != -1) { + Set_DPARAM_Road_Veh_Build_Window(selected_id[0]); + DrawString(2, 15 + (14 * w->vscroll.cap), STR_9008_COST_SPEED_RUNNING_COST, 0); + if (selected_id[1] != -1) { + Set_DPARAM_Road_Veh_Build_Window(selected_id[1]); + DrawString(2 + 228, 15 + (14 * w->vscroll.cap), STR_9008_COST_SPEED_RUNNING_COST, 0); + } + } + break; + } // end of VEH_Road + + case VEH_Ship: { + if (selected_id[0] != -1) { + Set_DPARAM_Ship_Build_Window(selected_id[0]); + DrawString(2, 15 + (24 * w->vscroll.cap), STR_980A_COST_SPEED_CAPACITY_RUNNING, 0); + if (selected_id[1] != -1) { + Set_DPARAM_Ship_Build_Window(selected_id[1]); + DrawString(2 + 228, 15 + (24 * w->vscroll.cap), STR_980A_COST_SPEED_CAPACITY_RUNNING, 0); + } + } + break; + } // end of VEH_Ship + + case VEH_Aircraft: { + if (selected_id[0] != -1) { + Set_DPARAM_Aircraft_Build_Window(selected_id[0]); + DrawString(2, 15 + (24 * w->vscroll.cap), STR_A007_COST_SPEED_CAPACITY_PASSENGERS, 0); + if (selected_id[1] != -1) { + Set_DPARAM_Aircraft_Build_Window(selected_id[1]); + DrawString(2 + 228, 15 + (24 * w->vscroll.cap), STR_A007_COST_SPEED_CAPACITY_PASSENGERS, 0); + } + } + break; + } // end of VEH_Aircraft + } + } // end of paint + + case WE_CLICK: { + switch(e->click.widget) { + /*case 0: + DeleteWindowById(WC_REPLACE_VEHICLE, WP(w,replaceveh_d).vehicletype ); + break;*/ + + case 14: case 15:/* Select sorting criteria dropdown menu */ + // finds mask for available engines + { + int engine_avail = 0; + if ( !(HASBIT(_engines[NUM_NORMAL_RAIL_ENGINES + NUM_MONORAIL_ENGINES].player_avail, _local_player))) { + engine_avail = 4; + if ( !(HASBIT(_engines[NUM_NORMAL_RAIL_ENGINES].player_avail, _local_player))) + engine_avail = 6; + } + ShowDropDownMenu(w, _rail_types_list, WP(w,replaceveh_d).railtype, 15, engine_avail, 1); + return; + } + case 4: { + _autoreplace_array[WP(w,replaceveh_d).sel_engine[0]] = WP(w,replaceveh_d).sel_engine[1]; + SetWindowDirty(w); + break; + } + + case 6: { + _autoreplace_array[WP(w,replaceveh_d).sel_engine[0]] = WP(w,replaceveh_d).sel_engine[0]; + SetWindowDirty(w); + break; + } + + case 7: + // sets up that the left one was clicked. The default values are for the right one (9) + // this way, the code for 9 handles both sides + click_scroll_pos = w->vscroll.pos; + click_scroll_cap = w->vscroll.cap; + click_side = 0; + case 9: { + uint i = (e->click.pt.y - 14) / WP(w,replaceveh_d).line_height; + if (i < click_scroll_cap) { + WP(w,replaceveh_d).sel_index[click_side] = i + click_scroll_pos; + SetWindowDirty(w); + } + } break; + } + + } break; + + case WE_DROPDOWN_SELECT: { /* we have selected a dropdown item in the list */ + //potiential bug: railtypes needs to be activated 0, 1, 2... If one is skipped, it messes up + WP(w,replaceveh_d).railtype = e->dropdown.index; + SetWindowDirty(w); + break; + } + } +} + +static const Widget _replace_rail_vehicle_widgets[] = { +{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, 14, 11, 443, 0, 13, STR_REPLACE_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_STICKYBOX, 14, 444, 455, 0, 13, 0x0, STR_STICKY_BUTTON}, +{ WWT_PANEL, 14, 0, 227, 126, 187, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 0, 138, 200, 211, STR_REPLACE_VEHICLES_START,STR_REPLACE_HELP_START_BUTTON}, +{ WWT_PANEL, 14, 139, 316, 188, 199, 0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB}, +{ WWT_PUSHTXTBTN, 14, 317, 455, 200, 211, STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON}, +{ WWT_MATRIX, 14, 0, 216, 14, 125, 0x801, STR_REPLACE_HELP_LEFT_ARRAY}, +{ WWT_SCROLLBAR, 14, 217, 227, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_MATRIX, 14, 228, 455, 14, 125, 0x801, STR_REPLACE_HELP_RIGHT_ARRAY}, +{ WWT_SCROLL2BAR, 14, 445, 455, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_PANEL, 14, 228, 455, 126, 187, 0x0, STR_NULL}, +// the rest are train specific stuff +{ WWT_PANEL, 14, 0, 138, 188, 199, 0x0, STR_NULL}, +{ WWT_PANEL, 3, 139, 153, 200, 211, 0x0, STR_NULL}, +{ WWT_PANEL, 14, 154, 290, 200, 211, 0x0, STR_REPLACE_HELP_RAILTYPE}, +{ WWT_CLOSEBOX, 14, 291, 301, 200, 210, STR_0225, STR_REPLACE_HELP_RAILTYPE}, +{ WWT_PANEL, 3, 301, 316, 200, 211, 0x0, STR_NULL}, +{ WWT_PANEL, 14, 317, 455, 188, 199, 0x0, STR_NULL}, + +{ WIDGETS_END}, +}; + +static const Widget _replace_road_vehicle_widgets[] = { +{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, 14, 11, 443, 0, 13, STR_REPLACE_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_STICKYBOX, 14, 444, 455, 0, 13, 0x0, STR_STICKY_BUTTON}, +{ WWT_PANEL, 14, 0, 227, 126, 187, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 0, 138, 188, 199, STR_REPLACE_VEHICLES_START,STR_REPLACE_HELP_START_BUTTON}, +{ WWT_PANEL, 14, 139, 316, 188, 199, 0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB}, +{ WWT_PUSHTXTBTN, 14, 317, 455, 188, 199, STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON}, +{ WWT_MATRIX, 14, 0, 216, 14, 125, 0x801, STR_REPLACE_HELP_LEFT_ARRAY}, +{ WWT_SCROLLBAR, 14, 217, 227, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_MATRIX, 14, 228, 455, 14, 125, 0x801, STR_REPLACE_HELP_RIGHT_ARRAY}, +{ WWT_SCROLL2BAR, 14, 445, 455, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_PANEL, 14, 228, 455, 126, 187, 0x0, STR_NULL}, +{ WIDGETS_END}, +}; + +static const Widget _replace_ship_aircraft_vehicle_widgets[] = { +{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, 14, 11, 443, 0, 13, STR_REPLACE_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_STICKYBOX, 14, 444, 455, 0, 13, 0x0, STR_STICKY_BUTTON}, +{ WWT_PANEL, 14, 0, 227, 110, 161, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, 14, 0, 138, 162, 173, STR_REPLACE_VEHICLES_START,STR_REPLACE_HELP_START_BUTTON}, +{ WWT_PANEL, 14, 139, 316, 162, 173, 0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB}, +{ WWT_PUSHTXTBTN, 14, 317, 455, 162, 173, STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON}, +{ WWT_MATRIX, 14, 0, 216, 14, 109, 0x401, STR_REPLACE_HELP_LEFT_ARRAY}, +{ WWT_SCROLLBAR, 14, 217, 227, 14, 109, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_MATRIX, 14, 228, 455, 14, 109, 0x401, STR_REPLACE_HELP_RIGHT_ARRAY}, +{ WWT_SCROLL2BAR, 14, 445, 455, 14, 109, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_PANEL, 14, 228, 455, 110, 161, 0x0, STR_NULL}, +{ WIDGETS_END}, +}; + +static const WindowDesc _replace_rail_vehicle_desc = { + -1, -1, 456, 212, + WC_REPLACE_VEHICLE,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON, + _replace_rail_vehicle_widgets, + ReplaceVehicleWndProc +}; + +static const WindowDesc _replace_road_vehicle_desc = { + -1, -1, 456, 200, + WC_REPLACE_VEHICLE,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON, + _replace_road_vehicle_widgets, + ReplaceVehicleWndProc +}; + +static const WindowDesc _replace_ship_aircraft_vehicle_desc = { + -1, -1, 456, 174, + WC_REPLACE_VEHICLE,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON, + _replace_ship_aircraft_vehicle_widgets, + ReplaceVehicleWndProc +}; + + +void ShowReplaceVehicleWindow(byte vehicletype) +{ + Window *w; + + DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype ); + + switch (vehicletype) { + case VEH_Train: + w = AllocateWindowDescFront(&_replace_rail_vehicle_desc, vehicletype); + w->vscroll.cap = 8; + WP(w,replaceveh_d).line_height = 14; + break; + case VEH_Road: + w = AllocateWindowDescFront(&_replace_road_vehicle_desc, vehicletype); + w->vscroll.cap = 8; + WP(w,replaceveh_d).line_height = 14; + break; + case VEH_Ship: case VEH_Aircraft: + w = AllocateWindowDescFront(&_replace_ship_aircraft_vehicle_desc, vehicletype); + w->vscroll.cap = 4; + WP(w,replaceveh_d).line_height = 24; + break; + } + WP(w,replaceveh_d).vehicletype = vehicletype; + w->vscroll2.cap = w->vscroll.cap; // these two are always the same +} diff --git a/vehicle_gui.h b/vehicle_gui.h index 9339d4647..46747d6bf 100644 --- a/vehicle_gui.h +++ b/vehicle_gui.h @@ -42,12 +42,13 @@ typedef DEF_SORTER(VehicleSortListingTypeFunctions); #define SORT_BY_UNSORTED 0 extern VehicleSortListingTypeFunctions * const _vehicle_sorter[]; extern const StringID _vehicle_sort_listing[]; +extern const StringID _rail_types_list[]; enum VehicleSortTypes { VEHTRAIN = 0, VEHROAD = 1, VEHSHIP = 2, - VEHAIRCRAFT = 3 + VEHAIRCRAFT = 3 }; enum { @@ -56,4 +57,13 @@ enum { PLY_WND_PRC__SIZE_OF_ROW_BIG = 36, }; +void ShowReplaceVehicleWindow(byte vehicletype); + +void Set_DPARAM_Train_Engine_Build_Window(uint16 engine_number); +void Set_DPARAM_Train_Car_Build_Window(Window *w, uint16 engine_number); +void Set_DPARAM_Road_Veh_Build_Window(uint16 engine_number); +void Set_DPARAM_Aircraft_Build_Window(uint16 engine_number); +void Set_DPARAM_Ship_Build_Window(uint16 engine_number); + + #endif /* VEHICLE_GUI_H */ @@ -46,23 +46,37 @@ void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y) int mi, ma, pos; Scrollbar *sb; - if (wi->type == WWT_SCROLLBAR) { - // vertical scroller - w->flags4 &= ~WF_HSCROLL; - mi = wi->top; - ma = wi->bottom; - pos = y; - sb = &w->vscroll; - } else { - // horizontal scroller - assert(wi->type == WWT_HSCROLLBAR); - w->flags4 |= WF_HSCROLL; - mi = wi->left; - ma = wi->right; - pos = x; - sb = &w->hscroll; + switch (wi->type) { + case WWT_SCROLLBAR: { + // vertical scroller + w->flags4 &= ~WF_HSCROLL; + w->flags4 &= ~WF_SCROLL2; + mi = wi->top; + ma = wi->bottom; + pos = y; + sb = &w->vscroll; + break; + } + case WWT_SCROLL2BAR: { + // 2nd vertical scroller + w->flags4 &= ~WF_HSCROLL; + w->flags4 |= WF_SCROLL2; + mi = wi->top; + ma = wi->bottom; + pos = y; + sb = &w->vscroll2; + break; + } + case WWT_HSCROLLBAR: { + // horizontal scroller + assert(wi->type == WWT_HSCROLLBAR); + w->flags4 |= WF_HSCROLL; + mi = wi->left; + ma = wi->right; + pos = x; + sb = &w->hscroll; + } } - if (pos <= mi+9) { // Pressing the upper button? if (!_demo_mode) { @@ -258,8 +272,8 @@ void DrawWindowWidgets(Window *w) int c1,c2; // draw up/down buttons - DrawFrameRect(r.left, r.top, r.right, r.top+9, wi->color, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == WF_SCROLL_UP ? 0x20 : 0); - DrawFrameRect(r.left, r.bottom-9, r.right, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == WF_SCROLL_DOWN ? 0x20 : 0); + DrawFrameRect(r.left, r.top, r.right, r.top+9, wi->color, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP ? 0x20 : 0); + DrawFrameRect(r.left, r.bottom-9, r.right, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN ? 0x20 : 0); // draw icons in up/down buttons DoDrawString("\xA0", r.left+2, r.top, 0x10); @@ -279,7 +293,36 @@ void DrawWindowWidgets(Window *w) GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2); pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom); - DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == WF_SCROLL_MIDDLE ? 0x20 : 0); + DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? 0x20 : 0); + break; + } + case WWT_SCROLL2BAR: { + Point pt; + int c1,c2; + + // draw up/down buttons + DrawFrameRect(r.left, r.top, r.right, r.top+9, wi->color, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2) ? 0x20 : 0); + DrawFrameRect(r.left, r.bottom-9, r.right, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2) ? 0x20 : 0); + + // draw icons in up/down buttons + DoDrawString("\xA0", r.left+2, r.top, 0x10); + DoDrawString("\xAA", r.left+2, r.bottom-9, 0x10); + + c1 = _color_list[wi->color&0xF].window_color_1a; + c2 = _color_list[wi->color&0xF].window_color_2; + + // draw "shaded" background + GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2); + GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | 0x8000); + + // draw shaded lines + GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1); + GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2); + GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1); + GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2); + + pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom); + DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? 0x20 : 0); break; } @@ -383,6 +426,7 @@ draw_default:; static uint _dropdown_item_count; static uint32 _dropdown_disabled; +static bool _dropdown_hide_disabled; static const StringID *_dropdown_items; static int _dropdown_selindex; static byte _dropdown_button; @@ -421,95 +465,100 @@ void DropdownMenuWndProc(Window *w, WindowEvent *e) int item; switch(e->event) { - case WE_PAINT: { - int x,y,i,sel; - uint32 dis; - - DrawWindowWidgets(w); - - x = 1; - y = 2; - sel = _dropdown_selindex; - dis = _dropdown_disabled; + case WE_PAINT: { + int x,y,i,sel; + uint32 dis; + bool hidden; + + DrawWindowWidgets(w); + + x = 1; + y = 2; + sel = _dropdown_selindex; + dis = _dropdown_disabled; + hidden = _dropdown_hide_disabled; + - for(i=0; _dropdown_items[i] != INVALID_STRING_ID; i++) { - if (_dropdown_items[i] != 0) { - if (sel == 0) { - GfxFillRect(x+1, y, x+w->width-4, y + 9, 0); + for(i=0; _dropdown_items[i] != INVALID_STRING_ID; i++) { + if (!(hidden) | !(dis & 1)) { + if (_dropdown_items[i] != 0) { + if (sel == 0) { + GfxFillRect(x+1, y, x+w->width-4, y + 9, 0); + } + DrawString(x+2, y, _dropdown_items[i], sel==0 ? 12 : 16); + + if (dis & 1) { + GfxFillRect(x, y, x+w->width-3, y + 9, 0x8000 + + _color_list[_dropdown_menu_widgets[0].color].window_color_bga); + } + } else { + int color_1 = _color_list[_dropdown_menu_widgets[0].color].window_color_1a; + int color_2 = _color_list[_dropdown_menu_widgets[0].color].window_color_2; + GfxFillRect(x+1, y+3, x+w->width-5, y+3, color_1); + GfxFillRect(x+1, y+4, x+w->width-5, y+4, color_2); + } + y += 10; + sel--; } - DrawString(x+2, y, _dropdown_items[i], sel==0 ? 12 : 16); + dis>>=1; + } + } break; - if (dis & 1) { - GfxFillRect(x, y, x+w->width-3, y + 9, 0x8000 + - _color_list[_dropdown_menu_widgets[0].color].window_color_bga); - } - } else { - int color_1 = _color_list[_dropdown_menu_widgets[0].color].window_color_1a; - int color_2 = _color_list[_dropdown_menu_widgets[0].color].window_color_2; - GfxFillRect(x+1, y+3, x+w->width-5, y+3, color_1); - GfxFillRect(x+1, y+4, x+w->width-5, y+4, color_2); + case WE_CLICK: { + item = GetDropdownItem(w); + if (item >= 0) { + _dropdown_var1 = 4; + _dropdown_selindex = item; + SetWindowDirty(w); } - y += 10; - sel--; - dis>>=1; - } - } break; - - case WE_CLICK: { - item = GetDropdownItem(w); - if (item >= 0) { - _dropdown_var1 = 4; - _dropdown_selindex = item; - SetWindowDirty(w); - } - } break; + } break; - case WE_MOUSELOOP: { - Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum); - if (w2 == NULL) { - DeleteWindow(w); - return; - } + case WE_MOUSELOOP: { + Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum); + if (w2 == NULL) { + DeleteWindow(w); + return; + } - if (_dropdown_var1 != 0 && --_dropdown_var1 == 0) { - WindowEvent e; - e.event = WE_DROPDOWN_SELECT; - e.dropdown.button = _dropdown_button; - e.dropdown.index = _dropdown_selindex; - w2->wndproc(w2, &e); - DeleteWindow(w); - return; - } + if (_dropdown_var1 != 0 && --_dropdown_var1 == 0) { + WindowEvent e; + e.event = WE_DROPDOWN_SELECT; + e.dropdown.button = _dropdown_button; + e.dropdown.index = _dropdown_selindex; + w2->wndproc(w2, &e); + DeleteWindow(w); + return; + } - if (_dropdown_var2 != 0) { - item = GetDropdownItem(w); + if (_dropdown_var2 != 0) { + item = GetDropdownItem(w); + + if (!_left_button_clicked) { + _dropdown_var2 = 0; + if (item < 0) + return; + _dropdown_var1 = 2; + } else { + if (item < 0) + return; + } - if (!_left_button_clicked) { - _dropdown_var2 = 0; - if (item < 0) - return; - _dropdown_var1 = 2; - } else { - if (item < 0) - return; + _dropdown_selindex = item; + SetWindowDirty(w); } + } break; - _dropdown_selindex = item; - SetWindowDirty(w); - } - } break; - - case WE_DESTROY: { - Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum); - if (w2 != NULL) { - CLRBIT(w2->click_state, _dropdown_button); - InvalidateWidget(w2, _dropdown_button); - } - } break; + case WE_DESTROY: { + Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum); + if (w2 != NULL) { + CLRBIT(w2->click_state, _dropdown_button); + InvalidateWidget(w2, _dropdown_button); + } + } break; } } -void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask) +void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, bool remove_filtered_strings) { WindowNumber num; WindowClass cls; @@ -519,6 +568,7 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt uint32 old_click_state = w->click_state; _dropdown_disabled = disabled_mask; + _dropdown_hide_disabled = remove_filtered_strings; cls = w->window_class; num = w->window_number; @@ -549,6 +599,16 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt wi = &w->widget[button]; + if ( remove_filtered_strings ) { + int j; + for(j=0; _dropdown_items[j] != INVALID_STRING_ID; j++) { + if ( disabled_mask & ( 1 << j )) { + _dropdown_item_count--; + i--; + } + } + } + _dropdown_menu_widgets[0].color = wi->color; w2 = AllocateWindow( @@ -44,7 +44,7 @@ void DispatchLeftClickEvent(Window *w, int x, int y) { case WWT_NODISTXTBTN: break; } - } else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_HSCROLLBAR) { + } else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) { ScrollbarClickHandler(w, wi, e.click.pt.x, e.click.pt.y); } @@ -953,6 +953,9 @@ static bool HandleScrollbarScrolling() if (w->flags4 & WF_HSCROLL) { sb = &w->hscroll; i = _cursor.pos.x - _cursorpos_drag_start.x; + } else if (w->flags4 & WF_SCROLL2){ + sb = &w->vscroll2; + i = _cursor.pos.y - _cursorpos_drag_start.y; } else { sb = &w->vscroll; i = _cursor.pos.y - _cursorpos_drag_start.y; @@ -200,7 +200,7 @@ struct Window { int left,top; int width,height; - Scrollbar hscroll, vscroll; + Scrollbar hscroll, vscroll, vscroll2; byte caption_color; @@ -255,6 +255,15 @@ typedef struct { } buildtrain_d; typedef struct { + byte railtype; + byte vehicletype; + byte sel_index[2]; + int16 sel_engine[2]; + uint16 count[2]; + byte line_height; +} replaceveh_d; + +typedef struct { VehicleID sel; } traindepot_d; @@ -358,7 +367,8 @@ enum WindowWidgetTypes { WWT_HSCROLLBAR = 11, WWT_STICKYBOX = 12, - WWT_LAST = 13, /* Last Item. use WIDGETS_END to fill up padding!! */ + WWT_SCROLL2BAR = 13, /* 2nd vertical scrollbar*/ + WWT_LAST = 14, /* Last Item. use WIDGETS_END to fill up padding!! */ WWT_MASK = 31, @@ -384,6 +394,7 @@ enum WindowFlags { WF_WHITE_BORDER_ONE = 1 << 11, WF_WHITE_BORDER_MASK = 3 << 11, + WF_SCROLL2 = 1 << 13, }; @@ -453,7 +464,7 @@ int PositionMainToolbar(Window *w); /* widget.c */ int GetWidgetFromPos(Window *w, int x, int y); void DrawWindowWidgets(Window *w); -void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask); +void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, bool remove_filtered_strings); void HandleButtonClick(Window *w, byte widget); |