00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "command_func.h"
00014 #include "functions.h"
00015 #include "date_func.h"
00016 #include "window_func.h"
00017 #include "vehicle_base.h"
00018
00019 #include "table/strings.h"
00020
00021 static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 time, bool is_journey)
00022 {
00023 Order *order = v->GetOrder(order_number);
00024 int delta;
00025
00026 if (is_journey) {
00027 delta = time - order->travel_time;
00028 order->travel_time = time;
00029 } else {
00030 delta = time - order->wait_time;
00031 order->wait_time = time;
00032 }
00033 v->orders.list->UpdateOrderTimetable(delta);
00034
00035 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00036 if (v->cur_order_index == order_number && v->current_order.Equals(*order)) {
00037 if (is_journey) {
00038 v->current_order.travel_time = time;
00039 } else {
00040 v->current_order.wait_time = time;
00041 }
00042 }
00043 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00044 }
00045 }
00046
00061 CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00062 {
00063 if (!_settings_game.order.timetabling) return CMD_ERROR;
00064
00065 VehicleID veh = GB(p1, 0, 20);
00066
00067 Vehicle *v = Vehicle::GetIfValid(veh);
00068 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00069
00070 CommandCost ret = CheckOwnership(v->owner);
00071 if (ret.Failed()) return ret;
00072
00073 VehicleOrderID order_number = GB(p1, 20, 8);
00074 Order *order = v->GetOrder(order_number);
00075 if (order == NULL || order->IsType(OT_AUTOMATIC)) return CMD_ERROR;
00076
00077 bool is_journey = HasBit(p1, 28);
00078
00079 int wait_time = order->wait_time;
00080 int travel_time = order->travel_time;
00081 if (is_journey) {
00082 travel_time = GB(p2, 0, 16);
00083 } else {
00084 wait_time = GB(p2, 0, 16);
00085 }
00086
00087 if (wait_time != order->wait_time) {
00088 switch (order->GetType()) {
00089 case OT_GOTO_STATION:
00090 if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE);
00091 break;
00092
00093 case OT_CONDITIONAL:
00094 break;
00095
00096 default: return_cmd_error(STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS);
00097 }
00098 }
00099
00100 if (travel_time != order->travel_time && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
00101
00102 if (flags & DC_EXEC) {
00103 if (wait_time != order->wait_time) ChangeTimetable(v, order_number, wait_time, false);
00104 if (travel_time != order->travel_time) ChangeTimetable(v, order_number, travel_time, true);
00105 }
00106
00107 return CommandCost();
00108 }
00109
00120 CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00121 {
00122 if (!_settings_game.order.timetabling) return CMD_ERROR;
00123
00124 VehicleID veh = GB(p1, 0, 20);
00125
00126 Vehicle *v = Vehicle::GetIfValid(veh);
00127 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00128
00129 CommandCost ret = CheckOwnership(v->owner);
00130 if (ret.Failed()) return ret;
00131
00132 if (flags & DC_EXEC) {
00133 v->lateness_counter = 0;
00134 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00135 }
00136
00137 return CommandCost();
00138 }
00139
00149 CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00150 {
00151 if (!_settings_game.order.timetabling) return CMD_ERROR;
00152
00153 Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
00154 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00155
00156 CommandCost ret = CheckOwnership(v->owner);
00157 if (ret.Failed()) return ret;
00158
00159
00160 Date start_date = (Date)p2;
00161 if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
00162 if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00163 if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00164
00165 if (flags & DC_EXEC) {
00166 v->lateness_counter = 0;
00167 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00168 v->timetable_start = start_date;
00169
00170 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00171 }
00172
00173 return CommandCost();
00174 }
00175
00176
00190 CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00191 {
00192 if (!_settings_game.order.timetabling) return CMD_ERROR;
00193
00194 VehicleID veh = GB(p1, 0, 20);
00195
00196 Vehicle *v = Vehicle::GetIfValid(veh);
00197 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00198
00199 CommandCost ret = CheckOwnership(v->owner);
00200 if (ret.Failed()) return ret;
00201
00202 if (flags & DC_EXEC) {
00203 if (HasBit(p2, 0)) {
00204
00205
00206
00207 SetBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00208 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00209
00210
00211 if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00212
00213 v->timetable_start = 0;
00214 v->lateness_counter = 0;
00215 } else {
00216 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00217 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00218 }
00219
00220 for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
00221 if (v2 != v) {
00222
00223 ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00224 ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00225 }
00226 SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
00227 }
00228 }
00229
00230 return CommandCost();
00231 }
00232
00233 void UpdateVehicleTimetable(Vehicle *v, bool travelling)
00234 {
00235 uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time;
00236 uint time_taken = v->current_order_time;
00237
00238 v->current_order_time = 0;
00239
00240 if (!_settings_game.order.timetabling) return;
00241 if (v->current_order.IsType(OT_AUTOMATIC)) return;
00242
00243 VehicleOrderID first_manual_order = 0;
00244 for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_AUTOMATIC); o = o->next) {
00245 ++first_manual_order;
00246 }
00247
00248 bool just_started = false;
00249
00250
00251 if (v->cur_order_index == first_manual_order && travelling) {
00252
00253
00254
00255
00256 just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00257
00258 if (v->timetable_start != 0) {
00259 v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract;
00260 v->timetable_start = 0;
00261 }
00262
00263 SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00264 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00265 }
00266
00267 if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
00268
00269 if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) {
00270 if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) {
00271
00272 v->current_order.wait_time = 0;
00273 }
00274
00275 if (just_started) return;
00276
00277
00278
00279 if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) {
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS;
00290
00291 ChangeTimetable(v, v->cur_order_index, time_taken, travelling);
00292 }
00293
00294 if (v->cur_order_index == first_manual_order && travelling) {
00295
00296
00297
00298 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00299 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00300 }
00301 return;
00302 }
00303
00304 if (just_started) return;
00305
00306
00307
00308
00309 if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
00310
00311 v->lateness_counter -= (timetabled - time_taken);
00312
00313
00314
00315
00316
00317
00318 if (v->lateness_counter > (int)timetabled) {
00319 Ticks cycle = v->orders.list->GetTimetableTotalDuration();
00320 if (cycle != INVALID_TICKS && v->lateness_counter > cycle) {
00321 v->lateness_counter %= cycle;
00322 }
00323 }
00324
00325 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00326 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00327 }
00328 }