Import auto timetable separation patch
http://www.tt-forums.net/viewtopic.php?p=1140899#p1140899
This commit is contained in:

committed by
Jonathan G Rennison

parent
59db260e63
commit
80deb3c01d
@@ -194,6 +194,7 @@ CommandProc CmdMoveOrder;
|
|||||||
CommandProc CmdChangeTimetable;
|
CommandProc CmdChangeTimetable;
|
||||||
CommandProc CmdSetVehicleOnTime;
|
CommandProc CmdSetVehicleOnTime;
|
||||||
CommandProc CmdAutofillTimetable;
|
CommandProc CmdAutofillTimetable;
|
||||||
|
CommandProc CmdAutomateTimetable;
|
||||||
CommandProc CmdSetTimetableStart;
|
CommandProc CmdSetTimetableStart;
|
||||||
|
|
||||||
CommandProc CmdOpenCloseAirport;
|
CommandProc CmdOpenCloseAirport;
|
||||||
@@ -351,6 +352,7 @@ static const Command _command_proc_table[] = {
|
|||||||
DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE
|
DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE
|
||||||
DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME
|
DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME
|
||||||
DEF_CMD(CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOFILL_TIMETABLE
|
DEF_CMD(CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOFILL_TIMETABLE
|
||||||
|
DEF_CMD(CmdAutomateTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOMATE_TIMETABLE]
|
||||||
DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
|
DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START
|
||||||
|
|
||||||
DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT
|
DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT
|
||||||
|
@@ -325,6 +325,7 @@ enum Commands {
|
|||||||
CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle
|
CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle
|
||||||
CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable)
|
CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable)
|
||||||
CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable
|
CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable
|
||||||
|
CMD_AUTOMATE_TIMETABLE, ///< automate the timetable
|
||||||
CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start
|
CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start
|
||||||
|
|
||||||
CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft
|
CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft
|
||||||
|
@@ -1398,8 +1398,12 @@ 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_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 :Use loading indicators: {STRING2}
|
||||||
STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles
|
STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles
|
||||||
|
STR_CONFIG_SETTING_TIMETABLE_AUTOMATED :{LTBLUE}Automatically manage timetables: {ORANGE}{STRING2}
|
||||||
|
STR_CONFIG_SETTING_TIMETABLE_AUTOMATED_HELPTEXT :Whether to enable automatic timetables
|
||||||
STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Show timetable in ticks rather than days: {STRING2}
|
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_IN_TICKS_HELPTEXT :Show travel times in time tables in game ticks instead of days
|
||||||
|
STR_CONFIG_SETTING_TIMETABLE_SEPARATION :{LTBLUE}Use timetable to ensure vehicle separation: {ORANGE}{STRING2}
|
||||||
|
STR_CONFIG_SETTING_TIMETABLE_SEPARATION_HELPTEXT :Select whether to ensure separation of vehicles when using automatic timetables
|
||||||
STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2}
|
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_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables
|
||||||
STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2}
|
STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2}
|
||||||
@@ -3937,6 +3941,9 @@ STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset th
|
|||||||
STR_TIMETABLE_AUTOFILL :{BLACK}Autofill
|
STR_TIMETABLE_AUTOFILL :{BLACK}Autofill
|
||||||
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times)
|
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times)
|
||||||
|
|
||||||
|
STR_TIMETABLE_AUTOMATE :{BLACK}Automate
|
||||||
|
STR_TIMETABLE_AUTOMATE_TOOLTIP :{BLACK}Manage the timetables automatically by updating the values for each journey
|
||||||
|
|
||||||
STR_TIMETABLE_EXPECTED :{BLACK}Expected
|
STR_TIMETABLE_EXPECTED :{BLACK}Expected
|
||||||
STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled
|
STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled
|
||||||
STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled
|
STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled
|
||||||
|
@@ -1160,6 +1160,9 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
v->UpdateRealOrderIndex();
|
v->UpdateRealOrderIndex();
|
||||||
|
|
||||||
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
|
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation) v->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have an aircraft/ship, they have a mini-schedule, so update them all */
|
/* We have an aircraft/ship, they have a mini-schedule, so update them all */
|
||||||
@@ -1617,9 +1620,18 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
/* Link this vehicle in the shared-list */
|
/* Link this vehicle in the shared-list */
|
||||||
dst->AddToShared(src);
|
dst->AddToShared(src);
|
||||||
|
|
||||||
|
|
||||||
|
/* Set automation bit if target has it. */
|
||||||
|
if (HasBit(src->vehicle_flags, VF_AUTOMATE_TIMETABLE))
|
||||||
|
SetBit(dst->vehicle_flags, VF_AUTOMATE_TIMETABLE);
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation) dst->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(dst->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
|
||||||
InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
|
InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
|
||||||
InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS);
|
InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS);
|
||||||
|
|
||||||
|
|
||||||
InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
|
InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -546,6 +546,9 @@ void NORETURN SlErrorCorrupt(const char *msg);
|
|||||||
|
|
||||||
bool SaveloadCrashWithMissingNewGRFs();
|
bool SaveloadCrashWithMissingNewGRFs();
|
||||||
|
|
||||||
|
/* Hack to change savegame version in only one place. Rmv and correct if trunk. */
|
||||||
|
const int TIMESEP_SV = 190;
|
||||||
|
|
||||||
extern char _savegame_format[8];
|
extern char _savegame_format[8];
|
||||||
extern bool _do_autosave;
|
extern bool _do_autosave;
|
||||||
|
|
||||||
|
@@ -692,6 +692,9 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
|
|||||||
SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, 2, SL_MAX_VERSION),
|
SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, 2, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, 2, SL_MAX_VERSION),
|
SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, 2, SL_MAX_VERSION),
|
||||||
|
|
||||||
|
SLE_CONDREF(Vehicle, ahead_separation, REF_VEHICLE, TIMESEP_SV, SL_MAX_VERSION),
|
||||||
|
SLE_CONDREF(Vehicle, behind_separation, REF_VEHICLE, TIMESEP_SV, SL_MAX_VERSION),
|
||||||
|
|
||||||
SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, 2, SL_MAX_VERSION),
|
SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, 2, SL_MAX_VERSION),
|
||||||
SLE_CONDNULL(2, 2, 68),
|
SLE_CONDNULL(2, 2, 68),
|
||||||
SLE_CONDNULL(4, 69, 100),
|
SLE_CONDNULL(4, 69, 100),
|
||||||
@@ -699,6 +702,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
|
|||||||
SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
|
SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
|
||||||
|
|
||||||
SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION),
|
SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Vehicle, current_loading_time, SLE_UINT32, TIMESEP_SV, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION),
|
SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION),
|
||||||
|
|
||||||
SLE_CONDNULL(10, 2, 143), // old reserved space
|
SLE_CONDNULL(10, 2, 143), // old reserved space
|
||||||
|
@@ -1626,6 +1626,8 @@ static SettingsContainer &GetSettingsTree()
|
|||||||
|
|
||||||
vehicles->Add(new SettingEntry("order.no_servicing_if_no_breakdowns"));
|
vehicles->Add(new SettingEntry("order.no_servicing_if_no_breakdowns"));
|
||||||
vehicles->Add(new SettingEntry("order.serviceathelipad"));
|
vehicles->Add(new SettingEntry("order.serviceathelipad"));
|
||||||
|
vehicles->Add(new SettingEntry("order.timetable_automated"));
|
||||||
|
vehicles->Add(new SettingEntry("order.timetable_separation"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS));
|
SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS));
|
||||||
|
@@ -438,6 +438,8 @@ struct OrderSettings {
|
|||||||
bool gradual_loading; ///< load vehicles gradually
|
bool gradual_loading; ///< load vehicles gradually
|
||||||
bool selectgoods; ///< only send the goods to station if a train has been there
|
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 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)
|
bool serviceathelipad; ///< service helicopters at helipads automatically (no need to send to depot)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -56,7 +56,8 @@ public:
|
|||||||
offset(0),
|
offset(0),
|
||||||
num_param(size)
|
num_param(size)
|
||||||
{
|
{
|
||||||
assert(size <= parent.GetDataLeft());
|
uint left = parent.GetDataLeft();
|
||||||
|
assert(size <= left);
|
||||||
if (parent.type == NULL) {
|
if (parent.type == NULL) {
|
||||||
this->type = NULL;
|
this->type = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -327,6 +327,24 @@ min = 0
|
|||||||
max = 3
|
max = 3
|
||||||
cat = SC_BASIC
|
cat = SC_BASIC
|
||||||
|
|
||||||
|
[SDT_BOOL]
|
||||||
|
base = GameSettings
|
||||||
|
var = order.timetable_automated
|
||||||
|
from = TIMESEP_SV
|
||||||
|
def = true
|
||||||
|
str = STR_CONFIG_SETTING_TIMETABLE_AUTOMATED
|
||||||
|
strhelp = STR_CONFIG_SETTING_TIMETABLE_AUTOMATED_HELPTEXT
|
||||||
|
cat = SC_EXPERT
|
||||||
|
|
||||||
|
[SDT_BOOL]
|
||||||
|
base = GameSettings
|
||||||
|
var = order.timetable_separation
|
||||||
|
from = TIMESEP_SV
|
||||||
|
def = true
|
||||||
|
str = STR_CONFIG_SETTING_TIMETABLE_SEPARATION
|
||||||
|
strhelp = STR_CONFIG_SETTING_TIMETABLE_SEPARATION_HELPTEXT
|
||||||
|
cat = SC_EXPERT
|
||||||
|
|
||||||
; There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow
|
; There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow
|
||||||
; these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI.
|
; these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI.
|
||||||
[SDT_OMANY]
|
[SDT_OMANY]
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "date_func.h"
|
#include "date_func.h"
|
||||||
#include "window_func.h"
|
#include "window_func.h"
|
||||||
#include "vehicle_base.h"
|
#include "vehicle_base.h"
|
||||||
|
#include "settings_type.h"
|
||||||
#include "cmd_helper.h"
|
#include "cmd_helper.h"
|
||||||
#include "core/sort_func.hpp"
|
#include "core/sort_func.hpp"
|
||||||
|
|
||||||
@@ -355,6 +356,167 @@ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
|||||||
return CommandCost();
|
return CommandCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start or stop automatic management of timetables.
|
||||||
|
* @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 automation.
|
||||||
|
* - p2 = (bit 1) - Ctrl was pressed. Used when disabling to keep times.
|
||||||
|
* @param text unused
|
||||||
|
* @return the cost of this operation or an error
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
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)) {
|
||||||
|
/* Automated timetable. Set flags and clear current times. */
|
||||||
|
SetBit(v2->vehicle_flags, VF_AUTOMATE_TIMETABLE);
|
||||||
|
ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
|
||||||
|
ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
|
||||||
|
ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
v2->timetable_start = 0;
|
||||||
|
v2->lateness_counter = 0;
|
||||||
|
v2->current_loading_time = 0;
|
||||||
|
v2->ClearSeparation();
|
||||||
|
} else {
|
||||||
|
/* De-automate timetable. Clear flags. */
|
||||||
|
ClrBit(v2->vehicle_flags, VF_AUTOMATE_TIMETABLE);
|
||||||
|
ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
|
||||||
|
ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
|
||||||
|
v2->ClearSeparation();
|
||||||
|
if (!HasBit(p2, 1)) {
|
||||||
|
/* Ctrl wasn't pressed, so clear all timetabled times. */
|
||||||
|
SetBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
v2->timetable_start = 0;
|
||||||
|
v2->lateness_counter = 0;
|
||||||
|
v2->current_loading_time = 0;
|
||||||
|
OrderList *orders = v2->orders.list;
|
||||||
|
if (orders != NULL) {
|
||||||
|
for (int i = 0; i < orders->GetNumOrders(); i++) {
|
||||||
|
ChangeTimetable(v2, i, 0, MTF_WAIT_TIME, true);
|
||||||
|
ChangeTimetable(v2, i, 0, MTF_TRAVEL_TIME, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommandCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TimeToFinishOrder(Vehicle *v, int n)
|
||||||
|
{
|
||||||
|
int left;
|
||||||
|
Order *order = v->GetOrder(n);
|
||||||
|
int wait_time = order->GetWaitTime();
|
||||||
|
int travel_time = order->GetTravelTime();
|
||||||
|
assert(order != NULL);
|
||||||
|
if ((v->cur_real_order_index == n) && (v->last_station_visited == order->GetDestination())) {
|
||||||
|
if (wait_time == 0) return -1;
|
||||||
|
if (v->current_loading_time > 0) {
|
||||||
|
left = wait_time - v->current_order_time;
|
||||||
|
} else {
|
||||||
|
left = wait_time;
|
||||||
|
}
|
||||||
|
if (left < 0) left = 0;
|
||||||
|
} else {
|
||||||
|
left = travel_time;
|
||||||
|
if (v->cur_real_order_index == n) left -= v->current_order_time;
|
||||||
|
if (travel_time == 0 || wait_time == 0) return -1;
|
||||||
|
if (left < 0) left = 0;
|
||||||
|
left +=wait_time;
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SeparationBetween(Vehicle *v1, Vehicle *v2)
|
||||||
|
{
|
||||||
|
if (v1 == v2) return -1;
|
||||||
|
int separation = 0;
|
||||||
|
int time;
|
||||||
|
int n = v1->cur_real_order_index;
|
||||||
|
while (n != v2->cur_real_order_index) {
|
||||||
|
time = TimeToFinishOrder(v1, n);
|
||||||
|
if (time == -1) return -1;
|
||||||
|
separation += time;
|
||||||
|
n++;
|
||||||
|
if (n >= v1->GetNumOrders()) n = 0;
|
||||||
|
}
|
||||||
|
int time1 = TimeToFinishOrder(v1, n);
|
||||||
|
int time2 = TimeToFinishOrder(v2, n);
|
||||||
|
if (time1 == -1 || time2 == -1) return -1;
|
||||||
|
time = time1 - time2;
|
||||||
|
if (time < 0) {
|
||||||
|
for (n = 0; n < v1->GetNumOrders(); n++) {
|
||||||
|
Order *order = v1->GetOrder(n);
|
||||||
|
int wait_time = order->GetWaitTime();
|
||||||
|
int travel_time = order->GetTravelTime();
|
||||||
|
if (travel_time == 0 || wait_time == 0) return -1;
|
||||||
|
time += travel_time + wait_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
separation += time;
|
||||||
|
assert(separation >= 0);
|
||||||
|
if (separation == 0) return -1;
|
||||||
|
return separation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateSeparationOrder(Vehicle *v_start)
|
||||||
|
{
|
||||||
|
/* First check if we have a vehicle ahead, and if not search for one. */
|
||||||
|
if (v_start->AheadSeparation() == NULL) {
|
||||||
|
v_start->InitSeparation();
|
||||||
|
}
|
||||||
|
if (v_start->AheadSeparation() == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Switch positions if necessary. */
|
||||||
|
int swaps = 0;
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
done = true;
|
||||||
|
int min_sep = SeparationBetween(v_start, v_start->AheadSeparation());
|
||||||
|
Vehicle *v = v_start;
|
||||||
|
do {
|
||||||
|
if (v != v_start) {
|
||||||
|
int tmp_sep = SeparationBetween(v_start, v);
|
||||||
|
if (tmp_sep < min_sep && tmp_sep != -1) {
|
||||||
|
swaps++;
|
||||||
|
if (swaps >= 50) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
done = false;
|
||||||
|
v_start->ClearSeparation();
|
||||||
|
v_start->AddToSeparationBehind(v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int separation_ahead = SeparationBetween(v, v->AheadSeparation());
|
||||||
|
int separation_behind = SeparationBetween(v->BehindSeparation(), v);
|
||||||
|
v->lateness_counter = (separation_ahead - separation_behind) / 2;
|
||||||
|
if (separation_ahead == -1 || separation_behind == -1) v->lateness_counter = 0;
|
||||||
|
v = v->AheadSeparation();
|
||||||
|
} while (v != v_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the timetable for the vehicle.
|
* Update the timetable for the vehicle.
|
||||||
* @param v The vehicle to update the timetable for.
|
* @param v The vehicle to update the timetable for.
|
||||||
@@ -362,9 +524,12 @@ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
|||||||
*/
|
*/
|
||||||
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
|
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
|
||||||
{
|
{
|
||||||
|
if (!travelling) v->current_loading_time++; // +1 because this time is one tick behind
|
||||||
uint time_taken = v->current_order_time;
|
uint time_taken = v->current_order_time;
|
||||||
|
uint time_loading = v->current_loading_time;
|
||||||
|
|
||||||
v->current_order_time = 0;
|
v->current_order_time = 0;
|
||||||
|
v->current_loading_time = 0;
|
||||||
|
|
||||||
if (v->current_order.IsType(OT_IMPLICIT)) return; // no timetabling of auto orders
|
if (v->current_order.IsType(OT_IMPLICIT)) return; // no timetabling of auto orders
|
||||||
|
|
||||||
@@ -375,6 +540,18 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
|
|||||||
|
|
||||||
bool just_started = false;
|
bool just_started = false;
|
||||||
|
|
||||||
|
/* Start automated timetables at first opportunity */
|
||||||
|
if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED) && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
|
||||||
|
if (_settings_game.order.timetable_separation) v->ClearSeparation();
|
||||||
|
SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
v->lateness_counter = 0;
|
||||||
|
if (_settings_game.order.timetable_separation) UpdateSeparationOrder(v);
|
||||||
|
for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
|
||||||
|
SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* This vehicle is arriving at the first destination in the timetable. */
|
/* This vehicle is arriving at the first destination in the timetable. */
|
||||||
if (v->cur_real_order_index == first_manual_order && travelling) {
|
if (v->cur_real_order_index == first_manual_order && travelling) {
|
||||||
/* If the start date hasn't been set, or it was set automatically when
|
/* If the start date hasn't been set, or it was set automatically when
|
||||||
@@ -437,12 +614,60 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
|
|||||||
uint timetabled = travelling ? v->current_order.GetTimetabledTravel() :
|
uint timetabled = travelling ? v->current_order.GetTimetabledTravel() :
|
||||||
v->current_order.GetTimetabledWait();
|
v->current_order.GetTimetabledWait();
|
||||||
|
|
||||||
|
/* Update the timetable to gradually shift order times towards the actual travel times. */
|
||||||
|
if (timetabled != 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
|
||||||
|
int32 new_time;
|
||||||
|
if (travelling) {
|
||||||
|
new_time = time_taken;
|
||||||
|
} else {
|
||||||
|
new_time = time_loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for too large a difference from expected time, and if so don't average. */
|
||||||
|
if (!(new_time > (int32)timetabled * 2 || new_time < (int32)timetabled / 2)) {
|
||||||
|
int arrival_error = timetabled - new_time;
|
||||||
|
/* Compute running average, with sign conversion to avoid negative overflow. */
|
||||||
|
new_time = ((int32)timetabled * 4 + new_time + 2) / 5;
|
||||||
|
/* Use arrival_error to finetune order ticks. */
|
||||||
|
if (arrival_error < 0) new_time++;
|
||||||
|
if (arrival_error > 0) new_time--;
|
||||||
|
} else if (new_time > (int32)timetabled * 10 && travelling) {
|
||||||
|
/* Possible jam, clear time and restart timetable for all vehicles.
|
||||||
|
* Otherwise we risk trains blocking 1-lane stations for long times. */
|
||||||
|
ChangeTimetable(v, v->cur_real_order_index, 0, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
|
||||||
|
for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
|
||||||
|
if (_settings_game.order.timetable_separation) v2->ClearSeparation();
|
||||||
|
ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_time < 1) new_time = 1;
|
||||||
|
if (new_time != (int32)timetabled)
|
||||||
|
ChangeTimetable(v, v->cur_real_order_index, new_time, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
|
||||||
|
} else if (timetabled == 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
|
||||||
|
/* Add times for orders that are not yet timetabled, even while not autofilling */
|
||||||
|
if (travelling)
|
||||||
|
ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
|
||||||
|
else
|
||||||
|
ChangeTimetable(v, v->cur_real_order_index, time_loading, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
|
||||||
|
}
|
||||||
|
|
||||||
/* Vehicles will wait at stations if they arrive early even if they are not
|
/* Vehicles will wait at stations if they arrive early even if they are not
|
||||||
* timetabled to wait there, so make sure the lateness counter is updated
|
* timetabled to wait there, so make sure the lateness counter is updated
|
||||||
* when this happens. */
|
* when this happens. */
|
||||||
if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
|
if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation && HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) {
|
||||||
|
v->current_order_time = time_taken;
|
||||||
|
v->current_loading_time = time_loading;
|
||||||
|
UpdateSeparationOrder(v);
|
||||||
|
v->current_order_time = 0;
|
||||||
|
v->current_loading_time = 0;
|
||||||
|
} else {
|
||||||
v->lateness_counter -= (timetabled - time_taken);
|
v->lateness_counter -= (timetabled - time_taken);
|
||||||
|
}
|
||||||
|
|
||||||
/* When we are more late than this timetabled bit takes we (somewhat expensively)
|
/* When we are more late than this timetabled bit takes we (somewhat expensively)
|
||||||
* check how many ticks the (fully filled) timetable has. If a timetable cycle is
|
* check how many ticks the (fully filled) timetable has. If a timetable cycle is
|
||||||
|
@@ -324,6 +324,7 @@ struct TimetableWindow : Window {
|
|||||||
this->SetWidgetDisabledState(WID_VT_START_DATE, v->orders.list == NULL);
|
this->SetWidgetDisabledState(WID_VT_START_DATE, v->orders.list == NULL);
|
||||||
this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == NULL);
|
this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == NULL);
|
||||||
this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == NULL);
|
this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == NULL);
|
||||||
|
this->EnableWidget(WID_VT_AUTOMATE);
|
||||||
} else {
|
} else {
|
||||||
this->DisableWidget(WID_VT_START_DATE);
|
this->DisableWidget(WID_VT_START_DATE);
|
||||||
this->DisableWidget(WID_VT_CHANGE_TIME);
|
this->DisableWidget(WID_VT_CHANGE_TIME);
|
||||||
@@ -332,10 +333,17 @@ struct TimetableWindow : Window {
|
|||||||
this->DisableWidget(WID_VT_CLEAR_SPEED);
|
this->DisableWidget(WID_VT_CLEAR_SPEED);
|
||||||
this->DisableWidget(WID_VT_RESET_LATENESS);
|
this->DisableWidget(WID_VT_RESET_LATENESS);
|
||||||
this->DisableWidget(WID_VT_AUTOFILL);
|
this->DisableWidget(WID_VT_AUTOFILL);
|
||||||
|
this->DisableWidget(WID_VT_AUTOMATE);
|
||||||
this->DisableWidget(WID_VT_SHARED_ORDER_LIST);
|
this->DisableWidget(WID_VT_SHARED_ORDER_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->SetWidgetLoweredState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
|
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->DrawWidgets();
|
this->DrawWidgets();
|
||||||
}
|
}
|
||||||
@@ -601,6 +609,14 @@ struct TimetableWindow : Window {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case WID_VT_AUTOMATE: {
|
||||||
|
uint32 p2 = 0;
|
||||||
|
if (!HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) SetBit(p2, 0);
|
||||||
|
if (!_ctrl_pressed) SetBit(p2, 1);
|
||||||
|
DoCommandP(0, v->index, p2, CMD_AUTOMATE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case WID_VT_EXPECTED:
|
case WID_VT_EXPECTED:
|
||||||
this->show_expected = !this->show_expected;
|
this->show_expected = !this->show_expected;
|
||||||
break;
|
break;
|
||||||
@@ -645,6 +661,7 @@ struct TimetableWindow : Window {
|
|||||||
void UpdateSelectionStates()
|
void UpdateSelectionStates()
|
||||||
{
|
{
|
||||||
this->GetWidget<NWidgetStacked>(WID_VT_ARRIVAL_DEPARTURE_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : SZSP_NONE);
|
this->GetWidget<NWidgetStacked>(WID_VT_ARRIVAL_DEPARTURE_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : SZSP_NONE);
|
||||||
|
// this->GetWidget<NWidgetStacked>(TTV_AUTO_SELECTION)->SetDisplayedPlane(!_settings_game.order.timetable_automated ? 0 : 1);
|
||||||
this->GetWidget<NWidgetStacked>(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1);
|
this->GetWidget<NWidgetStacked>(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -682,6 +699,7 @@ static const NWidgetPart _nested_timetable_widgets[] = {
|
|||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
||||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOFILL), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOFILL, STR_TIMETABLE_AUTOFILL_TOOLTIP),
|
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOFILL), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOFILL, STR_TIMETABLE_AUTOFILL_TOOLTIP),
|
||||||
|
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOMATE), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOMATE, STR_TIMETABLE_AUTOMATE_TOOLTIP),
|
||||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VT_EXPECTED_SELECTION),
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VT_EXPECTED_SELECTION),
|
||||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_EXPECTED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BLACK_STRING, STR_TIMETABLE_EXPECTED_TOOLTIP),
|
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_EXPECTED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BLACK_STRING, STR_TIMETABLE_EXPECTED_TOOLTIP),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
|
NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
|
||||||
@@ -690,6 +708,7 @@ static const NWidgetPart _nested_timetable_widgets[] = {
|
|||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
||||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VT_SHARED_ORDER_LIST), SetFill(0, 1), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP),
|
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VT_SHARED_ORDER_LIST), SetFill(0, 1), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
|
||||||
NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetFill(0, 1),
|
NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetFill(0, 1),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
|
@@ -209,6 +209,9 @@ uint Vehicle::Crash(bool flooded)
|
|||||||
v->MarkAllViewportsDirty();
|
v->MarkAllViewportsDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation) this->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
|
||||||
/* Dirty some windows */
|
/* Dirty some windows */
|
||||||
InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
|
InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
||||||
@@ -2138,6 +2141,10 @@ void Vehicle::HandleLoading(bool mode)
|
|||||||
case OT_LOADING: {
|
case OT_LOADING: {
|
||||||
uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
|
uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
|
||||||
|
|
||||||
|
/* Save time just loading took since that is what goes into the timetable */
|
||||||
|
if (!HasBit(this->vehicle_flags, VF_LOADING_FINISHED))
|
||||||
|
this->current_loading_time = this->current_order_time;
|
||||||
|
|
||||||
/* Not the first call for this tick, or still loading */
|
/* Not the first call for this tick, or still loading */
|
||||||
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
|
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
|
||||||
|
|
||||||
@@ -2214,6 +2221,8 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
|
|||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
this->current_order.SetDepotOrderType(ODTF_MANUAL);
|
this->current_order.SetDepotOrderType(ODTF_MANUAL);
|
||||||
this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
|
this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
|
||||||
|
if (_settings_game.order.timetable_separation) this->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
||||||
}
|
}
|
||||||
return CommandCost();
|
return CommandCost();
|
||||||
@@ -2230,6 +2239,9 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
|
|||||||
SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
|
SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation) this->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
|
||||||
this->current_order.MakeDummy();
|
this->current_order.MakeDummy();
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
||||||
}
|
}
|
||||||
@@ -2575,6 +2587,55 @@ void Vehicle::SetNext(Vehicle *next)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Vehicle::ClearSeparation()
|
||||||
|
{
|
||||||
|
if (this->ahead_separation == NULL && this->behind_separation == NULL) return;
|
||||||
|
|
||||||
|
assert(this->ahead_separation != NULL);
|
||||||
|
assert(this->behind_separation != NULL);
|
||||||
|
|
||||||
|
this->ahead_separation->behind_separation = this->behind_separation;
|
||||||
|
this->behind_separation->ahead_separation = this->ahead_separation;
|
||||||
|
|
||||||
|
this->ahead_separation = NULL;
|
||||||
|
this->behind_separation = NULL;
|
||||||
|
|
||||||
|
SetWindowDirty(WC_VEHICLE_TIMETABLE, this->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vehicle::InitSeparation()
|
||||||
|
{
|
||||||
|
assert(this->ahead_separation == NULL && this->behind_separation == NULL);
|
||||||
|
Vehicle *best_match = this;
|
||||||
|
int lowest_separation;
|
||||||
|
for (Vehicle *v_other = this->FirstShared(); v_other != NULL; v_other = v_other->NextShared()) {
|
||||||
|
if ((HasBit(v_other->vehicle_flags, VF_TIMETABLE_STARTED)) && v_other != this) {
|
||||||
|
if (best_match == this) {
|
||||||
|
best_match = v_other;
|
||||||
|
lowest_separation = 0; // TODO call SeparationBetween() here
|
||||||
|
} else {
|
||||||
|
int temp_sep = 0; // TODO call SeparationBetween() here
|
||||||
|
if (temp_sep < lowest_separation && temp_sep != -1) {
|
||||||
|
best_match = v_other;
|
||||||
|
lowest_separation = temp_sep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->AddToSeparationBehind(best_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vehicle::AddToSeparationBehind(Vehicle *v_other)
|
||||||
|
{
|
||||||
|
if (v_other->ahead_separation == NULL) v_other->ahead_separation = v_other;
|
||||||
|
if (v_other->behind_separation == NULL) v_other->behind_separation = v_other;
|
||||||
|
|
||||||
|
this->ahead_separation = v_other;
|
||||||
|
v_other->behind_separation->ahead_separation = this;
|
||||||
|
this->behind_separation = v_other->behind_separation;
|
||||||
|
v_other->behind_separation = this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds this vehicle to a shared vehicle chain.
|
* Adds this vehicle to a shared vehicle chain.
|
||||||
* @param shared_chain a vehicle of the chain with shared vehicles.
|
* @param shared_chain a vehicle of the chain with shared vehicles.
|
||||||
@@ -2632,6 +2693,9 @@ void Vehicle::RemoveFromShared()
|
|||||||
|
|
||||||
this->next_shared = NULL;
|
this->next_shared = NULL;
|
||||||
this->previous_shared = NULL;
|
this->previous_shared = NULL;
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation) this->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VehiclesYearlyLoop()
|
void VehiclesYearlyLoop()
|
||||||
|
@@ -46,6 +46,7 @@ enum VehicleFlags {
|
|||||||
VF_TIMETABLE_STARTED, ///< Whether the vehicle has started running on the timetable yet.
|
VF_TIMETABLE_STARTED, ///< Whether the vehicle has started running on the timetable yet.
|
||||||
VF_AUTOFILL_TIMETABLE, ///< Whether the vehicle should fill in the timetable automatically.
|
VF_AUTOFILL_TIMETABLE, ///< Whether the vehicle should fill in the timetable automatically.
|
||||||
VF_AUTOFILL_PRES_WAIT_TIME, ///< Whether non-destructive auto-fill should preserve waiting times
|
VF_AUTOFILL_PRES_WAIT_TIME, ///< Whether non-destructive auto-fill should preserve waiting times
|
||||||
|
VF_AUTOMATE_TIMETABLE, ///< Whether the vehicle should manage the timetable automatically.
|
||||||
VF_STOP_LOADING, ///< Don't load anymore during the next load cycle.
|
VF_STOP_LOADING, ///< Don't load anymore during the next load cycle.
|
||||||
VF_PATHFINDER_LOST, ///< Vehicle's pathfinder is lost.
|
VF_PATHFINDER_LOST, ///< Vehicle's pathfinder is lost.
|
||||||
VF_SERVINT_IS_CUSTOM, ///< Service interval is custom.
|
VF_SERVINT_IS_CUSTOM, ///< Service interval is custom.
|
||||||
@@ -163,6 +164,9 @@ private:
|
|||||||
Vehicle *next_shared; ///< pointer to the next vehicle that shares the order
|
Vehicle *next_shared; ///< pointer to the next vehicle that shares the order
|
||||||
Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain
|
Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain
|
||||||
|
|
||||||
|
Vehicle *ahead_separation;
|
||||||
|
Vehicle *behind_separation;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code
|
friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code
|
||||||
friend void FixOldVehicles();
|
friend void FixOldVehicles();
|
||||||
@@ -184,6 +188,13 @@ public:
|
|||||||
|
|
||||||
CargoPayment *cargo_payment; ///< The cargo payment we're currently in
|
CargoPayment *cargo_payment; ///< The cargo payment we're currently in
|
||||||
|
|
||||||
|
|
||||||
|
/* Used for timetabling. */
|
||||||
|
uint32 current_order_time; ///< How many ticks have passed since this order started.
|
||||||
|
uint32 current_loading_time; ///< How long loading took. Less than current_order_time if vehicle is early.
|
||||||
|
int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
|
||||||
|
Date timetable_start; ///< When the vehicle is supposed to start the timetable.
|
||||||
|
|
||||||
Rect coord; ///< NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
|
Rect coord; ///< NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
|
||||||
|
|
||||||
Vehicle *hash_viewport_next; ///< NOSAVE: Next vehicle in the visual location hash.
|
Vehicle *hash_viewport_next; ///< NOSAVE: Next vehicle in the visual location hash.
|
||||||
@@ -595,6 +606,37 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
|
inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the vehicle ahead on track.
|
||||||
|
* @return the vehicle ahead on track or NULL when there isn't one.
|
||||||
|
*/
|
||||||
|
inline Vehicle *AheadSeparation() const { return this->ahead_separation; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the vehicle behind on track.
|
||||||
|
* @return the vehicle behind on track or NULL when there isn't one.
|
||||||
|
*/
|
||||||
|
inline Vehicle *BehindSeparation() const { return this->behind_separation; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears a vehicle's separation status, removing it from any chain.
|
||||||
|
*/
|
||||||
|
void ClearSeparation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds this vehicle to a shared vehicle separation chain.
|
||||||
|
* @param v_other a vehicle of the separation chain
|
||||||
|
* @pre !this->IsOrderListShared()
|
||||||
|
*/
|
||||||
|
void InitSeparation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds this vehicle behind another in a separation chain.
|
||||||
|
* @param v_other a vehicle of the separation chain.
|
||||||
|
* @pre !this->IsOrderListShared()
|
||||||
|
*/
|
||||||
|
void AddToSeparationBehind(Vehicle *v_other);
|
||||||
|
|
||||||
void AddToShared(Vehicle *shared_chain);
|
void AddToShared(Vehicle *shared_chain);
|
||||||
void RemoveFromShared();
|
void RemoveFromShared();
|
||||||
|
|
||||||
@@ -662,6 +704,17 @@ public:
|
|||||||
|
|
||||||
this->profit_this_year = src->profit_this_year;
|
this->profit_this_year = src->profit_this_year;
|
||||||
this->profit_last_year = src->profit_last_year;
|
this->profit_last_year = src->profit_last_year;
|
||||||
|
|
||||||
|
this->current_order_time = src->current_order_time;
|
||||||
|
this->current_loading_time = src->current_loading_time;
|
||||||
|
this->lateness_counter = src->lateness_counter;
|
||||||
|
this->timetable_start = src->timetable_start;
|
||||||
|
|
||||||
|
if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
|
||||||
|
if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
|
||||||
|
|
||||||
|
this->service_interval = src->service_interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -569,6 +569,9 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
|||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(p1, STR_NEWS_TRAIN_IS_WAITING + v->type);
|
if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(p1, STR_NEWS_TRAIN_IS_WAITING + v->type);
|
||||||
|
|
||||||
|
if (_settings_game.order.timetable_separation) v->ClearSeparation();
|
||||||
|
if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
|
|
||||||
v->vehstatus ^= VS_STOPPED;
|
v->vehstatus ^= VS_STOPPED;
|
||||||
if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
|
if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly'
|
||||||
v->MarkDirty();
|
v->MarkDirty();
|
||||||
|
@@ -25,9 +25,11 @@ enum VehicleTimetableWidgets {
|
|||||||
WID_VT_CLEAR_TIME, ///< Clear time button.
|
WID_VT_CLEAR_TIME, ///< Clear time button.
|
||||||
WID_VT_RESET_LATENESS, ///< Reset lateness button.
|
WID_VT_RESET_LATENESS, ///< Reset lateness button.
|
||||||
WID_VT_AUTOFILL, ///< Autofill button.
|
WID_VT_AUTOFILL, ///< Autofill button.
|
||||||
|
WID_VT_AUTOMATE, ///< Automate button.
|
||||||
WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals.
|
WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals.
|
||||||
WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list.
|
WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list.
|
||||||
WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel.
|
WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel.
|
||||||
|
WID_VT_AUTO_SELECTION, ///< Disable/hide the automate button.
|
||||||
WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button.
|
WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button.
|
||||||
WID_VT_CHANGE_SPEED, ///< Change speed limit button.
|
WID_VT_CHANGE_SPEED, ///< Change speed limit button.
|
||||||
WID_VT_CLEAR_SPEED, ///< Clear speed limit button.
|
WID_VT_CLEAR_SPEED, ///< Clear speed limit button.
|
||||||
|
Reference in New Issue
Block a user