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 break;
00122
00123 default:
00124 NOT_REACHED();
00125 }
00126
00127 if (wait_time != order->wait_time) {
00128 switch (order->GetType()) {
00129 case OT_GOTO_STATION:
00130 if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE);
00131 break;
00132
00133 case OT_CONDITIONAL:
00134 break;
00135
00136 default: return_cmd_error(STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS);
00137 }
00138 }
00139
00140 if (travel_time != order->travel_time && order->IsType(OT_CONDITIONAL)) return CMD_ERROR;
00141 if (max_speed != order->max_speed && (order->IsType(OT_CONDITIONAL) || v->type == VEH_AIRCRAFT)) return CMD_ERROR;
00142
00143 if (flags & DC_EXEC) {
00144 if (wait_time != order->wait_time) ChangeTimetable(v, order_number, wait_time, MTF_WAIT_TIME);
00145 if (travel_time != order->travel_time) ChangeTimetable(v, order_number, travel_time, MTF_TRAVEL_TIME);
00146 if (max_speed != order->max_speed) ChangeTimetable(v, order_number, max_speed, MTF_TRAVEL_SPEED);
00147 }
00148
00149 return CommandCost();
00150 }
00151
00162 CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00163 {
00164 VehicleID veh = GB(p1, 0, 20);
00165
00166 Vehicle *v = Vehicle::GetIfValid(veh);
00167 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00168
00169 CommandCost ret = CheckOwnership(v->owner);
00170 if (ret.Failed()) return ret;
00171
00172 if (flags & DC_EXEC) {
00173 v->lateness_counter = 0;
00174 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00175 }
00176
00177 return CommandCost();
00178 }
00179
00189 CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00190 {
00191 Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
00192 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00193
00194 CommandCost ret = CheckOwnership(v->owner);
00195 if (ret.Failed()) return ret;
00196
00197
00198 Date start_date = (Date)p2;
00199 if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
00200 if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00201 if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
00202
00203 if (flags & DC_EXEC) {
00204 v->lateness_counter = 0;
00205 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00206 v->timetable_start = start_date;
00207
00208 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00209 }
00210
00211 return CommandCost();
00212 }
00213
00214
00228 CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00229 {
00230 VehicleID veh = GB(p1, 0, 20);
00231
00232 Vehicle *v = Vehicle::GetIfValid(veh);
00233 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00234
00235 CommandCost ret = CheckOwnership(v->owner);
00236 if (ret.Failed()) return ret;
00237
00238 if (flags & DC_EXEC) {
00239 if (HasBit(p2, 0)) {
00240
00241
00242
00243 SetBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00244 ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00245
00246
00247 if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00248
00249 v->timetable_start = 0;
00250 v->lateness_counter = 0;
00251 } else {
00252 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00253 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00254 }
00255
00256 for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
00257 if (v2 != v) {
00258
00259 ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00260 ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00261 }
00262 SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index);
00263 }
00264 }
00265
00266 return CommandCost();
00267 }
00268
00274 void UpdateVehicleTimetable(Vehicle *v, bool travelling)
00275 {
00276 uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time;
00277 uint time_taken = v->current_order_time;
00278
00279 v->current_order_time = 0;
00280
00281 if (v->current_order.IsType(OT_IMPLICIT)) return;
00282
00283 VehicleOrderID first_manual_order = 0;
00284 for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) {
00285 ++first_manual_order;
00286 }
00287
00288 bool just_started = false;
00289
00290
00291 if (v->cur_real_order_index == first_manual_order && travelling) {
00292
00293
00294
00295
00296 just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00297
00298 if (v->timetable_start != 0) {
00299 v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract;
00300 v->timetable_start = 0;
00301 }
00302
00303 SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
00304 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00305 }
00306
00307 if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
00308
00309 if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) {
00310 if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) {
00311
00312 v->current_order.wait_time = 0;
00313 }
00314
00315 if (just_started) return;
00316
00317
00318
00319 if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) {
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS;
00330
00331 ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME);
00332 }
00333
00334 if (v->cur_real_order_index == first_manual_order && travelling) {
00335
00336
00337
00338 ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00339 ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00340 }
00341 return;
00342 }
00343
00344 if (just_started) return;
00345
00346
00347
00348
00349 if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return;
00350
00351 v->lateness_counter -= (timetabled - time_taken);
00352
00353
00354
00355
00356
00357
00358 if (v->lateness_counter > (int)timetabled) {
00359 Ticks cycle = v->orders.list->GetTimetableTotalDuration();
00360 if (cycle != INVALID_TICKS && v->lateness_counter > cycle) {
00361 v->lateness_counter %= cycle;
00362 }
00363 }
00364
00365 for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
00366 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00367 }
00368 }