diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 963d7a2df2..bc1ca00711 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -334,8 +334,8 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine * v->vehicle_flags = 0; if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); - SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, - _settings_game.order.timetable_automated && Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_TIMETABLE_SEPARATION, 1, Company::Get(_current_company)->settings.vehicle.auto_separation_by_default); v->InvalidateNewGRFCacheOfChain(); diff --git a/src/command.cpp b/src/command.cpp index 1685c2b15b..a0aeb60877 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -221,6 +221,7 @@ CommandProc CmdBulkChangeTimetable; CommandProc CmdSetVehicleOnTime; CommandProc CmdAutofillTimetable; CommandProc CmdAutomateTimetable; +CommandProc CmdTimetableSeparation; CommandProc CmdSetTimetableStart; CommandProc CmdOpenCloseAirport; @@ -418,6 +419,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME DEF_CMD(CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOFILL_TIMETABLE DEF_CMD(CmdAutomateTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOMATE_TIMETABLE + DEF_CMD(CmdTimetableSeparation, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_TIMETABLE_SEPARATION DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT diff --git a/src/command_type.h b/src/command_type.h index 16277fde2b..56a4fbd100 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -364,6 +364,7 @@ enum Commands { CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable) CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable CMD_AUTOMATE_TIMETABLE, ///< automate the timetable + CMD_TIMETABLE_SEPARATION, ///< auto timetable separation CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft diff --git a/src/lang/english.txt b/src/lang/english.txt index ff9444dab7..bdd652eb08 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1446,8 +1446,10 @@ STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Use groups in v STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Enable usage of the advanced vehicle lists for grouping vehicles STR_CONFIG_SETTING_LOADING_INDICATORS :Use loading indicators: {STRING2} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles -STR_CONFIG_SETTING_TIMETABLE_AUTOMATED :Automatically manage timetables: {STRING2} -STR_CONFIG_SETTING_TIMETABLE_AUTOMATED_HELPTEXT :Whether to enable automatic timetables +STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT :Use automatic timetables by default: {STRING2} +STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT_HELPTEXT :Choose whether automatic timetables should by automatically enabled for new vehicles +STR_CONFIG_SETTING_TIMETABLE_SEPARATION_BY_DEFAULT :Use timetable to ensure vehicle separation by default: {STRING2} +STR_CONFIG_SETTING_TIMETABLE_SEPARATION_BY_DEFAULT_HELPTEXT :Choose whether to ensure separation of vehicles should by automatically enabled for new vehicles STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Show timetable in ticks rather than days: {STRING2} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Show travel times in time tables in game ticks instead of days STR_CONFIG_SETTING_TIMETABLE_LEFTOVER_TICKS :Show leftover ticks in timetable: {STRING2} @@ -1472,6 +1474,8 @@ STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE :Auto timetable STR_CONFIG_SETTING_TIMETABLE_SEPARATION_RATE_HELPTEXT :How much of the vehicle separation auto timetable change to apply at each step STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables +STR_CONFIG_SETTING_TIMETABLE_AUTOFILL_ROUNDING_TICKS :Round up auto-filled timetable times to multiples of this many ticks: {STRING2} +STR_CONFIG_SETTING_TIMETABLE_AUTOFILL_ROUNDING_TICKS_HELPTEXT :Timetable times adjusted by timetable automation are not rounded. A day at a a day length of 1 is 74 ticks. STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Pre-select the 'goto cursor' when opening the orders window STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Default rail type (after new game/game load): {STRING2} @@ -1566,8 +1570,6 @@ STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Default service STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Set the default service interval for new aircraft, if no explicit service interval is set for the vehicle STR_CONFIG_SETTING_SERVINT_SHIPS :Default service interval for ships: {STRING2} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Set the default service interval for new ships, if no explicit service interval is set for the vehicle -STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT :Use automatic timetables by default -STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT_HELPTEXT :Choose whether automatic timetables should by automatically enabled for new vehicles STR_CONFIG_SETTING_NOSERVICE :Disable servicing when breakdowns set to none: {STRING2} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} @@ -4489,6 +4491,9 @@ STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the STR_TIMETABLE_AUTOMATE :{BLACK}Automate STR_TIMETABLE_AUTOMATE_TOOLTIP :{BLACK}Manage the timetables automatically by updating the values for each journey (Ctrl+Click when disabling to keep the current timetable) +STR_TIMETABLE_AUTO_SEPARATION :{BLACK}Auto Separation +STR_TIMETABLE_AUTO_SEPARATION_TOOLTIP :{BLACK}Automatically adjust timetable start times to ensure vehicle separation + STR_TIMETABLE_EXPECTED :{BLACK}Expected STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 54a5cabee8..7d59fbeaed 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1221,7 +1221,7 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS); v->ClearSeparation(); - if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED); + if (HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED); } /* We have an aircraft/ship, they have a mini-schedule, so update them all */ @@ -1717,11 +1717,17 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } else { ClrBit(dst->vehicle_flags, VF_AUTOMATE_TIMETABLE); } + /* Set auto separation bit if target has it. */ + if (HasBit(src->vehicle_flags, VF_TIMETABLE_SEPARATION)) { + SetBit(dst->vehicle_flags, VF_TIMETABLE_SEPARATION); + } else { + ClrBit(dst->vehicle_flags, VF_TIMETABLE_SEPARATION); + } ClrBit(dst->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(dst->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); dst->ClearSeparation(); - if (_settings_game.order.timetable_separation) ClrBit(dst->vehicle_flags, VF_TIMETABLE_STARTED); + if (HasBit(dst->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(dst->vehicle_flags, VF_TIMETABLE_STARTED); InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS); InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS); @@ -1795,6 +1801,12 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } else { ClrBit(dst->vehicle_flags, VF_AUTOMATE_TIMETABLE); } + /* Set auto separation bit if target has it. */ + if (HasBit(src->vehicle_flags, VF_TIMETABLE_SEPARATION)) { + SetBit(dst->vehicle_flags, VF_TIMETABLE_SEPARATION); + } else { + ClrBit(dst->vehicle_flags, VF_TIMETABLE_SEPARATION); + } InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 091e4f533c..a15bcfbbe7 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -318,8 +318,8 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); - SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, - _settings_game.order.timetable_automated && Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_TIMETABLE_SEPARATION, 1, Company::Get(_current_company)->settings.vehicle.auto_separation_by_default); AddArticulatedParts(v); v->InvalidateNewGRFCacheOfChain(); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 2a27da4b97..3bda6c2528 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3227,6 +3227,11 @@ bool AfterLoadGame() } } + if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 3)) { + Vehicle *v; + FOR_ALL_VEHICLES(v) SB(v->vehicle_flags, VF_TIMETABLE_SEPARATION, 1, _settings_game.order.old_timetable_separation); + } + /* Road stops is 'only' updating some caches */ AfterLoadRoadStops(); AfterLoadLabelMaps(); diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 64926ecad0..6a0f019a21 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -494,10 +494,13 @@ static void Load_PLYR() SaveLoad_PLYR(c); _company_colours[index] = (Colours)c->colour; - // setting moved from game settings to company settings + // settings moved from game settings to company settings if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 2)) { c->settings.auto_timetable_separation_rate = _settings_game.order.old_timetable_separation_rate; } + if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 3)) { + c->settings.vehicle.auto_separation_by_default = _settings_game.order.old_timetable_separation; + } } } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 76e5d36e74..577c132275 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -57,7 +57,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 2, 2, "signal_tunnel_bridge", NULL, NULL, NULL }, { XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 3, 3, "improved_breakdowns", NULL, NULL, NULL }, { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", NULL, NULL, NULL }, - { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 3, 3, "auto_timetables", NULL, NULL, NULL }, + { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 4, 4, "auto_timetables", NULL, NULL, NULL }, { XSLFI_VEHICLE_REPAIR_COST, XSCF_NULL, 1, 1, "vehicle_repair_cost", NULL, NULL, NULL }, { XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 1, 1, "enh_viewport_plans", NULL, NULL, "PLAN,PLLN" }, { XSLFI_INFRA_SHARING, XSCF_NULL, 1, 1, "infra_sharing", NULL, NULL, NULL }, diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index cc5f2a8b0c..02d0b8bc8c 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1640,7 +1640,9 @@ static SettingsContainer &GetSettingsTree() company->Add(new SettingEntry("vehicle.servint_ships")); company->Add(new SettingEntry("vehicle.servint_aircraft")); company->Add(new SettingEntry("vehicle.auto_timetable_by_default")); + company->Add(new SettingEntry("vehicle.auto_separation_by_default")); company->Add(new SettingEntry("auto_timetable_separation_rate")); + company->Add(new SettingEntry("timetable_autofill_rounding")); company->Add(new SettingEntry("order_occupancy_smoothness")); company->Add(new SettingEntry("company.infra_others_buy_in_depot[0]")); company->Add(new SettingEntry("company.infra_others_buy_in_depot[1]")); @@ -1688,8 +1690,6 @@ static SettingsContainer &GetSettingsTree() vehicles->Add(new SettingEntry("order.no_servicing_if_no_breakdowns")); vehicles->Add(new SettingEntry("order.serviceathelipad")); - vehicles->Add(new SettingEntry("order.timetable_automated")); - vehicles->Add(new SettingEntry("order.timetable_separation")); vehicles->Add(new SettingEntry("vehicle.adjacent_crossings")); } diff --git a/src/settings_type.h b/src/settings_type.h index 6ed61a2564..8ba631e9db 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -481,11 +481,10 @@ struct OrderSettings { bool gradual_loading; ///< load vehicles gradually bool selectgoods; ///< only send the goods to station if a train has been there bool no_servicing_if_no_breakdowns; ///< don't send vehicles to depot when breakdowns are disabled - bool timetable_automated; ///< whether to automatically manage timetables - bool timetable_separation; ///< whether to perform automatic separation based on timetable bool serviceathelipad; ///< service helicopters at helipads automatically (no need to send to depot) uint8 old_occupancy_smoothness; ///< moved to company settings: percentage smoothness of occupancy measurement changes + bool old_timetable_separation; ///< moved to company settings: whether to perform automatic separation based on timetable uint8 old_timetable_separation_rate; ///< moved to company settings: percentage of timetable separation change to apply }; @@ -588,6 +587,7 @@ struct VehicleDefaultSettings { uint16 servint_aircraft; ///< service interval for aircraft uint16 servint_ships; ///< service interval for ships bool auto_timetable_by_default; ///< use automatic timetables by default + bool auto_separation_by_default; ///< use automatic timetable separation by default }; /** Settings that can be set per company. */ @@ -600,6 +600,7 @@ struct CompanySettings { uint8 order_occupancy_smoothness; ///< percentage smoothness of occupancy measurement changes uint8 auto_timetable_separation_rate; ///< percentage of auto timetable separation change to apply bool infra_others_buy_in_depot[4]; ///< other companies can buy/autorenew in this companies depots (where infra sharing enabled) + uint16 timetable_autofill_rounding; ///< round up timetable times to be a multiple of this number of ticks }; /** All settings together for the game. */ diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 6613139f5d..daf19687dd 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -775,8 +775,8 @@ CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, u if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); - SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, - _settings_game.order.timetable_automated && Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_TIMETABLE_SEPARATION, 1, Company::Get(_current_company)->settings.vehicle.auto_separation_by_default); v->InvalidateNewGRFCacheOfChain(); diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini index c45c967202..1b30cda52d 100644 --- a/src/table/company_settings.ini +++ b/src/table/company_settings.ini @@ -150,6 +150,15 @@ str = STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT strhelp = STR_CONFIG_SETTING_AUTO_TIMETABLE_BY_DEFAULT_HELPTEXT patxname = ""vehicle.auto_timetable_by_default"" +[SDT_BOOL] +base = CompanySettings +var = vehicle.auto_separation_by_default +guiflags = SGF_PER_COMPANY +def = true +str = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_BY_DEFAULT +strhelp = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_BY_DEFAULT_HELPTEXT +patxname = ""vehicle.auto_separation_by_default"" + [SDT_VAR] base = CompanySettings var = auto_timetable_separation_rate @@ -165,6 +174,21 @@ strval = STR_CONFIG_SETTING_PERCENTAGE cat = SC_EXPERT patxname = ""auto_timetable_separation_rate"" +[SDT_VAR] +base = CompanySettings +var = timetable_autofill_rounding +type = SLE_UINT16 +guiflags = SGF_PER_COMPANY +def = 74 +min = 1 +max = 1000 +interval = 10 +str = STR_CONFIG_SETTING_TIMETABLE_AUTOFILL_ROUNDING_TICKS +strhelp = STR_CONFIG_SETTING_TIMETABLE_AUTOFILL_ROUNDING_TICKS_HELPTEXT +strval = STR_JUST_INT +cat = SC_EXPERT +patxname = ""timetable_autofill_rounding"" + [SDT_VAR] base = CompanySettings var = order_occupancy_smoothness diff --git a/src/table/settings.ini b/src/table/settings.ini index a9c0703040..4ce32556b6 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -349,22 +349,10 @@ extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP) [SDT_BOOL] base = GameSettings -var = order.timetable_automated +var = order.old_timetable_separation def = true -str = STR_CONFIG_SETTING_TIMETABLE_AUTOMATED -strhelp = STR_CONFIG_SETTING_TIMETABLE_AUTOMATED_HELPTEXT cat = SC_EXPERT -extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE) -patxname = ""auto_timetables.order.timetable_automated"" - -[SDT_BOOL] -base = GameSettings -var = order.timetable_separation -def = true -str = STR_CONFIG_SETTING_TIMETABLE_SEPARATION -strhelp = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_HELPTEXT -cat = SC_EXPERT -extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE) +extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 1, 3) patxname = ""auto_timetables.order.timetable_separation"" [SDT_VAR] diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index d70a7a55b9..9eee2df554 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -440,8 +440,6 @@ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, CommandCost CmdAutomateTimetable(TileIndex index, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { - if (!_settings_game.order.timetable_automated) return CMD_ERROR; - VehicleID veh = GB(p1, 0, 16); Vehicle *v = Vehicle::GetIfValid(veh); @@ -490,6 +488,41 @@ CommandCost CmdAutomateTimetable(TileIndex index, DoCommandFlag flags, uint32 p1 return CommandCost(); } +/** + * Enable or disable auto timetable separation + * @param tile Not used. + * @param flags Operation to perform. + * @param p1 Vehicle index. + * @param p2 Various bitstuffed elements + * - p2 = (bit 0) - Set to 1 to enable, 0 to disable auto separatiom. + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdTimetableSeparation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + VehicleID veh = GB(p1, 0, 20); + + Vehicle *v = Vehicle::GetIfValid(veh); + if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + + CommandCost ret = CheckOwnership(v->owner); + if (ret.Failed()) return ret; + + if (flags & DC_EXEC) { + for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { + if (HasBit(p2, 0)) { + SetBit(v2->vehicle_flags, VF_TIMETABLE_SEPARATION); + } else { + ClrBit(v2->vehicle_flags, VF_TIMETABLE_SEPARATION); + } + v2->ClearSeparation(); + SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index); + } + } + + return CommandCost(); +} + static inline bool IsOrderUsableForSeparation(const Order *order) { if (order->IsType(OT_CONDITIONAL)) { @@ -641,7 +674,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) v->ClearSeparation(); SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED); v->lateness_counter = 0; - if (_settings_game.order.timetable_separation) UpdateSeparationOrder(v); + if (HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION)) UpdateSeparationOrder(v); for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } @@ -682,16 +715,18 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) /* Before modifying waiting times, check whether we want to preserve bigger ones. */ if (!real_current_order->IsType(OT_CONDITIONAL) && (travelling || time_taken > real_current_order->GetWaitTime() || remeasure_wait_time)) { - /* Round the time taken up to the nearest day, as this will avoid - * confusion for people who are timetabling in days, and can be - * adjusted later by people who aren't. + /* Round the time taken up to the nearest timetable rounding factor + * (default: day), as this will avoid confusion for people who are + * timetabling in days, and can be adjusted later by people who aren't. * For trains/aircraft multiple movement cycles are done in one * tick. This makes it possible to leave the station and process * e.g. a depot order in the same tick, causing it to not fill * the timetable entry like is done for road vehicles/ships. * Thus always make sure at least one tick is used between the * processing of different orders when filling the timetable. */ - uint time_to_set = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS; + Company *owner = Company::GetIfValid(v->owner); + uint rounding_factor = owner ? owner->settings.timetable_autofill_rounding : DAY_TICKS; + uint time_to_set = CeilDiv(max(time_taken, 1U), rounding_factor) * rounding_factor; if (travelling && (autofilling || !real_current_order->IsTravelTimetabled())) { ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_TRAVEL_TIME, autofilling); @@ -761,7 +796,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) * when this happens. */ if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return; - if (_settings_game.order.timetable_separation && HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { + if (HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION) && HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { v->current_order_time = time_taken; v->current_loading_time = time_loading; UpdateSeparationOrder(v); diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 9754091810..e5615b6a27 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -358,6 +358,11 @@ struct TimetableWindow : Window { this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == NULL); this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == NULL); this->EnableWidget(WID_VT_AUTOMATE); + this->EnableWidget(WID_VT_AUTO_SEPARATION); + this->SetWidgetDisabledState(WID_VT_START_DATE, HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION)); + this->SetWidgetDisabledState(WID_VT_CHANGE_TIME, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); + this->SetWidgetDisabledState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); + this->SetWidgetDisabledState(WID_VT_CLEAR_TIME, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); } else { this->DisableWidget(WID_VT_START_DATE); this->DisableWidget(WID_VT_CHANGE_TIME); @@ -367,16 +372,13 @@ struct TimetableWindow : Window { this->DisableWidget(WID_VT_RESET_LATENESS); this->DisableWidget(WID_VT_AUTOFILL); this->DisableWidget(WID_VT_AUTOMATE); + this->DisableWidget(WID_VT_AUTO_SEPARATION); this->DisableWidget(WID_VT_SHARED_ORDER_LIST); } this->SetWidgetLoweredState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)); this->SetWidgetLoweredState(WID_VT_AUTOMATE, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); - this->SetWidgetDisabledState(WID_VT_START_DATE, _settings_game.order.timetable_separation); - this->SetWidgetDisabledState(WID_VT_AUTOMATE, !_settings_game.order.timetable_automated); - this->SetWidgetDisabledState(WID_VT_CHANGE_TIME, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); - this->SetWidgetDisabledState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); - this->SetWidgetDisabledState(WID_VT_CLEAR_TIME, HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)); + this->SetWidgetLoweredState(WID_VT_AUTO_SEPARATION, HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION)); this->DrawWidgets(); } @@ -667,6 +669,13 @@ struct TimetableWindow : Window { break; } + case WID_VT_AUTO_SEPARATION: { + uint32 p2 = 0; + if (!HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION)) SetBit(p2, 0); + DoCommandP(0, v->index, p2, CMD_TIMETABLE_SEPARATION | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); + break; + } + case WID_VT_EXPECTED: this->show_expected = !this->show_expected; break; @@ -735,7 +744,6 @@ struct TimetableWindow : Window { void UpdateSelectionStates() { this->GetWidget(WID_VT_ARRIVAL_DEPARTURE_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : SZSP_NONE); - // this->GetWidget(TTV_AUTO_SELECTION)->SetDisplayedPlane(!_settings_game.order.timetable_automated ? 0 : 1); this->GetWidget(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1); } @@ -790,6 +798,7 @@ static const NWidgetPart _nested_timetable_widgets[] = { EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_START_DATE), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_STARTING_DATE, STR_TIMETABLE_STARTING_DATE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTO_SEPARATION), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTO_SEPARATION, STR_TIMETABLE_AUTO_SEPARATION_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_RESET_LATENESS), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_RESET_LATENESS, STR_TIMETABLE_RESET_LATENESS_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 5e62bae013..6f8610475d 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -843,8 +843,8 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); - SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, - _settings_game.order.timetable_automated && Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_AUTOMATE_TIMETABLE, 1, Company::Get(_current_company)->settings.vehicle.auto_timetable_by_default); + SB(v->vehicle_flags, VF_TIMETABLE_SEPARATION, 1, Company::Get(_current_company)->settings.vehicle.auto_separation_by_default); v->group_id = DEFAULT_GROUP; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index b6ebb5a47c..4f233bff30 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -274,9 +274,7 @@ uint Vehicle::Crash(bool flooded) } this->ClearSeparation(); - if (_settings_game.order.timetable_separation) { - ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); - } + if (HasBit(this->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); /* Dirty some windows */ InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0); @@ -2714,9 +2712,7 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) if (!(this->current_order.GetDepotOrderType() & ODTFB_BREAKDOWN)) this->current_order.SetDepotOrderType(ODTF_MANUAL); this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT); this->ClearSeparation(); - if (_settings_game.order.timetable_separation) { - ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); - } + if (HasBit(this->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); } return CommandCost(); @@ -2738,9 +2734,7 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) this->current_order.SetDepotActionType(this->current_order.GetDepotActionType() == ODATFB_HALT ? ODATF_SERVICE_ONLY : ODATFB_HALT); } else { this->ClearSeparation(); - if (_settings_game.order.timetable_separation) { - ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); - } + if (HasBit(this->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); this->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); @@ -3198,7 +3192,7 @@ void Vehicle::RemoveFromShared() this->previous_shared = NULL; this->ClearSeparation(); - if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); + if (HasBit(this->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED); } void VehiclesYearlyLoop() diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 40872dca0c..6c5bffce66 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -58,6 +58,7 @@ enum VehicleFlags { // Additional flags not in trunk are added at the end to avoid clashing with any new // flags which get added in future trunk, and to avoid re-ordering flags which are in trunk already, // as this breaks savegame compatibility. + VF_TIMETABLE_SEPARATION = 14,///< Whether the vehicle should manage the timetable automatically. VF_AUTOMATE_TIMETABLE = 15, ///< Whether the vehicle should manage the timetable automatically. }; diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 4d7bdc429d..558b5a47a2 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -633,7 +633,7 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(p1, STR_NEWS_TRAIN_IS_WAITING + v->type); v->ClearSeparation(); - if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED); + if (HasBit(v->vehicle_flags, VF_TIMETABLE_SEPARATION)) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED); v->vehstatus ^= VS_STOPPED; if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly' diff --git a/src/widgets/timetable_widget.h b/src/widgets/timetable_widget.h index d21e3c2b7e..341608c58b 100644 --- a/src/widgets/timetable_widget.h +++ b/src/widgets/timetable_widget.h @@ -26,6 +26,7 @@ enum VehicleTimetableWidgets { WID_VT_RESET_LATENESS, ///< Reset lateness button. WID_VT_AUTOFILL, ///< Autofill button. WID_VT_AUTOMATE, ///< Automate button. + WID_VT_AUTO_SEPARATION, ///< Auto separation button. WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals. WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list. WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel.