diff --git a/command.c b/command.c index f1f3c821c8..fc6ef7329e 100644 --- a/command.c +++ b/command.c @@ -160,6 +160,7 @@ DEF_COMMAND(CmdReplaceVehicle); DEF_COMMAND(CmdCloneVehicle); DEF_COMMAND(CmdMassStartStopVehicle); +DEF_COMMAND(CmdDepotSellAllVehicles); /* The master command table */ @@ -305,6 +306,7 @@ static const Command _command_proc_table[] = { {CmdReplaceVehicle, 0}, /* 115 */ {CmdCloneVehicle, 0}, /* 116 */ {CmdMassStartStopVehicle, 0}, /* 117 */ + {CmdDepotSellAllVehicles, 0}, /* 118 */ }; /* This function range-checks a cmd, and checks if the cmd is not NULL */ diff --git a/command.h b/command.h index b1d6a70d71..35eced22b9 100644 --- a/command.h +++ b/command.h @@ -137,6 +137,7 @@ enum { CMD_CLONE_VEHICLE = 116, CMD_MASS_START_STOP = 117, + CMD_DEPOT_SELL_ALL_VEHICLES = 118, }; diff --git a/depot_gui.c b/depot_gui.c index 8e279866bf..609c7b1819 100644 --- a/depot_gui.c +++ b/depot_gui.c @@ -50,6 +50,7 @@ typedef enum DepotWindowWidgets { DEPOT_WIDGET_STOP_ALL, DEPOT_WIDGET_START_ALL, DEPOT_WIDGET_SELL, + DEPOT_WIDGET_SELL_CHAIN, DEPOT_WIDGET_SELL_ALL, DEPOT_WIDGET_MATRIX, DEPOT_WIDGET_V_SCROLL, // Vertical scrollbar @@ -69,7 +70,8 @@ static const byte widget_moves[] = { DEPOT_MOVE_RIGHT, // DEPOT_WIDGET_STOP_ALL DEPOT_MOVE_RIGHT, // DEPOT_WIDGET_START_ALL DEPOT_MOVE_RIGHT, // DEPOT_WIDGET_SELL - DEPOT_MOVE_NONE, // DEPOT_WIDGET_SELL_ALL + DEPOT_MOVE_NONE, // DEPOT_WIDGET_SELL_CHAIN + DEPOT_MOVE_DOWN_RIGHT, // DEPOT_WIDGET_SELL_ALL DEPOT_STRETCH_DOWN_RIGHT, // DEPOT_WIDGET_MATRIX DEPOT_MOVE_RIGHT_STRETCH_DOWN, // DEPOT_WIDGET_V_SCROLL DEPOT_MOVE_NONE, // DEPOT_WIDGET_H_SCROLL @@ -96,20 +98,21 @@ static const Widget _depot_widgets[] = { { WWT_PUSHIMGBTN, RESIZE_LR, 14, 270, 280, 14, 25, SPR_FLAG_VEH_STOPPED,STR_MASS_STOP_DEPOT_TOOLTIP}, // DEPOT_WIDGET_STOP_ALL { WWT_PUSHIMGBTN, RESIZE_LR, 14, 281, 292, 14, 25, SPR_FLAG_VEH_RUNNING,STR_MASS_START_DEPOT_TOOLTIP}, // DEPOT_WIDGET_START_ALL - { WWT_IMGBTN, RESIZE_LRB, 14, 270, 292, 26, 61, 0x2A9, STR_NULL}, // DEPOT_WIDGET_SELL - { WWT_PANEL, RESIZE_LRTB, 14, 326, 348, 0, 0, 0x2BF, STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP}, // DEPOT_WIDGET_SELL_ALL, trains only + { WWT_IMGBTN, RESIZE_LRB, 14, 270, 292, 26, 60, 0x2A9, STR_NULL}, // DEPOT_WIDGET_SELL + { WWT_PANEL, RESIZE_LRTB, 14, 326, 348, 0, 0, 0x2BF, STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP}, // DEPOT_WIDGET_SELL_CHAIN, trains only + { WWT_PUSHIMGBTN, RESIZE_LRTB, 14, 270, 292, 61, 83, 0x0, STR_DEPOT_SELL_ALL_BUTTON_TIP}, // DEPOT_WIDGET_SELL_ALL - { WWT_MATRIX, RESIZE_RB, 14, 0, 269, 14, 61, 0x0, STR_NULL}, // DEPOT_WIDGET_MATRIX - { WWT_SCROLLBAR, RESIZE_LRB, 14, 293, 304, 14, 61, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DEPOT_WIDGET_V_SCROLL + { WWT_MATRIX, RESIZE_RB, 14, 0, 269, 14, 83, 0x0, STR_NULL}, // DEPOT_WIDGET_MATRIX + { WWT_SCROLLBAR, RESIZE_LRB, 14, 293, 304, 14, 83, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DEPOT_WIDGET_V_SCROLL { WWT_HSCROLLBAR, RESIZE_RTB, 14, 0, 325, 98, 109, 0x0, STR_HSCROLL_BAR_SCROLLS_LIST}, // DEPOT_WIDGET_H_SCROLL, trains only /* The buttons in the bottom of the window. left and right is not important as they are later resized to be equal in size * This calculation is based on right in DEPOT_WIDGET_LOCATION and it presumes left of DEPOT_WIDGET_BUILD is 0 */ - { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 96, 62, 73, 0x0, STR_NULL}, // DEPOT_WIDGET_BUILD - {WWT_NODISTXTBTN, RESIZE_TB, 14, 97, 194, 62, 73, 0x0, STR_NULL}, // DEPOT_WIDGET_CLONE - { WWT_PUSHTXTBTN, RESIZE_TB, 14, 195, 292, 62, 73, STR_00E4_LOCATION, STR_NULL}, // DEPOT_WIDGET_LOCATION - { WWT_RESIZEBOX, RESIZE_LRTB, 14, 293, 304, 62, 73, 0x0, STR_RESIZE_BUTTON}, // DEPOT_WIDGET_RESIZE + { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 96, 84, 95, 0x0, STR_NULL}, // DEPOT_WIDGET_BUILD + {WWT_NODISTXTBTN, RESIZE_TB, 14, 97, 194, 84, 95, 0x0, STR_NULL}, // DEPOT_WIDGET_CLONE + { WWT_PUSHTXTBTN, RESIZE_TB, 14, 195, 292, 84, 95, STR_00E4_LOCATION, STR_NULL}, // DEPOT_WIDGET_LOCATION + { WWT_RESIZEBOX, RESIZE_LRTB, 14, 293, 304, 84, 95, 0x0, STR_RESIZE_BUTTON}, // DEPOT_WIDGET_RESIZE { WIDGETS_END}, }; @@ -124,7 +127,7 @@ static const WindowDesc _train_depot_desc = { }; static const WindowDesc _road_depot_desc = { - -1, -1, 315, 68, + -1, -1, 315, 82, WC_VEHICLE_DEPOT,0, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, _depot_widgets, @@ -132,7 +135,7 @@ static const WindowDesc _road_depot_desc = { }; static const WindowDesc _ship_depot_desc = { - -1, -1, 305, 74, + -1, -1, 305, 96, WC_VEHICLE_DEPOT,0, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, _depot_widgets, @@ -140,7 +143,7 @@ static const WindowDesc _ship_depot_desc = { }; static const WindowDesc _aircraft_depot_desc = { - -1, -1, 331, 74, + -1, -1, 331, 96, WC_VEHICLE_DEPOT,0, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, _depot_widgets, @@ -171,6 +174,75 @@ static inline void ShowVehicleViewWindow(const Vehicle *v) } } +static void DepotSellAllWndProc(Window *w, WindowEvent *e) +{ + switch (e->event) { + case WE_PAINT: + if (WP(w, depot_d).type == VEH_Aircraft) { + SetDParam(0, GetStationIndex(w->window_number)); // Airport name + } else { + Depot *depot = GetDepotByTile(w->window_number); + assert(depot != NULL); + + SetDParam(0, depot->town_index); + } + DrawWindowWidgets(w); + + DrawStringCentered(150, 25, STR_DEPOT_SELL_ALL_VEHICLE_CONFIRM, 0); + DrawStringCentered(150, 38, STR_ARE_YOU_SURE, 0); + break; + + case WE_CLICK: + switch (e->we.click.widget) { + case 4: + DoCommandP(w->window_number, WP(w, depot_d).type, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES); + /* Fallthought */ + case 3: + DeleteWindow(w); + break; + } + break; + } +} + +static const Widget _depot_sell_all_widgets[] = { + { WWT_CLOSEBOX, RESIZE_NONE, 5, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, + { WWT_CAPTION, RESIZE_NONE, 5, 11, 299, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS}, + { WWT_PANEL, RESIZE_NONE, 5, 0, 299, 14, 71, 0x0, STR_NULL}, + { WWT_PUSHTXTBTN, RESIZE_NONE, 5, 85, 144, 52, 63, STR_012E_CANCEL, STR_DEPOT_SELL_ALL_CANCEL_TIP}, + { WWT_PUSHTXTBTN, RESIZE_NONE, 4, 155, 214, 52, 63, STR_SELL, STR_DEPOT_SELL_ALL_TIP}, + { WIDGETS_END}, +}; + +static const WindowDesc _depot_sell_all_desc = { + WDP_CENTER, WDP_CENTER, 300, 72, + WC_DEPOT_SELL_ALL,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, + _depot_sell_all_widgets, + DepotSellAllWndProc +}; + +static void ShowDepotSellAllWindow(TileIndex tile, byte type) +{ + Window *w; + + w = AllocateWindowDescFront(&_depot_sell_all_desc, tile); + + if (w != NULL) { + WP(w, depot_d).type = type; + switch (type) { + case VEH_Train: w->widget[1].data = STR_8800_TRAIN_DEPOT; break; + case VEH_Road: w->widget[1].data = STR_9003_ROAD_VEHICLE_DEPOT; break; + case VEH_Ship: w->widget[1].data = STR_9803_SHIP_DEPOT; break; + case VEH_Aircraft: + w->widget[1].data = STR_A002_AIRCRAFT_HANGAR; + w->widget[3].tooltips = STR_DEPOT_SELL_ALL_CANCEL_HANGAR_TIP; + w->widget[4].tooltips = STR_DEPOT_SELL_ALL_HANGAR_TIP; + break; + } + } +} + static void DrawDepotWindow(Window *w) { Vehicle **vl = WP(w, depot_d).vehicle_list; @@ -183,7 +255,8 @@ static void DrawDepotWindow(Window *w) /* setup disabled buttons */ w->disabled_state = IsTileOwner(tile, _local_player) ? 0 : ( (1 << DEPOT_WIDGET_STOP_ALL) | (1 << DEPOT_WIDGET_START_ALL) | - (1 << DEPOT_WIDGET_SELL) | (1 << DEPOT_WIDGET_SELL_ALL) | (1 << DEPOT_WIDGET_BUILD) | (1 << DEPOT_WIDGET_CLONE)); + (1 << DEPOT_WIDGET_SELL) | (1 << DEPOT_WIDGET_SELL_CHAIN) | (1 << DEPOT_WIDGET_SELL_ALL) | + (1 << DEPOT_WIDGET_BUILD) | (1 << DEPOT_WIDGET_CLONE)); /* determine amount of items for scroller */ if (WP(w, depot_d).type == VEH_Train) { @@ -512,11 +585,11 @@ static void ResizeDepotButtons(Window *w) w->widget[DEPOT_WIDGET_CLONE].right = w->widget[DEPOT_WIDGET_LOCATION].left - 1; if (WP(w, depot_d).type == VEH_Train) { - /* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_ALL will get the same size. - * This way it will stay the same even if DEPOT_WIDGET_SELL_ALL is resized for some reason */ - w->widget[DEPOT_WIDGET_SELL_ALL].bottom = w->widget[DEPOT_WIDGET_RESIZE].top - 1; - w->widget[DEPOT_WIDGET_SELL_ALL].top = ((w->widget[DEPOT_WIDGET_SELL_ALL].bottom - w->widget[DEPOT_WIDGET_SELL].top) / 2) + w->widget[DEPOT_WIDGET_SELL].top; - w->widget[DEPOT_WIDGET_SELL].bottom = w->widget[DEPOT_WIDGET_SELL_ALL].top - 1; + /* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size. + * This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason */ + w->widget[DEPOT_WIDGET_SELL_CHAIN].bottom = w->widget[DEPOT_WIDGET_SELL_ALL].top - 1; + w->widget[DEPOT_WIDGET_SELL_CHAIN].top = ((w->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - w->widget[DEPOT_WIDGET_SELL].top) / 2) + w->widget[DEPOT_WIDGET_SELL].top; + w->widget[DEPOT_WIDGET_SELL].bottom = w->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1; } } @@ -575,6 +648,10 @@ static void DepotWndProc(Window *w, WindowEvent *e) DoCommandP(w->window_number, WP(w, depot_d).type, e->we.click.widget == DEPOT_WIDGET_START_ALL ? 1 : 0, NULL, CMD_MASS_START_STOP); break; + case DEPOT_WIDGET_SELL_ALL: + ShowDepotSellAllWindow(w->window_number, WP(w, depot_d).type); + break; + } break; @@ -633,7 +710,7 @@ static void DepotWndProc(Window *w, WindowEvent *e) } } break; - case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_ALL: + case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN: if (!HASBIT(w->disabled_state, DEPOT_WIDGET_SELL) && WP(w, depot_d).sel != INVALID_VEHICLE) { Vehicle *v; @@ -650,7 +727,7 @@ static void DepotWndProc(Window *w, WindowEvent *e) WP(w, depot_d).sel = INVALID_VEHICLE; SetWindowDirty(w); - sell_cmd = (v->type == VEH_Train && (e->we.click.widget == DEPOT_WIDGET_SELL_ALL || _ctrl_pressed)) ? 1 : 0; + sell_cmd = (v->type == VEH_Train && (e->we.click.widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0; is_engine = (!(v->type == VEH_Train && !IsFrontEngine(v))); @@ -734,6 +811,7 @@ static void SetupStringsForDepotWindow(Window *w, byte type) /* Special strings only for hangars (using hangar instead of depot and so on) */ w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TOOLTIP; w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TOOLTIP; + w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_HANGAR_TIP; break; } } @@ -769,7 +847,7 @@ void ShowDepotWindow(TileIndex tile, byte type) switch (type) { case VEH_Train: horizontal = 56; - vertical = 48; + vertical = 26; w->vscroll.cap = 6; w->hscroll.cap = 10 * 29; w->resize.step_width = 1; @@ -778,15 +856,15 @@ void ShowDepotWindow(TileIndex tile, byte type) case VEH_Road: horizontal = 10; - vertical = -6; - w->vscroll.cap = 3; + vertical = - 14; + w->vscroll.cap = 4; w->hscroll.cap = 5; w->resize.step_width = 56; w->resize.step_height = 14; break; case VEH_Ship: - w->vscroll.cap = 2; + w->vscroll.cap = 3; w->hscroll.cap = 3; w->resize.step_width = 90; w->resize.step_height = 24; @@ -794,7 +872,7 @@ void ShowDepotWindow(TileIndex tile, byte type) case VEH_Aircraft: horizontal = 26; - w->vscroll.cap = 2; + w->vscroll.cap = 3; w->hscroll.cap = 4; w->resize.step_width = 74; w->resize.step_height = 24; @@ -811,7 +889,7 @@ void ShowDepotWindow(TileIndex tile, byte type) if (type != VEH_Train) { SETBIT(w->hidden_state, DEPOT_WIDGET_H_SCROLL); - SETBIT(w->hidden_state, DEPOT_WIDGET_SELL_ALL); + SETBIT(w->hidden_state, DEPOT_WIDGET_SELL_CHAIN); } /* Move the widgets to their right locations @@ -838,9 +916,9 @@ void ShowDepotWindow(TileIndex tile, byte type) w->widget[DEPOT_WIDGET_H_SCROLL].top = w->widget[DEPOT_WIDGET_MATRIX].bottom - 11; w->widget[DEPOT_WIDGET_MATRIX].bottom -= 12; - /* DEPOT_WIDGET_SELL_ALL is under DEPOT_WIDGET_SELL. They got the same left and right and height is controlled in ResizeDepotButtons() */ - w->widget[DEPOT_WIDGET_SELL_ALL].left = w->widget[DEPOT_WIDGET_SELL].left; - w->widget[DEPOT_WIDGET_SELL_ALL].right = w->widget[DEPOT_WIDGET_SELL].right; + /* DEPOT_WIDGET_SELL_CHAIN is under DEPOT_WIDGET_SELL. They got the same left and right and height is controlled in ResizeDepotButtons() */ + w->widget[DEPOT_WIDGET_SELL_CHAIN].left = w->widget[DEPOT_WIDGET_SELL].left; + w->widget[DEPOT_WIDGET_SELL_CHAIN].right = w->widget[DEPOT_WIDGET_SELL].right; } ResizeDepotButtons(w); } diff --git a/lang/english.txt b/lang/english.txt index b6dac79633..32816303b1 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -2901,6 +2901,16 @@ STR_SEND_TO_DEPOTS_TIP :{BLACK}Send al STR_SEND_TO_HANGARS :{BLACK}Send to Hangars STR_SEND_TO_HANGARS_TIP :{BLACK}Send all aircraft in list to hangar. CTRL+click will only service +STR_SELL :{BLACK}Sell +STR_DEPOT_SELL_ALL_VEHICLE_CONFIRM :{BLACK}You are about to sell all the vehicles in the depot. +STR_ARE_YOU_SURE :{BLACK}Are you sure? +STR_DEPOT_SELL_ALL_TIP :{BLACK}Confirm that you want to sell all the vehicles in the depot +STR_DEPOT_SELL_ALL_HANGAR_TIP :{BLACK}Confirm that you want to sell all the aircraft in the hangar +STR_DEPOT_SELL_ALL_CANCEL_TIP :{BLACK}Do not sell all vehicles in the depot +STR_DEPOT_SELL_ALL_CANCEL_HANGAR_TIP :{BLACK}Do not sell all aircraft in the hangar +STR_DEPOT_SELL_ALL_BUTTON_TIP :{BLACK}Sell all vehicles in the depot +STR_DEPOT_SELL_ALL_BUTTON_HANGAR_TIP :{BLACK}Sell all aircraft in the hangar + STR_REPLACE_VEHICLES :{BLACK}Replace Vehicles STR_REPLACE_VEHICLES_WHITE :{WHITE}Replace {STRING} STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles diff --git a/openttd.h b/openttd.h index 70c4cd4463..f50bbd4a7b 100644 --- a/openttd.h +++ b/openttd.h @@ -439,6 +439,7 @@ enum { WC_GENERATE_LANDSCAPE = 0x50, WC_GENERATE_PROGRESS_WINDOW = 0x51, WC_OK_CANCEL_QUERY = 0x52, + WC_DEPOT_SELL_ALL = 0x53, }; diff --git a/vehicle.c b/vehicle.c index 760ff64f23..638fdec7a6 100644 --- a/vehicle.c +++ b/vehicle.c @@ -1626,6 +1626,58 @@ int32 CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2 return return_value; } +/** Sells all vehicles in a depot +* @param tile Tile of the depot where the depot is +* @param p1 Vehicle type +* @param p2 unused +*/ +int32 CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) +{ + Vehicle **engines = NULL; + Vehicle **wagons = NULL; + uint16 engine_list_length = 0; + uint16 engine_count = 0; + uint16 wagon_list_length = 0; + uint16 wagon_count = 0; + + int32 cost = 0; + uint i, sell_command, total_number_vehicles; + byte vehicle_type = GB(p1, 0, 8); + + switch (vehicle_type) { + case VEH_Train: sell_command = CMD_SELL_RAIL_WAGON; break; + case VEH_Road: sell_command = CMD_SELL_ROAD_VEH; break; + case VEH_Ship: sell_command = CMD_SELL_SHIP; break; + case VEH_Aircraft: sell_command = CMD_SELL_AIRCRAFT; break; + default: return CMD_ERROR; + } + + /* Get the list of vehicles in the depot */ + BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count, + &wagons, &wagon_list_length, &wagon_count); + + total_number_vehicles = engine_count + wagon_count; + for (i = 0; i < total_number_vehicles; i++) { + const Vehicle *v; + int32 ret; + + if (i < engine_count) { + v = engines[i]; + } else { + v = wagons[i - engine_count]; + } + + ret = DoCommand(tile, v->index, 1, flags, sell_command); + + if (!CmdFailed(ret)) cost += ret; + } + + free(engines); + free(wagons); + if (cost == 0) return CMD_ERROR; // no vehicles to sell + return cost; +} + /** Clone a vehicle. If it is a train, it will clone all the cars too * @param tile tile of the depot where the cloned vehicle is build * @param p1 the original vehicle's index