Feature: When filtering purchase list by cargo type, make buy button perform a refit if required.

This commit is contained in:
peter1138 2019-02-28 21:32:08 +00:00 committed by PeterN
parent f6264e5212
commit d54b6ac09b
5 changed files with 95 additions and 28 deletions

View File

@ -294,7 +294,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
if (refit_cargo == CT_INVALID) return CommandCost(); // incompatible cargoes
/* Build the new vehicle */
cost = DoCommand(old_veh->tile, e, 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh));
cost = DoCommand(old_veh->tile, e | (CT_INVALID << 24), 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh));
if (cost.Failed()) return cost;
Vehicle *new_veh = Vehicle::Get(_new_vehicle_id);

View File

@ -989,6 +989,22 @@ struct BuildVehicleWindow : Window {
int details_height; ///< Minimal needed height of the details panels (found so far).
Scrollbar *vscroll;
void SetBuyVehicleText()
{
NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
bool refit = this->sel_engine != INVALID_ENGINE && this->cargo_filter[this->cargo_filter_criteria] != CF_ANY && this->cargo_filter[this->cargo_filter_criteria] != CF_NONE;
if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter[this->cargo_filter_criteria];
if (refit) {
widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type;
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type;
} else {
widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type;
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type;
}
}
BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc)
{
this->vehicle_type = type;
@ -1031,10 +1047,6 @@ struct BuildVehicleWindow : Window {
widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDE);
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type;
widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type;
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type;
widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type;
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type;
@ -1054,6 +1066,7 @@ struct BuildVehicleWindow : Window {
this->GenerateBuildList(); // generate the list, since we need it in the next line
/* Select the first engine in the list as default when opening the window */
if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0];
this->SetBuyVehicleText();
}
/** Populate the filter list and set the cargo filter criteria. */
@ -1111,8 +1124,10 @@ struct BuildVehicleWindow : Window {
this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]);
if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine
this->sel_engine = INVALID_ENGINE;
this->SetBuyVehicleText();
} else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list
this->sel_engine = this->eng_list[0];
this->SetBuyVehicleText();
}
}
@ -1294,6 +1309,7 @@ struct BuildVehicleWindow : Window {
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
size_t num_items = this->eng_list.Length();
this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
this->SetBuyVehicleText();
this->SetDirty();
if (_ctrl_pressed) {
this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
@ -1323,7 +1339,9 @@ struct BuildVehicleWindow : Window {
EngineID sel_eng = this->sel_engine;
if (sel_eng != INVALID_ENGINE) {
CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback);
bool refit = this->cargo_filter[this->cargo_filter_criteria] != CF_ANY && this->cargo_filter[this->cargo_filter_criteria] != CF_NONE;
CargoID cargo = refit ? this->cargo_filter[this->cargo_filter_criteria] : CT_INVALID;
DoCommandP(this->window_number, sel_eng | (cargo << 24), 0, GetCmdBuildVeh(this->vehicle_type), callback);
}
break;
}
@ -1411,6 +1429,13 @@ struct BuildVehicleWindow : Window {
break;
}
case WID_BV_BUILD:
*size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
*size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
size->width += padding.width;
size->height += padding.height;
break;
case WID_BV_SHOW_HIDE:
*size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
*size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
@ -1485,6 +1510,7 @@ struct BuildVehicleWindow : Window {
/* deactivate filter if criteria is 'Show All', activate it otherwise */
this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
this->eng_list.ForceRebuild();
this->SetBuyVehicleText();
}
break;
}

View File

@ -3501,11 +3501,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehi
STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship
STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft
STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle
STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle
STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Ship
STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Aircraft
STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted train vehicle. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted road vehicle. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted ship. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted aircraft. Shift+Click shows estimated cost without purchase
STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename
STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename
STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename

View File

@ -70,7 +70,7 @@
EnforcePreconditionCustomError(VEHICLE_INVALID, !ScriptGameSettings::IsDisabledVehicleType((ScriptVehicle::VehicleType)type), ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED);
if (!ScriptObject::DoCommand(depot, engine_id, 0, ::GetCmdBuildVeh(type), NULL, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID;
if (!ScriptObject::DoCommand(depot, engine_id | (CT_INVALID << 24), 0, ::GetCmdBuildVeh(type), NULL, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID;
/* In case of test-mode, we return VehicleID 0 */
return 0;

View File

@ -71,13 +71,16 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin
CommandCost CmdBuildShip (TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v);
CommandCost CmdBuildAircraft (TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v);
CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text);
/**
* Build a vehicle.
* @param tile tile of depot where the vehicle is built
* @param flags for command
* @param p1 various bitstuffed data
* bits 0-15: vehicle type being built.
* bits 16-31: vehicle type specific bits passed on to the vehicle build functions.
* bits 16-23: vehicle type specific bits passed on to the vehicle build functions.
* bits 24-31: refit cargo type.
* @param p2 User
* @param text unused
* @return the cost of this operation or an error
@ -93,11 +96,18 @@ CommandCost CmdBuildVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
EngineID eid = GB(p1, 0, 16);
if (!IsEngineBuildable(eid, type, _current_company)) return_cmd_error(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type);
/* Validate the cargo type. */
CargoID cargo = GB(p1, 24, 8);
if (cargo >= NUM_CARGO && cargo != CT_INVALID) return CMD_ERROR;
const Engine *e = Engine::Get(eid);
CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost());
/* Engines without valid cargo should not be available */
if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
CargoID default_cargo = e->GetDefaultCargoType();
if (default_cargo == CT_INVALID) return CMD_ERROR;
bool refitting = cargo != CT_INVALID && cargo != default_cargo;
/* Check whether the number of vehicles we need to build can be built according to pool space. */
uint num_vehicles;
@ -116,32 +126,53 @@ CommandCost CmdBuildVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
UnitID unit_num = (flags & DC_AUTOREPLACE || (type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON)) ? 0 : GetFreeUnitNumber(type);
if (unit_num == UINT16_MAX) return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
/* If we are refitting we need to temporarily purchase the vehicle to be able to
* test it. */
DoCommandFlag subflags = flags;
if (refitting) subflags |= DC_EXEC;
Vehicle *v;
switch (type) {
case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(tile, flags, e, GB(p1, 16, 16), &v)); break;
case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(tile, flags, e, GB(p1, 16, 16), &v)); break;
case VEH_SHIP: value.AddCost(CmdBuildShip (tile, flags, e, GB(p1, 16, 16), &v)); break;
case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (tile, flags, e, GB(p1, 16, 16), &v)); break;
case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(tile, subflags, e, GB(p1, 24, 8), &v)); break;
case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(tile, subflags, e, GB(p1, 24, 8), &v)); break;
case VEH_SHIP: value.AddCost(CmdBuildShip (tile, subflags, e, GB(p1, 24, 8), &v)); break;
case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (tile, subflags, e, GB(p1, 24, 8), &v)); break;
default: NOT_REACHED(); // Safe due to IsDepotTile()
}
if (value.Succeeded() && flags & DC_EXEC) {
v->unitnumber = unit_num;
v->value = value.GetCost();
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindowClassesData(GetWindowClassForVehicleType(type), 0);
SetWindowDirty(WC_COMPANY, _current_company);
if (IsLocalCompany()) {
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines)
if (value.Succeeded()) {
if (refitting || (flags & DC_EXEC)) {
v->unitnumber = unit_num;
v->value = value.GetCost();
}
GroupStatistics::CountEngine(v, 1);
GroupStatistics::UpdateAutoreplace(_current_company);
if (refitting) {
value.AddCost(CmdRefitVehicle(tile, flags, v->index, cargo, NULL));
}
if (v->IsPrimaryVehicle()) {
GroupStatistics::CountVehicle(v, 1);
OrderBackup::Restore(v, p2);
if (flags & DC_EXEC) {
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindowClassesData(GetWindowClassForVehicleType(type), 0);
SetWindowDirty(WC_COMPANY, _current_company);
if (IsLocalCompany()) {
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines)
}
}
if (refitting || (flags & DC_EXEC)) {
GroupStatistics::CountEngine(v, 1);
GroupStatistics::UpdateAutoreplace(_current_company);
if (v->IsPrimaryVehicle()) {
GroupStatistics::CountVehicle(v, 1);
OrderBackup::Restore(v, p2);
}
}
/* If we are not in DC_EXEC undo everything */
if (refitting && (flags & DC_EXEC) == 0) {
DoCommand(0, v->index, 0, DC_EXEC, GetCmdSellVeh(v));
}
}
@ -832,7 +863,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
DoCommandFlag build_flags = flags;
if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE;
CommandCost cost = DoCommand(tile, v->engine_type | (1 << 16), 0, build_flags, GetCmdBuildVeh(v));
CommandCost cost = DoCommand(tile, v->engine_type | (1 << 16) | (CT_INVALID << 24), 0, build_flags, GetCmdBuildVeh(v));
if (cost.Failed()) {
/* Can't build a part, then sell the stuff we already made; clear up the mess */