00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "command_func.h"
00014 #include "company_func.h"
00015 #include "date_func.h"
00016 #include "window_func.h"
00017 #include "vehicle_base.h"
00018 #include "cmd_helper.h"
00019
00020 #include "table/strings.h"
00021
00029 static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 val, ModifyTimetableFlags mtf)
00030 {
00031 Order *order = v->GetOrder(order_number);
00032 int delta = 0;
00033
00034 switch (mtf) {
00035 case MTF_WAIT_TIME:
00036 delta = val - order->wait_time;
00037 order->wait_time = val;
00038 break;
00039
00040 case MTF_TRAVEL_TIME:
00041 delta = val - order->travel_time;
00042 order->travel_time = val;
00043 break;
00044
00045 case MTF_TRAVEL_SPEED:
00046 order->max_speed = val;
00047 break;
00048
00049 default:
00050 NOT_REACHED();
00051 }
00052 v->orders.list->UpdateOrderTimetable(delta);
00053
00054 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00055 if (v->cur_real_order_index == order_number && v->current_order.Equals(*order)) {
00056 switch (mtf) {
00057 case MTF_WAIT_TIME:
00058 v->current_order.wait_time = val;
00059 break;
00060
00061 case MTF_TRAVEL_TIME:
00062 v->current_order.travel_time = val;
00063 break;
00064
00065 case MTF_TRAVEL_SPEED:
00066 v->current_order.max_speed = val;
00067 break;
00068
00069 default:
00070 NOT_REACHED();
00071 }
00072 }
00073 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00074 }
00075 }
00076
00090 CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00091 {
00092 VehicleID veh = GB(p1, 0, 20);
00093
00094 Vehicle *v = Vehicle::GetIfValid(veh);
00095 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00096
00097 CommandCost ret = CheckOwnership(v->owner);
00098 if (ret.Failed()) return ret;
00099
00100 VehicleOrderID order_number = GB(p1, 20, 8);
00101 Order *order = v->GetOrder(order_number);
00102 if (order == NULL || order->IsType(OT_IMPLICIT)) return CMD_ERROR;
00103
00104 ModifyTimetableFlags mtf = Extract<ModifyTimetableFlags, 28, 2>(p1);
00105 if (mtf >= MTF_END) return CMD_ERROR;
00106
00107 int wait_time = order->wait_time;
00108 int travel_time = order->travel_time;
00109 int max_speed = order->max_speed;
00110 switch (mtf) {
00111 case MTF_WAIT_TIME:
00112 wait_time = GB(p2, 0, 16);
00113 break;
00114
00115 case MTF_TRAVEL_TIME:
00116 travel_time = GB(p2, 0, 16);
00117 break;
00118
00119 case MTF_TRAVEL_SPEED:
00120 max_speed = GB(p2, 0, 16);
00121 if (max_speed == 0) max_speed = UINT16_MAX;
00122 break;
00123
00124 default:
00125 NOT_REACHED();
00126 }
00127
00128 if (wait_time != order->wait_time) {
00129 switch (order->GetType()) {
00130 case OT_GOTO_STATION:
00131 if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE);
00132 break;
00133
00134 case OT_CONDITIONAL:
00135 break;
00136
00137 default: return_cmd_error(STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS);
00138 }
00139 }
00140
00141 if (travel_time != order->travel_time && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
00142 if (max_speed != order->max_speed && (order->IsType(OT_CONDITIONAL) || v->type == VEH_AIRCRAFT)) return CMD_ERROR;
00143
00144 if (flags & DC_EXEC) {
00145 if (wait_time != order->wait_time) ChangeTimetable(v, order_number, wait_time, MTF_WAIT_TIME);
00146 if (travel_time != order->travel_time) ChangeTimetable(v, order_number, travel_time, MTF_TRAVEL_TIME);
00147 if (max_speed != order->max_speed) ChangeTimetable(v, order_number, max_speed, MTF_TRAVEL_SPEED);
00148 }
00149
00150 return CommandCost();
00151 }
00152
00163 CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00164 {
00165 VehicleID veh = GB(p1, 0, 20);
00166
00167 Vehicle *v = Vehicle::GetIfValid(veh);
00168 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00169
00170 CommandCost ret = CheckOwnership(v->owner);
00171 if (ret.Failed()) return ret;
00172
00173 if (flags & DC_EXEC) {
00174 v->lateness_counter = 0;
00175 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00176 }
00177
00178 return CommandCost();
00179 }
00180
00190 CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00191 {
00192 Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
00193 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00194
00195 CommandCost ret = CheckOwnership(v->owner);
00196 if (ret.Failed()) return ret;
00197
00198
00199 Date start_date = (Date)p2;
00200 if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
00201 if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00202 if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00203
00204 if (flags & DC_EXEC) {
00205 v->lateness_counter = 0;
00206 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00207 v->timetable_start = start_date;
00208
00209 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00210 }
00211
00212 return CommandCost();
00213 }
00214
00215
00229 CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00230 {
00231 VehicleID veh = GB(p1, 0, 20);
00232
00233 Vehicle *v = Vehicle::GetIfValid(veh);
00234 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00235
00236 CommandCost ret = CheckOwnership(v->owner);
00237 if (ret.Failed()) return ret;
00238
00239 if (flags & DC_EXEC) {
00240 if (HasBit(p2, 0)) {
00241
00242
00243
00244 SetBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00245 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00246
00247
00248 if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00249
00250 v->timetable_start = 0;
00251 v->lateness_counter = 0;
00252 } else {
00253 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00254 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00255 }
00256
00257 for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
00258 if (v2 != v) {
00259
00260 ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00261 ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00262 }
00263 SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
00264 }
00265 }
00266
00267 return CommandCost();
00268 }
00269
00275 void UpdateVehicleTimetable(Vehicle *v, bool travelling)
00276 {
00277 uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time;
00278 uint time_taken = v->current_order_time;
00279
00280 v->current_order_time = 0;
00281
00282 if (v->current_order.IsType(OT_IMPLICIT)) return;
00283
00284 VehicleOrderID first_manual_order = 0;
00285 for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) {
00286 ++first_manual_order;
00287 }
00288
00289 bool just_started = false;
00290
00291
00292 if (v->cur_real_order_index == first_manual_order && travelling) {
00293
00294
00295
00296
00297 just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00298
00299 if (v->timetable_start != 0) {
00300 v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract;
00301 v->timetable_start = 0;
00302 }
00303
00304 SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00305 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00306 }
00307
00308 if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
00309
00310 if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) {
00311 if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) {
00312
00313 v->current_order.wait_time = 0;
00314 }
00315
00316 if (just_started) return;
00317
00318
00319
00320 if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) {
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS;
00331
00332 ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME);
00333 }
00334
00335 if (v->cur_real_order_index == first_manual_order && travelling) {
00336
00337
00338
00339 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00340 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00341 }
00342 return;
00343 }
00344
00345 if (just_started) return;
00346
00347
00348
00349
00350 if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
00351
00352 v->lateness_counter -= (timetabled - time_taken);
00353
00354
00355
00356
00357
00358
00359 if (v->lateness_counter > (int)timetabled) {
00360 Ticks cycle = v->orders.list->GetTimetableTotalDuration();
00361 if (cycle != INVALID_TICKS && v->lateness_counter > cycle) {
00362 v->lateness_counter %= cycle;
00363 }
00364 }
00365
00366 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00367 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00368 }
00369 }